18fbde
From f31024cc83fd97bcfca101fa674081ba2ca4576b Mon Sep 17 00:00:00 2001
18fbde
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
18fbde
Date: Tue, 4 Jun 2019 19:22:26 +0000
18fbde
Subject: [PATCH 1/2] workspaceSwitcherPopup: Support horizontal layout
18fbde
18fbde
While mutter supports a variety of different grid layouts (n columns/rows,
18fbde
growing vertically or horizontally from any of the four corners), we
18fbde
hardcode a fixed vertical layout of a single column.
18fbde
18fbde
Now that mutter exposes the actual layout to us, add support for a more
18fbde
traditional horizontal layout as well.
18fbde
18fbde
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/575
18fbde
---
18fbde
 data/theme/gnome-shell-sass/_common.scss |   3 +-
18fbde
 js/ui/windowManager.js                   |  36 ++++++--
18fbde
 js/ui/workspaceSwitcherPopup.js          | 100 +++++++++++++++++------
18fbde
 3 files changed, 106 insertions(+), 33 deletions(-)
18fbde
18fbde
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
18fbde
index 5bf01a540..ac493ffa4 100644
18fbde
--- a/data/theme/gnome-shell-sass/_common.scss
18fbde
+++ b/data/theme/gnome-shell-sass/_common.scss
18fbde
@@ -683,7 +683,8 @@ StScrollBar {
18fbde
     spacing: 8px;
18fbde
   }
18fbde
 
18fbde
-  .ws-switcher-active-up, .ws-switcher-active-down {
18fbde
+  .ws-switcher-active-up, .ws-switcher-active-down,
18fbde
+  .ws-switcher-active-left, .ws-switcher-active-right {
18fbde
     height: 50px;
18fbde
     background-color: $selected_bg_color;
18fbde
     color: $selected_fg_color;
18fbde
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
18fbde
index 17576a07e..b439b3c0a 100644
18fbde
--- a/js/ui/windowManager.js
18fbde
+++ b/js/ui/windowManager.js
18fbde
@@ -1890,6 +1890,8 @@ var WindowManager = new Lang.Class({
18fbde
         let [action,,,target] = binding.get_name().split('-');
18fbde
         let newWs;
18fbde
         let direction;
18fbde
+        let vertical = screen.layout_rows == -1;
18fbde
+        let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
18fbde
 
18fbde
         if (action == 'move') {
18fbde
             // "Moving" a window to another workspace doesn't make sense when
18fbde
@@ -1902,7 +1904,12 @@ var WindowManager = new Lang.Class({
18fbde
         }
18fbde
 
18fbde
         if (target == 'last') {
18fbde
-            direction = Meta.MotionDirection.DOWN;
18fbde
+            if (vertical)
18fbde
+                direction = Meta.MotionDirection.DOWN;
18fbde
+            else if (rtl)
18fbde
+                direction = Meta.MotionDirection.LEFT;
18fbde
+            else
18fbde
+                direction = Meta.MotionDirection.RIGHT;
18fbde
             newWs = screen.get_workspace_by_index(screen.n_workspaces - 1);
18fbde
         } else if (isNaN(target)) {
18fbde
             // Prepend a new workspace dynamically
18fbde
@@ -1918,16 +1925,33 @@ var WindowManager = new Lang.Class({
18fbde
             target--;
18fbde
             newWs = screen.get_workspace_by_index(target);
18fbde
 
18fbde
-            if (screen.get_active_workspace().index() > target)
18fbde
-                direction = Meta.MotionDirection.UP;
18fbde
-            else
18fbde
-                direction = Meta.MotionDirection.DOWN;
18fbde
+            if (screen.get_active_workspace().index() > target) {
18fbde
+                if (vertical)
18fbde
+                    direction = Meta.MotionDirection.UP;
18fbde
+                else if (rtl)
18fbde
+                    direction = Meta.MotionDirection.RIGHT;
18fbde
+                else
18fbde
+                    direction = Meta.MotionDirection.LEFT;
18fbde
+            } else {
18fbde
+                if (vertical)
18fbde
+                    direction = Meta.MotionDirection.DOWN;
18fbde
+                else if (rtl)
18fbde
+                    direction = Meta.MotionDirection.LEFT;
18fbde
+                else
18fbde
+                    direction = Meta.MotionDirection.RIGHT;
18fbde
+            }
18fbde
         }
18fbde
 
18fbde
-        if (direction != Meta.MotionDirection.UP &&
18fbde
+        if (screen.layout_rows == -1 &&
18fbde
+            direction != Meta.MotionDirection.UP &&
18fbde
             direction != Meta.MotionDirection.DOWN)
18fbde
             return;
18fbde
 
18fbde
+        if (screen.layout_columns == -1 &&
18fbde
+            direction != Meta.MotionDirection.LEFT &&
18fbde
+            direction != Meta.MotionDirection.RIGHT)
18fbde
+            return;
18fbde
+
18fbde
         if (action == 'switch')
18fbde
             this.actionMoveWorkspace(newWs);
18fbde
         else
18fbde
diff --git a/js/ui/workspaceSwitcherPopup.js b/js/ui/workspaceSwitcherPopup.js
18fbde
index 12bff85d9..d2c161817 100644
18fbde
--- a/js/ui/workspaceSwitcherPopup.js
18fbde
+++ b/js/ui/workspaceSwitcherPopup.js
18fbde
@@ -32,6 +32,10 @@ var WorkspaceSwitcherPopup = new Lang.Class({
18fbde
         this._childHeight = 0;
18fbde
         this._childWidth = 0;
18fbde
         this._timeoutId = 0;
18fbde
+        this._orientation = global.screen.layout_rows == -1
18fbde
+            ? Clutter.Orientation.VERTICAL
18fbde
+            : Clutter.Orientation.HORIZONTAL;
18fbde
+
18fbde
         this._list.connect('style-changed', () => {
18fbde
            this._itemSpacing = this._list.get_theme_node().get_length('spacing');
18fbde
         });
18fbde
@@ -52,53 +56,93 @@ var WorkspaceSwitcherPopup = new Lang.Class({
18fbde
         this._globalSignals.push(global.screen.connect('workspace-removed', this._redisplay.bind(this)));
18fbde
     },
18fbde
 
18fbde
-    _getPreferredHeight(actor, forWidth, alloc) {
18fbde
+    _getPreferredSizeForOrientation(forSize) {
18fbde
         let children = this._list.get_children();
18fbde
         let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
18fbde
+        let themeNode = this.actor.get_theme_node();
18fbde
+
18fbde
+        let availSize;
18fbde
+        if (this._orientation == Clutter.Orientation.HORIZONTAL) {
18fbde
+            availSize = workArea.width - themeNode.get_horizontal_padding();
18fbde
+            availSize -= this._container.get_theme_node().get_horizontal_padding();
18fbde
+            availSize -= this._list.get_theme_node().get_horizontal_padding();
18fbde
+        } else {
18fbde
+            availSize = workArea.height - themeNode.get_vertical_padding();
18fbde
+            availSize -= this._container.get_theme_node().get_vertical_padding();
18fbde
+            availSize -= this._list.get_theme_node().get_vertical_padding();
18fbde
+        }
18fbde
 
18fbde
-        let availHeight = workArea.height;
18fbde
-        availHeight -= this.actor.get_theme_node().get_vertical_padding();
18fbde
-        availHeight -= this._container.get_theme_node().get_vertical_padding();
18fbde
-        availHeight -= this._list.get_theme_node().get_vertical_padding();
18fbde
-
18fbde
-        let height = 0;
18fbde
+        let size = 0;
18fbde
         for (let i = 0; i < children.length; i++) {
18fbde
             let [childMinHeight, childNaturalHeight] = children[i].get_preferred_height(-1);
18fbde
-            let [childMinWidth, childNaturalWidth] = children[i].get_preferred_width(childNaturalHeight);
18fbde
-            height += childNaturalHeight * workArea.width / workArea.height;
18fbde
+            let height = childNaturalHeight * workArea.width / workArea.height;
18fbde
+
18fbde
+            if (this._orientation == Clutter.Orientation.HORIZONTAL)
18fbde
+                size += height * workArea.width / workArea.height;
18fbde
+            else
18fbde
+                size += height;
18fbde
         }
18fbde
 
18fbde
         let spacing = this._itemSpacing * (global.screen.n_workspaces - 1);
18fbde
-        height += spacing;
18fbde
-        height = Math.min(height, availHeight);
18fbde
+        size += spacing;
18fbde
+        size = Math.min(size, availSize);
18fbde
+
18fbde
+        if (this._orientation == Clutter.Orientation.HORIZONTAL) {
18fbde
+            this._childWidth = (size - spacing) / global.screen.n_workspaces;
18fbde
+            return themeNode.adjust_preferred_width(size, size);
18fbde
+        } else {
18fbde
+            this._childHeight = (size - spacing) / global.screen.n_workspaces;
18fbde
+            return themeNode.adjust_preferred_height(size, size);
18fbde
+        }
18fbde
+    },
18fbde
 
18fbde
-        this._childHeight = (height - spacing) / global.screen.n_workspaces;
18fbde
+    _getSizeForOppositeOrientation() {
18fbde
+        let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
18fbde
 
18fbde
-        alloc.min_size = height;
18fbde
-        alloc.natural_size = height;
18fbde
+        if (this._orientation == Clutter.Orientation.HORIZONTAL) {
18fbde
+            this._childHeight = Math.round(this._childWidth * workArea.height / workArea.width);
18fbde
+            return [this._childHeight, this._childHeight];
18fbde
+        } else {
18fbde
+            this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
18fbde
+            return [this._childWidth, this._childWidth];
18fbde
+        }
18fbde
     },
18fbde
 
18fbde
-    _getPreferredWidth(actor, forHeight, alloc) {
18fbde
-        let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
18fbde
-        this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
18fbde
+    _getPreferredHeight(actor, forWidth, alloc) {
18fbde
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
18fbde
+            [alloc.min_size, alloc.natural_size] = this._getSizeForOppositeOrientation();
18fbde
+        else
18fbde
+            [alloc.min_size, alloc.natural_size] = this._getPreferredSizeForOrientation(forWidth);
18fbde
+    },
18fbde
 
18fbde
-        alloc.min_size = this._childWidth;
18fbde
-        alloc.natural_size = this._childWidth;
18fbde
+    _getPreferredWidth(actor, forHeight, alloc) {
18fbde
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
18fbde
+            [alloc.min_size, alloc.natural_size] = this._getPreferredSizeForOrientation(forHeight);
18fbde
+        else
18fbde
+            [alloc.min_size, alloc.natural_size] = this._getSizeForOppositeOrientation();
18fbde
     },
18fbde
 
18fbde
     _allocate(actor, box, flags) {
18fbde
         let children = this._list.get_children();
18fbde
         let childBox = new Clutter.ActorBox();
18fbde
 
18fbde
+        let rtl = this.text_direction == Clutter.TextDirection.RTL;
18fbde
+        let x = rtl ? box.x2 - this._childWidth : box.x1;
18fbde
         let y = box.y1;
18fbde
-        let prevChildBoxY2 = box.y1 - this._itemSpacing;
18fbde
         for (let i = 0; i < children.length; i++) {
18fbde
-            childBox.x1 = box.x1;
18fbde
-            childBox.x2 = box.x1 + this._childWidth;
18fbde
-            childBox.y1 = prevChildBoxY2 + this._itemSpacing;
18fbde
+            childBox.x1 = Math.round(x);
18fbde
+            childBox.x2 = Math.round(x + this._childWidth);
18fbde
+            childBox.y1 = Math.round(y);
18fbde
             childBox.y2 = Math.round(y + this._childHeight);
18fbde
-            y += this._childHeight + this._itemSpacing;
18fbde
-            prevChildBoxY2 = childBox.y2;
18fbde
+
18fbde
+            if (this._orientation == Clutter.Orientation.HORIZONTAL) {
18fbde
+                if (rtl)
18fbde
+                    x -= this._childWidth + this._itemSpacing;
18fbde
+                else
18fbde
+                    x += this._childWidth + this._itemSpacing;
18fbde
+            } else {
18fbde
+                y += this._childHeight + this._itemSpacing;
18fbde
+            }
18fbde
             children[i].allocate(childBox, flags);
18fbde
         }
18fbde
     },
18fbde
@@ -111,8 +155,12 @@ var WorkspaceSwitcherPopup = new Lang.Class({
18fbde
 
18fbde
            if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.UP)
18fbde
                indicator = new St.Bin({ style_class: 'ws-switcher-active-up' });
18fbde
-           else if(i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.DOWN)
18fbde
+           else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.DOWN)
18fbde
                indicator = new St.Bin({ style_class: 'ws-switcher-active-down' });
18fbde
+           else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.LEFT)
18fbde
+               indicator = new St.Bin({ style_class: 'ws-switcher-active-left' });
18fbde
+           else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.RIGHT)
18fbde
+               indicator = new St.Bin({ style_class: 'ws-switcher-active-right' });
18fbde
            else
18fbde
                indicator = new St.Bin({ style_class: 'ws-switcher-box' });
18fbde
 
18fbde
-- 
18fbde
2.21.0
18fbde
18fbde
18fbde
From b4e8d7e975cc1d74c4ed25f5f9667c090bfd59d4 Mon Sep 17 00:00:00 2001
18fbde
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
18fbde
Date: Tue, 4 Jun 2019 19:49:23 +0000
18fbde
Subject: [PATCH 2/2] workspacesView: Support horizontal layout
18fbde
18fbde
Just as we did for the workspace switcher popup, support workspaces
18fbde
being laid out in a single row in the window picker.
18fbde
18fbde
Note that this takes care of the various workspace switch actions in
18fbde
the overview (scrolling, panning, touch(pad) gestures) as well as the
18fbde
switch animation, but not of the overview's workspace switcher component.
18fbde
18fbde
There are currently no plans to support other layouts there, as the
18fbde
component is inherently vertical (in fact, it was the whole reason for
18fbde
switching the layout in the first place).
18fbde
18fbde
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/575
18fbde
---
18fbde
 js/ui/workspacesView.js | 74 ++++++++++++++++++++++++++++++-----------
18fbde
 1 file changed, 54 insertions(+), 20 deletions(-)
18fbde
18fbde
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
18fbde
index 563e43da4..dd7bb0e2a 100644
18fbde
--- a/js/ui/workspacesView.js
18fbde
+++ b/js/ui/workspacesView.js
18fbde
@@ -187,26 +187,32 @@ var WorkspacesView = new Lang.Class({
18fbde
 
18fbde
             Tweener.removeTweens(workspace.actor);
18fbde
 
18fbde
-            let y = (w - active) * this._fullGeometry.height;
18fbde
+            let params = {};
18fbde
+            if (global.screen.layout_rows == -1)
18fbde
+                params.y = (w - active) * this._fullGeometry.height;
18fbde
+            else if (this.actor.text_direction == Clutter.TextDirection.RTL)
18fbde
+                params.x = (active - w) * this._fullGeometry.width;
18fbde
+            else
18fbde
+                params.x = (w - active) * this._fullGeometry.width;
18fbde
 
18fbde
             if (showAnimation) {
18fbde
-                let params = { y: y,
18fbde
-                               time: WORKSPACE_SWITCH_TIME,
18fbde
-                               transition: 'easeOutQuad'
18fbde
-                             };
18fbde
+                let tweenParams = Object.assign(params, {
18fbde
+                    time: WORKSPACE_SWITCH_TIME,
18fbde
+                    transition: 'easeOutQuad'
18fbde
+                });
18fbde
                 // we have to call _updateVisibility() once before the
18fbde
                 // animation and once afterwards - it does not really
18fbde
                 // matter which tween we use, so we pick the first one ...
18fbde
                 if (w == 0) {
18fbde
                     this._updateVisibility();
18fbde
-                    params.onComplete = () => {
18fbde
+                    tweenParams.onComplete = () => {
18fbde
                         this._animating = false;
18fbde
                         this._updateVisibility();
18fbde
                     };
18fbde
                 }
18fbde
-                Tweener.addTween(workspace.actor, params);
18fbde
+                Tweener.addTween(workspace.actor, tweenParams);
18fbde
             } else {
18fbde
-                workspace.actor.set_position(0, y);
18fbde
+                Object.assign(workspace.actor, params);
18fbde
                 if (w == 0)
18fbde
                     this._updateVisibility();
18fbde
             }
18fbde
@@ -328,22 +334,39 @@ var WorkspacesView = new Lang.Class({
18fbde
             metaWorkspace.activate(global.get_current_time());
18fbde
         }
18fbde
 
18fbde
-        let last = this._workspaces.length - 1;
18fbde
-        let firstWorkspaceY = this._workspaces[0].actor.y;
18fbde
-        let lastWorkspaceY = this._workspaces[last].actor.y;
18fbde
-        let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
18fbde
-
18fbde
         if (adj.upper == 1)
18fbde
             return;
18fbde
 
18fbde
-        let currentY = firstWorkspaceY;
18fbde
-        let newY =  - adj.value / (adj.upper - 1) * workspacesHeight;
18fbde
+        let last = this._workspaces.length - 1;
18fbde
+
18fbde
+        if (global.screen.layout_rows == -1) {
18fbde
+            let firstWorkspaceY = this._workspaces[0].actor.y;
18fbde
+            let lastWorkspaceY = this._workspaces[last].actor.y;
18fbde
+            let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
18fbde
+
18fbde
+            let currentY = firstWorkspaceY;
18fbde
+            let newY = -adj.value / (adj.upper - 1) * workspacesHeight;
18fbde
+
18fbde
+            let dy = newY - currentY;
18fbde
 
18fbde
-        let dy = newY - currentY;
18fbde
+            for (let i = 0; i < this._workspaces.length; i++) {
18fbde
+                this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
18fbde
+                this._workspaces[i].actor.y += dy;
18fbde
+            }
18fbde
+        } else {
18fbde
+            let firstWorkspaceX = this._workspaces[0].actor.x;
18fbde
+            let lastWorkspaceX = this._workspaces[last].actor.x;
18fbde
+            let workspacesWidth = lastWorkspaceX - firstWorkspaceX;
18fbde
+
18fbde
+            let currentX = firstWorkspaceX;
18fbde
+            let newX = -adj.value / (adj.upper - 1) * workspacesWidth;
18fbde
 
18fbde
-        for (let i = 0; i < this._workspaces.length; i++) {
18fbde
-            this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
18fbde
-            this._workspaces[i].actor.y += dy;
18fbde
+            let dx = newX - currentX;
18fbde
+
18fbde
+            for (let i = 0; i < this._workspaces.length; i++) {
18fbde
+                this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
18fbde
+                this._workspaces[i].actor.x += dx;
18fbde
+            }
18fbde
         }
18fbde
     },
18fbde
 });
18fbde
@@ -479,7 +502,12 @@ var WorkspacesDisplay = new Lang.Class({
18fbde
     _onPan(action) {
18fbde
         let [dist, dx, dy] = action.get_motion_delta(0);
18fbde
         let adjustment = this._scrollAdjustment;
18fbde
-        adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
18fbde
+        if (global.screen.layout_rows == -1)
18fbde
+            adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
18fbde
+        else if (this.actor.text_direction == Clutter.TextDirection.RTL)
18fbde
+            adjustment.value += (dx / this.actor.width) * adjustment.page_size;
18fbde
+        else
18fbde
+            adjustment.value -= (dx / this.actor.width) * adjustment.page_size;
18fbde
         return false;
18fbde
     },
18fbde
 
18fbde
@@ -688,6 +716,12 @@ var WorkspacesDisplay = new Lang.Class({
18fbde
         case Clutter.ScrollDirection.DOWN:
18fbde
             ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN);
18fbde
             break;
18fbde
+        case Clutter.ScrollDirection.LEFT:
18fbde
+            ws = activeWs.get_neighbor(Meta.MotionDirection.LEFT);
18fbde
+            break;
18fbde
+        case Clutter.ScrollDirection.RIGHT:
18fbde
+            ws = activeWs.get_neighbor(Meta.MotionDirection.RIGHT);
18fbde
+            break;
18fbde
         default:
18fbde
             return Clutter.EVENT_PROPAGATE;
18fbde
         }
18fbde
-- 
18fbde
2.21.0
18fbde