windowManager: Use SwipeTracker
Replace existing four-finger gestures with SwipeTracker. Since TouchpadWorkspaceSwitchAction and WorkspaceSwitchAction are now unused, remove them. Change programmatic workspace transition to use easeOutCubic interpolator to match the gesture. Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/756 https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/826
This commit is contained in:
parent
3e6bcbb486
commit
a8dcfa4656
@ -2,7 +2,6 @@
|
||||
/* exported WindowManager */
|
||||
|
||||
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const AltTab = imports.ui.altTab;
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
@ -15,6 +14,7 @@ const WindowMenu = imports.ui.windowMenu;
|
||||
const PadOsd = imports.ui.padOsd;
|
||||
const EdgeDragAction = imports.ui.edgeDragAction;
|
||||
const CloseDialog = imports.ui.closeDialog;
|
||||
const SwipeTracker = imports.ui.swipeTracker;
|
||||
const SwitchMonitor = imports.ui.switchMonitor;
|
||||
const IBusManager = imports.misc.ibusManager;
|
||||
|
||||
@ -30,7 +30,6 @@ var WINDOW_ANIMATION_TIME = 250;
|
||||
var DIM_BRIGHTNESS = -0.3;
|
||||
var DIM_TIME = 500;
|
||||
var UNDIM_TIME = 250;
|
||||
var WS_MOTION_THRESHOLD = 100;
|
||||
var APP_MOTION_THRESHOLD = 30;
|
||||
|
||||
var ONE_SECOND = 1000; // in ms
|
||||
@ -468,147 +467,6 @@ class TilePreview extends St.Widget {
|
||||
}
|
||||
});
|
||||
|
||||
var TouchpadWorkspaceSwitchAction = class {
|
||||
constructor(actor, allowedModes) {
|
||||
this._allowedModes = allowedModes;
|
||||
this._dx = 0;
|
||||
this._dy = 0;
|
||||
this._enabled = true;
|
||||
actor.connect('captured-event', this._handleEvent.bind(this));
|
||||
this._touchpadSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.peripherals.touchpad' });
|
||||
}
|
||||
|
||||
get enabled() {
|
||||
return this._enabled;
|
||||
}
|
||||
|
||||
set enabled(enabled) {
|
||||
if (this._enabled == enabled)
|
||||
return;
|
||||
|
||||
this._enabled = enabled;
|
||||
if (!enabled)
|
||||
this.emit('cancel');
|
||||
}
|
||||
|
||||
_checkActivated() {
|
||||
let dir;
|
||||
|
||||
if (this._dy < -WS_MOTION_THRESHOLD)
|
||||
dir = Meta.MotionDirection.DOWN;
|
||||
else if (this._dy > WS_MOTION_THRESHOLD)
|
||||
dir = Meta.MotionDirection.UP;
|
||||
else if (this._dx < -WS_MOTION_THRESHOLD)
|
||||
dir = Meta.MotionDirection.RIGHT;
|
||||
else if (this._dx > WS_MOTION_THRESHOLD)
|
||||
dir = Meta.MotionDirection.LEFT;
|
||||
else
|
||||
return false;
|
||||
|
||||
this.emit('activated', dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
_handleEvent(actor, event) {
|
||||
if (event.type() != Clutter.EventType.TOUCHPAD_SWIPE)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (event.get_touchpad_gesture_finger_count() != 4)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if ((this._allowedModes & Main.actionMode) == 0)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (!this._enabled)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.UPDATE) {
|
||||
let [dx, dy] = event.get_gesture_motion_delta();
|
||||
|
||||
// Scale deltas up a bit to make it feel snappier
|
||||
this._dx += dx * 2;
|
||||
if (!this._touchpadSettings.get_boolean('natural-scroll'))
|
||||
this._dy -= dy * 2;
|
||||
else
|
||||
this._dy += dy * 2;
|
||||
|
||||
this.emit('motion', this._dx, this._dy);
|
||||
} else {
|
||||
if ((event.get_gesture_phase() == Clutter.TouchpadGesturePhase.END && !this._checkActivated()) ||
|
||||
event.get_gesture_phase() == Clutter.TouchpadGesturePhase.CANCEL)
|
||||
this.emit('cancel');
|
||||
|
||||
this._dx = 0;
|
||||
this._dy = 0;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(TouchpadWorkspaceSwitchAction.prototype);
|
||||
|
||||
var WorkspaceSwitchAction = GObject.registerClass({
|
||||
Signals: { 'activated': { param_types: [Meta.MotionDirection.$gtype] },
|
||||
'motion': { param_types: [GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE] },
|
||||
'cancel': { param_types: [] } },
|
||||
}, class WorkspaceSwitchAction extends Clutter.SwipeAction {
|
||||
_init(allowedModes) {
|
||||
super._init();
|
||||
this.set_n_touch_points(4);
|
||||
this._swept = false;
|
||||
this._allowedModes = allowedModes;
|
||||
|
||||
global.display.connect('grab-op-begin', () => {
|
||||
this.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_gesture_prepare(actor) {
|
||||
this._swept = false;
|
||||
|
||||
if (!super.vfunc_gesture_prepare(actor))
|
||||
return false;
|
||||
|
||||
return this._allowedModes & Main.actionMode;
|
||||
}
|
||||
|
||||
vfunc_gesture_progress(_actor) {
|
||||
let [x, y] = this.get_motion_coords(0);
|
||||
let [xPress, yPress] = this.get_press_coords(0);
|
||||
this.emit('motion', x - xPress, y - yPress);
|
||||
return true;
|
||||
}
|
||||
|
||||
vfunc_gesture_cancel(_actor) {
|
||||
if (!this._swept)
|
||||
this.emit('cancel');
|
||||
}
|
||||
|
||||
vfunc_swipe(actor, direction) {
|
||||
let [x, y] = this.get_motion_coords(0);
|
||||
let [xPress, yPress] = this.get_press_coords(0);
|
||||
if (Math.abs(x - xPress) < WS_MOTION_THRESHOLD &&
|
||||
Math.abs(y - yPress) < WS_MOTION_THRESHOLD) {
|
||||
this.emit('cancel');
|
||||
return;
|
||||
}
|
||||
|
||||
let dir;
|
||||
|
||||
if (direction & Clutter.SwipeDirection.UP)
|
||||
dir = Meta.MotionDirection.DOWN;
|
||||
else if (direction & Clutter.SwipeDirection.DOWN)
|
||||
dir = Meta.MotionDirection.UP;
|
||||
else if (direction & Clutter.SwipeDirection.LEFT)
|
||||
dir = Meta.MotionDirection.RIGHT;
|
||||
else if (direction & Clutter.SwipeDirection.RIGHT)
|
||||
dir = Meta.MotionDirection.LEFT;
|
||||
|
||||
this._swept = true;
|
||||
this.emit('activated', dir);
|
||||
}
|
||||
});
|
||||
|
||||
var AppSwitchAction = GObject.registerClass({
|
||||
Signals: { 'activated': {} },
|
||||
}, class AppSwitchAction extends Clutter.GestureAction {
|
||||
@ -1054,10 +912,17 @@ var WindowManager = class {
|
||||
Main.overview.connect('showing', () => {
|
||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||
this._undimWindow(this._dimmedWindows[i]);
|
||||
|
||||
if (this._switchData) {
|
||||
if (this._switchData.gestureActivated)
|
||||
this._switchWorkspaceStop();
|
||||
this._swipeTracker.enabled = false;
|
||||
}
|
||||
});
|
||||
Main.overview.connect('hiding', () => {
|
||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||
this._dimWindow(this._dimmedWindows[i]);
|
||||
this._swipeTracker.enabled = true;
|
||||
});
|
||||
|
||||
this._windowMenuManager = new WindowMenu.WindowMenuManager();
|
||||
@ -1068,18 +933,12 @@ var WindowManager = class {
|
||||
global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT,
|
||||
false, -1, 1);
|
||||
|
||||
let allowedModes = Shell.ActionMode.NORMAL;
|
||||
let workspaceSwitchAction = new WorkspaceSwitchAction(allowedModes);
|
||||
workspaceSwitchAction.connect('motion', this._switchWorkspaceMotion.bind(this));
|
||||
workspaceSwitchAction.connect('activated', this._actionSwitchWorkspace.bind(this));
|
||||
workspaceSwitchAction.connect('cancel', this._switchWorkspaceCancel.bind(this));
|
||||
global.stage.add_action(workspaceSwitchAction);
|
||||
|
||||
// This is not a normal Clutter.GestureAction, doesn't need add_action()
|
||||
let touchpadSwitchAction = new TouchpadWorkspaceSwitchAction(global.stage, allowedModes);
|
||||
touchpadSwitchAction.connect('motion', this._switchWorkspaceMotion.bind(this));
|
||||
touchpadSwitchAction.connect('activated', this._actionSwitchWorkspace.bind(this));
|
||||
touchpadSwitchAction.connect('cancel', this._switchWorkspaceCancel.bind(this));
|
||||
let swipeTracker = new SwipeTracker.SwipeTracker(global.stage,
|
||||
Shell.ActionMode.NORMAL, { allowDrag: false, allowScroll: false });
|
||||
swipeTracker.connect('begin', this._switchWorkspaceBegin.bind(this));
|
||||
swipeTracker.connect('update', this._switchWorkspaceUpdate.bind(this));
|
||||
swipeTracker.connect('end', this._switchWorkspaceEnd.bind(this));
|
||||
this._swipeTracker = swipeTracker;
|
||||
|
||||
let appSwitchAction = new AppSwitchAction();
|
||||
appSwitchAction.connect('activated', this._switchApp.bind(this));
|
||||
@ -1121,52 +980,6 @@ var WindowManager = class {
|
||||
return this._currentPadOsd;
|
||||
}
|
||||
|
||||
_switchWorkspaceMotion(action, xRel, yRel) {
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let activeWorkspace = workspaceManager.get_active_workspace();
|
||||
|
||||
if (!this._switchData)
|
||||
this._prepareWorkspaceSwitch(activeWorkspace.index(), -1);
|
||||
|
||||
if (yRel < 0 && !this._switchData.surroundings[Meta.MotionDirection.DOWN])
|
||||
yRel = 0;
|
||||
if (yRel > 0 && !this._switchData.surroundings[Meta.MotionDirection.UP])
|
||||
yRel = 0;
|
||||
if (xRel < 0 && !this._switchData.surroundings[Meta.MotionDirection.RIGHT])
|
||||
xRel = 0;
|
||||
if (xRel > 0 && !this._switchData.surroundings[Meta.MotionDirection.LEFT])
|
||||
xRel = 0;
|
||||
|
||||
this._switchData.container.set_position(xRel, yRel);
|
||||
}
|
||||
|
||||
_switchWorkspaceCancel() {
|
||||
if (!this._switchData || this._switchData.inProgress)
|
||||
return;
|
||||
let switchData = this._switchData;
|
||||
this._switchData = null;
|
||||
switchData.container.ease({
|
||||
x: 0,
|
||||
y: 0,
|
||||
duration: WINDOW_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => this._finishWorkspaceSwitch(switchData),
|
||||
});
|
||||
}
|
||||
|
||||
_actionSwitchWorkspace(action, direction) {
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let activeWorkspace = workspaceManager.get_active_workspace();
|
||||
let newWs = activeWorkspace.get_neighbor(direction);
|
||||
|
||||
if (newWs == activeWorkspace) {
|
||||
this._switchWorkspaceCancel();
|
||||
} else {
|
||||
this._switchData.gestureActivated = true;
|
||||
this.actionMoveWorkspace(newWs);
|
||||
}
|
||||
}
|
||||
|
||||
_lookupIndex(windows, metaWindow) {
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (windows[i].metaWindow == metaWindow)
|
||||
@ -1280,7 +1093,8 @@ var WindowManager = class {
|
||||
}
|
||||
|
||||
_shouldAnimate() {
|
||||
return !Main.overview.visible;
|
||||
return !(Main.overview.visible ||
|
||||
(this._switchData && this._switchData.gestureActivated));
|
||||
}
|
||||
|
||||
_shouldAnimateActor(actor, types) {
|
||||
@ -1860,13 +1674,17 @@ var WindowManager = class {
|
||||
continue;
|
||||
}
|
||||
|
||||
let info = { index: ws.index(),
|
||||
actor: new Clutter.Actor() };
|
||||
let [x, y] = this._getPositionForDirection(dir, curWs, ws);
|
||||
let info = {
|
||||
index: ws.index(),
|
||||
actor: new Clutter.Actor(),
|
||||
xDest: x,
|
||||
yDest: y,
|
||||
};
|
||||
switchData.surroundings[dir] = info;
|
||||
switchData.container.add_actor(info.actor);
|
||||
switchData.container.set_child_above_sibling(info.actor, null);
|
||||
|
||||
let [x, y] = this._getPositionForDirection(dir, curWs, ws);
|
||||
info.actor.set_position(x, y);
|
||||
}
|
||||
|
||||
@ -1948,11 +1766,7 @@ var WindowManager = class {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we come from a gesture, switchData will already be set,
|
||||
// and we don't want to overwrite it.
|
||||
if (!this._switchData)
|
||||
this._prepareWorkspaceSwitch(from, to, direction);
|
||||
|
||||
this._prepareWorkspaceSwitch(from, to, direction);
|
||||
this._switchData.inProgress = true;
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
@ -1972,7 +1786,7 @@ var WindowManager = class {
|
||||
x: xDest,
|
||||
y: yDest,
|
||||
duration: WINDOW_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
|
||||
onComplete: () => this._switchWorkspaceDone(shellwm),
|
||||
});
|
||||
}
|
||||
@ -1982,6 +1796,158 @@ var WindowManager = class {
|
||||
shellwm.completed_switch_workspace();
|
||||
}
|
||||
|
||||
_directionForProgress(progress) {
|
||||
if (global.workspace_manager.layout_rows === -1) {
|
||||
return progress > 0
|
||||
? Meta.MotionDirection.DOWN
|
||||
: Meta.MotionDirection.UP;
|
||||
} else if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL) {
|
||||
return progress > 0
|
||||
? Meta.MotionDirection.LEFT
|
||||
: Meta.MotionDirection.RIGHT;
|
||||
} else {
|
||||
return progress > 0
|
||||
? Meta.MotionDirection.RIGHT
|
||||
: Meta.MotionDirection.LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
_getProgressRange() {
|
||||
if (!this._switchData)
|
||||
return [0, 0];
|
||||
|
||||
let lower = 0;
|
||||
let upper = 0;
|
||||
|
||||
let horiz = global.workspace_manager.layout_rows !== -1;
|
||||
let baseDistance;
|
||||
if (horiz)
|
||||
baseDistance = global.screen_width;
|
||||
else
|
||||
baseDistance = global.screen_height;
|
||||
|
||||
let direction = this._directionForProgress(-1);
|
||||
let info = this._switchData.surroundings[direction];
|
||||
if (info !== null) {
|
||||
let distance = horiz ? info.xDest : info.yDest;
|
||||
lower = -Math.abs(distance) / baseDistance;
|
||||
}
|
||||
|
||||
direction = this._directionForProgress(1);
|
||||
info = this._switchData.surroundings[direction];
|
||||
if (info !== null) {
|
||||
let distance = horiz ? info.xDest : info.yDest;
|
||||
upper = Math.abs(distance) / baseDistance;
|
||||
}
|
||||
|
||||
return [lower, upper];
|
||||
}
|
||||
|
||||
_switchWorkspaceBegin(tracker, monitor) {
|
||||
if (Meta.prefs_get_workspaces_only_on_primary() &&
|
||||
monitor !== Main.layoutManager.primaryIndex)
|
||||
return;
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let horiz = workspaceManager.layout_rows !== -1;
|
||||
tracker.orientation = horiz
|
||||
? Clutter.Orientation.HORIZONTAL
|
||||
: Clutter.Orientation.VERTICAL;
|
||||
|
||||
let activeWorkspace = workspaceManager.get_active_workspace();
|
||||
|
||||
let baseDistance;
|
||||
if (horiz)
|
||||
baseDistance = global.screen_width;
|
||||
else
|
||||
baseDistance = global.screen_height;
|
||||
|
||||
let progress;
|
||||
if (this._switchData && this._switchData.gestureActivated) {
|
||||
this._switchData.container.remove_all_transitions();
|
||||
if (!horiz)
|
||||
progress = -this._switchData.container.y / baseDistance;
|
||||
else if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL)
|
||||
progress = this._switchData.container.x / baseDistance;
|
||||
else
|
||||
progress = -this._switchData.container.x / baseDistance;
|
||||
} else {
|
||||
this._prepareWorkspaceSwitch(activeWorkspace.index(), -1);
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
let points = [];
|
||||
let [lower, upper] = this._getProgressRange();
|
||||
|
||||
if (lower !== 0)
|
||||
points.push(lower);
|
||||
|
||||
points.push(0);
|
||||
|
||||
if (upper !== 0)
|
||||
points.push(upper);
|
||||
|
||||
tracker.confirmSwipe(baseDistance, points, progress, 0);
|
||||
}
|
||||
|
||||
_switchWorkspaceUpdate(tracker, progress) {
|
||||
if (!this._switchData)
|
||||
return;
|
||||
|
||||
let direction = this._directionForProgress(progress);
|
||||
let info = this._switchData.surroundings[direction];
|
||||
let xPos = 0;
|
||||
let yPos = 0;
|
||||
if (info) {
|
||||
if (global.workspace_manager.layout_rows === -1)
|
||||
yPos = -Math.round(progress * global.screen_height);
|
||||
else if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL)
|
||||
xPos = Math.round(progress * global.screen_width);
|
||||
else
|
||||
xPos = -Math.round(progress * global.screen_width);
|
||||
}
|
||||
|
||||
this._switchData.container.set_position(xPos, yPos);
|
||||
}
|
||||
|
||||
_switchWorkspaceEnd(tracker, duration, endProgress) {
|
||||
if (!this._switchData)
|
||||
return;
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let activeWorkspace = workspaceManager.get_active_workspace();
|
||||
let newWs = activeWorkspace;
|
||||
let xDest = 0;
|
||||
let yDest = 0;
|
||||
if (endProgress !== 0) {
|
||||
let direction = this._directionForProgress(endProgress);
|
||||
newWs = activeWorkspace.get_neighbor(direction);
|
||||
xDest = -this._switchData.surroundings[direction].xDest;
|
||||
yDest = -this._switchData.surroundings[direction].yDest;
|
||||
}
|
||||
|
||||
let switchData = this._switchData;
|
||||
switchData.gestureActivated = true;
|
||||
|
||||
this._switchData.container.ease({
|
||||
x: xDest,
|
||||
y: yDest,
|
||||
duration,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
|
||||
onComplete: () => {
|
||||
if (newWs !== activeWorkspace)
|
||||
this.actionMoveWorkspace(newWs);
|
||||
this._finishWorkspaceSwitch(switchData);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_switchWorkspaceStop() {
|
||||
this._switchData.container.x = 0;
|
||||
this._switchData.container.y = 0;
|
||||
this._finishWorkspaceSwitch(this._switchData);
|
||||
}
|
||||
|
||||
_showTilePreview(shellwm, window, tileRect, monitorIndex) {
|
||||
if (!this._tilePreview)
|
||||
this._tilePreview = new TilePreview();
|
||||
|
Loading…
Reference in New Issue
Block a user