Compare commits
7 Commits
citadel
...
wip/exalm/
Author | SHA1 | Date | |
---|---|---|---|
|
b1afb946b2 | ||
|
46d5bccfc6 | ||
|
f0d498062d | ||
|
eeac4a3b6d | ||
|
272cb4d523 | ||
|
6d5446e4a6 | ||
|
fa31bcaa7a |
@ -109,6 +109,7 @@
|
||||
<file>ui/windowMenu.js</file>
|
||||
<file>ui/windowManager.js</file>
|
||||
<file>ui/workspace.js</file>
|
||||
<file>ui/workspaceAnimation.js</file>
|
||||
<file>ui/workspaceSwitcherPopup.js</file>
|
||||
<file>ui/workspaceThumbnail.js</file>
|
||||
<file>ui/workspacesView.js</file>
|
||||
|
@ -14,9 +14,9 @@ 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;
|
||||
const WorkspaceAnimation = imports.ui.workspaceAnimation;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
@ -559,7 +559,6 @@ var WindowManager = class {
|
||||
this._resizing = new Set();
|
||||
this._resizePending = new Set();
|
||||
this._destroying = new Set();
|
||||
this._movingWindow = null;
|
||||
|
||||
this._dimmedWindows = [];
|
||||
|
||||
@ -569,15 +568,6 @@ var WindowManager = class {
|
||||
|
||||
this._isWorkspacePrepended = false;
|
||||
|
||||
this._switchData = null;
|
||||
this._shellwm.connect('kill-switch-workspace', shellwm => {
|
||||
if (this._switchData) {
|
||||
if (this._switchData.inProgress)
|
||||
this._switchWorkspaceDone(shellwm);
|
||||
else if (!this._switchData.gestureActivated)
|
||||
this._finishWorkspaceSwitch(this._switchData);
|
||||
}
|
||||
});
|
||||
this._shellwm.connect('kill-window-effects', (shellwm, actor) => {
|
||||
this._minimizeWindowDone(shellwm, actor);
|
||||
this._mapWindowDone(shellwm, actor);
|
||||
@ -599,7 +589,6 @@ var WindowManager = class {
|
||||
this._shellwm.connect('confirm-display-change', this._confirmDisplayChange.bind(this));
|
||||
this._shellwm.connect('create-close-dialog', this._createCloseDialog.bind(this));
|
||||
this._shellwm.connect('create-inhibit-shortcuts-dialog', this._createInhibitShortcutsDialog.bind(this));
|
||||
global.display.connect('restacked', this._syncStacking.bind(this));
|
||||
|
||||
this._workspaceSwitcherPopup = null;
|
||||
this._tilePreview = null;
|
||||
@ -908,17 +897,10 @@ 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();
|
||||
@ -929,13 +911,6 @@ var WindowManager = class {
|
||||
global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT,
|
||||
false, -1, 1);
|
||||
|
||||
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));
|
||||
global.stage.add_action(appSwitchAction);
|
||||
@ -967,6 +942,17 @@ var WindowManager = class {
|
||||
global.display.connect('in-fullscreen-changed', updateUnfullscreenGesture);
|
||||
|
||||
global.stage.add_action(topDragAction);
|
||||
|
||||
this._workspaceAnimation =
|
||||
new WorkspaceAnimation.WorkspaceAnimationController();
|
||||
|
||||
this._shellwm.connect('kill-switch-workspace', () => {
|
||||
if (!this._workspaceAnimation.isAnimating() || this._workspaceAnimation.canCancelGesture())
|
||||
return;
|
||||
|
||||
this._workspaceAnimation.cancelSwitchAnimation();
|
||||
this._shellwm.completed_switch_workspace();
|
||||
});
|
||||
}
|
||||
|
||||
_showPadOsd(display, device, settings, imagePath, editionMode, monitorIndex) {
|
||||
@ -1089,8 +1075,7 @@ var WindowManager = class {
|
||||
}
|
||||
|
||||
_shouldAnimate() {
|
||||
return !(Main.overview.visible ||
|
||||
(this._switchData && this._switchData.gestureActivated));
|
||||
return !(Main.overview.visible || this._workspaceAnimation.isAnimating());
|
||||
}
|
||||
|
||||
_shouldAnimateActor(actor, types) {
|
||||
@ -1571,379 +1556,17 @@ var WindowManager = class {
|
||||
return !(this._allowedKeybindings[binding.get_name()] & Main.actionMode);
|
||||
}
|
||||
|
||||
_syncStacking() {
|
||||
if (this._switchData == null)
|
||||
return;
|
||||
|
||||
let windows = global.get_window_actors();
|
||||
let lastCurSibling = null;
|
||||
let lastDirSibling = [];
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (windows[i].get_parent() == this._switchData.curGroup) {
|
||||
this._switchData.curGroup.set_child_above_sibling(windows[i], lastCurSibling);
|
||||
lastCurSibling = windows[i];
|
||||
} else {
|
||||
for (let dir of Object.values(Meta.MotionDirection)) {
|
||||
let info = this._switchData.surroundings[dir];
|
||||
if (!info || windows[i].get_parent() != info.actor)
|
||||
continue;
|
||||
|
||||
let sibling = lastDirSibling[dir];
|
||||
if (sibling == undefined)
|
||||
sibling = null;
|
||||
|
||||
info.actor.set_child_above_sibling(windows[i], sibling);
|
||||
lastDirSibling[dir] = windows[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_getPositionForDirection(direction, fromWs, toWs) {
|
||||
let xDest = 0, yDest = 0;
|
||||
|
||||
let oldWsIsFullscreen = fromWs.list_windows().some(w => w.is_fullscreen());
|
||||
let newWsIsFullscreen = toWs.list_windows().some(w => w.is_fullscreen());
|
||||
|
||||
// We have to shift windows up or down by the height of the panel to prevent having a
|
||||
// visible gap between the windows while switching workspaces. Since fullscreen windows
|
||||
// hide the panel, they don't need to be shifted up or down.
|
||||
let shiftHeight = Main.panel.height;
|
||||
|
||||
if (direction == Meta.MotionDirection.UP ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT)
|
||||
yDest = -global.screen_height + (oldWsIsFullscreen ? 0 : shiftHeight);
|
||||
else if (direction == Meta.MotionDirection.DOWN ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
yDest = global.screen_height - (newWsIsFullscreen ? 0 : shiftHeight);
|
||||
|
||||
if (direction == Meta.MotionDirection.LEFT ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT)
|
||||
xDest = -global.screen_width;
|
||||
else if (direction == Meta.MotionDirection.RIGHT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
xDest = global.screen_width;
|
||||
|
||||
return [xDest, yDest];
|
||||
}
|
||||
|
||||
_prepareWorkspaceSwitch(from, to, direction) {
|
||||
if (this._switchData)
|
||||
return;
|
||||
|
||||
let wgroup = global.window_group;
|
||||
let windows = global.get_window_actors();
|
||||
let switchData = {};
|
||||
|
||||
this._switchData = switchData;
|
||||
switchData.curGroup = new Clutter.Actor();
|
||||
switchData.movingWindowBin = new Clutter.Actor();
|
||||
switchData.windows = [];
|
||||
switchData.surroundings = {};
|
||||
switchData.gestureActivated = false;
|
||||
switchData.inProgress = false;
|
||||
|
||||
switchData.container = new Clutter.Actor();
|
||||
switchData.container.add_actor(switchData.curGroup);
|
||||
|
||||
wgroup.add_actor(switchData.movingWindowBin);
|
||||
wgroup.add_actor(switchData.container);
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let curWs = workspaceManager.get_workspace_by_index(from);
|
||||
|
||||
for (let dir of Object.values(Meta.MotionDirection)) {
|
||||
let ws = null;
|
||||
|
||||
if (to < 0)
|
||||
ws = curWs.get_neighbor(dir);
|
||||
else if (dir == direction)
|
||||
ws = workspaceManager.get_workspace_by_index(to);
|
||||
|
||||
if (ws == null || ws == curWs) {
|
||||
switchData.surroundings[dir] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
info.actor.set_position(x, y);
|
||||
}
|
||||
|
||||
wgroup.set_child_above_sibling(switchData.movingWindowBin, null);
|
||||
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let actor = windows[i];
|
||||
let window = actor.get_meta_window();
|
||||
|
||||
if (!window.showing_on_its_workspace())
|
||||
continue;
|
||||
|
||||
if (window.is_on_all_workspaces())
|
||||
continue;
|
||||
|
||||
let record = { window: actor,
|
||||
parent: actor.get_parent() };
|
||||
|
||||
if (this._movingWindow && window == this._movingWindow) {
|
||||
record.parent.remove_child(actor);
|
||||
switchData.movingWindow = record;
|
||||
switchData.windows.push(switchData.movingWindow);
|
||||
switchData.movingWindowBin.add_child(actor);
|
||||
} else if (window.get_workspace().index() == from) {
|
||||
record.parent.remove_child(actor);
|
||||
switchData.windows.push(record);
|
||||
switchData.curGroup.add_child(actor);
|
||||
} else {
|
||||
let visible = false;
|
||||
for (let dir of Object.values(Meta.MotionDirection)) {
|
||||
let info = switchData.surroundings[dir];
|
||||
|
||||
if (!info || info.index != window.get_workspace().index())
|
||||
continue;
|
||||
|
||||
record.parent.remove_child(actor);
|
||||
switchData.windows.push(record);
|
||||
info.actor.add_child(actor);
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
|
||||
actor.visible = visible;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < switchData.windows.length; i++) {
|
||||
let w = switchData.windows[i];
|
||||
|
||||
w.windowDestroyId = w.window.connect('destroy', () => {
|
||||
switchData.windows.splice(switchData.windows.indexOf(w), 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_finishWorkspaceSwitch(switchData) {
|
||||
this._switchData = null;
|
||||
|
||||
for (let i = 0; i < switchData.windows.length; i++) {
|
||||
let w = switchData.windows[i];
|
||||
|
||||
w.window.disconnect(w.windowDestroyId);
|
||||
w.window.get_parent().remove_child(w.window);
|
||||
w.parent.add_child(w.window);
|
||||
|
||||
if (w.window.get_meta_window().get_workspace() !=
|
||||
global.workspace_manager.get_active_workspace())
|
||||
w.window.hide();
|
||||
}
|
||||
switchData.container.destroy();
|
||||
switchData.movingWindowBin.destroy();
|
||||
|
||||
this._movingWindow = null;
|
||||
}
|
||||
|
||||
_switchWorkspace(shellwm, from, to, direction) {
|
||||
if (!Main.sessionMode.hasWorkspaces || !this._shouldAnimate()) {
|
||||
shellwm.completed_switch_workspace();
|
||||
return;
|
||||
}
|
||||
|
||||
this._prepareWorkspaceSwitch(from, to, direction);
|
||||
this._switchData.inProgress = true;
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let fromWs = workspaceManager.get_workspace_by_index(from);
|
||||
let toWs = workspaceManager.get_workspace_by_index(to);
|
||||
|
||||
let [xDest, yDest] = this._getPositionForDirection(direction, fromWs, toWs);
|
||||
|
||||
/* @direction is the direction that the "camera" moves, so the
|
||||
* screen contents have to move one screen's worth in the
|
||||
* opposite direction.
|
||||
*/
|
||||
xDest = -xDest;
|
||||
yDest = -yDest;
|
||||
|
||||
this._switchData.container.ease({
|
||||
x: xDest,
|
||||
y: yDest,
|
||||
duration: WINDOW_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
|
||||
onComplete: () => this._switchWorkspaceDone(shellwm),
|
||||
this._workspaceAnimation.animateSwitchWorkspace(from, to, direction, () => {
|
||||
this._shellwm.completed_switch_workspace();
|
||||
});
|
||||
}
|
||||
|
||||
_switchWorkspaceDone(shellwm) {
|
||||
this._finishWorkspaceSwitch(this._switchData);
|
||||
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();
|
||||
@ -2141,7 +1764,7 @@ var WindowManager = class {
|
||||
// This won't have any effect for "always sticky" windows
|
||||
// (like desktop windows or docks)
|
||||
|
||||
this._movingWindow = window;
|
||||
this._workspaceAnimation.movingWindow = window;
|
||||
window.change_workspace(workspace);
|
||||
|
||||
global.display.clear_mouse_mode();
|
||||
|
511
js/ui/workspaceAnimation.js
Normal file
511
js/ui/workspaceAnimation.js
Normal file
@ -0,0 +1,511 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported WorkspaceAnimationController */
|
||||
|
||||
const { Clutter, GObject, Meta, Shell } = imports.gi;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Layout = imports.ui.layout;
|
||||
const SwipeTracker = imports.ui.swipeTracker;
|
||||
|
||||
const WINDOW_ANIMATION_TIME = 250;
|
||||
|
||||
const WorkspaceGroup = GObject.registerClass(
|
||||
class WorkspaceGroup extends Clutter.Actor {
|
||||
_init(controller, workspace, monitor) {
|
||||
super._init();
|
||||
|
||||
this._controller = controller;
|
||||
this._workspace = workspace;
|
||||
this._monitor = monitor;
|
||||
this._windows = [];
|
||||
|
||||
this._refreshWindows();
|
||||
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
this._restackedId = global.display.connect('restacked',
|
||||
this._refreshWindows.bind(this));
|
||||
}
|
||||
|
||||
_shouldShowWindow(window) {
|
||||
if (window.get_workspace() !== this._workspace)
|
||||
return false;
|
||||
|
||||
let geometry = global.display.get_monitor_geometry(this._monitor.index);
|
||||
let [intersects, intersection_] = window.get_frame_rect().intersect(geometry);
|
||||
if (!intersects)
|
||||
return false;
|
||||
|
||||
if (!window.showing_on_its_workspace())
|
||||
return false;
|
||||
|
||||
if (window.is_on_all_workspaces())
|
||||
return false;
|
||||
|
||||
if (this._controller.movingWindow &&
|
||||
window === this._controller.movingWindow)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_refreshWindows() {
|
||||
if (this._windows.length > 0)
|
||||
this._removeWindows();
|
||||
|
||||
let windows = global.get_window_actors();
|
||||
windows = windows.filter(w => this._shouldShowWindow(w.meta_window));
|
||||
|
||||
for (let window of windows) {
|
||||
let clone = new Clutter.Clone({
|
||||
source: window,
|
||||
x: window.x - this._monitor.x,
|
||||
y: window.y - this._monitor.y,
|
||||
});
|
||||
|
||||
this.add_actor(clone);
|
||||
window.hide();
|
||||
|
||||
let record = { window, clone };
|
||||
|
||||
record.windowDestroyId = window.connect('destroy', () => {
|
||||
clone.destroy();
|
||||
this._windows.splice(this._windows.indexOf(record), 1);
|
||||
});
|
||||
|
||||
this._windows.push(record);
|
||||
}
|
||||
}
|
||||
|
||||
_removeWindows() {
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
let w = this._windows[i];
|
||||
|
||||
w.window.disconnect(w.windowDestroyId);
|
||||
w.clone.destroy();
|
||||
|
||||
if (w.window.get_meta_window().get_workspace() ===
|
||||
global.workspace_manager.get_active_workspace())
|
||||
w.window.show();
|
||||
}
|
||||
|
||||
this._windows = [];
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
global.display.disconnect(this._restackedId);
|
||||
this._removeWindows();
|
||||
}
|
||||
});
|
||||
|
||||
const WorkspaceAnimation = GObject.registerClass({
|
||||
Properties: {
|
||||
'progress': GObject.ParamSpec.double(
|
||||
'progress', 'progress', 'progress',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
-1, 1, 0),
|
||||
},
|
||||
}, class WorkspaceAnimation extends Clutter.Actor {
|
||||
_init(controller, from, to, direction) {
|
||||
super._init();
|
||||
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
|
||||
this._controller = controller;
|
||||
this._movingWindow = null;
|
||||
this._monitors = [];
|
||||
this._progress = 0;
|
||||
|
||||
global.window_group.add_actor(this);
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let curWs = workspaceManager.get_workspace_by_index(from);
|
||||
|
||||
for (let monitor of Main.layoutManager.monitors) {
|
||||
let record = {
|
||||
index: monitor.index,
|
||||
clipBin: new Clutter.Actor({
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
clip_to_allocation: true,
|
||||
}),
|
||||
container: new Clutter.Actor(),
|
||||
surroundings: {},
|
||||
};
|
||||
|
||||
let constraint = new Layout.MonitorConstraint({ index: monitor.index });
|
||||
record.clipBin.add_constraint(constraint);
|
||||
|
||||
record.clipBin.add_actor(record.container);
|
||||
|
||||
this.add_actor(record.clipBin);
|
||||
|
||||
record.curGroup = new WorkspaceGroup(controller, curWs, monitor);
|
||||
record.container.add_actor(record.curGroup);
|
||||
|
||||
for (let dir of Object.values(Meta.MotionDirection)) {
|
||||
let ws = null;
|
||||
|
||||
if (to < 0)
|
||||
ws = curWs.get_neighbor(dir);
|
||||
else if (dir === direction)
|
||||
ws = workspaceManager.get_workspace_by_index(to);
|
||||
|
||||
if (ws === null || ws === curWs) {
|
||||
record.surroundings[dir] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
let [x, y] = this._getPositionForDirection(dir, curWs, ws,
|
||||
monitor.index);
|
||||
let info = {
|
||||
index: ws.index(),
|
||||
actor: new WorkspaceGroup(controller, ws, monitor),
|
||||
xDest: x,
|
||||
yDest: y,
|
||||
};
|
||||
record.surroundings[dir] = info;
|
||||
record.container.add_actor(info.actor);
|
||||
record.container.set_child_above_sibling(info.actor, null);
|
||||
|
||||
info.actor.set_position(x, y);
|
||||
}
|
||||
|
||||
this._monitors.push(record);
|
||||
}
|
||||
|
||||
if (this._controller.movingWindow) {
|
||||
let actor = this._controller.movingWindow.get_compositor_private();
|
||||
let container = new Clutter.Actor();
|
||||
|
||||
this._movingWindow = {
|
||||
container,
|
||||
window: actor,
|
||||
parent: actor.get_parent(),
|
||||
};
|
||||
|
||||
this._movingWindow.parent.remove_child(actor);
|
||||
this._movingWindow.container.add_child(actor);
|
||||
this._movingWindow.windowDestroyId = actor.connect('destroy', () => {
|
||||
this._movingWindow = null;
|
||||
});
|
||||
|
||||
global.window_group.add_actor(container);
|
||||
global.window_group.set_child_above_sibling(container, null);
|
||||
}
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
this._monitors = [];
|
||||
|
||||
if (this._movingWindow) {
|
||||
let record = this._movingWindow;
|
||||
record.window.disconnect(record.windowDestroyId);
|
||||
record.window.get_parent().remove_child(record.window);
|
||||
record.parent.add_child(record.window);
|
||||
record.container.destroy();
|
||||
|
||||
this._movingWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
_getPositionForDirection(direction, fromWs, toWs, monitor) {
|
||||
let xDest = 0, yDest = 0;
|
||||
|
||||
let condition = w => w.get_monitor() === monitor && w.is_fullscreen();
|
||||
|
||||
let oldWsIsFullscreen = fromWs.list_windows().some(condition);
|
||||
let newWsIsFullscreen = toWs.list_windows().some(condition);
|
||||
|
||||
let geometry = Main.layoutManager.monitors[monitor];
|
||||
|
||||
// We have to shift windows up or down by the height of the panel to prevent having a
|
||||
// visible gap between the windows while switching workspaces. Since fullscreen windows
|
||||
// hide the panel, they don't need to be shifted up or down.
|
||||
let shiftHeight = monitor === Main.layoutManager.primaryIndex
|
||||
? Main.panel.height : 0;
|
||||
|
||||
if (direction === Meta.MotionDirection.UP ||
|
||||
direction === Meta.MotionDirection.UP_LEFT ||
|
||||
direction === Meta.MotionDirection.UP_RIGHT)
|
||||
yDest = -geometry.height + (oldWsIsFullscreen ? 0 : shiftHeight);
|
||||
else if (direction === Meta.MotionDirection.DOWN ||
|
||||
direction === Meta.MotionDirection.DOWN_LEFT ||
|
||||
direction === Meta.MotionDirection.DOWN_RIGHT)
|
||||
yDest = geometry.height - (newWsIsFullscreen ? 0 : shiftHeight);
|
||||
|
||||
if (direction === Meta.MotionDirection.LEFT ||
|
||||
direction === Meta.MotionDirection.UP_LEFT ||
|
||||
direction === Meta.MotionDirection.DOWN_LEFT)
|
||||
xDest = -geometry.width;
|
||||
else if (direction === Meta.MotionDirection.RIGHT ||
|
||||
direction === Meta.MotionDirection.UP_RIGHT ||
|
||||
direction === Meta.MotionDirection.DOWN_RIGHT)
|
||||
xDest = geometry.width;
|
||||
|
||||
return [xDest, yDest];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
progressForDirection(dir) {
|
||||
if (global.workspace_manager.layout_rows === -1)
|
||||
return dir === Meta.MotionDirection.DOWN ? 1 : -1;
|
||||
else if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL)
|
||||
return dir === Meta.MotionDirection.LEFT ? 1 : -1;
|
||||
else
|
||||
return dir === Meta.MotionDirection.RIGHT ? 1 : -1;
|
||||
}
|
||||
|
||||
get progress() {
|
||||
return this._progress;
|
||||
}
|
||||
|
||||
set progress(progress) {
|
||||
this._progress = progress;
|
||||
|
||||
let direction = this.directionForProgress(progress);
|
||||
|
||||
for (let monitorData of this._monitors) {
|
||||
let xPos = 0;
|
||||
let yPos = 0;
|
||||
|
||||
if (global.workspace_manager.layout_rows === -1)
|
||||
yPos = -Math.round(progress * this._getDistance(monitorData, direction));
|
||||
else if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL)
|
||||
xPos = Math.round(progress * this._getDistance(monitorData, direction));
|
||||
else
|
||||
xPos = -Math.round(progress * this._getDistance(monitorData, direction));
|
||||
|
||||
monitorData.container.set_position(xPos, yPos);
|
||||
}
|
||||
}
|
||||
|
||||
_getDistance(monitorData, direction) {
|
||||
let info = monitorData.surroundings[direction];
|
||||
if (!info)
|
||||
return 0;
|
||||
|
||||
switch (direction) {
|
||||
case Meta.MotionDirection.UP:
|
||||
return -info.yDest;
|
||||
case Meta.MotionDirection.DOWN:
|
||||
return info.yDest;
|
||||
case Meta.MotionDirection.LEFT:
|
||||
return -info.xDest;
|
||||
case Meta.MotionDirection.RIGHT:
|
||||
return info.xDest;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
getProgressRange(monitor) {
|
||||
let monitorData = null;
|
||||
for (let data of this._monitors) {
|
||||
if (data.index === monitor) {
|
||||
monitorData = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!monitorData)
|
||||
return 0;
|
||||
|
||||
let baseDistance;
|
||||
if (global.workspace_manager.layout_rows !== -1)
|
||||
baseDistance = Main.layoutManager.monitors[monitor].width;
|
||||
else
|
||||
baseDistance = Main.layoutManager.monitors[monitor].height;
|
||||
|
||||
let direction = this.directionForProgress(-1);
|
||||
let distance = this._getDistance(monitorData, direction);
|
||||
let lower = -distance / baseDistance;
|
||||
|
||||
direction = this.directionForProgress(1);
|
||||
distance = this._getDistance(monitorData, direction);
|
||||
let upper = distance / baseDistance;
|
||||
|
||||
return [lower, upper];
|
||||
}
|
||||
});
|
||||
|
||||
var WorkspaceAnimationController = class {
|
||||
constructor() {
|
||||
this._blockAnimations = false;
|
||||
this._movingWindow = null;
|
||||
this._inProgress = false;
|
||||
this._gestureActivated = false;
|
||||
this._animation = null;
|
||||
|
||||
Main.overview.connect('showing', () => {
|
||||
if (this._gestureActivated)
|
||||
this._switchWorkspaceStop();
|
||||
|
||||
this._swipeTracker.enabled = false;
|
||||
});
|
||||
Main.overview.connect('hiding', () => {
|
||||
this._swipeTracker.enabled = true;
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
_prepareWorkspaceSwitch(from, to, direction) {
|
||||
if (this._animation)
|
||||
return;
|
||||
|
||||
this._animation = new WorkspaceAnimation(this, from, to, direction);
|
||||
}
|
||||
|
||||
_finishWorkspaceSwitch() {
|
||||
if (this._animation)
|
||||
this._animation.destroy();
|
||||
this._animation = null;
|
||||
this._inProgress = false;
|
||||
this._gestureActivated = false;
|
||||
this.movingWindow = null;
|
||||
this._monitor = null;
|
||||
}
|
||||
|
||||
animateSwitchWorkspace(from, to, direction, onComplete) {
|
||||
this._prepareWorkspaceSwitch(from, to, direction);
|
||||
this._inProgress = true;
|
||||
|
||||
let progress = this._animation.progressForDirection(direction);
|
||||
|
||||
this._animation.ease_property('progress', progress, {
|
||||
duration: WINDOW_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
|
||||
onComplete: () => {
|
||||
this._finishWorkspaceSwitch();
|
||||
onComplete();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_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 = Main.layoutManager.monitors[monitor].width;
|
||||
else
|
||||
baseDistance = Main.layoutManager.monitors[monitor].height;
|
||||
|
||||
let progress;
|
||||
if (this._gestureActivated) {
|
||||
this._animation.remove_all_transitions();
|
||||
progress = this._animation.progress;
|
||||
} else {
|
||||
this._prepareWorkspaceSwitch(activeWorkspace.index(), -1);
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
this._monitor = monitor;
|
||||
let [lower, upper] = this._animation.getProgressRange(monitor);
|
||||
if (progress < 0)
|
||||
progress *= -lower;
|
||||
else if (progress > 0)
|
||||
progress *= upper;
|
||||
|
||||
let points = [];
|
||||
if (lower !== 0)
|
||||
points.push(lower);
|
||||
|
||||
points.push(0);
|
||||
|
||||
if (upper !== 0)
|
||||
points.push(upper);
|
||||
|
||||
tracker.confirmSwipe(baseDistance, points, progress, 0);
|
||||
}
|
||||
|
||||
_switchWorkspaceUpdate(tracker, progress) {
|
||||
// Translate the progress into [-1;1] range
|
||||
let [lower, upper] = this._animation.getProgressRange(this._monitor);
|
||||
if (progress < 0)
|
||||
progress /= -lower;
|
||||
else if (progress > 0)
|
||||
progress /= upper;
|
||||
|
||||
this._animation.progress = progress;
|
||||
}
|
||||
|
||||
_switchWorkspaceEnd(tracker, duration, endProgress) {
|
||||
if (!this._animation)
|
||||
return;
|
||||
|
||||
// Translate the progress into [-1;1] range
|
||||
endProgress = Math.sign(endProgress);
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let activeWorkspace = workspaceManager.get_active_workspace();
|
||||
let newWs = activeWorkspace;
|
||||
if (endProgress !== 0) {
|
||||
let direction = this._animation.directionForProgress(endProgress);
|
||||
newWs = activeWorkspace.get_neighbor(direction);
|
||||
}
|
||||
|
||||
this._gestureActivated = true;
|
||||
|
||||
this._animation.ease_property('progress', endProgress, {
|
||||
duration,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
|
||||
onComplete: () => {
|
||||
if (newWs !== activeWorkspace)
|
||||
newWs.activate(global.get_current_time());
|
||||
this._finishWorkspaceSwitch();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_switchWorkspaceStop() {
|
||||
this._animation.progress = 0;
|
||||
this._finishWorkspaceSwitch();
|
||||
}
|
||||
|
||||
isAnimating() {
|
||||
return this._animation !== null;
|
||||
}
|
||||
|
||||
canCancelGesture() {
|
||||
return this.isAnimating() && this._gestureActivated;
|
||||
}
|
||||
|
||||
set movingWindow(movingWindow) {
|
||||
this._movingWindow = movingWindow;
|
||||
}
|
||||
|
||||
get movingWindow() {
|
||||
return this._movingWindow;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user