From b250a72fcfa0a30bf2ca6cc2878667496f32e9e5 Mon Sep 17 00:00:00 2001 From: Tanner Doshier Date: Fri, 10 Aug 2012 13:13:39 -0500 Subject: [PATCH] overview, workspacesView: Use ThumbnailsBox for independent workspace thumbnails Both WorkspacesDisplay and ThumbnailsBox need to know when windows have been restacked. Instead of each tracking changes on their own or trying to call each other, have the overview keep track and do the calculations, emitting a signal with the result. https://bugzilla.gnome.org/show_bug.cgi?id=682050 --- data/theme/gnome-shell.css | 4 - js/ui/overview.js | 17 +++ js/ui/workspaceThumbnail.js | 9 +- js/ui/workspacesView.js | 211 ++---------------------------------- 4 files changed, 33 insertions(+), 208 deletions(-) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index c0c6aa935..4467e69bd 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -624,10 +624,6 @@ StScrollBar StButton#vhandle:active { spacing: 25px; } -.workspace-controls { - visible-width: 32px; /* Amount visible before hovering */ -} - .workspace-thumbnails-background { border: 1px solid rgba(128, 128, 128, 0.4); border-right: 0px; diff --git a/js/ui/overview.js b/js/ui/overview.js index 8cfe025ae..915c3dbee 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -183,6 +183,8 @@ const Overview = new Lang.Class({ Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin)); Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd)); + global.screen.connect('restacked', Lang.bind(this, this._onRestacked)); + this._windowSwitchTimeoutId = 0; this._windowSwitchTimestamp = 0; this._lastActiveWorkspaceIndex = -1; @@ -246,6 +248,9 @@ const Overview = new Lang.Class({ this._dash.showAppsButton); this._group.add_actor(this._viewSelector.actor); + this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox(); + this._group.add_actor(this._thumbnailsBox.actor); + // Add our same-line elements after the search entry this._overview.add_actor(this._group); @@ -390,6 +395,18 @@ const Overview = new Lang.Class({ this._coverPane.set_size(primary.width, contentHeight); }, + _onRestacked: function() { + let stack = global.get_window_actors(); + let stackIndices = {}; + + for (let i = 0; i < stack.length; i++) { + // Use the stable sequence for an integer to use as a hash key + stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i; + } + + this.emit('sync-window-stacking', stackIndices); + }, + //// Public methods //// beginItemDrag: function(source) { diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js index 381c12c4f..428b1b5dc 100644 --- a/js/ui/workspaceThumbnail.js +++ b/js/ui/workspaceThumbnail.js @@ -746,6 +746,9 @@ const ThumbnailsBox = new Lang.Class({ this._nWorkspacesNotifyId = global.screen.connect('notify::n-workspaces', Lang.bind(this, this._workspacesChanged)); + this._syncStackingId = + Main.overview.connect('sync-window-stacking', + Lang.bind(this, this._syncStacking)); this._targetScale = 0; this._scale = 0; @@ -785,6 +788,10 @@ const ThumbnailsBox = new Lang.Class({ global.screen.disconnect(this._nWorkspacesNotifyId); this._nWorkspacesNotifyId = 0; } + if (this._syncStackingId > 0) { + Main.overview.disconnect(this._syncStackingId); + this._syncStackingId = 0; + } for (let w = 0; w < this._thumbnails.length; w++) this._thumbnails[w].destroy(); @@ -906,7 +913,7 @@ const ThumbnailsBox = new Lang.Class({ this._queueUpdateStates(); }, - syncStacking: function(stackIndices) { + _syncStacking: function(actor, stackIndices) { for (let i = 0; i < this._thumbnails.length; i++) this._thumbnails[i].syncStacking(stackIndices); }, diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js index 8ea5d0165..b635596ab 100644 --- a/js/ui/workspacesView.js +++ b/js/ui/workspacesView.js @@ -23,8 +23,6 @@ const MAX_WORKSPACES = 16; const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides'; -const CONTROLS_POP_IN_TIME = 0.1; - const WorkspacesView = new Lang.Class({ Name: 'WorkspacesView', @@ -439,9 +437,7 @@ const WorkspacesDisplay = new Lang.Class({ _init: function() { this.actor = new Shell.GenericContainer(); - 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.connect('allocate', Lang.bind(this, this._updateWorkspacesGeometry)); this.actor.connect('parent-set', Lang.bind(this, this._parentSet)); this.actor.set_clip_to_allocation(true); @@ -472,23 +468,8 @@ const WorkspacesDisplay = new Lang.Class({ Main.overview.addAction(panAction); this.actor.bind_property('mapped', panAction, 'enabled', GObject.BindingFlags.SYNC_CREATE); - let controls = new St.Bin({ style_class: 'workspace-controls', - request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT, - y_align: St.Align.START, - y_fill: true }); - this._controls = controls; - this.actor.add_actor(controls); - - controls.reactive = true; - controls.track_hover = true; - controls.connect('notify::hover', - Lang.bind(this, this._onControlsHoverChanged)); - this._primaryIndex = Main.layoutManager.primaryIndex; - this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox(); - controls.add_actor(this._thumbnailsBox.actor); - this._workspacesViews = null; this._primaryScrollAdjustment = null; @@ -501,26 +482,6 @@ const WorkspacesDisplay = new Lang.Class({ this._inDrag = false; this._cancelledDrag = false; - this._controlsInitiallyHovered = false; - this._alwaysZoomOut = false; - this._zoomOut = false; - this._zoomFraction = 0; - - this._updateAlwaysZoom(); - - // If we stop hiding the overview on layout changes, we will need to - // update the _workspacesViews here - Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom)); - - Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){ - this._alwaysZoomOut = true; - })); - - Main.xdndHandler.connect('drag-end', Lang.bind(this, function(){ - this._alwaysZoomOut = false; - this._updateAlwaysZoom(); - })); - global.screen.connect('notify::n-workspaces', Lang.bind(this, this._workspacesChanged)); @@ -545,30 +506,10 @@ const WorkspacesDisplay = new Lang.Class({ }, show: function() { - if(!this._alwaysZoomOut) { - let [mouseX, mouseY] = global.get_pointer(); - let [x, y] = this._controls.get_transformed_position(); - let [width, height] = this._controls.get_transformed_size(); - let visibleWidth = this._controls.get_theme_node().get_length('visible-width'); - let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL); - if(rtl) - x = x + width - visibleWidth; - if(mouseX > x - 0.5 && mouseX < x + visibleWidth + 0.5 && - mouseY > y - 0.5 && mouseY < y + height + 0.5) - this._controlsInitiallyHovered = true; - } - - this._zoomOut = this._alwaysZoomOut; - this._zoomFraction = this._alwaysZoomOut ? 1 : 0; - this._updateZoom(); - - this._controls.show(); - this._thumbnailsBox.show(); - this._updateWorkspacesViews(); this._restackedNotifyId = - global.screen.connect('restacked', + Main.overview.connect('sync-window-stacking', Lang.bind(this, this._onRestacked)); if (this._itemDragBeginId == 0) @@ -589,8 +530,6 @@ const WorkspacesDisplay = new Lang.Class({ if (this._windowDragEndId == 0) this._windowDragEndId = Main.overview.connect('window-drag-end', Lang.bind(this, this._dragEnd)); - - this._onRestacked(); }, zoomFromOverview: function() { @@ -600,14 +539,8 @@ const WorkspacesDisplay = new Lang.Class({ }, hide: function() { - this._controls.hide(); - this._thumbnailsBox.hide(); - - if (!this._alwaysZoomOut) - this.zoomFraction = 0; - if (this._restackedNotifyId > 0){ - global.screen.disconnect(this._restackedNotifyId); + Main.overview.disconnect(this._restackedNotifyId); this._restackedNotifyId = 0; } if (this._itemDragBeginId > 0) { @@ -723,76 +656,6 @@ const WorkspacesDisplay = new Lang.Class({ return this._getPrimaryView().getActiveWorkspace().hasMaximizedWindows(); }, - // zoomFraction property allows us to tween the controls sliding in and out - set zoomFraction(fraction) { - this._zoomFraction = fraction; - this.actor.queue_relayout(); - }, - - get zoomFraction() { - return this._zoomFraction; - }, - - _updateAlwaysZoom: function() { - // Always show the pager if workspaces are actually used, - // e.g. there are windows on more than one - this._alwaysZoomOut = global.screen.n_workspaces > 2; - - if (this._alwaysZoomOut) - return; - - let monitors = Main.layoutManager.monitors; - let primary = Main.layoutManager.primaryMonitor; - - /* Look for any monitor to the right of the primary, if there is - * one, we always keep zoom out, otherwise its hard to reach - * the thumbnail area without passing into the next monitor. */ - for (let i = 0; i < monitors.length; i++) { - if (monitors[i].x >= primary.x + primary.width) { - this._alwaysZoomOut = true; - break; - } - } - }, - - _getPreferredWidth: function (actor, forHeight, alloc) { - // pass through the call in case the child needs it, but report 0x0 - this._controls.get_preferred_width(forHeight); - }, - - _getPreferredHeight: function (actor, forWidth, alloc) { - // pass through the call in case the child needs it, but report 0x0 - this._controls.get_preferred_height(forWidth); - }, - - _allocate: function (actor, box, flags) { - let childBox = new Clutter.ActorBox(); - - let totalWidth = box.x2 - box.x1; - - // width of the controls - let [controlsMin, controlsNatural] = this._controls.get_preferred_width(box.y2 - box.y1); - - // Amount of space on the screen we reserve for the visible control - let controlsVisible = this._controls.get_theme_node().get_length('visible-width'); - let controlsReserved = controlsVisible * (1 - this._zoomFraction) + controlsNatural * this._zoomFraction; - - let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL); - if (rtl) { - childBox.x2 = controlsReserved; - childBox.x1 = childBox.x2 - controlsNatural; - } else { - childBox.x1 = totalWidth - controlsReserved; - childBox.x2 = childBox.x1 + controlsNatural; - } - - childBox.y1 = 0; - childBox.y2 = box.y2- box.y1; - this._controls.allocate(childBox, flags); - - this._updateWorkspacesGeometry(); - }, - _parentSet: function(actor, oldParent) { if (oldParent && this._notifyOpacityId) oldParent.disconnect(this._notifyOpacityId); @@ -829,24 +692,19 @@ const WorkspacesDisplay = new Lang.Class({ let width = fullWidth; let height = fullHeight; - let [controlsMin, controlsNatural] = this._controls.get_preferred_width(height); - let controlsVisible = this._controls.get_theme_node().get_length('visible-width'); - let [x, y] = this.actor.get_transformed_position(); let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL); - let clipWidth = width - controlsVisible; + let clipWidth = width; let clipHeight = fullHeight; - let clipX = rtl ? x + controlsVisible : x; + let clipX = x; let clipY = y + (fullHeight - clipHeight) / 2; let overviewSpacing = Main.overview._spacing; - let widthAdjust = this._zoomOut ? controlsNatural : controlsVisible; - widthAdjust += overviewSpacing; - width -= widthAdjust; + width -= overviewSpacing; if (rtl) - x += widthAdjust; + x += overviewSpacing; let monitors = Main.layoutManager.monitors; let m = 0; @@ -870,25 +728,12 @@ const WorkspacesDisplay = new Lang.Class({ } }, - _onRestacked: function() { - let stack = global.get_window_actors(); - let stackIndices = {}; - - for (let i = 0; i < stack.length; i++) { - // Use the stable sequence for an integer to use as a hash key - stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i; - } - + _onRestacked: function(actor, stackIndices) { for (let i = 0; i < this._workspacesViews.length; i++) this._workspacesViews[i].syncStacking(stackIndices); - - this._thumbnailsBox.syncStacking(stackIndices); }, _workspacesChanged: function() { - this._updateAlwaysZoom(); - this._updateZoom(); - if (this._workspacesViews == null) return; @@ -942,35 +787,6 @@ const WorkspacesDisplay = new Lang.Class({ newNumWorkspaces); }, - _updateZoom : function() { - if (Main.overview.animationInProgress) - return; - - let shouldZoom = this._alwaysZoomOut || this._controls.hover; - if (shouldZoom != this._zoomOut) { - this._zoomOut = shouldZoom; - this._updateWorkspacesGeometry(); - - if (!this._workspacesViews) - return; - - Tweener.addTween(this, - { zoomFraction: this._zoomOut ? 1 : 0, - time: WORKSPACE_SWITCH_TIME, - transition: 'easeOutQuad' }); - - for (let i = 0; i < this._workspacesViews.length; i++) - this._workspacesViews[i].updateWindowPositions(); - } - }, - - _onControlsHoverChanged: function() { - if(!this._controls.hover) - this._controlsInitiallyHovered = false; - if(!this._controlsInitiallyHovered) - this._updateZoom(); - }, - _dragBegin: function() { this._inDrag = true; this._cancelledDrag = false; @@ -986,22 +802,11 @@ const WorkspacesDisplay = new Lang.Class({ }, _onDragMotion: function(dragEvent) { - let controlsHovered = this._controls.contains(dragEvent.targetActor); - this._controls.set_hover(controlsHovered); - return DND.DragMotionResult.CONTINUE; }, _dragEnd: function() { this._inDrag = false; - - // We do this deferred because drag-end is emitted before dnd.js emits - // event/leave events that were suppressed during the drag. If we didn't - // defer this, we'd zoom out then immediately zoom in because of the - // enter event we received. That would normally be invisible but we - // might as well avoid it. - Meta.later_add(Meta.LaterType.BEFORE_REDRAW, - Lang.bind(this, this._updateZoom)); } }); Signals.addSignalMethods(WorkspacesDisplay.prototype);