77 * SPDX-License-Identifier: GPL-3.0-or-later
88 */
99
10- public class Gala.WindowSwitcher : CanvasActor {
10+ public class Gala.WindowSwitcher : CanvasActor , GestureTarget {
1111 public const int ICON_SIZE = 64 ;
1212 public const int WRAPPER_PADDING = 12 ;
1313
1414 private const string CAPTION_FONT_NAME = " Inter" ;
1515 private const int MIN_OFFSET = 64 ;
1616 private const int ANIMATION_DURATION = 200 ;
17- // https://github.com/elementary/gala/issues/1317#issuecomment-982484415
18- private const int GESTURE_RANGE_LIMIT = 10 ;
17+ private const double GESTURE_STEP = 0.1 ;
1918
20- public Gala . WindowManager ? wm { get ; construct; }
21- public GestureTracker gesture_tracker { get ; construct; }
19+ public WindowManager wm { get ; construct; }
2220 public bool opened { get ; private set ; default = false ; }
2321
24- private bool handling_gesture = false ;
22+ public Clutter . Actor ? actor { get { return this ; } }
23+
24+ private GestureController gesture_controller;
2525 private int modifier_mask;
2626 private Gala . ModalProxy modal_proxy = null ;
2727 private Drawing . StyleManager style_manager;
@@ -49,18 +49,25 @@ public class Gala.WindowSwitcher : CanvasActor {
4949 }
5050 }
5151
52+ private double previous_progress = 0d ;
53+
5254 private float scaling_factor = 1.0f ;
5355
54- public WindowSwitcher (Gala .WindowManager wm , GestureTracker gesture_tracker ) {
55- Object (
56- wm: wm,
57- gesture_tracker: gesture_tracker
58- );
56+ public WindowSwitcher (WindowManager wm ) {
57+ Object (wm: wm);
5958 }
6059
6160 construct {
6261 style_manager = Drawing . StyleManager . get_instance ();
6362
63+ gesture_controller = new GestureController (SWITCH_WINDOWS , this ) {
64+ overshoot_upper_clamp = int . MAX ,
65+ overshoot_lower_clamp = int . MIN ,
66+ snap = false
67+ };
68+ gesture_controller. enable_touchpad ();
69+ gesture_controller. notify[" recognizing" ]. connect (recognizing_changed);
70+
6471 container = new Clutter .Actor () {
6572 reactive = true ,
6673#if HAS_MUTTER46
@@ -220,12 +227,55 @@ public class Gala.WindowSwitcher : CanvasActor {
220227 ctx. restore ();
221228 }
222229
230+ public override void propagate (UpdateType update_type, GestureAction action, double progress) {
231+ if (update_type != UPDATE || container. get_n_children () == 0 ) {
232+ return ;
233+ }
234+
235+ var is_step = ((int ) (previous_progress / GESTURE_STEP ) - (int ) (progress / GESTURE_STEP )). abs () >= 1 ;
236+
237+ previous_progress = progress;
238+
239+ if (container. get_n_children () == 1 && current_icon != null && is_step) {
240+ InternalUtils . bell_notify (wm. get_display ());
241+ return ;
242+ }
243+
244+ var current_index = (int ) (progress / GESTURE_STEP ) % container. get_n_children ();
245+
246+ if (current_index < 0 ) {
247+ current_index = container. get_n_children () + current_index;
248+ }
249+
250+ var new_icon = (WindowSwitcherIcon ) container. get_child_at_index (current_index);
251+ if (new_icon != current_icon) {
252+ current_icon = new_icon;
253+ }
254+ }
255+
256+ private void select_icon (WindowSwitcherIcon ? icon) {
257+ if (icon == null ) {
258+ gesture_controller. progress = 0 ;
259+ current_icon = null ;
260+ return ;
261+ }
262+
263+ int index = 0 ;
264+ for (var child = container. get_first_child (); child != null ; child = child. get_next_sibling ()) {
265+ if (child == icon) {
266+ gesture_controller. progress = index * GESTURE_STEP ;
267+ break ;
268+ }
269+ index++ ;
270+ }
271+ }
272+
223273 [CCode (instance_pos = - 1 )]
224274 public void handle_switch_windows (
225275 Meta . Display display, Meta . Window ? window,
226276 Clutter . KeyEvent event, Meta . KeyBinding binding
227277 ) {
228- if (handling_gesture ) {
278+ if (gesture_controller . recognizing ) {
229279 return ;
230280 }
231281
@@ -264,83 +314,55 @@ public class Gala.WindowSwitcher : CanvasActor {
264314 next_window (backward);
265315 }
266316
267- public void handle_gesture (GestureDirection direction) {
268- handling_gesture = true ;
317+ private void recognizing_changed () {
318+ if (gesture_controller. recognizing) {
319+ unowned var display = wm. get_display ();
320+ unowned var workspace_manager = display. get_workspace_manager ();
321+ unowned var active_workspace = workspace_manager. get_active_workspace ();
269322
270- unowned var display = wm. get_display ();
271- unowned var workspace_manager = display. get_workspace_manager ();
272- unowned var active_workspace = workspace_manager. get_active_workspace ();
273-
274- var windows_exist = collect_all_windows (display, active_workspace);
275- if (! windows_exist) {
276- return ;
277- }
278- open_switcher ();
279-
280- // if direction == LEFT we need to move to the end of the list first, thats why last_window_index is set to -1
281- var last_window_index = direction == RIGHT ? 0 : - 1 ;
282- GestureTracker . OnUpdate on_animation_update = (percentage) = > {
283- var window_index = GestureTracker . animation_value (0 , GESTURE_RANGE_LIMIT , percentage, true );
284-
285- if (window_index >= container. get_n_children ()) {
323+ var windows_exist = collect_all_windows (display, active_workspace);
324+ if (! windows_exist) {
286325 return ;
287326 }
288-
289- if (window_index > last_window_index) {
290- while (last_window_index < window_index) {
291- next_window (direction == LEFT );
292- last_window_index++ ;
293- }
294- } else if (window_index < last_window_index) {
295- while (last_window_index > window_index) {
296- next_window (direction == RIGHT );
297- last_window_index-- ;
298- }
299- }
300- };
301-
302- GestureTracker . OnEnd on_animation_end = (percentage, cancel_action, calculated_duration) = > {
303- handling_gesture = false ;
327+ open_switcher ();
328+ } else {
304329 close_switcher (wm. get_display (). get_current_time ());
305- };
306-
307- gesture_tracker. connect_handlers (null , (owned ) on_animation_update, (owned ) on_animation_end);
330+ }
308331 }
309332
310333 private bool collect_all_windows (Meta . Display display, Meta . Workspace ? workspace) {
334+ select_icon (null );
335+
311336 var windows = display. get_tab_list (Meta . TabList . NORMAL , workspace);
312337 if (windows == null ) {
313338 return false ;
314339 }
315340
316- unowned var current_window = display. get_tab_current (Meta . TabList . NORMAL , workspace);
317- if (current_window == null ) {
318- current_icon = null ;
319- }
320-
321341 container. remove_all_children ();
322342
343+ unowned var current_window = display. get_tab_current (Meta . TabList . NORMAL , workspace);
323344 foreach (unowned var window in windows) {
324345 var icon = new WindowSwitcherIcon (window, ICON_SIZE , scaling_factor);
346+ add_icon (icon);
347+
325348 if (window == current_window) {
326- current_icon = icon;
349+ select_icon ( icon) ;
327350 }
328-
329- add_icon (icon);
330351 }
331352
332353 return true ;
333354 }
334355
335356 private bool collect_current_windows (Meta . Display display, Meta . Workspace ? workspace) {
357+ select_icon (null );
358+
336359 var windows = display. get_tab_list (Meta . TabList . NORMAL , workspace);
337360 if (windows == null ) {
338361 return false ;
339362 }
340363
341364 unowned var current_window = display. get_tab_current (Meta . TabList . NORMAL , workspace);
342365 if (current_window == null ) {
343- current_icon = null ;
344366 return false ;
345367 }
346368
@@ -351,11 +373,11 @@ public class Gala.WindowSwitcher : CanvasActor {
351373 foreach (unowned var window in windows) {
352374 if (window_tracker. get_app_for_window (window) == app) {
353375 var icon = new WindowSwitcherIcon (window, ICON_SIZE , scaling_factor);
376+ add_icon (icon);
377+
354378 if (window == current_window) {
355- current_icon = icon;
379+ select_icon ( icon) ;
356380 }
357-
358- add_icon (icon);
359381 }
360382 }
361383
@@ -367,8 +389,8 @@ public class Gala.WindowSwitcher : CanvasActor {
367389 icon. get_accessible (). accessible_parent = container. get_accessible ();
368390
369391 icon. motion_event. connect ((_icon, event) = > {
370- if (current_icon != _icon && ! handling_gesture ) {
371- current_icon = ( WindowSwitcherIcon ) _icon;
392+ if (current_icon != _icon && ! gesture_controller . recognizing ) {
393+ select_icon (( WindowSwitcherIcon ) _icon) ;
372394 }
373395
374396 return Clutter . EVENT_PROPAGATE ;
@@ -470,28 +492,7 @@ public class Gala.WindowSwitcher : CanvasActor {
470492 }
471493
472494 private void next_window (bool backward) {
473- Clutter . Actor actor;
474-
475- if (container. get_n_children () == 1 && current_icon != null ) {
476- InternalUtils . bell_notify (wm. get_display ());
477- return ;
478- }
479-
480- if (current_icon == null ) {
481- actor = container. get_first_child ();
482- } else if (! backward) {
483- actor = current_icon. get_next_sibling ();
484- if (actor == null ) {
485- actor = container. get_first_child ();
486- }
487- } else {
488- actor = current_icon. get_previous_sibling ();
489- if (actor == null ) {
490- actor = container. get_last_child ();
491- }
492- }
493-
494- current_icon = (WindowSwitcherIcon ) actor;
495+ gesture_controller. progress + = backward ? - GESTURE_STEP : GESTURE_STEP ;
495496 }
496497
497498 private void update_caption_text () {
@@ -501,7 +502,7 @@ public class Gala.WindowSwitcher : CanvasActor {
501502 }
502503
503504 public override void key_focus_out () {
504- if (! handling_gesture ) {
505+ if (! gesture_controller . recognizing ) {
505506 close_switcher (wm. get_display (). get_current_time ());
506507 }
507508 }
@@ -511,7 +512,7 @@ public class Gala.WindowSwitcher : CanvasActor {
511512#else
512513 private bool container_mouse_release (Clutter . ButtonEvent event) {
513514#endif
514- if (opened && event. get_button () == Clutter . Button . PRIMARY && ! handling_gesture ) {
515+ if (opened && event. get_button () == Clutter . Button . PRIMARY && ! gesture_controller . recognizing ) {
515516 close_switcher (event. get_time ());
516517 }
517518
@@ -523,7 +524,7 @@ public class Gala.WindowSwitcher : CanvasActor {
523524#else
524525 public override bool key_release_event (Clutter . KeyEvent event) {
525526#endif
526- if ((get_current_modifiers () & modifier_mask) == 0 && ! handling_gesture ) {
527+ if ((get_current_modifiers () & modifier_mask) == 0 && ! gesture_controller . recognizing ) {
527528 close_switcher (event. get_time ());
528529 }
529530
@@ -537,12 +538,12 @@ public class Gala.WindowSwitcher : CanvasActor {
537538#endif
538539 switch (event. get_key_symbol ()) {
539540 case Clutter . Key . Right :
540- if (! handling_gesture ) {
541+ if (! gesture_controller . recognizing ) {
541542 next_window (false );
542543 }
543544 return Clutter . EVENT_STOP ;
544545 case Clutter . Key . Left :
545- if (! handling_gesture ) {
546+ if (! gesture_controller . recognizing ) {
546547 next_window (true );
547548 }
548549 return Clutter . EVENT_STOP ;
0 commit comments