@@ -75,10 +75,12 @@ public class Gala.WindowClone : ActorTarget, RootTarget {
7575 private bool in_slot_animation = false ;
7676
7777 private Clutter . Clone clone;
78+ private Clutter . Actor windows_container;
7879 private Gala . CloseButton close_button;
7980 private ActiveShape active_shape;
8081 private Clutter . Actor window_icon;
8182 private Tooltip window_title;
83+ private HashTable<Meta . Window , Clutter . Clone > child_clones = new HashTable<Meta . Window , Clutter .Clone > (null , null );
8284
8385 private GestureController gesture_controller;
8486
@@ -132,10 +134,13 @@ public class Gala.WindowClone : ActorTarget, RootTarget {
132134
133135 clone = new Clutter .Clone ((Meta . WindowActor ) window. get_compositor_private ());
134136
137+ windows_container = new Clutter .Actor ();
138+ windows_container. add_child (clone);
139+
135140 window_title = new Tooltip ();
136141
137142 add_child (active_shape);
138- add_child (clone );
143+ add_child (windows_container );
139144 add_child (window_title);
140145
141146 notify[" monitor-scale" ]. connect (reallocate);
@@ -147,6 +152,39 @@ public class Gala.WindowClone : ActorTarget, RootTarget {
147152 window_title. set_text (window. get_title () ?? " " );
148153
149154 notify[" has-pointer" ]. connect (() = > update_hover_widgets ());
155+
156+ unowned var display = wm. get_display ();
157+ foreach (unowned var child_window in display. list_all_windows ()) {
158+ InternalUtils . wait_for_window_actor_visible (
159+ child_window,
160+ (window_actor) = > add_child_window (window_actor. meta_window)
161+ );
162+ }
163+
164+ display. window_created. connect (
165+ (new_window) = > InternalUtils . wait_for_window_actor_visible (
166+ new_window,
167+ (window_actor) = > add_child_window (window_actor. meta_window)
168+ )
169+ );
170+ }
171+
172+ private void add_child_window (Meta . Window new_window) requires (new_window. get_compositor_private () != null ) {
173+ if (new_window == window || ! window. is_ancestor_of_transient (new_window) && new_window. find_root_ancestor () != window) {
174+ return ;
175+ }
176+
177+ unowned var new_window_actor = (Meta . WindowActor ) new_window. get_compositor_private ();
178+ var actor_clone = new Clutter .Clone (new_window_actor);
179+ windows_container. add_child (actor_clone);
180+
181+ child_clones. insert (new_window, actor_clone);
182+
183+ new_window. unmanaged. connect ((new_window) = > {
184+ windows_container. remove_child (child_clones. take (new_window));
185+ });
186+
187+ update_targets ();
150188 }
151189
152190 ~WindowClone () {
@@ -242,6 +280,35 @@ public class Gala.WindowClone : ActorTarget, RootTarget {
242280 add_target (new PropertyTarget (MULTITASKING_VIEW , window_icon, " opacity" , typeof (uint ), 0u , 255u ));
243281
244282 add_target (new PropertyTarget (MULTITASKING_VIEW , window_title, " opacity" , typeof (uint ), 0u , 255u ));
283+
284+ var window_buffer_rect = window. get_buffer_rect ();
285+ var window_shadow_spread_x = window_rect. x - window_buffer_rect. x;
286+ var window_shadow_spread_y = window_rect. y - window_buffer_rect. y;
287+
288+ child_clones. foreach ((child_window, child_clone) = > {
289+ var child_buffer_rect = child_window. get_buffer_rect ();
290+ var child_frame_rect = child_window. get_frame_rect ();
291+
292+ var scale = 1.0f ;
293+ if (child_frame_rect. width > window_rect. width || child_frame_rect. height > window_rect. height) {
294+ scale = float . min ((float ) window_rect. width / child_frame_rect. width, (float ) window_rect. height / child_frame_rect. height);
295+
296+ add_target (new PropertyTarget (MULTITASKING_VIEW , child_clone, " width" , typeof (float ), (float ) child_buffer_rect. width, child_buffer_rect. width * scale));
297+ add_target (new PropertyTarget (MULTITASKING_VIEW , child_clone, " height" , typeof (float ), (float ) child_buffer_rect. height, child_buffer_rect. height * scale));
298+ }
299+
300+ var child_parent_x_diff = child_buffer_rect. x - window_buffer_rect. x;
301+ var child_parent_y_diff = child_buffer_rect. y - window_buffer_rect. y;
302+
303+ // Center the window
304+ var child_shadow_spread_x = (child_frame_rect. x - child_buffer_rect. x) * scale;
305+ var child_shadow_spread_y = (child_frame_rect. y - child_buffer_rect. y) * scale;
306+ var target_x = window_shadow_spread_x - child_shadow_spread_x + (window_rect. width - child_frame_rect. width * scale) / 2.0f ;
307+ var target_y = window_shadow_spread_y - child_shadow_spread_y + (window_rect. height - child_frame_rect. height * scale) / 2.0f ;
308+
309+ add_target (new PropertyTarget (MULTITASKING_VIEW , child_clone, " x" , typeof (float ), (float ) child_parent_x_diff, target_x));
310+ add_target (new PropertyTarget (MULTITASKING_VIEW , child_clone, " y" , typeof (float ), (float ) child_parent_y_diff, target_y));
311+ });
245312 }
246313
247314 public override void start_progress (GestureAction action) {
@@ -256,8 +323,8 @@ public class Gala.WindowClone : ActorTarget, RootTarget {
256323 var target_translation_y = (float ) (- CLOSE_TRANSLATION * monitor_scale * progress);
257324 var target_opacity = (uint ) (255 * (1 - progress));
258325
259- clone . translation_y = target_translation_y;
260- clone . opacity = target_opacity;
326+ windows_container . translation_y = target_translation_y;
327+ windows_container . opacity = target_opacity;
261328
262329 window_icon. translation_y = target_translation_y;
263330 window_icon. opacity = target_opacity;
@@ -284,21 +351,19 @@ public class Gala.WindowClone : ActorTarget, RootTarget {
284351 return ;
285352 }
286353
287- var input_rect = window. get_buffer_rect ();
288- var outer_rect = window. get_frame_rect ();
289- var clone_scale_factor = width / outer_rect. width;
290-
291- clone. set_scale (clone_scale_factor, clone_scale_factor);
292-
293- float clone_width, clone_height;
294- clone. get_preferred_size (null , null , out clone_width, out clone_height);
354+ var buffer_rect = window. get_buffer_rect ();
355+ var frame_rect = window. get_frame_rect ();
356+ var scale_factor = width / frame_rect. width;
295357
296358 // Compensate for invisible borders of the texture
297- float clone_x = (input_rect. x - outer_rect. x) * clone_scale_factor;
298- float clone_y = (input_rect. y - outer_rect. y) * clone_scale_factor;
359+ var shadow_offset_x = buffer_rect. x - frame_rect. x;
360+ var shadow_offset_y = buffer_rect. y - frame_rect. y;
361+
362+ windows_container. set_scale (scale_factor, scale_factor);
363+ float preferred_width, preferred_height;
364+ windows_container. get_preferred_size (null , null , out preferred_width, out preferred_height);
299365
300- var clone_alloc = InternalUtils . actor_box_from_rect (clone_x, clone_y, clone_width, clone_height);
301- clone. allocate (clone_alloc);
366+ windows_container. allocate (InternalUtils . actor_box_from_rect (shadow_offset_x * scale_factor, shadow_offset_y * scale_factor, preferred_width, preferred_height));
302367
303368 Clutter . ActorBox shape_alloc = {
304369 - ACTIVE_SHAPE_SIZE ,
@@ -442,17 +507,17 @@ public class Gala.WindowClone : ActorTarget, RootTarget {
442507
443508 active_shape. hide ();
444509
445- var scale = window_icon. width / clone . width;
510+ var scale = window_icon. width / windows_container . width;
446511 var duration = Utils . get_animation_duration (FADE_ANIMATION_DURATION );
447512
448- clone . get_transformed_position (out abs_x, out abs_y);
449- clone . save_easing_state ();
450- clone . set_easing_duration (duration);
451- clone . set_easing_mode (Clutter . AnimationMode . EASE_IN_CUBIC );
452- clone . set_pivot_point ((click_x - abs_x) / clone . width, (click_y - abs_y) / clone . height);
453- clone . set_scale (scale, scale);
454- clone . opacity = 0 ;
455- clone . restore_easing_state ();
513+ windows_container . get_transformed_position (out abs_x, out abs_y);
514+ windows_container . save_easing_state ();
515+ windows_container . set_easing_duration (duration);
516+ windows_container . set_easing_mode (Clutter . AnimationMode . EASE_IN_CUBIC );
517+ windows_container . set_pivot_point ((click_x - abs_x) / windows_container . width, (click_y - abs_y) / windows_container . height);
518+ windows_container . set_scale (scale, scale);
519+ windows_container . opacity = 0 ;
520+ windows_container . restore_easing_state ();
456521
457522 request_reposition ();
458523
@@ -567,23 +632,23 @@ public class Gala.WindowClone : ActorTarget, RootTarget {
567632 prev_parent. add_child (this ); // Add above so that it is above while it animates back to its place
568633 restore_easing_state ();
569634
570- clone . set_pivot_point (0.0f , 0.0f );
571- clone . save_easing_state ();
572- clone . set_easing_duration (duration);
573- clone . set_easing_mode (Clutter . AnimationMode . EASE_OUT_QUAD );
574- clone . set_scale (1 , 1 );
575- clone . opacity = 255 ;
576- clone . restore_easing_state ();
635+ windows_container . set_pivot_point (0.0f , 0.0f );
636+ windows_container . save_easing_state ();
637+ windows_container . set_easing_duration (duration);
638+ windows_container . set_easing_mode (Clutter . AnimationMode . EASE_OUT_QUAD );
639+ windows_container . set_scale (1 , 1 );
640+ windows_container . opacity = 255 ;
641+ windows_container . restore_easing_state ();
577642
578643 request_reposition ();
579644
580645 wm. get_display (). set_cursor (Meta . Cursor . DEFAULT );
581646
582647 if (duration > 0 ) {
583648 ulong handler = 0 ;
584- handler = clone . transitions_completed. connect (() = > {
649+ handler = windows_container . transitions_completed. connect (() = > {
585650 prev_parent. set_child_at_index (this , prev_index); // Set the correct index so that correct stacking order is kept
586- clone . disconnect (handler);
651+ windows_container . disconnect (handler);
587652 });
588653 } else {
589654 prev_parent. set_child_at_index (this , prev_index); // Set the correct index so that correct stacking order is kept
0 commit comments