Blob Blame History Raw
From f31024cc83fd97bcfca101fa674081ba2ca4576b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 4 Jun 2019 19:22:26 +0000
Subject: [PATCH 1/2] workspaceSwitcherPopup: Support horizontal layout

While mutter supports a variety of different grid layouts (n columns/rows,
growing vertically or horizontally from any of the four corners), we
hardcode a fixed vertical layout of a single column.

Now that mutter exposes the actual layout to us, add support for a more
traditional horizontal layout as well.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/575
---
 data/theme/gnome-shell-sass/_common.scss |   3 +-
 js/ui/windowManager.js                   |  36 ++++++--
 js/ui/workspaceSwitcherPopup.js          | 100 +++++++++++++++++------
 3 files changed, 106 insertions(+), 33 deletions(-)

diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
index 5bf01a540..ac493ffa4 100644
--- a/data/theme/gnome-shell-sass/_common.scss
+++ b/data/theme/gnome-shell-sass/_common.scss
@@ -683,7 +683,8 @@ StScrollBar {
     spacing: 8px;
   }
 
-  .ws-switcher-active-up, .ws-switcher-active-down {
+  .ws-switcher-active-up, .ws-switcher-active-down,
+  .ws-switcher-active-left, .ws-switcher-active-right {
     height: 50px;
     background-color: $selected_bg_color;
     color: $selected_fg_color;
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 17576a07e..b439b3c0a 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -1890,6 +1890,8 @@ var WindowManager = new Lang.Class({
         let [action,,,target] = binding.get_name().split('-');
         let newWs;
         let direction;
+        let vertical = screen.layout_rows == -1;
+        let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
 
         if (action == 'move') {
             // "Moving" a window to another workspace doesn't make sense when
@@ -1902,7 +1904,12 @@ var WindowManager = new Lang.Class({
         }
 
         if (target == 'last') {
-            direction = Meta.MotionDirection.DOWN;
+            if (vertical)
+                direction = Meta.MotionDirection.DOWN;
+            else if (rtl)
+                direction = Meta.MotionDirection.LEFT;
+            else
+                direction = Meta.MotionDirection.RIGHT;
             newWs = screen.get_workspace_by_index(screen.n_workspaces - 1);
         } else if (isNaN(target)) {
             // Prepend a new workspace dynamically
@@ -1918,16 +1925,33 @@ var WindowManager = new Lang.Class({
             target--;
             newWs = screen.get_workspace_by_index(target);
 
-            if (screen.get_active_workspace().index() > target)
-                direction = Meta.MotionDirection.UP;
-            else
-                direction = Meta.MotionDirection.DOWN;
+            if (screen.get_active_workspace().index() > target) {
+                if (vertical)
+                    direction = Meta.MotionDirection.UP;
+                else if (rtl)
+                    direction = Meta.MotionDirection.RIGHT;
+                else
+                    direction = Meta.MotionDirection.LEFT;
+            } else {
+                if (vertical)
+                    direction = Meta.MotionDirection.DOWN;
+                else if (rtl)
+                    direction = Meta.MotionDirection.LEFT;
+                else
+                    direction = Meta.MotionDirection.RIGHT;
+            }
         }
 
-        if (direction != Meta.MotionDirection.UP &&
+        if (screen.layout_rows == -1 &&
+            direction != Meta.MotionDirection.UP &&
             direction != Meta.MotionDirection.DOWN)
             return;
 
+        if (screen.layout_columns == -1 &&
+            direction != Meta.MotionDirection.LEFT &&
+            direction != Meta.MotionDirection.RIGHT)
+            return;
+
         if (action == 'switch')
             this.actionMoveWorkspace(newWs);
         else
diff --git a/js/ui/workspaceSwitcherPopup.js b/js/ui/workspaceSwitcherPopup.js
index 12bff85d9..d2c161817 100644
--- a/js/ui/workspaceSwitcherPopup.js
+++ b/js/ui/workspaceSwitcherPopup.js
@@ -32,6 +32,10 @@ var WorkspaceSwitcherPopup = new Lang.Class({
         this._childHeight = 0;
         this._childWidth = 0;
         this._timeoutId = 0;
+        this._orientation = global.screen.layout_rows == -1
+            ? Clutter.Orientation.VERTICAL
+            : Clutter.Orientation.HORIZONTAL;
+
         this._list.connect('style-changed', () => {
            this._itemSpacing = this._list.get_theme_node().get_length('spacing');
         });
@@ -52,53 +56,93 @@ var WorkspaceSwitcherPopup = new Lang.Class({
         this._globalSignals.push(global.screen.connect('workspace-removed', this._redisplay.bind(this)));
     },
 
-    _getPreferredHeight(actor, forWidth, alloc) {
+    _getPreferredSizeForOrientation(forSize) {
         let children = this._list.get_children();
         let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
+        let themeNode = this.actor.get_theme_node();
+
+        let availSize;
+        if (this._orientation == Clutter.Orientation.HORIZONTAL) {
+            availSize = workArea.width - themeNode.get_horizontal_padding();
+            availSize -= this._container.get_theme_node().get_horizontal_padding();
+            availSize -= this._list.get_theme_node().get_horizontal_padding();
+        } else {
+            availSize = workArea.height - themeNode.get_vertical_padding();
+            availSize -= this._container.get_theme_node().get_vertical_padding();
+            availSize -= this._list.get_theme_node().get_vertical_padding();
+        }
 
-        let availHeight = workArea.height;
-        availHeight -= this.actor.get_theme_node().get_vertical_padding();
-        availHeight -= this._container.get_theme_node().get_vertical_padding();
-        availHeight -= this._list.get_theme_node().get_vertical_padding();
-
-        let height = 0;
+        let size = 0;
         for (let i = 0; i < children.length; i++) {
             let [childMinHeight, childNaturalHeight] = children[i].get_preferred_height(-1);
-            let [childMinWidth, childNaturalWidth] = children[i].get_preferred_width(childNaturalHeight);
-            height += childNaturalHeight * workArea.width / workArea.height;
+            let height = childNaturalHeight * workArea.width / workArea.height;
+
+            if (this._orientation == Clutter.Orientation.HORIZONTAL)
+                size += height * workArea.width / workArea.height;
+            else
+                size += height;
         }
 
         let spacing = this._itemSpacing * (global.screen.n_workspaces - 1);
-        height += spacing;
-        height = Math.min(height, availHeight);
+        size += spacing;
+        size = Math.min(size, availSize);
+
+        if (this._orientation == Clutter.Orientation.HORIZONTAL) {
+            this._childWidth = (size - spacing) / global.screen.n_workspaces;
+            return themeNode.adjust_preferred_width(size, size);
+        } else {
+            this._childHeight = (size - spacing) / global.screen.n_workspaces;
+            return themeNode.adjust_preferred_height(size, size);
+        }
+    },
 
-        this._childHeight = (height - spacing) / global.screen.n_workspaces;
+    _getSizeForOppositeOrientation() {
+        let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
 
-        alloc.min_size = height;
-        alloc.natural_size = height;
+        if (this._orientation == Clutter.Orientation.HORIZONTAL) {
+            this._childHeight = Math.round(this._childWidth * workArea.height / workArea.width);
+            return [this._childHeight, this._childHeight];
+        } else {
+            this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
+            return [this._childWidth, this._childWidth];
+        }
     },
 
-    _getPreferredWidth(actor, forHeight, alloc) {
-        let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
-        this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
+    _getPreferredHeight(actor, forWidth, alloc) {
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
+            [alloc.min_size, alloc.natural_size] = this._getSizeForOppositeOrientation();
+        else
+            [alloc.min_size, alloc.natural_size] = this._getPreferredSizeForOrientation(forWidth);
+    },
 
-        alloc.min_size = this._childWidth;
-        alloc.natural_size = this._childWidth;
+    _getPreferredWidth(actor, forHeight, alloc) {
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
+            [alloc.min_size, alloc.natural_size] = this._getPreferredSizeForOrientation(forHeight);
+        else
+            [alloc.min_size, alloc.natural_size] = this._getSizeForOppositeOrientation();
     },
 
     _allocate(actor, box, flags) {
         let children = this._list.get_children();
         let childBox = new Clutter.ActorBox();
 
+        let rtl = this.text_direction == Clutter.TextDirection.RTL;
+        let x = rtl ? box.x2 - this._childWidth : box.x1;
         let y = box.y1;
-        let prevChildBoxY2 = box.y1 - this._itemSpacing;
         for (let i = 0; i < children.length; i++) {
-            childBox.x1 = box.x1;
-            childBox.x2 = box.x1 + this._childWidth;
-            childBox.y1 = prevChildBoxY2 + this._itemSpacing;
+            childBox.x1 = Math.round(x);
+            childBox.x2 = Math.round(x + this._childWidth);
+            childBox.y1 = Math.round(y);
             childBox.y2 = Math.round(y + this._childHeight);
-            y += this._childHeight + this._itemSpacing;
-            prevChildBoxY2 = childBox.y2;
+
+            if (this._orientation == Clutter.Orientation.HORIZONTAL) {
+                if (rtl)
+                    x -= this._childWidth + this._itemSpacing;
+                else
+                    x += this._childWidth + this._itemSpacing;
+            } else {
+                y += this._childHeight + this._itemSpacing;
+            }
             children[i].allocate(childBox, flags);
         }
     },
@@ -111,8 +155,12 @@ var WorkspaceSwitcherPopup = new Lang.Class({
 
            if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.UP)
                indicator = new St.Bin({ style_class: 'ws-switcher-active-up' });
-           else if(i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.DOWN)
+           else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.DOWN)
                indicator = new St.Bin({ style_class: 'ws-switcher-active-down' });
+           else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.LEFT)
+               indicator = new St.Bin({ style_class: 'ws-switcher-active-left' });
+           else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.RIGHT)
+               indicator = new St.Bin({ style_class: 'ws-switcher-active-right' });
            else
                indicator = new St.Bin({ style_class: 'ws-switcher-box' });
 
-- 
2.21.0


From b4e8d7e975cc1d74c4ed25f5f9667c090bfd59d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 4 Jun 2019 19:49:23 +0000
Subject: [PATCH 2/2] workspacesView: Support horizontal layout

Just as we did for the workspace switcher popup, support workspaces
being laid out in a single row in the window picker.

Note that this takes care of the various workspace switch actions in
the overview (scrolling, panning, touch(pad) gestures) as well as the
switch animation, but not of the overview's workspace switcher component.

There are currently no plans to support other layouts there, as the
component is inherently vertical (in fact, it was the whole reason for
switching the layout in the first place).

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/575
---
 js/ui/workspacesView.js | 74 ++++++++++++++++++++++++++++++-----------
 1 file changed, 54 insertions(+), 20 deletions(-)

diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
index 563e43da4..dd7bb0e2a 100644
--- a/js/ui/workspacesView.js
+++ b/js/ui/workspacesView.js
@@ -187,26 +187,32 @@ var WorkspacesView = new Lang.Class({
 
             Tweener.removeTweens(workspace.actor);
 
-            let y = (w - active) * this._fullGeometry.height;
+            let params = {};
+            if (global.screen.layout_rows == -1)
+                params.y = (w - active) * this._fullGeometry.height;
+            else if (this.actor.text_direction == Clutter.TextDirection.RTL)
+                params.x = (active - w) * this._fullGeometry.width;
+            else
+                params.x = (w - active) * this._fullGeometry.width;
 
             if (showAnimation) {
-                let params = { y: y,
-                               time: WORKSPACE_SWITCH_TIME,
-                               transition: 'easeOutQuad'
-                             };
+                let tweenParams = Object.assign(params, {
+                    time: WORKSPACE_SWITCH_TIME,
+                    transition: 'easeOutQuad'
+                });
                 // we have to call _updateVisibility() once before the
                 // animation and once afterwards - it does not really
                 // matter which tween we use, so we pick the first one ...
                 if (w == 0) {
                     this._updateVisibility();
-                    params.onComplete = () => {
+                    tweenParams.onComplete = () => {
                         this._animating = false;
                         this._updateVisibility();
                     };
                 }
-                Tweener.addTween(workspace.actor, params);
+                Tweener.addTween(workspace.actor, tweenParams);
             } else {
-                workspace.actor.set_position(0, y);
+                Object.assign(workspace.actor, params);
                 if (w == 0)
                     this._updateVisibility();
             }
@@ -328,22 +334,39 @@ var WorkspacesView = new Lang.Class({
             metaWorkspace.activate(global.get_current_time());
         }
 
-        let last = this._workspaces.length - 1;
-        let firstWorkspaceY = this._workspaces[0].actor.y;
-        let lastWorkspaceY = this._workspaces[last].actor.y;
-        let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
-
         if (adj.upper == 1)
             return;
 
-        let currentY = firstWorkspaceY;
-        let newY =  - adj.value / (adj.upper - 1) * workspacesHeight;
+        let last = this._workspaces.length - 1;
+
+        if (global.screen.layout_rows == -1) {
+            let firstWorkspaceY = this._workspaces[0].actor.y;
+            let lastWorkspaceY = this._workspaces[last].actor.y;
+            let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
+
+            let currentY = firstWorkspaceY;
+            let newY = -adj.value / (adj.upper - 1) * workspacesHeight;
+
+            let dy = newY - currentY;
 
-        let dy = newY - currentY;
+            for (let i = 0; i < this._workspaces.length; i++) {
+                this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
+                this._workspaces[i].actor.y += dy;
+            }
+        } else {
+            let firstWorkspaceX = this._workspaces[0].actor.x;
+            let lastWorkspaceX = this._workspaces[last].actor.x;
+            let workspacesWidth = lastWorkspaceX - firstWorkspaceX;
+
+            let currentX = firstWorkspaceX;
+            let newX = -adj.value / (adj.upper - 1) * workspacesWidth;
 
-        for (let i = 0; i < this._workspaces.length; i++) {
-            this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
-            this._workspaces[i].actor.y += dy;
+            let dx = newX - currentX;
+
+            for (let i = 0; i < this._workspaces.length; i++) {
+                this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
+                this._workspaces[i].actor.x += dx;
+            }
         }
     },
 });
@@ -479,7 +502,12 @@ var WorkspacesDisplay = new Lang.Class({
     _onPan(action) {
         let [dist, dx, dy] = action.get_motion_delta(0);
         let adjustment = this._scrollAdjustment;
-        adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
+        if (global.screen.layout_rows == -1)
+            adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
+        else if (this.actor.text_direction == Clutter.TextDirection.RTL)
+            adjustment.value += (dx / this.actor.width) * adjustment.page_size;
+        else
+            adjustment.value -= (dx / this.actor.width) * adjustment.page_size;
         return false;
     },
 
@@ -688,6 +716,12 @@ var WorkspacesDisplay = new Lang.Class({
         case Clutter.ScrollDirection.DOWN:
             ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN);
             break;
+        case Clutter.ScrollDirection.LEFT:
+            ws = activeWs.get_neighbor(Meta.MotionDirection.LEFT);
+            break;
+        case Clutter.ScrollDirection.RIGHT:
+            ws = activeWs.get_neighbor(Meta.MotionDirection.RIGHT);
+            break;
         default:
             return Clutter.EVENT_PROPAGATE;
         }
-- 
2.21.0