[gnome-shell/overview-relayout: 12/15] workspaces: Rework workspace controls for the view selector



commit ca4eb9148c9f98282c749cd369f50fa76a058971
Author: Florian Müllner <fmuellner gnome org>
Date:   Mon Oct 4 16:42:11 2010 +0200

    workspaces: Rework workspace controls for the view selector
    
    As workspaces will appear as a particular view in the view selector,
    merge WorkspacesControls and WorkspacesManager to control workspaces
    and related controls, so that a single actor can be added to the
    selector instead of positioning the elements from the overview.
    
    Also enforce linear view, the grid will have its comeback with the
    new DND behavior.

 data/theme/gnome-shell.css |   39 ++--
 js/ui/overview.js          |   65 ++----
 js/ui/workspace.js         |   63 -----
 js/ui/workspacesView.js    |  567 ++++++++++++++++++--------------------------
 4 files changed, 269 insertions(+), 465 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 15982cb..5303503 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -293,8 +293,8 @@ StTooltip {
 .workspace-indicator {
     width: 24px;
     height: 16px;
-    background: rgba(155,155,155,0.8);
-    border-spacing: 16px;
+    background: rgba(255,255,255,0.2);
+    border-spacing: 8px;
 }
 
 .workspace-indicator.active {
@@ -319,36 +319,33 @@ StTooltip {
 }
 
 .single-view-controls {
-    padding: 0px 15px;
+    padding: 8px 0px;
 }
 
 .workspace-controls {
-    width: 24px;
-    height: 16px;
-}
-
-.workspace-controls.add {
-    background-image: url("add-workspace.svg");
-}
-
-.workspace-controls.remove {
-    background-image: url("remove-workspace.svg");
+    width: 48px;
+    font-size: 32px;
+    font-weight: bold;
+    color: #ffffff;
+    border: 2px solid rgba(128, 128, 128, 0.4);
+    border-right: 0px;
+    border-radius: 9px 0px 0px 9px;
 }
 
-.workspace-controls.switch-single {
-    background-image: url("single-view.svg");
+.add-workspace {
+    background-color: rgba(128, 128, 128, 0.4);
 }
 
-.workspace-controls.switch-mosaic {
-    background-image: url("mosaic-view.svg");
+.add-workspace:hover {
+    background-color: rgba(128, 128, 128, 0.6);
 }
 
-.workspace-controls.switch-single:checked {
-    background-image: url("single-view-active.svg");
+.remove-workspace {
+    height: 48px;
 }
 
-.workspace-controls.switch-mosaic:checked {
-    background-image: url("mosaic-view-active.svg");
+.remove-workspace:hover {
+    background-color: rgba(128, 128, 128, 0.2);
 }
 
 /* Dash */
diff --git a/js/ui/overview.js b/js/ui/overview.js
index 184f685..ae89d8b 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -177,18 +177,10 @@ Overview.prototype = {
 
         this._group = new St.Group({ style_class: 'overview' });
         this._group._delegate = this;
-        this._group.connect('destroy', Lang.bind(this,
-            function() {
-                if (this._lightbox) {
-                    this._lightbox.destroy();
-                    this._lightbox = null;
-                }
-            }));
 
         this.shellInfo = new ShellInfo();
 
-        this._workspacesManager = null;
-        this._lightbox = null;
+        this._workspacesDisplay = null;
 
         this.visible = false;
         this.animationInProgress = false;
@@ -250,18 +242,6 @@ Overview.prototype = {
         return new Clutter.Clone({ source: windows[0].get_texture() });
     },
 
-    _onViewChanged: function() {
-        if (!this.visible)
-            return;
-
-        this.workspaces = this._workspacesManager.workspacesView;
-
-        // Show new workspacesView
-        this._group.add_actor(this.workspaces.actor);
-        this._workspacesBar.raise(this.workspaces.actor);
-        this._appWell.actor.raise(this.workspaces.actor);
-    },
-
     _recalculateGridSizes: function () {
         let primary = global.get_primary_monitor();
         wideScreen = (primary.width/primary.height > WIDE_SCREEN_CUT_OFF_RATIO) &&
@@ -317,11 +297,6 @@ Overview.prototype = {
             this._appWell.actor.set_position(0, this._workspacesY);
         }
 
-        // place the 'Add Workspace' button in the bottom row of the grid
-        this._workspacesBarX = this._workspacesX;
-        this._workspacesBarWidth = this._workspacesWidth;
-        this._workspacesBarY = primary.height - displayGridRowHeight;
-
         // The parent (this._group) is positioned at the top left of the primary monitor
         // while this._backOver occupies the entire screen.
         this._backOver.set_position(- primary.x, - primary.y);
@@ -371,11 +346,6 @@ Overview.prototype = {
                         this._activeDisplayPane.close();
                     return true;
                 }));
-                if (!this._lightbox)
-                    this._lightbox = new Lightbox.Lightbox(this._group,
-                                                           { fadeTime: PANE_FADE_TIME });
-                this._lightbox.show();
-                this._lightbox.highlight(this._paneContainer);
             } else if (pane == this._activeDisplayPane) {
                 this._activeDisplayPane = null;
                 if (backgroundEventId != null) {
@@ -384,7 +354,6 @@ Overview.prototype = {
                 }
                 this._transparentBackground.lower_bottom();
                 this._paneContainer.hide();
-                this._lightbox.hide();
             }
         }));
     },
@@ -439,29 +408,29 @@ Overview.prototype = {
         this.animationInProgress = true;
 
         /* TODO: make this stuff dynamic */
-        this._workspacesManager =
-            new WorkspacesView.WorkspacesManager(this._workspacesWidth,
+        this._workspacesDisplay =
+            new WorkspacesView.WorkspacesDisplay(this._workspacesWidth,
                                                  this._workspacesHeight,
                                                  this._workspacesX,
                                                  this._workspacesY);
-        this._workspacesManager.connect('view-changed',
-                                        Lang.bind(this, this._onViewChanged));
-        this.workspaces = this._workspacesManager.workspacesView;
+        this._workspacesDisplay.actor.set_size(this._workspacesWidth,
+                                               this._workspacesHeight);
+        this._workspacesDisplay.actor.set_position(this._workspacesX,
+                                                   this._workspacesY);
+        this._group.add_actor(this._workspacesDisplay.actor);
+
+        this._workspacesDisplay.show();
+        this.workspaces = this._workspacesDisplay.workspacesView;
+
+        // Show new workspacesView
         this._group.add_actor(this.workspaces.actor);
+        this._appWell.actor.raise(this.workspaces.actor);
 
         // The workspaces actor is as big as the screen, so we have to raise the dash above it
         // for drag and drop to work.  In the future we should fix the workspaces to not
         // be as big as the screen.
         this._appWell.actor.raise(this.workspaces.actor);
 
-        this._workspacesBar = this._workspacesManager.controlsBar.actor;
-        this._workspacesBar.set_position(this._workspacesBarX,
-                                         this._workspacesBarY);
-        this._workspacesBar.width = this._workspacesBarWidth;
-
-        this._group.add_actor(this._workspacesBar);
-        this._workspacesBar.raise(this.workspaces.actor);
-
         if (!this._desktop.child)
             this._desktop.child = this._getDesktopClone();
 
@@ -601,10 +570,8 @@ Overview.prototype = {
         this.workspaces.destroy();
         this.workspaces = null;
 
-        this._workspacesBar.destroy();
-        this._workspacesBar = null;
-
-        this._workspacesManager = null;
+        this._workspacesDisplay.actor.destroy();
+        this._workspacesDisplay = null;
 
         this._desktop.hide();
         this._group.hide();
diff --git a/js/ui/workspace.js b/js/ui/workspace.js
index 574f8e4..65c3718 100644
--- a/js/ui/workspace.js
+++ b/js/ui/workspace.js
@@ -1329,69 +1329,6 @@ Workspace.prototype = {
         this._visible = false;
     },
 
-    // Animates grid shrinking/expanding when a row or column
-    // of workspaces is added or removed
-    resizeToGrid : function (oldScale) {
-        this._hideAllOverlays();
-        Tweener.addTween(this.actor,
-                         { x: this.gridX,
-                           y: this.gridY,
-                           scale_x: this.scale,
-                           scale_y: this.scale,
-                           time: Overview.ANIMATION_TIME,
-                           transition: 'easeOutQuad',
-                           onComplete: Lang.bind(this, this._fadeInAllOverlays)
-                         });
-    },
-
-    // Animates the addition of a new (empty) workspace
-    slideIn : function(oldScale) {
-        if (this.gridCol > this.gridRow) {
-            this.actor.set_position(global.screen_width, this.gridY);
-            this.actor.set_scale(oldScale, oldScale);
-        } else {
-            this.actor.set_position(this.gridX, global.screen_height);
-            this.actor.set_scale(this.scale, this.scale);
-        }
-        Tweener.addTween(this.actor,
-                         { x: this.gridX,
-                           y: this.gridY,
-                           scale_x: this.scale,
-                           scale_y: this.scale,
-                           time: Overview.ANIMATION_TIME,
-                           transition: 'easeOutQuad'
-                         });
-
-        this._visible = true;
-    },
-
-    // Animates the removal of a workspace
-    slideOut : function(onComplete) {
-        let destX = this.actor.x, destY = this.actor.y;
-
-        this._hideAllOverlays();
-
-        if (this.gridCol > this.gridRow)
-            destX = global.screen_width;
-        else
-            destY = global.screen_height;
-        Tweener.addTween(this.actor,
-                         { x: destX,
-                           y: destY,
-                           scale_x: this.scale,
-                           scale_y: this.scale,
-                           time: Overview.ANIMATION_TIME,
-                           transition: 'easeOutQuad',
-                           onComplete: onComplete
-                         });
-
-        this._visible = false;
-
-        // Don't let the user try to select this workspace as it's
-        // making its exit.
-        this._desktop.reactive = false;
-    },
-
     destroy : function() {
         this.actor.destroy();
     },
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
index da5db2b..f0afb4f 100644
--- a/js/ui/workspacesView.js
+++ b/js/ui/workspacesView.js
@@ -30,6 +30,9 @@ const WORKSPACES_VIEW_KEY = 'workspaces-view';
 const WORKSPACE_DRAGGING_SCALE = 0.85;
 const WORKSPACE_SHADOW_SCALE = (1 - WORKSPACE_DRAGGING_SCALE) / 2;
 
+const CONTROLS_POP_IN_FRACTION = 0.8;
+const CONTROLS_POP_IN_TIME = 0.1;
+
 function GenericWorkspacesView(width, height, x, y, workspaces) {
     this._init(width, height, x, y, workspaces);
 }
@@ -221,10 +224,6 @@ GenericWorkspacesView.prototype = {
         return [activeWorkspace.gridX, activeWorkspace.gridY];
     },
 
-    createControllerBar: function() {
-        throw new Error('Not implemented');
-    },
-
     canAddWorkspace: function() {
         return global.screen.n_workspaces < MAX_WORKSPACES;
     },
@@ -463,110 +462,65 @@ MosaicView.prototype = {
         this._workspaces[to].setSelected(true);
     },
 
-    createControllerBar: function() {
-        return null;
-    },
-
     _getWorkspaceIndexToRemove: function() {
         return this._workspaces.length - 1;
     }
 };
 
-function NewWorkspaceArea() {
+function WorkspaceIndicatorPanel() {
     this._init();
 }
 
-NewWorkspaceArea.prototype = {
+WorkspaceIndicatorPanel.prototype = {
     _init: function() {
-        let width = Math.ceil(global.screen_width * WORKSPACE_SHADOW_SCALE);
-        this.actor = new Clutter.Group({ width: width,
-                                         height: global.screen_height,
-                                         x: global.screen_width });
-
-        this._child1 = new St.Bin({ style_class: 'new-workspace-area',
-                                    width: width,
-                                    height: global.screen_height });
-        this._child2 =  new St.Bin({ style_class: 'new-workspace-area-internal',
-                                     width: width,
-                                     height: global.screen_height,
-                                     reactive: true });
-        this.actor.add_actor(this._child1);
-        this.actor.add_actor(this._child2);
-    },
-
-    setStyle: function(isHover) {
-        this._child1.set_hover(isHover);
-    }
-};
+        this.actor = new St.Bin({ style_class: 'workspace-indicator-panel',
+                                  x_align: St.Align.MIDDLE,
+                                  y_align: St.Align.MIDDLE
+                                });
 
-function WorkspaceIndicator(activateWorkspace, workspaceAcceptDrop, workspaceHandleDragOver, scrollEventCb) {
-    this._init(activateWorkspace, workspaceAcceptDrop, workspaceHandleDragOver, scrollEventCb);
-}
+        this._indicatorPanel = new Shell.GenericContainer({ clip_to_allocation: true });
+        this._indicatorPanel.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
+        this._indicatorPanel.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
+        this._indicatorPanel.connect('allocate', Lang.bind(this, this._allocate));
 
-WorkspaceIndicator.prototype = {
-    _init: function(activateWorkspace, workspaceAcceptDrop, workspaceHandleDragOver, scrollEventCb) {
-        this._activateWorkspace = activateWorkspace;
-        this._workspaceAcceptDrop = workspaceAcceptDrop;
-        this._workspaceHandleDragOver = workspaceHandleDragOver;
-        this._scrollEventCb = scrollEventCb;
-        let actor = new St.Bin({ style_class: 'panel-button' });
-
-        this._indicatorsPanel = new Shell.GenericContainer();
-        this._indicatorsPanel.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
-        this._indicatorsPanel.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
-        this._indicatorsPanel.connect('allocate', Lang.bind(this, this._allocate));
-        this._indicatorsPanel.clip_to_allocation = true;
-
-        actor.set_child(this._indicatorsPanel);
-        actor.set_alignment(St.Align.MIDDLE, St.Align.MIDDLE);
-        this._indicatorsPanel.hide();
-        actor.connect('destroy', Lang.bind(this, this._onDestroy));
-
-        let workId = Main.initializeDeferredWork(actor, Lang.bind(this, this._workspacesChanged));
-        this._nWorkspacesNotifyId =
-            global.screen.connect('notify::n-workspaces', function() {
-                Main.queueDeferredWork(workId);
-            });
+        this.actor.set_child(this._indicatorPanel);
+        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+
+        let workId = Main.initializeDeferredWork(this._indicatorPanel,
+                                                 Lang.bind(this, this._updateActive));
         this._switchWorkspaceNotifyId =
             global.window_manager.connect('switch-workspace', function() {
                 Main.queueDeferredWork(workId);
             });
-
-        this.actor = actor;
-    },
-
-    _workspacesChanged: function() {
-        let active = global.screen.get_active_workspace_index();
-        let n = global.screen.n_workspaces;
-        if (n > 1)
-            this._indicatorsPanel.show();
-        else
-            this._indicatorsPanel.hide();
-        this._fillPositionalIndicator();
     },
 
     _onDestroy: function() {
-        if (this._nWorkspacesNotifyId > 0)
-            global.screen.disconnect(this._nWorkspacesNotifyId);
-        this._nWorkspacesNotifyId = 0;
         if (this._switchWorkspaceNotifyId > 0)
             global.window_manager.disconnect(this._switchWorkspaceNotifyId);
         this._switchWorkspaceNotifyId = 0;
+        this._workspaces = null;
     },
 
     _allocate: function(actor, box, flags) {
         let children = actor.get_children();
+
+        // Don't display a single indicator
+        if (children.length == 1)
+            return;
+
         let childBox = new Clutter.ActorBox();
+        let height = box.y2 - box.y1;
+
         for (let i = 0; i < children.length; i++) {
             childBox.x1 = children[i].x;
             childBox.y1 = 0;
             childBox.x2 = children[i].x + children[i].width;
-            childBox.y2 = children[i].height;
+            childBox.y2 = height;
             children[i].allocate(childBox, flags);
         }
     },
 
-    _getPreferredWidth: function(actor, fh, alloc) {
+    _getPreferredWidth: function(actor, forHeight, alloc) {
         let children = actor.get_children();
         let width = 0;
         for (let i = 0; i < children.length; i++) {
@@ -578,52 +532,81 @@ WorkspaceIndicator.prototype = {
         alloc.natural_size = width;
     },
 
-    _getPreferredHeight: function(actor, fw, alloc) {
-            let children = actor.get_children();
-            let height = 0;
-            if (children.length)
-                height = children[0].height;
-            alloc.min_size = height;
-            alloc.natural_size = height;
+    _getPreferredHeight: function(actor, forWidth, alloc) {
+        let children = actor.get_children();
+        let height = 0;
+        if (children.length)
+            height = children[0].height;
+        alloc.min_size = height;
+        alloc.natural_size = height;
     },
 
-    _addIndicatorClone: function(i, active) {
-        let actor = new St.Button({ style_class: 'workspace-indicator' });
-        if (active) {
-            actor.style_class = 'workspace-indicator active';
-        }
-        actor.connect('clicked', Lang.bind(this, function() {
-            this._activateWorkspace(i);
-        }));
+    updateWorkspaces: function(workspaces) {
+        this._workspaces = workspaces;
 
-        actor._delegate = {};
-        actor._delegate.acceptDrop = Lang.bind(this, function(source, actor, x, y, time) {
-            if (this._workspaceAcceptDrop(i, source, actor, x, y, time)) {
-                this._activateWorkspace(i);
-                return true;
-            }
-            else
-                return false;
-        });
-        actor._delegate.handleDragOver = Lang.bind(this, function(source, actor, x, y, time) {
-            return this._workspaceHandleDragOver(i, source, actor, x, y, time);
-        });
+        this._indicatorPanel.remove_all();
+        for (let i = 0; i < this._workspaces.length; i++) {
+            let actor = new St.Button({ style_class: 'workspace-indicator' });
+            let workspace = this._workspaces[i];
+            let metaWorkspace = this._workspaces[i].metaWorkspace;
 
-        actor.connect('scroll-event', this._scrollEventCb);
+            actor.connect('clicked', Lang.bind(this, function() {
+                metaWorkspace.activate(global.get_current_time());
+            }));
 
-        this._indicatorsPanel.add_actor(actor);
+            actor._delegate = {
+                acceptDrop: Lang.bind(this,
+                    function(source, actor, x, y, time) {
+                        if (workspace.acceptDrop(source, actor, x, y, time)) {
+                            metaWorkspace.activate(time);
+                            return true;
+                        }
+                        return false;
+                    }),
+                handleDragOver: Lang.bind(this,
+                    function(source, actor, x, y, time) {
+                        return workspace.handleDragOver(source, actor, x, y, time);
+                    })
+            };
+
+            actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
+
+            this._indicatorPanel.add_actor(actor);
+
+            let spacing = actor.get_theme_node().get_length('border-spacing');
+            actor.x = (actor.width + spacing) * i;
+        }
 
-        let spacing = actor.get_theme_node().get_length('border-spacing');
-        actor.x = spacing * i + actor.width * i;
+        this._updateActive();
     },
 
-    _fillPositionalIndicator: function() {
-        this._indicatorsPanel.remove_all();
+    _updateActive: function() {
+        let children = this._indicatorPanel.get_children();
+        let activeIndex = global.screen.get_active_workspace_index();
+        for (let i = 0; i < children.length; i++) {
+            if (i == activeIndex)
+                children[i].add_style_class_name('active');
+            else
+                children[i].remove_style_class_name('active');
+        }
+    },
 
-        let activeWorkspaceIndex = global.screen.get_active_workspace_index();
-        let n = global.screen.n_workspaces;
-        for (let i = 0; i < n; i++) {
-            this._addIndicatorClone(i, i == activeWorkspaceIndex);
+    // handle scroll wheel events:
+    // activate the next or previous workspace and let the signal handler
+    // manage the animation
+    _onScrollEvent: function(actor, event) {
+        let direction = event.get_scroll_direction();
+        let current = global.screen.get_active_workspace_index();
+        let last = global.screen.n_workspaces - 1;
+        let activate = current;
+        if (direction == Clutter.ScrollDirection.DOWN && current < last)
+            activate++;
+        else if (direction == Clutter.ScrollDirection.UP && current > 0)
+            activate--;
+
+        if (activate != current) {
+            let metaWorkspace = this._workspaces[activate].metaWorkspace;
+            metaWorkspace.activate(global.get_current_time());
         }
     }
 };
@@ -1072,6 +1055,8 @@ SingleView.prototype = {
             dragMotion: Lang.bind(this, this._onDragMotion)
         };
         DND.addDragMonitor(this._dragMonitor);
+
+        this.emit('window-drag-begin');
     },
 
     _onDragMotion: function(dragEvent) {
@@ -1156,6 +1141,8 @@ SingleView.prototype = {
 
         for (let i = 0; i < this._workspaces.length; i++)
             this._workspaces[i].setReservedSlot(null);
+
+        this.emit('window-drag-end');
     },
 
     // sync the workspaces' positions to the value of the scroll adjustment
@@ -1192,47 +1179,6 @@ SingleView.prototype = {
         }
     },
 
-    // handle scroll wheel events:
-    // activate the next or previous workspace and let the signal handler
-    // manage the animation
-    _onScrollEvent: function(actor, event) {
-        let direction = event.get_scroll_direction();
-        let current = global.screen.get_active_workspace_index();
-        let last = global.screen.n_workspaces - 1;
-        let activate = current;
-        if (direction == Clutter.ScrollDirection.DOWN && current < last)
-            activate++;
-        else if (direction == Clutter.ScrollDirection.UP && current > 0)
-            activate--;
-
-        if (activate != current) {
-            let metaWorkspace = this._workspaces[activate].metaWorkspace;
-            metaWorkspace.activate(global.get_current_time());
-        }
-    },
-
-    createControllerBar: function() {
-        let actor = new St.BoxLayout({ style_class: 'single-view-controls',
-                                       pack_start: true,
-                                       vertical: true });
-
-        let indicator = new WorkspaceIndicator(Lang.bind(this, function(i) {
-            if (this._workspaces[i] != undefined)
-                this._workspaces[i].metaWorkspace.activate(global.get_current_time());
-        }), Lang.bind(this, function(i, source, actor, x, y, time) {
-            if (this._workspaces[i] != undefined)
-                return this._workspaces[i].acceptDrop(source, actor, x, y, time);
-            return false;
-        }), Lang.bind(this, function(i, source, actor, x, y, time) {
-            if (this._workspaces[i] != undefined)
-                return this._workspaces[i].handleDragOver(source, actor, x, y, time);
-            return DND.DragMotionResult.CONTINUE;
-        }), Lang.bind(this, this._onScrollEvent));
-
-        actor.add(indicator.actor, { expand: true, x_fill: true, y_fill: true });
-        return actor;
-    },
-
     addWorkspace: function() {
         let ws = GenericWorkspacesView.prototype.addWorkspace.call(this);
         if (ws != null)
@@ -1245,160 +1191,95 @@ SingleView.prototype = {
         return global.screen.get_active_workspace_index();
     }
 };
+Signals.addSignalMethods(SingleView.prototype);
 
-function WorkspacesControls() {
-    this._init();
-}
-
-WorkspacesControls.prototype = {
-    _init: function() {
-        this.actor = new St.BoxLayout({ style_class: 'workspaces-bar' });
-        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
-
-        let view = global.settings.get_string(WORKSPACES_VIEW_KEY).toUpperCase();
-        if (view in WorkspacesViewType)
-            this._currentViewType = WorkspacesViewType[view];
-        else
-            this._currentViewType = WorkspacesViewType.SINGLE;
-
-        this._currentView = null;
-
-        // View switcher button
-        this._toggleViewButton = new St.Button();
-        this._updateToggleButtonStyle();
-
-        this._toggleViewButton.connect('clicked', Lang.bind(this, function() {
-            if (this._currentViewType == WorkspacesViewType.SINGLE)
-                this._setView(WorkspacesViewType.GRID);
-            else
-                this._setView(WorkspacesViewType.SINGLE);
-         }));
-
-        this.actor.add(this._toggleViewButton, { y_fill: false, y_align: St.Align.START });
 
-        // View specific controls
-        this._viewControls = new St.Bin({ x_fill: true, y_fill: true });
-        this.actor.add(this._viewControls, { expand: true, x_fill: true });
-
-        // Add/remove workspace buttons
-        this._removeButton = new St.Button({ style_class: 'workspace-controls remove' });
-        this._removeButton.connect('clicked', Lang.bind(this, function() {
-            this._currentView.removeWorkspace();
-        }));
-        this.actor.add(this._removeButton, { y_fill: false,
-                                             y_align: St.Align.START });
-
-        this._addButton = new St.Button({ style_class: 'workspace-controls add' });
-        this._addButton.connect('clicked', Lang.bind(this, function() {
-            this._currentView.addWorkspace();
-        }));
-        this._addButton._delegate = this._addButton;
-        this._addButton._delegate.acceptDrop = Lang.bind(this,
-            function(source, actor, x, y, time) {
-                return this._currentView._acceptNewWorkspaceDrop(source, actor, x, y, time);
-            });
-        this._addButton._delegate.handleDragOver = Lang.bind(this,
-            function(source, actor, x, y, time) {
-                return this._currentView._handleDragOverNewWorkspace(source, actor, x, y, time);
-            });
-        this.actor.add(this._addButton, { y_fill: false,
-                                          y_align: St.Align.START });
-
-        this._nWorkspacesNotifyId =
-            global.screen.connect('notify::n-workspaces',
-                                  Lang.bind(this, this._workspacesChanged));
-        this._switchWorkspaceNotifyId =
-            global.window_manager.connect('switch-workspace',
-                                          Lang.bind(this, this.updateControlsSensitivity));
+function WorkspaceControlsContainer(controls) {
+    this._init(controls);
+}
 
-        this._workspacesChanged();
+WorkspaceControlsContainer.prototype = {
+    _init: function(controls) {
+        this.actor = new Shell.GenericContainer({ clip_to_allocation: true });
+        this.actor.connect('get-preferred-width',
+                           Lang.bind(this, this._getPreferredWidth));
+        this.actor.connect('get-preferred-height',
+                           Lang.bind(this, this._getPreferredHeight));
+        this.actor.connect('allocate', Lang.bind(this, this._allocate));
+
+        this.actor.add_actor(controls);
+
+        this._controls = controls;
+        this._controls.reactive = true;
+        this._controls.track_hover = true;
+        this._controls.connect('notify::hover',
+                               Lang.bind(this, this._onHoverChanged));
+
+        let workId = Main.initializeDeferredWork(this.actor,
+            Lang.bind(this, function() {
+                Main.overview.connect('item-drag-begin',
+                                      Lang.bind(this, this.popOut));
+                Main.overview.connect('item-drag-end',
+                                      Lang.bind(this, this.popIn));
+                this._controls.x = this._poppedInX();
+            }));
     },
 
-    updateControls: function(view) {
-        this._currentView = view;
-
-        this.updateControlsSensitivity();
-
-        let newControls = this._currentView.createControllerBar();
-        if (newControls) {
-            this._viewControls.child = newControls;
-            this._viewControls.child.opacity = 0;
-            Tweener.addTween(this._viewControls.child,
-                             { opacity: 255,
-                               time: Overview.ANIMATION_TIME,
-                               transition: 'easeOutQuad' });
-        } else {
-            if (this._viewControls.child)
-                Tweener.addTween(this._viewControls.child,
-                                 { opacity: 0,
-                                   time: Overview.ANIMATION_TIME,
-                                   transition: 'easeOutQuad',
-                                   onComplete: Lang.bind(this, function() {
-                                       this._viewControls.child.destroy();
-                                 })});
-        }
+    _getPreferredWidth: function(actor, forHeight, alloc) {
+        let [minWidth, natWidth] = this._controls.get_preferred_width(-1);
+        alloc.min_size = minWidth;
+        alloc.natural_size = natWidth;
     },
 
-    _updateToggleButtonStyle: function() {
-       if (this._currentViewType == WorkspacesViewType.SINGLE)
-            this._toggleViewButton.set_style_class_name('workspace-controls switch-mosaic');
-        else
-            this._toggleViewButton.set_style_class_name('workspace-controls switch-single');
+    _getPreferredHeight: function(actor, forWidth, alloc) {
+        let [minHeight, natHeight] = this._controls.get_preferred_height(-1);
+        alloc.min_size = minHeight;
+        alloc.natural_size = natHeight;
     },
 
-    _setView: function(view) {
-        if (this._currentViewType == view)
-            return;
-
-        if (WorkspacesViewType.SINGLE == view)
-            this._toggleViewButton.set_style_class_name('workspace-controls switch-mosaic');
-        else
-            this._toggleViewButton.set_style_class_name('workspace-controls switch-single');
-
-        this._currentViewType = view;
-        global.settings.set_string(WORKSPACES_VIEW_KEY, view);
+    _allocate: function(actor, box, flags) {
+        let childBox = new Clutter.ActorBox();
+        childBox.x1 = this._controls.x;
+        childBox.x2 = this._controls.x + this._controls.width;
+        childBox.y1 = 0;
+        childBox.y2 = box.y2 - box.y1;
+        this._controls.allocate(childBox, flags);
     },
 
-    _onDestroy: function() {
-        if (this._nWorkspacesNotifyId > 0) {
-            global.screen.disconnect(this._nWorkspacesNotifyId);
-            this._nWorkspacesNotifyId = 0;
-        }
-        if (this._switchWorkspaceNotifyId > 0) {
-            global.window_manager.disconnect(this._switchWorkspaceNotifyId);
-            this._switchWorkspaceNotifyId = 0;
-        }
+    _onHoverChanged: function() {
+        if (this._controls.hover)
+            this.popOut();
+        else
+            this.popIn();
     },
 
-    _setButtonSensitivity: function(button, sensitive) {
-        if (button == null)
-            return;
-        button.opacity = sensitive ? 255 : 85;
+    _poppedInX: function() {
+        let x = CONTROLS_POP_IN_FRACTION * this._controls.width;
+        if (St.Widget.get_default_direction() == St.TextDirection.RTL)
+            return -x;
+        return x;
     },
 
-    updateControlsSensitivity: function() {
-        if (this._currentView) {
-            this._setButtonSensitivity(this._removeButton, this._currentView.canRemoveWorkspace());
-            this._setButtonSensitivity(this._addButton, this._currentView.canAddWorkspace());
-        }
+    popOut: function() {
+        Tweener.addTween(this._controls,
+                         { x: 0,
+                           time: CONTROLS_POP_IN_TIME,
+                           transition: 'easeOutQuad' });
     },
 
-    _workspacesChanged: function() {
-        let showToggleButton = (global.screen.n_workspaces > 1);
-        Tweener.addTween(this._toggleViewButton,
-                         { opacity: showToggleButton ? 255 : 0,
-                           time: WORKSPACE_SWITCH_TIME,
+    popIn: function() {
+        Tweener.addTween(this._controls,
+                         { x: this._poppedInX(),
+                           time: CONTROLS_POP_IN_TIME,
                            transition: 'easeOutQuad' });
-        this.updateControlsSensitivity();
     }
 };
-Signals.addSignalMethods(WorkspacesControls.prototype);
 
-function WorkspacesManager(width, height, x, y) {
+function WorkspacesDisplay(width, height, x, y) {
     this._init(width, height, x, y);
 }
 
-WorkspacesManager.prototype = {
+WorkspacesDisplay.prototype = {
     _init: function(width, height, x, y) {
         this._workspacesWidth = width;
         this._workspacesHeight = height;
@@ -1411,53 +1292,85 @@ WorkspacesManager.prototype = {
             this._workspaces[w] = new Workspace.Workspace(metaWorkspace);
         }
 
+        this.actor = new St.BoxLayout();
+
+        let workspacesBox = new St.BoxLayout({ vertical: true });
+        this.actor.add(workspacesBox, { expand: true });
+
+        // placeholder for window previews
+        workspacesBox.add(new St.Bin(), { expand: true });
+
+        this._workspaceIndicatorPanel = new WorkspaceIndicatorPanel();
+        workspacesBox.add(this._workspaceIndicatorPanel.actor);
+
+        let controls = new St.BoxLayout({ vertical: true,
+                                          style_class: 'workspace-controls' });
+        this._controlsContainer = new WorkspaceControlsContainer(controls);
+        this.actor.add(this._controlsContainer.actor);
+
+        // Add/remove workspace buttons
+        this._removeButton = new St.Button({ label: '&#8211;', // n-dash
+                                             style_class: 'remove-workspace' });
+        this._removeButton.connect('clicked', Lang.bind(this, function() {
+            this.workspacesView.removeWorkspace();
+        }));
+        controls.add(this._removeButton);
+
+        this._addButton = new St.Button({ label: '+',
+                                          style_class: 'add-workspace' });
+        this._addButton.connect('clicked', Lang.bind(this, function() {
+            this.workspacesView.addWorkspace();
+        }));
+        this._addButton._delegate = this._addButton;
+        this._addButton._delegate.acceptDrop = Lang.bind(this,
+            function(source, actor, x, y, time) {
+                return this.workspacesView._acceptNewWorkspaceDrop(source, actor, x, y, time);
+            });
+        this._addButton._delegate.handleDragOver = Lang.bind(this,
+            function(source, actor, x, y, time) {
+                return this.workspacesView._handleDragOverNewWorkspace(source, actor, x, y, time);
+            });
+        controls.add(this._addButton, { expand: true });
+
         this.workspacesView = null;
-        this.controlsBar = new WorkspacesControls();
-        this._updateView();
-
-        this.controlsBar.actor.connect('destroy',
-                                       Lang.bind(this, this._onDestroy));
-        this._viewChangedId =
-            global.settings.connect('changed::' + WORKSPACES_VIEW_KEY,
-                                    Lang.bind(this, this._updateView));
-        this._nWorkspacesNotifyId =
-            global.screen.connect('notify::n-workspaces',
-                                  Lang.bind(this, this._workspacesChanged));
     },
 
-    _updateView: function() {
-        let viewType, newView;
+   show: function() {
+        let newView = new SingleView(this._workspacesWidth,
+                                     this._workspacesHeight,
+                                     this._workspacesX,
+                                     this._workspacesY,
+                                     this._workspaces);
 
-        let view = global.settings.get_string(WORKSPACES_VIEW_KEY).toUpperCase();
-        if (view in WorkspacesViewType)
-            viewType = WorkspacesViewType[view];
-        else
-            viewType = WorkspacesViewType.SINGLE;
-
-        switch (viewType) {
-            case WorkspacesViewType.SINGLE:
-                newView = new SingleView(this._workspacesWidth,
-                                         this._workspacesHeight,
-                                         this._workspacesX,
-                                         this._workspacesY,
-                                         this._workspaces);
-                break;
-            case WorkspacesViewType.GRID:
-            default:
-                newView = new MosaicView(this._workspacesWidth,
-                                         this._workspacesHeight,
-                                         this._workspacesX,
-                                         this._workspacesY,
-                                         this._workspaces);
-                break;
-        }
         if (this.workspacesView)
             this.workspacesView.destroy();
         this.workspacesView = newView;
 
-        this.controlsBar.updateControls(this.workspacesView);
+        this.workspacesView.connect('window-drag-begin', Lang.bind(this,
+            function() {
+                this._controlsContainer.popOut();
+            }));
+        this.workspacesView.connect('window-drag-end', Lang.bind(this,
+            function() {
+                this._controlsContainer.popIn();
+            }));
+
+        this._workspaceIndicatorPanel.updateWorkspaces(this._workspaces);
+
+        this._nWorkspacesNotifyId =
+            global.screen.connect('notify::n-workspaces',
+                                  Lang.bind(this, this._workspacesChanged));
+    },
 
-        this.emit('view-changed');
+    hide: function() {
+        if (this._nWorkspacesNotifyId > 0)
+            global.screen.disconnect(this._nWorkspacesNotifyId);
+        this.workspacesView.destroy();
+        this.workspacesView = null;
+        for (let w = 0; w < this._workspaces.length; w++) {
+            this._workspaces[w].disconnectAll();
+            this._workspaces[w].destroy();
+        }
     },
 
     _workspacesChanged: function() {
@@ -1500,17 +1413,7 @@ WorkspacesManager.prototype = {
         this.workspacesView.updateWorkspaces(oldNumWorkspaces,
                                              newNumWorkspaces,
                                              lostWorkspaces);
-    },
-
-    _onDestroy: function() {
-        if (this._nWorkspacesNotifyId > 0)
-            global.screen.disconnect(this._nWorkspacesNotifyId);
-        if (this._viewChangedId > 0)
-            global.settings.disconnect(this._viewChangedId);
-        for (let w = 0; w < this._workspaces.length; w++) {
-            this._workspaces[w].disconnectAll();
-            this._workspaces[w].destroy();
-        }
+        this._workspaceIndicatorPanel.updateWorkspaces(this._workspaces);
     }
 };
-Signals.addSignalMethods(WorkspacesManager.prototype);
+Signals.addSignalMethods(WorkspacesDisplay.prototype);



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