workspacesView: Support touch/touchpad gestures to switch workspaces

Now that the existing touch/touchpad gestures in windowManager only
handle normal mode, add corresponding gestures for the overview and
hook them up to the existing workspace scroll animations.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/516
This commit is contained in:
Florian Müllner 2019-03-20 17:19:01 +00:00 committed by Florian Müllner
parent c0012c2ea4
commit e5b9043435

View File

@ -1,10 +1,11 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const { Clutter, Gio, GObject, Meta, St } = imports.gi; const { Clutter, Gio, GObject, Meta, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Main = imports.ui.main; const Main = imports.ui.main;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const WindowManager = imports.ui.windowManager;
const Workspace = imports.ui.workspace; const Workspace = imports.ui.workspace;
var WORKSPACE_SWITCH_TIME = 0.25; var WORKSPACE_SWITCH_TIME = 0.25;
@ -82,6 +83,7 @@ var WorkspacesView = class extends WorkspacesViewBase {
this._animating = false; // tweening this._animating = false; // tweening
this._scrolling = false; // swipe-scrolling this._scrolling = false; // swipe-scrolling
this._gestureActive = false; // touch(pad) gestures
this._animatingScroll = false; // programatically updating the adjustment this._animatingScroll = false; // programatically updating the adjustment
let activeWorkspaceIndex = workspaceManager.get_active_workspace_index(); let activeWorkspaceIndex = workspaceManager.get_active_workspace_index();
@ -211,7 +213,7 @@ var WorkspacesView = class extends WorkspacesViewBase {
for (let w = 0; w < this._workspaces.length; w++) { for (let w = 0; w < this._workspaces.length; w++) {
let workspace = this._workspaces[w]; let workspace = this._workspaces[w];
if (this._animating || this._scrolling) { if (this._animating || this._scrolling || this._gestureActive) {
workspace.actor.show(); workspace.actor.show();
} else { } else {
if (this._inDrag) if (this._inDrag)
@ -223,7 +225,7 @@ var WorkspacesView = class extends WorkspacesViewBase {
} }
_updateScrollAdjustment(index) { _updateScrollAdjustment(index) {
if (this._scrolling) if (this._scrolling || this._gestureActive)
return; return;
this._animatingScroll = true; this._animatingScroll = true;
@ -300,6 +302,18 @@ var WorkspacesView = class extends WorkspacesViewBase {
this._updateVisibility(); this._updateVisibility();
} }
startTouchGesture() {
this._gestureActive = true;
}
endTouchGesture() {
this._gestureActive = false;
// Make sure title captions etc are shown as necessary
this._scrollToActive();
this._updateVisibility();
}
// sync the workspaces' positions to the value of the scroll adjustment // sync the workspaces' positions to the value of the scroll adjustment
// and change the active workspace if appropriate // and change the active workspace if appropriate
_onScroll(adj) { _onScroll(adj) {
@ -310,7 +324,7 @@ var WorkspacesView = class extends WorkspacesViewBase {
let active = workspaceManager.get_active_workspace_index(); let active = workspaceManager.get_active_workspace_index();
let current = Math.round(adj.value); let current = Math.round(adj.value);
if (active != current) { if (active != current && !this._gestureActive) {
if (!this._workspaces[current]) { if (!this._workspaces[current]) {
// The current workspace was destroyed. This could happen // The current workspace was destroyed. This could happen
// when you are on the last empty workspace, and consolidate // when you are on the last empty workspace, and consolidate
@ -391,6 +405,12 @@ var ExtraWorkspaceView = class extends WorkspacesViewBase {
endSwipeScroll() { endSwipeScroll() {
} }
startTouchGesture() {
}
endTouchGesture() {
}
}; };
var DelegateFocusNavigator = GObject.registerClass( var DelegateFocusNavigator = GObject.registerClass(
@ -430,23 +450,37 @@ var WorkspacesDisplay = class {
return false; return false;
} }
for (let i = 0; i < this._workspacesViews.length; i++) this._startSwipeScroll();
this._workspacesViews[i].startSwipeScroll();
return true; return true;
}); });
panAction.connect('gesture-cancel', () => { panAction.connect('gesture-cancel', () => {
clickAction.release(); clickAction.release();
for (let i = 0; i < this._workspacesViews.length; i++) this._endSwipeScroll();
this._workspacesViews[i].endSwipeScroll();
}); });
panAction.connect('gesture-end', () => { panAction.connect('gesture-end', () => {
clickAction.release(); clickAction.release();
for (let i = 0; i < this._workspacesViews.length; i++) this._endSwipeScroll();
this._workspacesViews[i].endSwipeScroll();
}); });
Main.overview.addAction(panAction); Main.overview.addAction(panAction);
this.actor.bind_property('mapped', panAction, 'enabled', GObject.BindingFlags.SYNC_CREATE); this.actor.bind_property('mapped', panAction, 'enabled', GObject.BindingFlags.SYNC_CREATE);
let allowedModes = Shell.ActionMode.OVERVIEW;
let switchGesture = new WindowManager.WorkspaceSwitchAction(allowedModes);
switchGesture.connect('motion', this._onSwitchWorkspaceMotion.bind(this));
switchGesture.connect('activated', this._onSwitchWorkspaceActivated.bind(this));
switchGesture.connect('cancel', this._endTouchGesture.bind(this));
Main.overview.addAction(switchGesture);
this.actor.bind_property('mapped', switchGesture, 'enabled', GObject.BindingFlags.SYNC_CREATE);
switchGesture = new WindowManager.TouchpadWorkspaceSwitchAction(global.stage, allowedModes);
switchGesture.connect('motion', this._onSwitchWorkspaceMotion.bind(this));
switchGesture.connect('activated', this._onSwitchWorkspaceActivated.bind(this));
switchGesture.connect('cancel', this._endTouchGesture.bind(this));
this.actor.connect('notify::mapped', () => {
switchGesture.enabled = this.actor.mapped;
});
switchGesture.enabled = this.actor.mapped;
this._primaryIndex = Main.layoutManager.primaryIndex; this._primaryIndex = Main.layoutManager.primaryIndex;
this._workspacesViews = []; this._workspacesViews = [];
@ -474,6 +508,47 @@ var WorkspacesDisplay = class {
return false; return false;
} }
_startSwipeScroll() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startSwipeScroll();
}
_endSwipeScroll() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll();
}
_startTouchGesture() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startTouchGesture();
}
_endTouchGesture() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endTouchGesture();
}
_onSwitchWorkspaceMotion(action, xRel, yRel) {
// We don't have a way to hook into start of touchpad actions,
// luckily this is safe to call repeatedly.
this._startTouchGesture();
let workspaceManager = global.workspace_manager;
let active = workspaceManager.get_active_workspace_index();
let adjustment = this._scrollAdjustment;
adjustment.value = (active - yRel / this.actor.height) * adjustment.page_size;
}
_onSwitchWorkspaceActivated(action, direction) {
let workspaceManager = global.workspace_manager;
let activeWorkspace = workspaceManager.get_active_workspace();
let newWs = activeWorkspace.get_neighbor(direction);
if (newWs != activeWorkspace)
newWs.activate(global.get_current_time());
this._endTouchGesture();
}
navigateFocus(from, direction) { navigateFocus(from, direction) {
return this._getPrimaryView().actor.navigate_focus(from, direction, false); return this._getPrimaryView().actor.navigate_focus(from, direction, false);
} }