diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 888f76cca..ce6b1a9c8 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -216,7 +216,7 @@ StTooltip { height: 48px; } -.workspaces-bar, .workspaces-bar * { +.workspaces-bar { spacing: 5px; } diff --git a/js/ui/overview.js b/js/ui/overview.js index 92847b171..bc0304f13 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -197,8 +197,8 @@ Overview.prototype = { this.infoBar = new InfoBar(); this._group.add_actor(this.infoBar.actor); - this._workspacesViewSwitch = new WorkspacesView.WorkspacesViewSwitch(); - this._workspacesViewSwitch.connect('view-changed', Lang.bind(this, this._onViewChanged)); + this._workspacesControls = new WorkspacesView.WorkspacesControls(); + this._workspacesControls.connect('view-changed', Lang.bind(this, this._onViewChanged)); this.visible = false; this.animationInProgress = false; @@ -251,41 +251,21 @@ Overview.prototype = { this._workspaces = null; }, - _createControlsBar: function() { - this._workspacesBar = new St.BoxLayout({ 'pack-start': true, - style_class: 'workspaces-bar' }); - this._workspacesBar.move_by(this._workspacesBarX, this._workspacesBarY); - - let controlsBar = this._workspacesViewSwitch.createControlsBar(); - let bar = this._workspaces.createControllerBar(); - this._workspacesBar.add(bar, { expand: true, 'x-fill': true, 'y-fill': true, - y_align: St.Align.MIDDLE, x_align: St.Align.START }); - this._workspacesBar.add(controlsBar, {x_align: St.Align.END}); - this._workspacesBar.width = this._workspacesBarWidth; - - this._group.add_actor(this._workspacesBar); - this._workspacesBar.raise(this._workspaces.actor); - }, - _onViewChanged: function() { if (!this.visible) return; - //Remove old worspacesView - this._group.remove_actor(this._workspacesBar); + // Remove old workspacesView this._workspaces.hide(); this._group.remove_actor(this._workspaces.actor); this._workspaces.destroy(); - this._workspacesBar.destroy(); - this._workspaces = this._workspacesViewSwitch.createCurrentWorkspaceView(this._workspacesWidth, this._workspacesHeight, - this._workspacesX, this._workspacesY, false); + this._workspaces = this._workspacesControls.createCurrentWorkspaceView(this._workspacesWidth, this._workspacesHeight, + this._workspacesX, this._workspacesY, false); - //Show new workspacesView + // Show new workspacesView this._group.add_actor(this._workspaces.actor); this._dash.actor.raise(this._workspaces.actor); - this._createControlsBar(); - // Set new position and scale to workspaces. this.emit('showing'); }, @@ -472,8 +452,8 @@ Overview.prototype = { this._dash.show(); /* TODO: make this stuff dynamic */ - this._workspaces = this._workspacesViewSwitch.createCurrentWorkspaceView(this._workspacesWidth, this._workspacesHeight, - this._workspacesX, this._workspacesY, true); + this._workspaces = this._workspacesControls.createCurrentWorkspaceView(this._workspacesWidth, this._workspacesHeight, + this._workspacesX, this._workspacesY, true); this._group.add_actor(this._workspaces.actor); // The workspaces actor is as big as the screen, so we have to raise the dash above it @@ -481,7 +461,13 @@ Overview.prototype = { // be as big as the screen. this._dash.actor.raise(this._workspaces.actor); - this._createControlsBar(); + this._workspacesBar = this._workspacesControls.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); // All the the actors in the window group are completely obscured, // hiding the group holding them while the Overview is displayed greatly @@ -511,7 +497,7 @@ Overview.prototype = { onCompleteScope: this }); - // Make Dash fade in so that it doesn't appear to big. + // Make Dash fade in so that it doesn't appear too big. this._dash.actor.opacity = 0; Tweener.addTween(this._dash.actor, { opacity: 255, @@ -533,9 +519,6 @@ Overview.prototype = { this._activeDisplayPane.close(); this._workspaces.hide(); - this._workspacesBar.destroy(); - this._workspacesBar = null; - // Create a zoom in effect by transforming the Overview group so that // the active workspace fills up the whole screen. The opposite // transition is used in show(). @@ -600,6 +583,9 @@ Overview.prototype = { this._workspaces.destroy(); this._workspaces = null; + this._workspacesBar.destroy(); + this._workspacesBar = null; + this._dash.hide(); this._group.hide(); diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js index 7876cf1ef..6555e3d77 100644 --- a/js/ui/workspacesView.js +++ b/js/ui/workspacesView.js @@ -234,19 +234,23 @@ GenericWorkspacesView.prototype = { return [activeWorkspace.gridX, activeWorkspace.gridY]; }, - _setButtonSensitivity: function(button, sensitive) { - if (button == null) - return; - if (sensitive && !button.reactive) { - button.reactive = true; - button.opacity = 255; - } else if (!sensitive && button.reactive) { - button.reactive = false; - button.opacity = 85; - } + createControllerBar: function() { + throw new Error("Not implemented"); }, - createControllerBar: function() { + canAddWorkspace: function() { + return global.screen.n_workspaces < MAX_WORKSPACES; + }, + + addWorkspace: function() { + throw new Error("Not implemented"); + }, + + canRemoveWorkspace: function() { + throw new Error("Not implemented"); + }, + + removeWorkspace: function() { throw new Error("Not implemented"); }, @@ -283,9 +287,6 @@ MosaicView.prototype = { width + 2 * Workspace.FRAME_SIZE, height + 2 * Workspace.FRAME_SIZE); this._workspaces[global.screen.get_active_workspace_index()].setSelected(true); - - this._removeButton = null; - this._addButton = null; }, // Assign grid positions to workspaces. We can't just do a simple @@ -406,8 +407,6 @@ MosaicView.prototype = { // this has the side effect of removing the frame border let activeIndex = global.screen.get_active_workspace_index(); this._workspaces[activeIndex].setSelected(true); - - this._updateButtonsVisibility(); }, _activeWorkspaceChanged: function(wm, from, to, direction) { @@ -422,47 +421,23 @@ MosaicView.prototype = { }, createControllerBar: function() { - let actor = new St.BoxLayout({ 'pack-start': true }); - let bin = new St.Bin(); - let addButton = new St.Button({ style_class: "workspace-controls add" }); - this._addButton = addButton; - addButton.connect('clicked', Lang.bind(this, this._addNewWorkspace)); - addButton._delegate = addButton; - addButton._delegate.acceptDrop = Lang.bind(this, function(source, actor, x, y, time) { - return this._acceptNewWorkspaceDrop(source, actor, x, y, time); - }); - actor.add(bin, { x_align: St.Align.END }); - bin.set_child(addButton); - bin.set_alignment(St.Align.END, St.Align.START); - - bin = new St.Bin(); - let removeButton = new St.Button({ style_class: "workspace-controls remove" }); - this._removeButton = removeButton; - removeButton.connect('clicked', Lang.bind(this, function() { - if (this._workspaces.length <= 1) - return; - global.screen.remove_workspace(this._workspaces[this._workspaces.length - 1]._metaWorkspace, global.get_current_time()); - })); - actor.add(bin, { expand: true, x_fill: true, x_align: St.Align.END }); - this._updateButtonsVisibility(); - bin.set_child(removeButton); - bin.set_alignment(St.Align.END, St.Align.START); - - return actor; + return null; }, - _updateButtonsVisibility: function() { - let canRemove = (global.screen.n_workspaces > 1); - let canAdd = (global.screen.n_workspaces < MAX_WORKSPACES); - - this._setButtonSensitivity(this._removeButton, canRemove); - this._setButtonSensitivity(this._addButton, canAdd); - }, - - _addNewWorkspace: function() { + addWorkspace: function() { global.screen.append_new_workspace(false, global.get_current_time()); }, + canRemoveWorkspace: function() { + return global.screen.n_workspaces > 1; + }, + + removeWorkspace: function() { + let last = this._workspaces.length - 1; + global.screen.remove_workspace(this._workspaces[last]._metaWorkspace, + global.get_current_time()); + }, + _acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) { this._addNewWorkspace(); return this.acceptNewWorkspaceDrop(source, dropActor, x, y, time); @@ -522,10 +497,8 @@ SingleView.prototype = { this.actor.style_class = "workspaces single"; this._actor.set_clip(x, y, width, height); - this._addButton = null; - this._removeButton = null; this._indicatorsPanel = null; - this._indicatorsPanelWidth = null; + this._indicatorsPanelWidth = 0; this._scroll = null; this._lostWorkspaces = []; this._scrolling = false; @@ -988,11 +961,10 @@ SingleView.prototype = { }, createControllerBar: function() { - let panel = new St.BoxLayout({ style_class: 'single-view-controls', + let actor = new St.BoxLayout({ style_class: 'single-view-controls', pack_start: true, vertical: true }); - let actor = new St.BoxLayout({ 'pack-start': true }); let active = global.screen.get_active_workspace_index(); let adj = new St.Adjustment({ value: active, lower: 0, @@ -1024,34 +996,15 @@ SingleView.prototype = { this._scrollToActive(true); })); - let addButton = new St.Button({ style_class: "workspace-controls add" }); - this._addButton = addButton; - addButton.connect('clicked', Lang.bind(this, this._addNewWorkspace)); - addButton._delegate = addButton; - addButton._delegate.acceptDrop = Lang.bind(this, function(source, actor, x, y, time) { - return this._acceptNewWorkspaceDrop(source, actor, x, y, time); - }); - actor.add(addButton, {x_align: St.Align.END, y_align: St.Align.START, 'y-fill': false}); - - let removeButton = new St.Button({ style_class: "workspace-controls remove" }); - this._removeButton = removeButton; - removeButton.connect('clicked', Lang.bind(this, function() { - if (this._workspaces.length <= 1) - return; - let index = global.screen.get_active_workspace_index(); - if (index == 0) - return; - global.screen.remove_workspace(this._workspaces[index]._metaWorkspace, global.get_current_time()); - })); - actor.add(removeButton, { x_align: St.Align.END, y_align: St.Align.START, 'y-fill': false }); - this._updatePanelVisibility(); - - panel.add(this._createPositionalIndicator(), {expand: true, 'x-fill': true, 'y-fill': true}); - panel.add(this._scroll, { expand: true, - 'x-fill': true, - 'y-fill': false, + actor.add(this._createPositionalIndicator(), { expand: true, + x_fill: true, + y_fill: true }); + actor.add(this._scroll, { expand: true, + x_fill: true, + y_fill: false, y_align: St.Align.START }); - actor.add(panel, {expand: true, 'x-fill': true, 'y-fill': true}); + + this._updatePanelVisibility(); return actor; }, @@ -1087,7 +1040,7 @@ SingleView.prototype = { }, _fillPositionalIndicator: function() { - if (this._indicatorsPanel == null || this._indicatorsPanelWidth == null) + if (this._indicatorsPanel == null || this._indicatorsPanelWidth == 0) return; let width = this._indicatorsPanelWidth; this._indicatorsPanel.remove_all(); @@ -1154,13 +1107,11 @@ SingleView.prototype = { return actor; }, + canRemoveWorkspace: function() { + return global.screen.get_active_workspace_index() != 0; + }, + _updatePanelVisibility: function() { - let canRemove = (global.screen.get_active_workspace_index() != 0); - let canAdd = (global.screen.n_workspaces < MAX_WORKSPACES); - - this._setButtonSensitivity(this._removeButton, canRemove); - this._setButtonSensitivity(this._addButton, canAdd); - let showSwitches = (global.screen.n_workspaces > 1); if (this._scroll != null) { if (showSwitches) @@ -1177,34 +1128,46 @@ SingleView.prototype = { this._fillPositionalIndicator(); }, - _addNewWorkspace: function() { + addWorkspace: function() { let ws = global.screen.append_new_workspace(false, global.get_current_time()); ws.activate(global.get_current_time()); }, + removeWorkspace: function() { + let active = global.screen.get_active_workspace_index(); + global.screen.remove_workspace(this._workspaces[active]._metaWorkspace, + global.get_current_time()); + }, + _acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) { - this._addNewWorkspace(); + this.addWorkspace(); return this.acceptNewWorkspaceDrop(source, dropActor, x, y, time); } }; -function WorkspacesViewSwitch() { +function WorkspacesControls() { this._init(); } -WorkspacesViewSwitch.prototype = { +WorkspacesControls.prototype = { _init: function() { + this.actor = null; this._gconf = Shell.GConf.get_default(); this._mosaicViewButton = null; this._singleViewButton = null; - this._controlsBar = null; + this._addButton = null; + this._removeButton = null; let view = this._gconf.get_string(WORKSPACES_VIEW_KEY).toUpperCase(); if (view in WorkspacesViewType) this._currentViewType = WorkspacesViewType[view]; else this._currentViewType = WorkspacesViewType.SINGLE; + + this._currentView = null; + this._nWorkspacesNotifyId = 0; + this._switchWorkspaceNotifyId = 0; }, _setView: function(view) { @@ -1221,58 +1184,130 @@ WorkspacesViewSwitch.prototype = { createCurrentWorkspaceView: function(width, height, x, y, animate) { switch (this._currentViewType) { case WorkspacesViewType.SINGLE: - return new SingleView(width, height, x, y, animate); + this._currentView = new SingleView(width, height, x, y, animate); + break; case WorkspacesViewType.GRID: - return new MosaicView(width, height, x, y, animate); default: - return new MosaicView(width, height, x, y, animate); + this._currentView = new MosaicView(width, height, x, y, animate); + break; } + this._updateControlsBar(); + return this._currentView; }, - createControlsBar: function() { - let actor = new St.BoxLayout(); + _updateControlsBar: function() { + if (this.actor) + this.actor.remove_all(); + else + this.actor = new St.BoxLayout({ style_class: 'workspaces-bar' }); - this._mosaicViewButton = new St.Button({ style_class: "workspace-controls switch-mosaic" }); - this._mosaicViewButton.set_toggle_mode(true); + // View switcher buttons + this._mosaicViewButton = new St.Button({ style_class: 'workspace-controls switch-mosaic', + toggle_mode: true }); this._mosaicViewButton.connect('clicked', Lang.bind(this, function() { this._setView(WorkspacesViewType.GRID); })); - actor.add(this._mosaicViewButton, {'y-fill' : false, 'y-align' : St.Align.START}); + this.actor.add(this._mosaicViewButton, { y_fill: false, + y_align: St.Align.START }); - this._singleViewButton = new St.Button({ style_class: "workspace-controls switch-single" }); - this._singleViewButton.set_toggle_mode(true); + this._singleViewButton = new St.Button({ style_class: 'workspace-controls switch-single', + toggle_mode: true }); this._singleViewButton.connect('clicked', Lang.bind(this, function() { this._setView(WorkspacesViewType.SINGLE); })); - actor.add(this._singleViewButton, {'y-fill' : false, 'y-align' : St.Align.START}); + this.actor.add(this._singleViewButton, { y_fill: false, + y_align: St.Align.START }); if (this._currentViewType == WorkspacesViewType.GRID) this._mosaicViewButton.set_checked(true); else this._singleViewButton.set_checked(true); + // View specific controls + let bar = this._currentView.createControllerBar(); + if (!bar) + bar = new St.Bin(); + + this.actor.add(bar, { expand: true, + x_fill: true, + y_fill: true, + y_align: St.Align.MIDDLE, + x_align: St.Align.START }); + + // 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) { + let view = this._currentView; + return view._acceptNewWorkspaceDrop(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)); - actor.connect('destroy', Lang.bind(this, function() { - this._controlsBar = null; - global.screen.disconnect(this._nWorkspacesNotifyId); - })); + this._switchWorkspaceNotifyId = + global.window_manager.connect('switch-workspace', + Lang.bind(this, this._updateButtonSensitivity)); + + this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); - this._controlsBar = actor; this._workspacesChanged(); - return actor; + }, + + _onDestroy: function() { + this.actor = null; + 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; + } + }, + + _setButtonSensitivity: function(button, sensitive) { + if (button == null) + return; + button.reactive = sensitive; + button.opacity = sensitive ? 255 : 85; + }, + + _updateButtonSensitivity: function() { + this._setButtonSensitivity(this._addButton, + this._currentView.canAddWorkspace()); + this._setButtonSensitivity(this._removeButton, + this._currentView.canRemoveWorkspace()); }, _workspacesChanged: function() { - if (this._controlsBar == null) + if (this.actor == null) return; - if (global.screen.n_workspaces == 1) - this._controlsBar.set_opacity(0); - else - this._controlsBar.set_opacity(255); + + this._updateButtonSensitivity(); + + if (global.screen.n_workspaces == 1) { + this._mosaicViewButton.hide(); + this._singleViewButton.hide(); + } else { + this._mosaicViewButton.show(); + this._singleViewButton.show(); + } } }; -Signals.addSignalMethods(WorkspacesViewSwitch.prototype); +Signals.addSignalMethods(WorkspacesControls.prototype);