mirror of
https://github.com/elementary/gala.git
synced 2024-11-23 20:07:21 +03:00
Add "Switch windows" gesture (#1802)
This commit is contained in:
parent
72b9e012f3
commit
2699c5a453
@ -355,6 +355,7 @@
|
|||||||
<value nick="none" value="0" />
|
<value nick="none" value="0" />
|
||||||
<value nick="switch-to-workspace" value="1" />
|
<value nick="switch-to-workspace" value="1" />
|
||||||
<value nick="move-to-workspace" value="2" />
|
<value nick="move-to-workspace" value="2" />
|
||||||
|
<value nick="switch-windows" value="3" />
|
||||||
</enum>
|
</enum>
|
||||||
<enum id="GestureSwipeUp">
|
<enum id="GestureSwipeUp">
|
||||||
<value nick="none" value="0" />
|
<value nick="none" value="0" />
|
||||||
|
@ -10,15 +10,20 @@
|
|||||||
public class Gala.WindowSwitcher : Clutter.Actor {
|
public class Gala.WindowSwitcher : Clutter.Actor {
|
||||||
public const int ICON_SIZE = 64;
|
public const int ICON_SIZE = 64;
|
||||||
public const int WRAPPER_PADDING = 12;
|
public const int WRAPPER_PADDING = 12;
|
||||||
|
|
||||||
private const string CAPTION_FONT_NAME = "Inter";
|
private const string CAPTION_FONT_NAME = "Inter";
|
||||||
private const int MIN_OFFSET = 64;
|
private const int MIN_OFFSET = 64;
|
||||||
private const int ANIMATION_DURATION = 200;
|
private const int ANIMATION_DURATION = 200;
|
||||||
|
// https://github.com/elementary/gala/issues/1317#issuecomment-982484415
|
||||||
public bool opened { get; private set; default = false; }
|
private const int GESTURE_RANGE_LIMIT = 10;
|
||||||
|
|
||||||
public Gala.WindowManager? wm { get; construct; }
|
public Gala.WindowManager? wm { get; construct; }
|
||||||
private Gala.ModalProxy modal_proxy = null;
|
public GestureTracker gesture_tracker { get; construct; }
|
||||||
|
public bool opened { get; private set; default = false; }
|
||||||
|
|
||||||
|
private bool handling_gesture = false;
|
||||||
|
private int modifier_mask;
|
||||||
|
private Gala.ModalProxy modal_proxy = null;
|
||||||
private Granite.Settings granite_settings;
|
private Granite.Settings granite_settings;
|
||||||
private Clutter.Canvas canvas;
|
private Clutter.Canvas canvas;
|
||||||
private Clutter.Actor container;
|
private Clutter.Actor container;
|
||||||
@ -28,8 +33,6 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
private Gtk.StyleContext style_context;
|
private Gtk.StyleContext style_context;
|
||||||
private unowned Gtk.CssProvider? dark_style_provider = null;
|
private unowned Gtk.CssProvider? dark_style_provider = null;
|
||||||
|
|
||||||
private int modifier_mask;
|
|
||||||
|
|
||||||
private WindowSwitcherIcon? _current_icon = null;
|
private WindowSwitcherIcon? _current_icon = null;
|
||||||
private WindowSwitcherIcon? current_icon {
|
private WindowSwitcherIcon? current_icon {
|
||||||
get {
|
get {
|
||||||
@ -51,8 +54,11 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
|
|
||||||
private float scaling_factor = 1.0f;
|
private float scaling_factor = 1.0f;
|
||||||
|
|
||||||
public WindowSwitcher (Gala.WindowManager wm) {
|
public WindowSwitcher (Gala.WindowManager wm, GestureTracker gesture_tracker) {
|
||||||
Object (wm: wm);
|
Object (
|
||||||
|
wm: wm,
|
||||||
|
gesture_tracker: gesture_tracker
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
construct {
|
construct {
|
||||||
@ -184,6 +190,10 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
Meta.Display display, Meta.Window? window,
|
Meta.Display display, Meta.Window? window,
|
||||||
Clutter.KeyEvent event, Meta.KeyBinding binding
|
Clutter.KeyEvent event, Meta.KeyBinding binding
|
||||||
) {
|
) {
|
||||||
|
if (handling_gesture) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var workspace = display.get_workspace_manager ().get_active_workspace ();
|
var workspace = display.get_workspace_manager ().get_active_workspace ();
|
||||||
|
|
||||||
// copied from gnome-shell, finds the primary modifier in the mask
|
// copied from gnome-shell, finds the primary modifier in the mask
|
||||||
@ -219,6 +229,49 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
next_window (backward);
|
next_window (backward);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handle_gesture (GestureDirection direction) {
|
||||||
|
handling_gesture = true;
|
||||||
|
|
||||||
|
unowned var display = wm.get_display ();
|
||||||
|
unowned var workspace_manager = display.get_workspace_manager ();
|
||||||
|
unowned var active_workspace = workspace_manager.get_active_workspace ();
|
||||||
|
|
||||||
|
var windows_exist = collect_all_windows (display, active_workspace);
|
||||||
|
if (!windows_exist) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
open_switcher ();
|
||||||
|
|
||||||
|
// if direction == LEFT we need to move to the end of the list first, thats why last_window_index is set to -1
|
||||||
|
var last_window_index = direction == RIGHT ? 0 : -1;
|
||||||
|
GestureTracker.OnUpdate on_animation_update = (percentage) => {
|
||||||
|
var window_index = GestureTracker.animation_value (0, GESTURE_RANGE_LIMIT, percentage, true);
|
||||||
|
|
||||||
|
if (window_index >= container.get_n_children ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window_index > last_window_index) {
|
||||||
|
while (last_window_index < window_index) {
|
||||||
|
next_window (direction == LEFT);
|
||||||
|
last_window_index++;
|
||||||
|
}
|
||||||
|
} else if (window_index < last_window_index) {
|
||||||
|
while (last_window_index > window_index) {
|
||||||
|
next_window (direction == RIGHT);
|
||||||
|
last_window_index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GestureTracker.OnEnd on_animation_end = (percentage, cancel_action, calculated_duration) => {
|
||||||
|
handling_gesture = false;
|
||||||
|
close_switcher (wm.get_display ().get_current_time ());
|
||||||
|
};
|
||||||
|
|
||||||
|
gesture_tracker.connect_handlers (null, (owned) on_animation_update, (owned) on_animation_end);
|
||||||
|
}
|
||||||
|
|
||||||
private bool collect_all_windows (Meta.Display display, Meta.Workspace? workspace) {
|
private bool collect_all_windows (Meta.Display display, Meta.Workspace? workspace) {
|
||||||
var windows = display.get_tab_list (Meta.TabList.NORMAL, workspace);
|
var windows = display.get_tab_list (Meta.TabList.NORMAL, workspace);
|
||||||
if (windows == null) {
|
if (windows == null) {
|
||||||
@ -319,11 +372,6 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
);
|
);
|
||||||
|
|
||||||
toggle_display (true);
|
toggle_display (true);
|
||||||
|
|
||||||
// if we did not have the grab before the key was released, close immediately
|
|
||||||
if ((get_current_modifiers () & modifier_mask) == 0) {
|
|
||||||
close_switcher (wm.get_display ().get_current_time ());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggle_display (bool show) {
|
private void toggle_display (bool show) {
|
||||||
@ -381,7 +429,7 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!cancel) {
|
if (!cancel) {
|
||||||
var workspace = window.get_workspace ();
|
unowned var workspace = window.get_workspace ();
|
||||||
if (workspace != wm.get_display ().get_workspace_manager ().get_active_workspace ()) {
|
if (workspace != wm.get_display ().get_workspace_manager ().get_active_workspace ()) {
|
||||||
workspace.activate_with_focus (window, time);
|
workspace.activate_with_focus (window, time);
|
||||||
} else {
|
} else {
|
||||||
@ -431,7 +479,9 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void key_focus_out () {
|
public override void key_focus_out () {
|
||||||
close_switcher (wm.get_display ().get_current_time ());
|
if (!handling_gesture) {
|
||||||
|
close_switcher (wm.get_display ().get_current_time ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAS_MUTTER45
|
#if HAS_MUTTER45
|
||||||
@ -439,16 +489,20 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
#else
|
#else
|
||||||
private bool container_motion_event (Clutter.MotionEvent event) {
|
private bool container_motion_event (Clutter.MotionEvent event) {
|
||||||
#endif
|
#endif
|
||||||
|
if (handling_gesture) {
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
float x, y;
|
float x, y;
|
||||||
event.get_coords (out x, out y);
|
event.get_coords (out x, out y);
|
||||||
var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y);
|
var actor = container.get_stage ().get_actor_at_pos (Clutter.PickMode.ALL, (int)x, (int)y);
|
||||||
if (actor == null) {
|
if (actor == null) {
|
||||||
return true;
|
return Clutter.EVENT_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
var selected = actor as WindowSwitcherIcon;
|
var selected = actor as WindowSwitcherIcon;
|
||||||
if (selected == null) {
|
if (selected == null) {
|
||||||
return true;
|
return Clutter.EVENT_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_icon != selected) {
|
if (current_icon != selected) {
|
||||||
@ -463,7 +517,7 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
#else
|
#else
|
||||||
private bool container_mouse_release (Clutter.ButtonEvent event) {
|
private bool container_mouse_release (Clutter.ButtonEvent event) {
|
||||||
#endif
|
#endif
|
||||||
if (opened && event.get_button () == Clutter.Button.PRIMARY) {
|
if (opened && event.get_button () == Clutter.Button.PRIMARY && !handling_gesture) {
|
||||||
close_switcher (event.get_time ());
|
close_switcher (event.get_time ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,7 +529,7 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
#else
|
#else
|
||||||
public override bool key_release_event (Clutter.KeyEvent event) {
|
public override bool key_release_event (Clutter.KeyEvent event) {
|
||||||
#endif
|
#endif
|
||||||
if ((get_current_modifiers () & modifier_mask) == 0) {
|
if ((get_current_modifiers () & modifier_mask) == 0 && !handling_gesture) {
|
||||||
close_switcher (event.get_time ());
|
close_switcher (event.get_time ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,10 +543,14 @@ public class Gala.WindowSwitcher : Clutter.Actor {
|
|||||||
#endif
|
#endif
|
||||||
switch (event.get_key_symbol ()) {
|
switch (event.get_key_symbol ()) {
|
||||||
case Clutter.Key.Right:
|
case Clutter.Key.Right:
|
||||||
next_window (false);
|
if (!handling_gesture) {
|
||||||
|
next_window (false);
|
||||||
|
}
|
||||||
return Clutter.EVENT_STOP;
|
return Clutter.EVENT_STOP;
|
||||||
case Clutter.Key.Left:
|
case Clutter.Key.Left:
|
||||||
next_window (true);
|
if (!handling_gesture) {
|
||||||
|
next_window (true);
|
||||||
|
}
|
||||||
return Clutter.EVENT_STOP;
|
return Clutter.EVENT_STOP;
|
||||||
case Clutter.Key.Escape:
|
case Clutter.Key.Escape:
|
||||||
close_switcher (event.get_time (), true);
|
close_switcher (event.get_time (), true);
|
||||||
|
@ -71,7 +71,7 @@ namespace Gala {
|
|||||||
|
|
||||||
private Meta.PluginInfo info;
|
private Meta.PluginInfo info;
|
||||||
|
|
||||||
private WindowSwitcher? winswitcher = null;
|
private WindowSwitcher? window_switcher = null;
|
||||||
private ActivatableComponent? window_overview = null;
|
private ActivatableComponent? window_overview = null;
|
||||||
|
|
||||||
public ScreenSaverManager? screensaver { get; private set; }
|
public ScreenSaverManager? screensaver { get; private set; }
|
||||||
@ -332,15 +332,15 @@ namespace Gala {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (plugin_manager.window_switcher_provider == null) {
|
if (plugin_manager.window_switcher_provider == null) {
|
||||||
winswitcher = new WindowSwitcher (this);
|
window_switcher = new WindowSwitcher (this, gesture_tracker);
|
||||||
ui_group.add_child (winswitcher);
|
ui_group.add_child (window_switcher);
|
||||||
|
|
||||||
Meta.KeyBinding.set_custom_handler ("switch-applications", (Meta.KeyHandlerFunc) winswitcher.handle_switch_windows);
|
Meta.KeyBinding.set_custom_handler ("switch-applications", (Meta.KeyHandlerFunc) window_switcher.handle_switch_windows);
|
||||||
Meta.KeyBinding.set_custom_handler ("switch-applications-backward", (Meta.KeyHandlerFunc) winswitcher.handle_switch_windows);
|
Meta.KeyBinding.set_custom_handler ("switch-applications-backward", (Meta.KeyHandlerFunc) window_switcher.handle_switch_windows);
|
||||||
Meta.KeyBinding.set_custom_handler ("switch-windows", (Meta.KeyHandlerFunc) winswitcher.handle_switch_windows);
|
Meta.KeyBinding.set_custom_handler ("switch-windows", (Meta.KeyHandlerFunc) window_switcher.handle_switch_windows);
|
||||||
Meta.KeyBinding.set_custom_handler ("switch-windows-backward", (Meta.KeyHandlerFunc) winswitcher.handle_switch_windows);
|
Meta.KeyBinding.set_custom_handler ("switch-windows-backward", (Meta.KeyHandlerFunc) window_switcher.handle_switch_windows);
|
||||||
Meta.KeyBinding.set_custom_handler ("switch-group", (Meta.KeyHandlerFunc) winswitcher.handle_switch_windows);
|
Meta.KeyBinding.set_custom_handler ("switch-group", (Meta.KeyHandlerFunc) window_switcher.handle_switch_windows);
|
||||||
Meta.KeyBinding.set_custom_handler ("switch-group-backward", (Meta.KeyHandlerFunc) winswitcher.handle_switch_windows);
|
Meta.KeyBinding.set_custom_handler ("switch-group-backward", (Meta.KeyHandlerFunc) window_switcher.handle_switch_windows);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin_manager.window_overview_provider == null
|
if (plugin_manager.window_overview_provider == null
|
||||||
@ -530,12 +530,8 @@ namespace Gala {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var can_handle_swipe = (
|
if (gesture.type != Clutter.EventType.TOUCHPAD_SWIPE ||
|
||||||
gesture.type == Clutter.EventType.TOUCHPAD_SWIPE &&
|
(gesture.direction != GestureDirection.LEFT && gesture.direction != GestureDirection.RIGHT)) {
|
||||||
(gesture.direction == GestureDirection.LEFT || gesture.direction == GestureDirection.RIGHT)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!can_handle_swipe) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,6 +546,9 @@ namespace Gala {
|
|||||||
var three_fingers_move_to_workspace = fingers == 3 && three_finger_swipe_horizontal == "move-to-workspace";
|
var three_fingers_move_to_workspace = fingers == 3 && three_finger_swipe_horizontal == "move-to-workspace";
|
||||||
var four_fingers_move_to_workspace = fingers == 4 && four_finger_swipe_horizontal == "move-to-workspace";
|
var four_fingers_move_to_workspace = fingers == 4 && four_finger_swipe_horizontal == "move-to-workspace";
|
||||||
|
|
||||||
|
var three_fingers_switch_windows = fingers == 3 && three_finger_swipe_horizontal == "switch-windows";
|
||||||
|
var four_fingers_switch_windows = fingers == 4 && four_finger_swipe_horizontal == "switch-windows";
|
||||||
|
|
||||||
switch_workspace_with_gesture = three_fingers_switch_to_workspace || four_fingers_switch_to_workspace;
|
switch_workspace_with_gesture = three_fingers_switch_to_workspace || four_fingers_switch_to_workspace;
|
||||||
if (switch_workspace_with_gesture) {
|
if (switch_workspace_with_gesture) {
|
||||||
var direction = gesture_tracker.settings.get_natural_scroll_direction (gesture);
|
var direction = gesture_tracker.settings.get_natural_scroll_direction (gesture);
|
||||||
@ -572,6 +571,11 @@ namespace Gala {
|
|||||||
switch_to_next_workspace (direction);
|
switch_to_next_workspace (direction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var switch_windows = three_fingers_switch_windows || four_fingers_switch_windows;
|
||||||
|
if (switch_windows && !window_switcher.opened) {
|
||||||
|
window_switcher.handle_gesture (gesture.direction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user