[gnome-shell/wip/exalm/gestures: 7/7] workspaceAnimation: Support multiple monitors



commit ec14448d84916fc24b46b767d458220304386d3c
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Thu Jul 4 23:43:23 2019 +0500

    workspaceAnimation: Support multiple monitors
    
    Currently, there's one animation for the whole canvas. While it looks fine
    with just one screen, it causes windows to move between screens when
    switching workspaces. Instead, have a separate animation on each screen,
    and sync their progress so that at any given time the progress "fraction"
    is the same between all screens. Clip all animations to their screens so
    that the windows don't leak to other screens.
    
    If a window is placed between every screen, can end up in multiple
    animations, in that case each part is still animated separately.
    
    Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1213
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605

 js/ui/workspaceAnimation.js | 166 ++++++++++++++++++++++++++++----------------
 1 file changed, 108 insertions(+), 58 deletions(-)
---
diff --git a/js/ui/workspaceAnimation.js b/js/ui/workspaceAnimation.js
index 1dbd873b7e..664e98a65b 100644
--- a/js/ui/workspaceAnimation.js
+++ b/js/ui/workspaceAnimation.js
@@ -4,17 +4,19 @@
 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) {
+    _init(controller, workspace, monitor) {
         super._init();
 
         this._controller = controller;
         this._workspace = workspace;
+        this._monitor = monitor;
         this._windows = [];
 
         this._refreshWindows();
@@ -28,6 +30,11 @@ class WorkspaceGroup extends Clutter.Actor {
         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;
 
@@ -51,8 +58,8 @@ class WorkspaceGroup extends Clutter.Actor {
         for (let window of windows) {
             let clone = new Clutter.Clone({
                 source: window,
-                x: window.x,
-                y: window.y,
+                x: window.x - this._monitor.x,
+                y: window.y - this._monitor.y,
             });
 
             this.add_actor(clone);
@@ -105,45 +112,65 @@ const WorkspaceAnimation = GObject.registerClass({
 
         this._controller = controller;
         this._movingWindow = null;
-        this._surroundings = {};
+        this._monitors = [];
         this._progress = 0;
 
-        this._container = new Clutter.Actor();
-
-        this.add_actor(this._container);
         global.window_group.add_actor(this);
 
         let workspaceManager = global.workspace_manager;
         let curWs = workspaceManager.get_workspace_by_index(from);
 
-        this._curGroup = new WorkspaceGroup(controller, curWs);
-        this._container.add_actor(this._curGroup);
+        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: {},
+            };
 
-        for (let dir of Object.values(Meta.MotionDirection)) {
-            let ws = null;
+            let constraint = new Layout.MonitorConstraint({ index: monitor.index });
+            record.clipBin.add_constraint(constraint);
 
-            if (to < 0)
-                ws = curWs.get_neighbor(dir);
-            else if (dir === direction)
-                ws = workspaceManager.get_workspace_by_index(to);
+            record.clipBin.add_actor(record.container);
 
-            if (ws === null || ws === curWs) {
-                this._surroundings[dir] = null;
-                continue;
-            }
+            this.add_actor(record.clipBin);
 
-            let [x, y] = this._getPositionForDirection(dir, curWs, ws);
-            let info = {
-                index: ws.index(),
-                actor: new WorkspaceGroup(controller, ws),
-                xDest: x,
-                yDest: y,
-            };
-            this._surroundings[dir] = info;
-            this._container.add_actor(info.actor);
-            this._container.set_child_above_sibling(info.actor, null);
+            record.curGroup = new WorkspaceGroup(controller, curWs, monitor);
+            record.container.add_actor(record.curGroup);
+
+            for (let dir of Object.values(Meta.MotionDirection)) {
+                let ws = null;
 
-            info.actor.set_position(x, y);
+                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) {
@@ -168,6 +195,8 @@ const WorkspaceAnimation = GObject.registerClass({
     }
 
     _onDestroy() {
+        this._monitors = [];
+
         if (this._movingWindow) {
             let record = this._movingWindow;
             record.window.disconnect(record.windowDestroyId);
@@ -179,34 +208,39 @@ const WorkspaceAnimation = GObject.registerClass({
         }
     }
 
-    _getPositionForDirection(direction, fromWs, toWs) {
+    _getPositionForDirection(direction, fromWs, toWs, monitor) {
         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());
+        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 = Main.panel.height;
+        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 = -global.screen_height + (oldWsIsFullscreen ? 0 : shiftHeight);
+            yDest = -geometry.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);
+            yDest = geometry.height - (newWsIsFullscreen ? 0 : shiftHeight);
 
         if (direction === Meta.MotionDirection.LEFT ||
             direction === Meta.MotionDirection.UP_LEFT ||
             direction === Meta.MotionDirection.DOWN_LEFT)
-            xDest = -global.screen_width;
+            xDest = -geometry.width;
         else if (direction === Meta.MotionDirection.RIGHT ||
                  direction === Meta.MotionDirection.UP_RIGHT ||
                  direction === Meta.MotionDirection.DOWN_RIGHT)
-            xDest = global.screen_width;
+            xDest = geometry.width;
 
         return [xDest, yDest];
     }
@@ -244,21 +278,24 @@ const WorkspaceAnimation = GObject.registerClass({
         this._progress = progress;
 
         let direction = this.directionForProgress(progress);
-        let xPos = 0;
-        let yPos = 0;
 
-        if (global.workspace_manager.layout_rows === -1)
-            yPos = -Math.round(progress * this._getDistance(direction));
-        else if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL)
-            xPos = Math.round(progress * this._getDistance(direction));
-        else
-            xPos = -Math.round(progress * this._getDistance(direction));
+        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));
 
-        this._container.set_position(xPos, yPos);
+            monitorData.container.set_position(xPos, yPos);
+        }
     }
 
-    _getDistance(direction) {
-        let info = this._surroundings[direction];
+    _getDistance(monitorData, direction) {
+        let info = monitorData.surroundings[direction];
         if (!info)
             return 0;
 
@@ -276,19 +313,30 @@ const WorkspaceAnimation = GObject.registerClass({
         return 0;
     }
 
-    getProgressRange() {
+    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 = global.screen_width;
+            baseDistance = Main.layoutManager.monitors[monitor].width;
         else
-            baseDistance = global.screen_height;
+            baseDistance = Main.layoutManager.monitors[monitor].height;
 
         let direction = this.directionForProgress(-1);
-        let distance = this._getDistance(direction);
+        let distance = this._getDistance(monitorData, direction);
         let lower = -distance / baseDistance;
 
         direction = this.directionForProgress(1);
-        distance = this._getDistance(direction);
+        distance = this._getDistance(monitorData, direction);
         let upper = distance / baseDistance;
 
         return [lower, upper];
@@ -335,6 +383,7 @@ var WorkspaceAnimationController = class {
         this._inProgress = false;
         this._gestureActivated = false;
         this.movingWindow = null;
+        this._monitor = null;
     }
 
     animateSwitchWorkspace(from, to, direction, onComplete) {
@@ -368,9 +417,9 @@ var WorkspaceAnimationController = class {
 
         let baseDistance;
         if (horiz)
-            baseDistance = global.screen_width;
+            baseDistance = Main.layoutManager.monitors[monitor].width;
         else
-            baseDistance = global.screen_height;
+            baseDistance = Main.layoutManager.monitors[monitor].height;
 
         let progress;
         if (this._gestureActivated) {
@@ -381,7 +430,8 @@ var WorkspaceAnimationController = class {
             progress = 0;
         }
 
-        let [lower, upper] = this._animation.getProgressRange();
+        this._monitor = monitor;
+        let [lower, upper] = this._animation.getProgressRange(monitor);
         if (progress < 0)
             progress *= -lower;
         else if (progress > 0)
@@ -401,7 +451,7 @@ var WorkspaceAnimationController = class {
 
     _switchWorkspaceUpdate(tracker, progress) {
         // Translate the progress into [-1;1] range
-        let [lower, upper] = this._animation.getProgressRange();
+        let [lower, upper] = this._animation.getProgressRange(this._monitor);
         if (progress < 0)
             progress /= -lower;
         else if (progress > 0)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]