[gnome-shell] Add automatic workspace management



commit e6938ed06ca3851d606e5bedca079121d0e5992b
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Tue Jan 25 16:29:45 2011 -0500

    Add automatic workspace management
    
    Automatically add and remove workspaces so that the last workspace is
    always empty and no workspaces are empty other than that workspace.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=640996

 js/ui/main.js           |  121 +++++++++++++++++++++++++++++++++++------------
 js/ui/workspacesView.js |    9 ++++
 2 files changed, 100 insertions(+), 30 deletions(-)
---
diff --git a/js/ui/main.js b/js/ui/main.js
index 7e17873..d9569cb 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -201,14 +201,103 @@ function start() {
     _log('info', 'loaded at ' + _startDate);
     log('GNOME Shell started at ' + _startDate);
 
-    Mainloop.idle_add(_removeUnusedWorkspaces);
-
     let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
     if (perfModuleName) {
         let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT");
         let module = eval('imports.perf.' + perfModuleName + ';');
         Scripting.runPerfScript(module, perfOutput);
     }
+
+    global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
+    Mainloop.idle_add(_nWorkspacesChanged);
+}
+
+let _workspaces = [];
+let _checkWorkspacesId = 0;
+
+function _checkWorkspaces() {
+    let i;
+    let emptyWorkspaces = [];
+
+    for (i = 0; i < _workspaces.length; i++)
+        emptyWorkspaces[i] = true;
+
+    let windows = global.get_window_actors();
+    for (i = 0; i < windows.length; i++) {
+        let win = windows[i];
+
+        if (win.get_meta_window().is_on_all_workspaces())
+            continue;
+
+        let workspaceIndex = win.get_workspace();
+        emptyWorkspaces[workspaceIndex] = false;
+    }
+
+    // If we don't have an empty workspace at the end, add one
+    if (!emptyWorkspaces[emptyWorkspaces.length -1]) {
+        global.screen.append_new_workspace(false, global.get_current_time());
+        emptyWorkspaces.push(false);
+    }
+
+    // Delete other empty workspaces; do it from the end to avoid index changes
+    for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
+        if (emptyWorkspaces[i])
+            global.screen.remove_workspace(_workspaces[i], global.get_current_time());
+    }
+
+    _checkWorkspacesId = 0;
+    return false;
+}
+
+function _queueCheckWorkspaces() {
+    if (_checkWorkspacesId == 0)
+        _checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces);
+}
+
+function _nWorkspacesChanged() {
+    let oldNumWorkspaces = _workspaces.length;
+    let newNumWorkspaces = global.screen.n_workspaces;
+
+    if (oldNumWorkspaces == newNumWorkspaces)
+        return false;
+
+    let lostWorkspaces = [];
+    if (newNumWorkspaces > oldNumWorkspaces) {
+        let w;
+
+        // Assume workspaces are only added at the end
+        for (w = oldNumWorkspaces; w < newNumWorkspaces; w++)
+            _workspaces[w] = global.screen.get_workspace_by_index(w);
+
+        for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
+            let workspace = _workspaces[w];
+            workspace._windowAddedId = workspace.connect('window-added', _queueCheckWorkspaces);
+            workspace._windowRemovedId = workspace.connect('window-removed', _queueCheckWorkspaces);
+        }
+
+    } else {
+        // Assume workspaces are only removed sequentially
+        // (e.g. 2,3,4 - not 2,4,7)
+        let removedIndex;
+        let removedNum = oldNumWorkspaces - newNumWorkspaces;
+        for (let w = 0; w < oldNumWorkspaces; w++) {
+            let workspace = global.screen.get_workspace_by_index(w);
+            if (_workspaces[w] != workspace) {
+                removedIndex = w;
+                break;
+            }
+        }
+
+        let lostWorkspaces = _workspaces.splice(removedIndex, removedNum);
+        lostWorkspaces.forEach(function(workspace) {
+                                   workspace.disconnect(workspace._windowAddedId);
+                                   workspace.disconnect(workspace._windowRemovedId);
+                               });
+    }
+
+    _queueCheckWorkspaces();
+
+    return false;
 }
 
 /**
@@ -316,34 +405,6 @@ function getWindowActorsForWorkspace(workspaceIndex) {
     });
 }
 
-// metacity-clutter currently uses the same prefs as plain metacity,
-// which probably means we'll be starting out with multiple workspaces;
-// remove any unused ones. (We do this from an idle handler, because
-// global.get_window_actors() still returns NULL at the point when start()
-// is called.)
-function _removeUnusedWorkspaces() {
-
-    let windows = global.get_window_actors();
-    let maxWorkspace = 0;
-    for (let i = 0; i < windows.length; i++) {
-        let win = windows[i];
-
-        if (!win.get_meta_window().is_on_all_workspaces() &&
-            win.get_workspace() > maxWorkspace) {
-            maxWorkspace = win.get_workspace();
-        }
-    }
-    let screen = global.screen;
-    if (screen.n_workspaces > maxWorkspace) {
-        for (let w = screen.n_workspaces - 1; w > maxWorkspace; w--) {
-            let workspace = screen.get_workspace_by_index(w);
-            screen.remove_workspace(workspace, 0);
-        }
-    }
-
-    return false;
-}
-
 // This function encapsulates hacks to make certain global keybindings
 // work even when we are in one of our modes where global keybindings
 // are disabled with a global grab. (When there is a global grab, then
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
index 024698d..5e05108 100644
--- a/js/ui/workspacesView.js
+++ b/js/ui/workspacesView.js
@@ -1006,6 +1006,15 @@ WorkspacesDisplay.prototype = {
             this._workspaceThumbnails.splice(removedIndex, removedNum);
         }
 
+        // If we removed the current workspace, then metacity will have already
+        // switched to an adjacent workspace. Leaving the animation we
+        // started in response to that around will look funny because it's an
+        // animation for the *old* workspace configuration. So, kill it.
+        // If we animate the workspace removal in the future, we should animate
+        // the indicator as part of that.
+        Tweener.removeTweens(this._thumbnailIndicator);
+        this._constrainThumbnailIndicator();
+
         this.workspacesView.updateWorkspaces(oldNumWorkspaces,
                                              newNumWorkspaces,
                                              lostWorkspaces);



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