21e770
From b42dd3f87ad5fb6c7ee139cb0de22e0fbb393ba2 Mon Sep 17 00:00:00 2001
21e770
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
21e770
Date: Tue, 4 Jun 2019 19:22:26 +0000
21e770
Subject: [PATCH 1/2] workspaceSwitcherPopup: Support horizontal layout
21e770
21e770
While mutter supports a variety of different grid layouts (n columns/rows,
21e770
growing vertically or horizontally from any of the four corners), we
21e770
hardcode a fixed vertical layout of a single column.
21e770
21e770
Now that mutter exposes the actual layout to us, add support for a more
21e770
traditional horizontal layout as well.
21e770
21e770
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/575
21e770
---
21e770
 data/theme/gnome-shell-sass/_common.scss |  3 +-
21e770
 js/ui/windowManager.js                   | 36 ++++++++--
21e770
 js/ui/workspaceSwitcherPopup.js          | 86 ++++++++++++++++++------
21e770
 3 files changed, 98 insertions(+), 27 deletions(-)
21e770
21e770
diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss
21e770
index 293ea2ab9..b1eeb0ce9 100644
21e770
--- a/data/theme/gnome-shell-sass/_common.scss
21e770
+++ b/data/theme/gnome-shell-sass/_common.scss
21e770
@@ -680,7 +680,8 @@ StScrollBar {
21e770
     spacing: 8px;
21e770
   }
21e770
 
21e770
-  .ws-switcher-active-up, .ws-switcher-active-down {
21e770
+  .ws-switcher-active-up, .ws-switcher-active-down,
21e770
+  .ws-switcher-active-left, .ws-switcher-active-right {
21e770
     height: 50px;
21e770
     background-color: $selected_bg_color;
21e770
     color: $selected_fg_color;
21e770
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
21e770
index b9f5fef46..dfe1b4460 100644
21e770
--- a/js/ui/windowManager.js
21e770
+++ b/js/ui/windowManager.js
21e770
@@ -2145,6 +2145,8 @@ var WindowManager = class {
21e770
         let [action,,,target] = binding.get_name().split('-');
21e770
         let newWs;
21e770
         let direction;
21e770
+        let vertical = workspaceManager.layout_rows == -1;
21e770
+        let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
21e770
 
21e770
         if (action == 'move') {
21e770
             // "Moving" a window to another workspace doesn't make sense when
21e770
@@ -2157,7 +2159,12 @@ var WindowManager = class {
21e770
         }
21e770
 
21e770
         if (target == 'last') {
21e770
-            direction = Meta.MotionDirection.DOWN;
21e770
+            if (vertical)
21e770
+                direction = Meta.MotionDirection.DOWN;
21e770
+            else if (rtl)
21e770
+                direction = Meta.MotionDirection.LEFT;
21e770
+            else
21e770
+                direction = Meta.MotionDirection.RIGHT;
21e770
             newWs = workspaceManager.get_workspace_by_index(workspaceManager.n_workspaces - 1);
21e770
         } else if (isNaN(target)) {
21e770
             // Prepend a new workspace dynamically
21e770
@@ -2173,16 +2180,33 @@ var WindowManager = class {
21e770
             target--;
21e770
             newWs = workspaceManager.get_workspace_by_index(target);
21e770
 
21e770
-            if (workspaceManager.get_active_workspace().index() > target)
21e770
-                direction = Meta.MotionDirection.UP;
21e770
-            else
21e770
-                direction = Meta.MotionDirection.DOWN;
21e770
+            if (workspaceManager.get_active_workspace().index() > target) {
21e770
+                if (vertical)
21e770
+                    direction = Meta.MotionDirection.UP;
21e770
+                else if (rtl)
21e770
+                    direction = Meta.MotionDirection.RIGHT;
21e770
+                else
21e770
+                    direction = Meta.MotionDirection.LEFT;
21e770
+            } else {
21e770
+                if (vertical)
21e770
+                    direction = Meta.MotionDirection.DOWN;
21e770
+                else if (rtl)
21e770
+                    direction = Meta.MotionDirection.LEFT;
21e770
+                else
21e770
+                    direction = Meta.MotionDirection.RIGHT;
21e770
+            }
21e770
         }
21e770
 
21e770
-        if (direction != Meta.MotionDirection.UP &&
21e770
+        if (workspaceManager.layout_rows == -1 &&
21e770
+            direction != Meta.MotionDirection.UP &&
21e770
             direction != Meta.MotionDirection.DOWN)
21e770
             return;
21e770
 
21e770
+        if (workspaceManager.layout_columns == -1 &&
21e770
+            direction != Meta.MotionDirection.LEFT &&
21e770
+            direction != Meta.MotionDirection.RIGHT)
21e770
+            return;
21e770
+
21e770
         if (action == 'switch')
21e770
             this.actionMoveWorkspace(newWs);
21e770
         else
21e770
diff --git a/js/ui/workspaceSwitcherPopup.js b/js/ui/workspaceSwitcherPopup.js
21e770
index 26404eaab..d21c5de4d 100644
21e770
--- a/js/ui/workspaceSwitcherPopup.js
21e770
+++ b/js/ui/workspaceSwitcherPopup.js
21e770
@@ -17,41 +17,75 @@ class WorkspaceSwitcherPopupList extends St.Widget {
21e770
         this._itemSpacing = 0;
21e770
         this._childHeight = 0;
21e770
         this._childWidth = 0;
21e770
+        this._orientation = global.workspace_manager.layout_rows == -1
21e770
+            ? Clutter.Orientation.VERTICAL
21e770
+            : Clutter.Orientation.HORIZONTAL;
21e770
 
21e770
         this.connect('style-changed', () => {
21e770
            this._itemSpacing = this.get_theme_node().get_length('spacing');
21e770
         });
21e770
     }
21e770
 
21e770
-    vfunc_get_preferred_height(forWidth) {
21e770
+    _getPreferredSizeForOrientation(forSize) {
21e770
         let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
21e770
         let themeNode = this.get_theme_node();
21e770
 
21e770
-        let availHeight = workArea.height;
21e770
-        availHeight -= themeNode.get_vertical_padding();
21e770
+        let availSize;
21e770
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
21e770
+            availSize = workArea.width - themeNode.get_horizontal_padding();
21e770
+        else
21e770
+            availSize = workArea.height - themeNode.get_vertical_padding();
21e770
 
21e770
-        let height = 0;
21e770
+        let size = 0;
21e770
         for (let child of this.get_children()) {
21e770
             let [childMinHeight, childNaturalHeight] = child.get_preferred_height(-1);
21e770
-            let [childMinWidth, childNaturalWidth] = child.get_preferred_width(childNaturalHeight);
21e770
-            height += childNaturalHeight * workArea.width / workArea.height;
21e770
+            let height = childNaturalHeight * workArea.width / workArea.height;
21e770
+
21e770
+            if (this._orientation == Clutter.Orientation.HORIZONTAL) {
21e770
+                size += height * workArea.width / workArea.height;
21e770
+            } else {
21e770
+                size += height;
21e770
+            }
21e770
         }
21e770
 
21e770
         let workspaceManager = global.workspace_manager;
21e770
         let spacing = this._itemSpacing * (workspaceManager.n_workspaces - 1);
21e770
-        height += spacing;
21e770
-        height = Math.min(height, availHeight);
21e770
+        size += spacing;
21e770
+        size = Math.min(size, availSize);
21e770
+
21e770
+        if (this._orientation == Clutter.Orientation.HORIZONTAL) {
21e770
+            this._childWidth = (size - spacing) / workspaceManager.n_workspaces;
21e770
+            return themeNode.adjust_preferred_width(size, size);
21e770
+        } else {
21e770
+            this._childHeight = (size - spacing) / workspaceManager.n_workspaces;
21e770
+            return themeNode.adjust_preferred_height(size, size);
21e770
+        }
21e770
+    }
21e770
+
21e770
+    _getSizeForOppositeOrientation() {
21e770
+        let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
21e770
 
21e770
-        this._childHeight = (height - spacing) / workspaceManager.n_workspaces;
21e770
+        if (this._orientation == Clutter.Orientation.HORIZONTAL) {
21e770
+            this._childHeight = Math.round(this._childWidth * workArea.height / workArea.width);
21e770
+            return [this._childHeight, this._childHeight];
21e770
+        } else {
21e770
+            this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
21e770
+            return [this._childWidth, this._childWidth];
21e770
+        }
21e770
+    }
21e770
 
21e770
-        return themeNode.adjust_preferred_height(height, height);
21e770
+    vfunc_get_preferred_height(forWidth) {
21e770
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
21e770
+            return this._getSizeForOppositeOrientation();
21e770
+        else
21e770
+            return this._getPreferredSizeForOrientation(forWidth);
21e770
     }
21e770
 
21e770
     vfunc_get_preferred_width(forHeight) {
21e770
-        let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
21e770
-        this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
21e770
-
21e770
-        return [this._childWidth, this._childWidth];
21e770
+        if (this._orientation == Clutter.Orientation.HORIZONTAL)
21e770
+            return this._getPreferredSizeForOrientation(forHeight);
21e770
+        else
21e770
+            return this._getSizeForOppositeOrientation();
21e770
     }
21e770
 
21e770
     vfunc_allocate(box, flags) {
21e770
@@ -62,15 +96,23 @@ class WorkspaceSwitcherPopupList extends St.Widget {
21e770
 
21e770
         let childBox = new Clutter.ActorBox();
21e770
 
21e770
+        let rtl = this.text_direction == Clutter.TextDirection.RTL;
21e770
+        let x = rtl ? box.x2 - this._childWidth : box.x1;
21e770
         let y = box.y1;
21e770
-        let prevChildBoxY2 = box.y1 - this._itemSpacing;
21e770
         for (let child of this.get_children()) {
21e770
-            childBox.x1 = box.x1;
21e770
-            childBox.x2 = box.x1 + this._childWidth;
21e770
-            childBox.y1 = prevChildBoxY2 + this._itemSpacing;
21e770
+            childBox.x1 = Math.round(x);
21e770
+            childBox.x2 = Math.round(x + this._childWidth);
21e770
+            childBox.y1 = Math.round(y);
21e770
             childBox.y2 = Math.round(y + this._childHeight);
21e770
-            y += this._childHeight + this._itemSpacing;
21e770
-            prevChildBoxY2 = childBox.y2;
21e770
+
21e770
+            if (this._orientation == Clutter.Orientation.HORIZONTAL) {
21e770
+                if (rtl)
21e770
+                    x -= this._childWidth + this._itemSpacing;
21e770
+                else
21e770
+                    x += this._childWidth + this._itemSpacing;
21e770
+            } else {
21e770
+                y += this._childHeight + this._itemSpacing;
21e770
+            }
21e770
             child.allocate(childBox, flags);
21e770
         }
21e770
     }
21e770
@@ -123,6 +165,10 @@ class WorkspaceSwitcherPopup extends St.Widget {
21e770
                indicator = new St.Bin({ style_class: 'ws-switcher-active-up' });
21e770
            else if(i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.DOWN)
21e770
                indicator = new St.Bin({ style_class: 'ws-switcher-active-down' });
21e770
+           else if(i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.LEFT)
21e770
+               indicator = new St.Bin({ style_class: 'ws-switcher-active-left' });
21e770
+           else if(i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.RIGHT)
21e770
+               indicator = new St.Bin({ style_class: 'ws-switcher-active-right' });
21e770
            else
21e770
                indicator = new St.Bin({ style_class: 'ws-switcher-box' });
21e770
 
21e770
-- 
21e770
2.21.0
21e770
21e770
21e770
From 813976ff69b15ab884d44f5f6a56ae66f407acfd Mon Sep 17 00:00:00 2001
21e770
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
21e770
Date: Tue, 4 Jun 2019 19:49:23 +0000
21e770
Subject: [PATCH 2/2] workspacesView: Support horizontal layout
21e770
21e770
Just as we did for the workspace switcher popup, support workspaces
21e770
being laid out in a single row in the window picker.
21e770
21e770
Note that this takes care of the various workspace switch actions in
21e770
the overview (scrolling, panning, touch(pad) gestures) as well as the
21e770
switch animation, but not of the overview's workspace switcher component.
21e770
21e770
There are currently no plans to support other layouts there, as the
21e770
component is inherently vertical (in fact, it was the whole reason for
21e770
switching the layout in the first place).
21e770
21e770
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/575
21e770
---
21e770
 js/ui/workspacesView.js | 81 ++++++++++++++++++++++++++++++-----------
21e770
 1 file changed, 60 insertions(+), 21 deletions(-)
21e770
21e770
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
21e770
index fe06d9dae..069937d5a 100644
21e770
--- a/js/ui/workspacesView.js
21e770
+++ b/js/ui/workspacesView.js
21e770
@@ -181,26 +181,32 @@ var WorkspacesView = class extends WorkspacesViewBase {
21e770
 
21e770
             Tweener.removeTweens(workspace.actor);
21e770
 
21e770
-            let y = (w - active) * this._fullGeometry.height;
21e770
+            let params = {};
21e770
+            if (workspaceManager.layout_rows == -1)
21e770
+                params.y = (w - active) * this._fullGeometry.height;
21e770
+            else if (this.actor.text_direction == Clutter.TextDirection.RTL)
21e770
+                params.x = (active - w) * this._fullGeometry.width;
21e770
+            else
21e770
+                params.x = (w - active) * this._fullGeometry.width;
21e770
 
21e770
             if (showAnimation) {
21e770
-                let params = { y: y,
21e770
-                               time: WORKSPACE_SWITCH_TIME,
21e770
-                               transition: 'easeOutQuad'
21e770
-                             };
21e770
+                let tweenParams = Object.assign(params, {
21e770
+                    time: WORKSPACE_SWITCH_TIME,
21e770
+                    transition: 'easeOutQuad'
21e770
+                });
21e770
                 // we have to call _updateVisibility() once before the
21e770
                 // animation and once afterwards - it does not really
21e770
                 // matter which tween we use, so we pick the first one ...
21e770
                 if (w == 0) {
21e770
                     this._updateVisibility();
21e770
-                    params.onComplete = () => {
21e770
+                    tweenParams.onComplete = () => {
21e770
                         this._animating = false;
21e770
                         this._updateVisibility();
21e770
                     };
21e770
                 }
21e770
-                Tweener.addTween(workspace.actor, params);
21e770
+                Tweener.addTween(workspace.actor, tweenParams);
21e770
             } else {
21e770
-                workspace.actor.set_position(0, y);
21e770
+                workspace.actor.set(params);
21e770
                 if (w == 0)
21e770
                     this._updateVisibility();
21e770
             }
21e770
@@ -338,22 +344,39 @@ var WorkspacesView = class extends WorkspacesViewBase {
21e770
             metaWorkspace.activate(global.get_current_time());
21e770
         }
21e770
 
21e770
-        let last = this._workspaces.length - 1;
21e770
-        let firstWorkspaceY = this._workspaces[0].actor.y;
21e770
-        let lastWorkspaceY = this._workspaces[last].actor.y;
21e770
-        let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
21e770
-
21e770
         if (adj.upper == 1)
21e770
             return;
21e770
 
21e770
-        let currentY = firstWorkspaceY;
21e770
-        let newY =  - adj.value / (adj.upper - 1) * workspacesHeight;
21e770
+        let last = this._workspaces.length - 1;
21e770
+
21e770
+        if (workspaceManager.layout_rows == -1) {
21e770
+            let firstWorkspaceY = this._workspaces[0].actor.y;
21e770
+            let lastWorkspaceY = this._workspaces[last].actor.y;
21e770
+            let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
21e770
+
21e770
+            let currentY = firstWorkspaceY;
21e770
+            let newY = -adj.value / (adj.upper - 1) * workspacesHeight;
21e770
 
21e770
-        let dy = newY - currentY;
21e770
+            let dy = newY - currentY;
21e770
+
21e770
+            for (let i = 0; i < this._workspaces.length; i++) {
21e770
+                this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
21e770
+                this._workspaces[i].actor.y += dy;
21e770
+            }
21e770
+        } else {
21e770
+            let firstWorkspaceX = this._workspaces[0].actor.x;
21e770
+            let lastWorkspaceX = this._workspaces[last].actor.x;
21e770
+            let workspacesWidth = lastWorkspaceX - firstWorkspaceX;
21e770
 
21e770
-        for (let i = 0; i < this._workspaces.length; i++) {
21e770
-            this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
21e770
-            this._workspaces[i].actor.y += dy;
21e770
+            let currentX = firstWorkspaceX;
21e770
+            let newX = -adj.value / (adj.upper - 1) * workspacesWidth;
21e770
+
21e770
+            let dx = newX - currentX;
21e770
+
21e770
+            for (let i = 0; i < this._workspaces.length; i++) {
21e770
+                this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
21e770
+                this._workspaces[i].actor.x += dx;
21e770
+            }
21e770
         }
21e770
     }
21e770
 };
21e770
@@ -504,7 +527,12 @@ var WorkspacesDisplay = class {
21e770
     _onPan(action) {
21e770
         let [dist, dx, dy] = action.get_motion_delta(0);
21e770
         let adjustment = this._scrollAdjustment;
21e770
-        adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
21e770
+        if (global.workspace_manager.layout_rows == -1)
21e770
+            adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
21e770
+        else if (this.actor.text_direction == Clutter.TextDirection.RTL)
21e770
+            adjustment.value += (dx / this.actor.width) * adjustment.page_size;
21e770
+        else
21e770
+            adjustment.value -= (dx / this.actor.width) * adjustment.page_size;
21e770
         return false;
21e770
     }
21e770
 
21e770
@@ -536,7 +564,12 @@ var WorkspacesDisplay = class {
21e770
         let workspaceManager = global.workspace_manager;
21e770
         let active = workspaceManager.get_active_workspace_index();
21e770
         let adjustment = this._scrollAdjustment;
21e770
-        adjustment.value = (active - yRel / this.actor.height) * adjustment.page_size;
21e770
+        if (workspaceManager.layout_rows == -1)
21e770
+            adjustment.value = (active - yRel / this.actor.height) * adjustment.page_size;
21e770
+        else if (this.actor.text_direction == Clutter.TextDirection.RTL)
21e770
+            adjustment.value = (active + xRel / this.actor.width) * adjustment.page_size;
21e770
+        else
21e770
+            adjustment.value = (active - xRel / this.actor.width) * adjustment.page_size;
21e770
     }
21e770
 
21e770
     _onSwitchWorkspaceActivated(action, direction) {
21e770
@@ -755,6 +788,12 @@ var WorkspacesDisplay = class {
21e770
         case Clutter.ScrollDirection.DOWN:
21e770
             ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN);
21e770
             break;
21e770
+        case Clutter.ScrollDirection.LEFT:
21e770
+            ws = activeWs.get_neighbor(Meta.MotionDirection.LEFT);
21e770
+            break;
21e770
+        case Clutter.ScrollDirection.RIGHT:
21e770
+            ws = activeWs.get_neighbor(Meta.MotionDirection.RIGHT);
21e770
+            break;
21e770
         default:
21e770
             return Clutter.EVENT_PROPAGATE;
21e770
         }
21e770
-- 
21e770
2.21.0
21e770