99 * a close button and a shadow. Used together with the WindowCloneContainer.
1010 */
1111public class Gala.WindowClone : Clutter .Actor {
12- private const int CLOSE_WINDOW_ICON_SIZE = 36 ;
1312 private const int WINDOW_ICON_SIZE = 64 ;
1413 private const int ACTIVE_SHAPE_SIZE = 12 ;
1514 private const int FADE_ANIMATION_DURATION = 200 ;
@@ -144,6 +143,11 @@ public class Gala.WindowClone : Clutter.Actor {
144143 reallocate ();
145144
146145 load_clone ();
146+
147+ window. notify[" title" ]. connect (() = > window_title. set_text (window. get_title () ?? " " ));
148+ window_title. set_text (window. get_title () ?? " " );
149+
150+ notify[" has-pointer" ]. connect (() = > update_hover_widgets ());
147151 }
148152
149153 ~WindowClone () {
@@ -186,10 +190,10 @@ public class Gala.WindowClone : Clutter.Actor {
186190 private void load_clone (bool was_waiting = false ) {
187191 var actor = (Meta . WindowActor ) window. get_compositor_private ();
188192 if (actor == null ) {
189- ulong shown_handler = 0 ;
190- shown_handler = window. shown . connect (() = > {
191- load_clone (true );
192- window . disconnect (shown_handler) ;
193+ Idle . add (() = > {
194+ if ( window. get_compositor_private () != null )
195+ load_clone (true );
196+ return Source . REMOVE ;
193197 });
194198
195199 return ;
@@ -200,6 +204,7 @@ public class Gala.WindowClone : Clutter.Actor {
200204 }
201205
202206 clone = new Clutter .Clone (actor);
207+ clone. set_content_scaling_filters (TRILINEAR , TRILINEAR );
203208 add_child (clone);
204209
205210 set_child_below_sibling (active_shape, clone);
@@ -283,17 +288,15 @@ public class Gala.WindowClone : Clutter.Actor {
283288 var target_y = outer_rect. y - offset_y;
284289
285290 active = false ;
286- in_slot_animation = true ;
287- place_widgets (outer_rect. width, outer_rect. height, initial_scale);
291+ update_hover_widgets (true );
288292
289293 new GesturePropertyTransition (this , gesture_tracker, " x" , null , (float ) target_x). start (with_gesture);
290294 new GesturePropertyTransition (this , gesture_tracker, " y" , null , (float ) target_y). start (with_gesture);
291295 new GesturePropertyTransition (this , gesture_tracker, " width" , null , (float ) outer_rect. width). start (with_gesture);
292296 new GesturePropertyTransition (this , gesture_tracker, " height" , null , (float ) outer_rect. height). start (with_gesture);
293297 new GesturePropertyTransition (this , gesture_tracker, " shadow-opacity" , (uint8 ) 255 , (uint8 ) 0 ). start (with_gesture);
294298 new GesturePropertyTransition (window_icon, gesture_tracker, " opacity" , 255u , 0u ). start (with_gesture, () = > {
295- in_slot_animation = false ;
296- place_widgets (outer_rect. width, outer_rect. height, target_scale);
299+ update_hover_widgets (false );
297300 });
298301
299302 GestureTracker . OnUpdate on_animation_update = (percentage) = > {
@@ -302,7 +305,6 @@ public class Gala.WindowClone : Clutter.Actor {
302305 var scale = GestureTracker . animation_value (initial_scale, target_scale, percentage);
303306
304307 set_window_icon_position (width, height, scale, false );
305- place_widgets ((int )width, (int )height, scale);
306308 };
307309
308310 GestureTracker . OnEnd on_animation_end = (percentage, cancel_action) = > {
@@ -335,8 +337,6 @@ public class Gala.WindowClone : Clutter.Actor {
335337 public void take_slot (Meta . Rectangle rect, bool from_window_position, bool with_gesture = false , bool is_cancel_animation = false ) {
336338#endif
337339 slot = rect;
338- in_slot_animation = true ;
339-
340340 active = false ;
341341
342342 var outer_rect = window. get_frame_rect ();
@@ -349,8 +349,8 @@ public class Gala.WindowClone : Clutter.Actor {
349349 float intial_y = from_window_position ? outer_rect. y - monitor_geom. y : y;
350350
351351 var scale = display. get_monitor_scale (display. get_monitor_index_for_rect (rect));
352- place_widgets (rect. width, rect. height, scale);
353352
353+ update_hover_widgets (true );
354354 set_window_icon_position (initial_width, initial_height, scale);
355355
356356 new GesturePropertyTransition (this , gesture_tracker, " x" , intial_x, (float ) rect. x). start (with_gesture);
@@ -359,8 +359,7 @@ public class Gala.WindowClone : Clutter.Actor {
359359 new GesturePropertyTransition (this , gesture_tracker, " height" , (float ) initial_height, (float ) rect. height). start (with_gesture);
360360 new GesturePropertyTransition (this , gesture_tracker, " shadow-opacity" , (uint8 ) 0 , (uint8 ) 255 ). start (with_gesture);
361361 new GesturePropertyTransition (window_icon, gesture_tracker, " opacity" , 0u , 255u ). start (with_gesture, () = > {
362- in_slot_animation = false ;
363- place_widgets (rect. width, rect. height, scale);
362+ update_hover_widgets (false );
364363 });
365364
366365 GestureTracker . OnUpdate on_animation_update = (percentage) = > {
@@ -393,33 +392,62 @@ public class Gala.WindowClone : Clutter.Actor {
393392 }
394393 }
395394
396- /**
397- * Except for the texture clone and the highlight all children are placed
398- * according to their given allocations. The first two are placed in a way
399- * that compensates for invisible borders of the texture.
400- */
401395 public override void allocate (Clutter . ActorBox box) {
402396 base . allocate (box);
403397
398+ if (clone == null || (drag_action != null && drag_action. dragging)) {
399+ return ;
400+ }
401+
404402 var input_rect = window. get_buffer_rect ();
405403 var outer_rect = window. get_frame_rect ();
406- var scale_factor = width / outer_rect. width;
404+ var clone_scale_factor = width / outer_rect. width;
405+
406+ clone. set_scale (clone_scale_factor, clone_scale_factor);
407+
408+ float clone_width, clone_height;
409+ clone. get_preferred_size (null , null , out clone_width, out clone_height);
410+
411+ // Compensate for invisible borders of the texture
412+ float clone_x = (input_rect. x - outer_rect. x) * clone_scale_factor;
413+ float clone_y = (input_rect. y - outer_rect. y) * clone_scale_factor;
414+
415+ var clone_alloc = InternalUtils . actor_box_from_rect (clone_x, clone_y, clone_width, clone_height);
416+ clone. allocate (clone_alloc);
407417
408418 Clutter . ActorBox shape_alloc = {
409419 - ACTIVE_SHAPE_SIZE ,
410420 - ACTIVE_SHAPE_SIZE ,
411- outer_rect . width * scale_factor + ACTIVE_SHAPE_SIZE ,
412- outer_rect . height * scale_factor + ACTIVE_SHAPE_SIZE
421+ box . get_width () + ACTIVE_SHAPE_SIZE ,
422+ box . get_height () + ACTIVE_SHAPE_SIZE
413423 };
424+ Clutter . ActorBox . clamp_to_pixel (ref shape_alloc);
414425 active_shape. allocate (shape_alloc);
415426
416- if (clone == null || (drag_action != null && drag_action. dragging)) {
417- return ;
418- }
427+ float close_button_width, close_button_height;
428+ close_button. get_preferred_size (null , null , out close_button_width, out close_button_height);
429+
430+ var close_button_x = is_close_button_on_left () ?
431+ - close_button_width * 0.5f : box. get_width () - close_button_width * 0.5f ;
432+
433+ var close_button_alloc = InternalUtils . actor_box_from_rect (close_button_x, - close_button_height * 0.33f , close_button_width, close_button_height);
434+ close_button. allocate (close_button_alloc);
435+
436+ var rect = get_transformed_extents ();
437+ var monitor_index = display. get_monitor_index_for_rect (Mtk . Rectangle . from_graphene_rect (rect, ROUND ));
438+ var monitor_scale = display. get_monitor_scale (monitor_index);
439+
440+ float window_title_max_width = box. get_width () - InternalUtils . scale_to_int (TITLE_MAX_WIDTH_MARGIN , monitor_scale);
441+ float window_title_height, window_title_nat_width;
442+ window_title. get_preferred_size (null , null , out window_title_nat_width, out window_title_height);
419443
420- clone. set_scale (scale_factor, scale_factor);
421- clone. set_position ((input_rect. x - outer_rect. x) * scale_factor,
422- (input_rect. y - outer_rect. y) * scale_factor);
444+ var window_title_width = window_title_nat_width. clamp (0 , window_title_max_width);
445+
446+ float window_title_x = (box. get_width () - window_title_width) / 2 ;
447+ float window_title_y = box. get_height () - InternalUtils . scale_to_int (WINDOW_ICON_SIZE , monitor_scale) * 0.75f - (window_title_height / 2 ) - InternalUtils . scale_to_int (18 , monitor_scale);
448+
449+ var window_title_alloc = InternalUtils . actor_box_from_rect (window_title_x, window_title_y, window_title_width, window_title_height);
450+ window_title. allocate (window_title_alloc);
423451 }
424452
425453#if HAS_MUTTER45
@@ -430,74 +458,26 @@ public class Gala.WindowClone : Clutter.Actor {
430458 return Clutter . EVENT_STOP ;
431459 }
432460
433- #if HAS_MUTTER45
434- public override bool enter_event (Clutter . Event event) {
435- #else
436- public override bool enter_event (Clutter . CrossingEvent event) {
437- #endif
438- if (drag_action != null && drag_action. dragging) {
439- return Clutter . EVENT_PROPAGATE ;
461+ private void update_hover_widgets (bool ? animating = null ) {
462+ if (animating != null ) {
463+ in_slot_animation = animating;
440464 }
441465
442466 var duration = AnimationsSettings . get_animation_duration (FADE_ANIMATION_DURATION );
443467
444- close_button. save_easing_state ();
445- close_button. set_easing_mode (Clutter . AnimationMode . LINEAR );
446- close_button. set_easing_duration (duration);
447- close_button. opacity = in_slot_animation ? 0 : 255 ;
448- close_button. restore_easing_state ();
449-
450- window_title. save_easing_state ();
451- window_title. set_easing_mode (Clutter . AnimationMode . LINEAR );
452- window_title. set_easing_duration (duration);
453- window_title. opacity = in_slot_animation ? 0 : 255 ;
454- window_title. restore_easing_state ();
455-
456- return Clutter . EVENT_PROPAGATE ;
457- }
458-
459- #if HAS_MUTTER45
460- public override bool leave_event (Clutter . Event event) {
461- #else
462- public override bool leave_event (Clutter . CrossingEvent event) {
463- #endif
464- var duration = AnimationsSettings . get_animation_duration (FADE_ANIMATION_DURATION );
468+ var show = has_pointer && ! in_slot_animation;
465469
466470 close_button. save_easing_state ();
467471 close_button. set_easing_mode (Clutter . AnimationMode . LINEAR );
468472 close_button. set_easing_duration (duration);
469- close_button. opacity = 0 ;
473+ close_button. opacity = show ? 255 : 0 ;
470474 close_button. restore_easing_state ();
471475
472476 window_title. save_easing_state ();
473477 window_title. set_easing_mode (Clutter . AnimationMode . LINEAR );
474478 window_title. set_easing_duration (duration);
475- window_title. opacity = 0 ;
479+ window_title. opacity = show ? 255 : 0 ;
476480 window_title. restore_easing_state ();
477-
478- return Clutter . EVENT_PROPAGATE ;
479- }
480-
481- /**
482- * Place the widgets, that is the close button and the WindowIcon of the window,
483- * at their positions inside the actor for a given width and height.
484- */
485- public void place_widgets (int dest_width, int dest_height, float scale_factor) {
486- var close_button_size = InternalUtils . scale_to_int (CLOSE_WINDOW_ICON_SIZE , scale_factor);
487- close_button. set_size (close_button_size, close_button_size);
488-
489- close_button. y = - close_button. height * 0.33f ;
490- close_button. x = is_close_button_on_left () ?
491- - close_button. width * 0.5f :
492- dest_width - close_button. width * 0.5f ;
493-
494- bool show = has_pointer && ! in_slot_animation;
495- close_button. opacity = show ? 255 : 0 ;
496- window_title. opacity = close_button. opacity;
497-
498- window_title. set_text (window. get_title () ?? " " );
499- window_title. set_max_width (dest_width - InternalUtils . scale_to_int (TITLE_MAX_WIDTH_MARGIN , scale_factor));
500- set_window_title_position (dest_width, dest_height, scale_factor);
501481 }
502482
503483 private void toggle_shadow (bool show) {
@@ -800,12 +780,6 @@ public class Gala.WindowClone : Clutter.Actor {
800780 window_icon. set_position (x, y);
801781 }
802782
803- private void set_window_title_position (float window_width, float window_height, float scale_factor) {
804- var x = (int )Math . round ((window_width - window_title. width) / 2 );
805- var y = (int )Math . round (window_height - InternalUtils . scale_to_int (WINDOW_ICON_SIZE , scale_factor) * 0.75f - (window_title. height / 2 ) - InternalUtils . scale_to_int (18 , scale_factor));
806- window_title. set_position (x, y);
807- }
808-
809783 private static bool is_close_button_on_left () {
810784 var layout = Meta . Prefs . get_button_layout ();
811785 foreach (var button_function in layout. left_buttons) {
0 commit comments