11/*
22 * SPDX-License-Identifier: GPL-3.0
3- * SPDX-FileCopyrightText: 2022 elementary, Inc. (https://elementary.io)
3+ * SPDX-FileCopyrightText: 2022-2025 elementary, Inc. (https://elementary.io)
44 */
55
6- public class Dock.Launcher : Gtk .Box {
7- private static Settings settings;
6+ public class Dock.Launcher : BaseItem {
7+ private const int DND_TIMEOUT = 1000 ;
8+
89 private static Settings ? notify_settings;
910
1011 static construct {
11- settings = new Settings (" io.elementary.dock" );
12-
1312 if (SettingsSchemaSource . get_default (). lookup (" io.elementary.notifications" , true ) != null ) {
1413 notify_settings = new Settings (" io.elementary.notifications" );
1514 }
1615 }
1716
18- public signal void removed ();
19- public signal void revealed_done ();
20-
2117 // Matches icon size and padding in Launcher.css
2218 public const int ICON_SIZE = 48 ;
2319 public const int PADDING = 6 ;
@@ -29,8 +25,6 @@ public class Dock.Launcher : Gtk.Box {
2925
3026 public App app { get ; construct; }
3127
32- public double current_pos { get ; set ; }
33-
3428 private bool _moving = false ;
3529 public bool moving {
3630 get {
@@ -55,23 +49,17 @@ public class Dock.Launcher : Gtk.Box {
5549 private Gtk . Image image;
5650 private Gtk . Revealer progress_revealer;
5751 private Gtk . Revealer badge_revealer;
58- private Gtk . Revealer running_revealer;
5952 private Adw . TimedAnimation bounce_up;
6053 private Adw . TimedAnimation bounce_down;
61- private Adw . TimedAnimation timed_animation;
62-
63- private Gtk . GestureClick gesture_click;
64- private Gtk . Overlay overlay;
6554 private Gtk . PopoverMenu popover;
6655
6756 private Binding current_count_binding;
6857
69- private Adw . TimedAnimation ? fade;
70- private Adw . TimedAnimation ? reveal;
71-
7258 private int drag_offset_x = 0 ;
7359 private int drag_offset_y = 0 ;
7460
61+ private uint queue_dnd_cycle_id = 0 ;
62+
7563 private bool flagged_for_removal = false ;
7664
7765 public Launcher (App app ) {
@@ -115,32 +103,12 @@ public class Dock.Launcher : Gtk.Box {
115103 transition_type = CROSSFADE
116104 };
117105
118- var running_indicator = new Gtk .Image .from_icon_name (" pager-checked-symbolic" );
119- running_indicator. add_css_class (" running-indicator" );
120-
121- running_revealer = new Gtk .Revealer () {
122- can_target = false ,
123- child = running_indicator,
124- overflow = VISIBLE ,
125- transition_type = CROSSFADE ,
126- valign = END
127- };
128-
129- overlay = new Gtk .Overlay () {
130- child = image
131- };
106+ overlay. child = image;
132107 overlay. add_overlay (badge_revealer);
133108 overlay. add_overlay (progress_revealer);
134109
135- // Needed to work around DnD bug where it
136- // would stop working once the button got clicked
137- append (overlay);
138- append (running_revealer);
139- orientation = VERTICAL ;
140110 tooltip_text = app. app_info. get_display_name ();
141111
142- var launcher_manager = ItemManager . get_default ();
143-
144112 insert_action_group (ACTION_GROUP_PREFIX , app. action_group);
145113
146114 // We have to destroy the progressbar when it is not needed otherwise it will
@@ -190,21 +158,6 @@ public class Dock.Launcher : Gtk.Box {
190158 };
191159 bounce_up. done. connect (bounce_down. play);
192160
193- var animation_target = new Adw .CallbackAnimationTarget ((val) = > {
194- launcher_manager. move (this , val, 0 );
195- current_pos = val;
196- });
197-
198- timed_animation = new Adw .TimedAnimation (
199- this ,
200- 0 ,
201- 0 ,
202- 200 ,
203- animation_target
204- ) {
205- easing = EASE_IN_OUT_QUAD
206- };
207-
208161 var drag_source = new Gtk .DragSource () {
209162 actions = MOVE
210163 };
@@ -224,10 +177,7 @@ public class Dock.Launcher : Gtk.Box {
224177 add_controller (drop_target);
225178 drop_target. enter. connect (on_drop_enter);
226179
227- gesture_click = new Gtk .GestureClick () {
228- button = 0
229- };
230- add_controller (gesture_click);
180+ gesture_click. button = 0 ;
231181 gesture_click. released. connect (on_click_released);
232182
233183 var scroll_controller = new Gtk .EventControllerScroll (VERTICAL );
@@ -237,7 +187,7 @@ public class Dock.Launcher : Gtk.Box {
237187 return Gdk . EVENT_STOP ;
238188 });
239189
240- settings . bind (" icon-size" , image, " pixel-size" , DEFAULT );
190+ bind_property (" icon-size" , image, " pixel-size" , SYNC_CREATE );
241191
242192 app. notify[" count-visible" ]. connect (update_badge_revealer);
243193 update_badge_revealer ();
@@ -286,25 +236,10 @@ public class Dock.Launcher : Gtk.Box {
286236 }
287237 });
288238
289- fade = new Adw .TimedAnimation (
290- this , 0 , 1 ,
291- Granite . TRANSITION_DURATION_OPEN ,
292- new Adw .CallbackAnimationTarget ((val) = > {
293- opacity = val;
294- })
295- ) {
296- easing = EASE_IN_OUT_QUAD
297- };
298-
299- reveal = new Adw .TimedAnimation (
300- overlay, image. pixel_size, 0 ,
301- Granite . TRANSITION_DURATION_OPEN ,
302- new Adw .CallbackAnimationTarget ((val) = > {
303- overlay. allocate (image. pixel_size, image. pixel_size, - 1 ,
304- new Gsk .Transform (). translate (Graphene . Point () { y = (float ) val }
305- ));
306- })
307- );
239+ var drop_controller_motion = new Gtk .DropControllerMotion ();
240+ add_controller (drop_controller_motion);
241+ drop_controller_motion. enter. connect (queue_dnd_cycle);
242+ drop_controller_motion. leave. connect (remove_dnd_cycle);
308243 }
309244
310245 ~Launcher () {
@@ -313,13 +248,14 @@ public class Dock.Launcher : Gtk.Box {
313248 }
314249
315250 /**
316- * If the launcher isn't needed anymore call this otherwise it won't be freed.
251+ * { @inheritDoc }
317252 */
318- public void cleanup () {
319- timed_animation = null ;
253+ public override void cleanup () {
254+ base . cleanup () ;
320255 bounce_down = null ;
321256 bounce_up = null ;
322257 current_count_binding. unbind ();
258+ remove_dnd_cycle ();
323259 }
324260
325261 private void on_click_released (int n_press , double x , double y ) {
@@ -355,47 +291,6 @@ public class Dock.Launcher : Gtk.Box {
355291 bounce_up. play ();
356292 }
357293
358- /**
359- * Makes the launcher animate a move to the given position. Make sure to
360- * always use this instead of manually calling Gtk.Fixed.move on the manager
361- * when moving a launcher so that its current_pos is always up to date.
362- */
363- public void animate_move (double new_position ) {
364- timed_animation. value_from = current_pos;
365- timed_animation. value_to = new_position;
366-
367- timed_animation. play ();
368- }
369-
370- public void set_revealed (bool revealed ) {
371- fade. skip ();
372- reveal. skip ();
373-
374- // Avoid a stutter at the beginning
375- opacity = 0 ;
376- // clip launcher to dock size until we finish animating
377- overflow = HIDDEN ;
378-
379- if (revealed) {
380- reveal. easing = EASE_OUT_BACK ;
381- } else {
382- fade. duration = Granite . TRANSITION_DURATION_CLOSE ;
383- fade. reverse = true ;
384-
385- reveal. duration = Granite . TRANSITION_DURATION_CLOSE ;
386- reveal. easing = EASE_IN_OUT_QUAD ;
387- reveal. reverse = true ;
388- }
389-
390- fade. play ();
391- reveal. play ();
392-
393- reveal. done. connect (() = > {
394- overflow = VISIBLE ;
395- revealed_done ();
396- });
397- }
398-
399294 private Gdk .ContentProvider ? on_drag_prepare (double x , double y ) {
400295 drag_offset_x = (int ) x;
401296 drag_offset_y = (int ) y;
@@ -496,6 +391,20 @@ public class Dock.Launcher : Gtk.Box {
496391 launcher_manager. move_launcher_after (source, target_index);
497392 }
498393
394+ private void queue_dnd_cycle () {
395+ queue_dnd_cycle_id = Timeout . add (DND_TIMEOUT , () = > {
396+ app. next_window. begin (false );
397+ return Source . CONTINUE ;
398+ });
399+ }
400+
401+ private void remove_dnd_cycle () {
402+ if (queue_dnd_cycle_id > 0 ) {
403+ Source . remove (queue_dnd_cycle_id);
404+ queue_dnd_cycle_id = 0 ;
405+ }
406+ }
407+
499408 private void update_badge_revealer () {
500409 badge_revealer. reveal_child = ! moving && app. count_visible
501410 && (notify_settings == null || ! notify_settings. get_boolean (" do-not-disturb" ));
0 commit comments