diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 0a62039c8..8c5c0d2f0 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -257,10 +257,6 @@ StTooltip StLabel { /* Overview */ -.overview { - background-color: #111; -} - .new-workspace-area { border: 2px solid rgba(255, 255, 255, 0.8); border-radius: 10px; diff --git a/js/ui/overview.js b/js/ui/overview.js index bec99c707..3c398d0e8 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -1,6 +1,7 @@ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ const Clutter = imports.gi.Clutter; +const Meta = imports.gi.Meta; const Mainloop = imports.mainloop; const Signals = imports.signals; const Lang = imports.lang; @@ -172,7 +173,16 @@ function Overview() { Overview.prototype = { _init : function() { - this._group = new St.Group({ style_class: 'overview' }); + this._desktopFade = new St.Bin(); + global.overlay_group.add_actor(this._desktopFade); + + // The actual global.background_actor is inside global.window_group, + // which is hidden when displaying the overview, so we display a clone. + this._background = new Clutter.Clone({ source: global.background_actor }); + this._background.hide(); + global.overlay_group.add_actor(this._background); + + this._group = new St.Group({ name: 'overview' }); this._group._delegate = this; this._group.connect('destroy', Lang.bind(this, function() { @@ -209,10 +219,6 @@ Overview.prototype = { reactive: true }); this._group.add_actor(this._transparentBackground); - // Background color for the Overview - this._backOver = new St.Label(); - this._group.add_actor(this._backOver); - this._group.hide(); global.overlay_group.add_actor(this._group); @@ -238,6 +244,20 @@ Overview.prototype = { this.workspaces = null; }, + _getDesktopClone: function() { + let windows = global.get_window_actors().filter(function(w) { + return w.meta_window.get_window_type() == Meta.WindowType.DESKTOP; + }); + if (windows.length == 0) + return null; + + let clone = new Clutter.Clone({ source: windows[0].get_texture() }); + clone.source.connect('destroy', Lang.bind(this, function() { + clone.destroy(); + })); + return clone; + }, + _onViewChanged: function() { if (!this.visible) return; @@ -314,11 +334,6 @@ Overview.prototype = { 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); - this._backOver.set_size(global.screen_width, global.screen_height); - this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING, this._workspacesY); // Dynamic width @@ -456,6 +471,19 @@ Overview.prototype = { this._group.add_actor(this._workspacesBar); this._workspacesBar.raise(this.workspaces.actor); + if (!this._desktopFade.child) + this._desktopFade.child = this._getDesktopClone(); + + if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) { + this._desktopFade.opacity = 255; + this._desktopFade.show(); + Tweener.addTween(this._desktopFade, + { opacity: 0, + time: ANIMATION_TIME, + transition: 'easeOutQuad' + }); + } + // All the the actors in the window group are completely obscured, // hiding the group holding them while the Overview is displayed greatly // increases performance of the Overview especially when there are many @@ -465,6 +493,7 @@ Overview.prototype = { // clones of them, this would obviously no longer be necessary. global.window_group.hide(); this._group.show(); + this._background.show(); // Create a zoom out effect. First scale the Overview group up and // position it so that the active workspace fills up the whole screen, @@ -502,6 +531,16 @@ Overview.prototype = { this.animationInProgress = true; this._hideInProgress = true; + + if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) { + this._desktopFade.opacity = 0; + this._desktopFade.show(); + Tweener.addTween(this._desktopFade, + { opacity: 255, + time: ANIMATION_TIME, + transition: 'easeOutQuad' }); + } + if (this._activeDisplayPane != null) this._activeDisplayPane.close(); this.workspaces.hide(); @@ -559,6 +598,7 @@ Overview.prototype = { return; this.animationInProgress = false; + this._desktopFade.hide(); this._coverPane.lower_bottom(); this.emit('shown'); @@ -576,6 +616,8 @@ Overview.prototype = { this._workspacesManager = null; this._dash.hide(); + this._desktopFade.hide(); + this._background.hide(); this._group.hide(); this.visible = false; diff --git a/js/ui/workspace.js b/js/ui/workspace.js index 349c87b5e..200217570 100644 --- a/js/ui/workspace.js +++ b/js/ui/workspace.js @@ -289,76 +289,9 @@ WindowClone.prototype = { this.emit('drag-end'); } }; - Signals.addSignalMethods(WindowClone.prototype); -function DesktopClone(window) { - this._init(window); -} - -DesktopClone.prototype = { - _init : function(window) { - this.actor = new Clutter.Group({ reactive: true }); - - let background = new Clutter.Clone({ source: global.background_actor }); - this.actor.add_actor(background); - - if (window) { - this._desktop = new Clutter.Clone({ source: window.get_texture() }); - this.actor.add_actor(this._desktop); - this._desktop.hide(); - } else { - this._desktop = null; - } - - this.actor.connect('button-release-event', - Lang.bind(this, this._onButtonRelease)); - }, - - zoomFromOverview: function(fadeInIcons) { - if (this._desktop == null) - return; - - if (fadeInIcons) { - this._desktop.opacity = 0; - this._desktop.show(); - Tweener.addTween(this._desktop, - { opacity: 255, - time: Overview.ANIMATION_TIME, - transition: 'easeOutQuad' }); - } - }, - - zoomToOverview: function(fadeOutIcons) { - if (this._desktop == null) - return; - - if (fadeOutIcons) { - this._desktop.opacity = 255; - this._desktop.show(); - Tweener.addTween(this._desktop, - { opacity: 0, - time: Overview.ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, - function() { - this._desktop.hide(); - }) - }); - } else { - this._desktop.hide(); - } - }, - - _onButtonRelease : function (actor, event) { - this.emit('selected', event.get_time()); - } -}; - -Signals.addSignalMethods(DesktopClone.prototype); - - /** * @windowClone: Corresponding window clone * @parentActor: The actor which will be the parent of all overlay items @@ -561,7 +494,6 @@ WindowOverlay.prototype = { this._parentActor.queue_relayout(); } }; - Signals.addSignalMethods(WindowOverlay.prototype); const WindowPositionFlags = { @@ -585,10 +517,20 @@ Workspace.prototype = { // Without this the drop area will be overlapped. this._windowOverlaysGroup.set_size(0, 0); - this.actor = new Clutter.Group(); + this.actor = new Clutter.Group({ reactive: true }); this.actor._delegate = this; this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); + this.actor.connect('button-release-event', Lang.bind(this, + function(actor, event) { + // Only switch to the workspace when there's no application + // windows open. The problem is that it's too easy to miss + // an app window and get the wrong one focused. + if (this._windows.length == 0) { + this.metaWorkspace.activate(event.get_time()); + Main.overview.hide(); + } + })); // Items in _windowOverlaysGroup should not be scaled, so we don't // add them to this.actor, but to its parent whenever it changes @@ -604,35 +546,10 @@ Workspace.prototype = { let windows = global.get_window_actors().filter(this._isMyWindow, this); - // Find the desktop window - for (let i = 0; i < windows.length; i++) { - if (windows[i].meta_window.get_window_type() == Meta.WindowType.DESKTOP) { - this._desktop = new DesktopClone(windows[i]); - break; - } - } - // If there wasn't one, fake it - if (!this._desktop) - this._desktop = new DesktopClone(); - - this._desktop.connect('selected', - Lang.bind(this, - function(clone, time) { - // Only switch to the workspace when there's no application windows - // open (we always have one window for the desktop). The problem - // is that it's too easy to miss an app window and get the wrong - // one focused. - if (this._windows.length == 1) { - this.metaWorkspace.activate(time); - Main.overview.hide(); - } - })); - this.actor.add_actor(this._desktop.actor); - // Create clones for remaining windows that should be // visible in the Overview - this._windows = [this._desktop]; - this._windowOverlays = [ null ]; + this._windows = []; + this._windowOverlays = []; for (let i = 0; i < windows.length; i++) { if (this._isOverviewWindow(windows[i])) { this._addWindowClone(windows[i]); @@ -747,10 +664,10 @@ Workspace.prototype = { // FIXME: do something cooler-looking using clutter-cairo this._frame = new Clutter.Rectangle({ color: FRAME_COLOR }); this.actor.add_actor(this._frame); - this._frame.set_position(this._desktop.actor.x - FRAME_SIZE / this.actor.scale_x, - this._desktop.actor.y - FRAME_SIZE / this.actor.scale_y); - this._frame.set_size(this._desktop.actor.width + 2 * FRAME_SIZE / this.actor.scale_x, - this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y); + this._frame.set_position(- FRAME_SIZE / this.actor.scale_x, + - FRAME_SIZE / this.actor.scale_y); + this._frame.set_size(this.actor.width + 2 * FRAME_SIZE / this.actor.scale_x, + this.actor.height + 2 * FRAME_SIZE / this.actor.scale_y); this._frame.lower_bottom(); this._framePosHandler = this.actor.connect('notify::scale-x', Lang.bind(this, this._updateFramePosition)); @@ -770,14 +687,14 @@ Workspace.prototype = { * Set the workspace (desktop) reactive **/ setReactive: function(reactive) { - this._desktop.actor.reactive = reactive; + this.actor.reactive = reactive; }, _updateFramePosition : function() { - this._frame.set_position(this._desktop.actor.x - FRAME_SIZE / this.actor.scale_x, - this._desktop.actor.y - FRAME_SIZE / this.actor.scale_y); - this._frame.set_size(this._desktop.actor.width + 2 * FRAME_SIZE / this.actor.scale_x, - this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y); + this._frame.set_position(- FRAME_SIZE / this.actor.scale_x, + - FRAME_SIZE / this.actor.scale_y); + this._frame.set_size(this.actor.width + 2 * FRAME_SIZE / this.actor.scale_x, + this.actor.height + 2 * FRAME_SIZE / this.actor.scale_y); }, _isCloneVisible: function(clone) { @@ -788,7 +705,7 @@ Workspace.prototype = { * _getVisibleClones: * * Returns a list WindowClone objects where the clone isn't filtered - * out by any application filter. The clone for the desktop is excluded. + * out by any application filter. * The returned array will always be newly allocated; it is not in any * defined order, and thus it's convenient to call .sort() with your * choice of sorting function. @@ -796,7 +713,7 @@ Workspace.prototype = { _getVisibleClones: function() { let visible = []; - for (let i = 1; i < this._windows.length; i++) { + for (let i = 0; i < this._windows.length; i++) { let clone = this._windows[i]; if (!this._isCloneVisible(clone)) @@ -808,7 +725,7 @@ Workspace.prototype = { }, _resetCloneVisibility: function () { - for (let i = 1; i < this._windows.length; i++) { + for (let i = 0; i < this._windows.length; i++) { let clone = this._windows[i]; let overlay = this._windowOverlays[i]; @@ -1007,9 +924,9 @@ Workspace.prototype = { let buttonOuterHeight, captionHeight; let buttonOuterWidth = 0; - if (this._windowOverlays[1]) { - [buttonOuterHeight, captionHeight] = this._windowOverlays[1].chromeHeights(); - buttonOuterWidth = this._windowOverlays[1].chromeWidth() / this.scale; + if (this._windowOverlays[0]) { + [buttonOuterHeight, captionHeight] = this._windowOverlays[0].chromeHeights(); + buttonOuterWidth = this._windowOverlays[0].chromeWidth() / this.scale; } else [buttonOuterHeight, captionHeight] = [0, 0]; buttonOuterHeight /= this.scale; @@ -1172,7 +1089,7 @@ Workspace.prototype = { }, _fadeInAllOverlays: function() { - for (let i = 1; i < this._windows.length; i++) { + for (let i = 0; i < this._windows.length; i++) { let clone = this._windows[i]; let overlay = this._windowOverlays[i]; if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows)) @@ -1182,7 +1099,7 @@ Workspace.prototype = { }, _hideAllOverlays: function() { - for (let i = 1; i< this._windows.length; i++) { + for (let i = 0; i < this._windows.length; i++) { let overlay = this._windowOverlays[i]; overlay.hide(); } @@ -1309,8 +1226,8 @@ Workspace.prototype = { }, // check for maximized windows on the workspace - _haveMaximizedWindows: function() { - for (let i = 1; i < this._windows.length; i++) { + hasMaximizedWindows: function() { + for (let i = 0; i < this._windows.length; i++) { let metaWindow = this._windows[i].metaWindow; if (metaWindow.showing_on_its_workspace() && metaWindow.maximized_horizontally && @@ -1331,12 +1248,6 @@ Workspace.prototype = { else this.positionWindows(WindowPositionFlags.ZOOM); - let active = global.screen.get_active_workspace(); - let fadeInIcons = (Main.overview.animationInProgress && - active == this.metaWorkspace && - !this._haveMaximizedWindows()); - this._desktop.zoomToOverview(fadeInIcons); - this._visible = true; }, @@ -1354,7 +1265,7 @@ Workspace.prototype = { this._doneLeavingOverview)); // Position and scale the windows. - for (let i = 1; i < this._windows.length; i++) { + for (let i = 0; i < this._windows.length; i++) { let clone = this._windows[i]; clone.zoomFromOverview(); @@ -1383,11 +1294,6 @@ Workspace.prototype = { } } - let active = global.screen.get_active_workspace(); - let fadeOutIcons = (active == this.metaWorkspace && - !this._haveMaximizedWindows()); - this._desktop.zoomFromOverview(fadeOutIcons); - this._visible = false; }, @@ -1451,7 +1357,7 @@ Workspace.prototype = { // Don't let the user try to select this workspace as it's // making its exit. - this._desktop.reactive = false; + this.actor.reactive = false; }, destroy : function() { @@ -1475,7 +1381,7 @@ Workspace.prototype = { // their parent (this.actor), but we might have a zoomed window // which has been reparented to the stage - _windows[0] holds // the desktop window, which is never reparented - for (let w = 1; w < this._windows.length; w++) + for (let w = 0; w < this._windows.length; w++) this._windows[w].destroy(); this._windows = []; }, @@ -1534,7 +1440,7 @@ Workspace.prototype = { }, _onShowOverlayClose: function (windowOverlay) { - for (let i = 1; i < this._windowOverlays.length; i++) { + for (let i = 0; i < this._windowOverlays.length; i++) { let overlay = this._windowOverlays[i]; if (overlay == windowOverlay) continue; diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js index 34945d776..4a7edc9c3 100644 --- a/js/ui/workspacesView.js +++ b/js/ui/workspacesView.js @@ -117,6 +117,11 @@ GenericWorkspacesView.prototype = { } }, + getActiveWorkspace: function() { + let active = global.screen.get_active_workspace_index(); + return this._workspaces[active]; + }, + _clearApplicationWindowSelection: function(reposition) { if (this._windowSelectionAppId == null) return; @@ -826,7 +831,7 @@ SingleView.prototype = { if (index < 0 || index >= global.n_workspaces) return; - let dragActor = this._workspaces[index]._desktop.actor; + let dragActor = this._workspaces[index].actor; if (draggable) { this._workspaces[index].actor.reactive = true; @@ -856,6 +861,9 @@ SingleView.prototype = { // start dragging the active workspace _onButtonPress: function(actor, event) { + if (actor != event.get_source()) + return; + if (this._dragIndex == -1) return;