From 4d52c1095816bfba51715b5e836f29483960ea13 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 23 Jul 2009 17:36:41 -0400 Subject: [PATCH] Bug 589316 - Add application/window icon to overlay windows To better distinguish between vast fields of white of which many windows are composed, add the application icon to the bottom right of the window. We fade them in to avoid an abrupt feel. The icons are in the workspaces group, not individual workspace groups to avoid having to adjust them when we scale the workspaces. Replace Workspace._lookupIndexAndClone with Workspace.lookupIndex, and make the caller go from index to clone, or clone and index. --- js/ui/workspaces.js | 146 +++++++++++++++++++++++++++++++++----------- 1 file changed, 112 insertions(+), 34 deletions(-) diff --git a/js/ui/workspaces.js b/js/ui/workspaces.js index 2325b5abb..6babf822e 100644 --- a/js/ui/workspaces.js +++ b/js/ui/workspaces.js @@ -121,9 +121,10 @@ WindowClone.prototype = { _onDragBegin : function (draggable, time) { this._inDrag = true; this._updateTitle(); + this.emit('drag-begin'); }, - _onDragEnd : function (draggable, time) { + _onDragEnd : function (draggable, time, snapback) { this._inDrag = false; // Most likely, the clone is going to move away from the @@ -133,6 +134,8 @@ WindowClone.prototype = { // better to have the label mysteriously missing than // mysteriously present this._havePointer = false; + + this.emit('drag-end'); }, // Called by Tweener @@ -155,16 +158,7 @@ WindowClone.prototype = { padding: 4, spacing: 4, orientation: Big.BoxOrientation.HORIZONTAL }); - - let icon = this.metaWindow.mini_icon; - let iconTexture = new Clutter.Texture({ x: this.actor.x, - y: this.actor.y + this.actor.height - 16, - width: 16, - height: 16, - keep_aspect_ratio: true }); - Shell.clutter_texture_set_from_pixbuf(iconTexture, icon); - box.append(iconTexture, Big.BoxPackFlags.NONE); - + let title = new Clutter.Text({ color: WINDOWCLONE_TITLE_COLOR, font_name: "Sans 12", text: this.metaWindow.title, @@ -258,18 +252,26 @@ DesktopClone.prototype = { Signals.addSignalMethods(DesktopClone.prototype); -function Workspace(workspaceNum) { - this._init(workspaceNum); +/** + * @workspaceNum: Workspace index + * @parentActor: The actor which will be the parent of this workspace; + * we need this in order to add chrome such as the icons + * on top of the windows without having them be scaled. + */ +function Workspace(workspaceNum, parentActor) { + this._init(workspaceNum, parentActor); } Workspace.prototype = { - _init : function(workspaceNum) { + _init : function(workspaceNum, parentActor) { let me = this; let global = Shell.Global.get(); this.workspaceNum = workspaceNum; this._metaWorkspace = global.screen.get_workspace_by_index(workspaceNum); + this.parentActor = parentActor; + this.actor = new Clutter.Group(); this.actor._delegate = this; this.scale = 1.0; @@ -298,6 +300,7 @@ Workspace.prototype = { // Create clones for remaining windows that should be // visible in the overlay this._windows = [this._desktop]; + this._windowIcons = [ null ]; for (let i = 0; i < windows.length; i++) { if (this._isOverlayWindow(windows[i])) { this._addWindowClone(windows[i]); @@ -364,21 +367,19 @@ Workspace.prototype = { } }, - _lookupIndexAndClone: function (metaWindow) { + _lookupIndex: function (metaWindow) { let index, clone; for (let i = 0; i < this._windows.length; i++) { if (this._windows[i].metaWindow == metaWindow) { - index = i; - clone = this._windows[index]; - return [index, clone]; + return i; } } - return [-1, null]; + return -1; }, lookupCloneForMetaWindow: function (metaWindow) { - let [index, clone] = this._lookupIndexAndClone (metaWindow); - return clone; + let index = this._lookupIndex (metaWindow); + return index < 0 ? null : this._windows[index]; }, _adjustRemoveButton : function() { @@ -440,6 +441,7 @@ Workspace.prototype = { for (let i = 1; i < this._windows.length; i++) { let clone = this._windows[i]; + let icon = this._windowIcons[i]; clone.stackAbove = this._windows[i - 1].actor; let [xCenter, yCenter, fraction] = this._computeWindowPosition(i); @@ -450,6 +452,7 @@ Workspace.prototype = { let desiredSize = global.screen_width * fraction; let scale = Math.min(desiredSize / size, 1.0 / this.scale); + icon.hide(); Tweener.addTween(clone.actor, { x: xCenter - 0.5 * scale * clone.actor.width, y: yCenter - 0.5 * scale * clone.actor.height, @@ -457,22 +460,63 @@ Workspace.prototype = { scale_y: scale, workspace_relative: workspaceZooming ? this : null, time: Overlay.ANIMATION_TIME, - transition: "easeOutQuad" + transition: "easeOutQuad", + onComplete: Lang.bind(this, function() { + this._fadeInWindowIcon(clone, icon); + }) }); } }, + _fadeInWindowIcon: function (clone, icon) { + icon.opacity = 0; + icon.show(); + let [parentX, parentY] = icon.get_parent().get_transformed_position(); + let [cloneX, cloneY] = clone.actor.get_transformed_position(); + let [cloneWidth, cloneHeight] = clone.actor.get_transformed_size(); + // Note we only round the first part, because we're still going to be + // positioned relative to the parent. By subtracting a possibly + // non-integral parent X/Y we cancel it out. + let x = Math.round(cloneX + cloneWidth - icon.width) - parentX; + let y = Math.round(cloneY + cloneHeight - icon.height) - parentY; + icon.set_position(x, y); + icon.raise(this.actor); + Tweener.addTween(icon, + { opacity: 255, + time: Overlay.ANIMATION_TIME, + transition: "easeOutQuad" }); + }, + + _fadeInAllIcons: function () { + for (let i = 1; i < this._windows.length; i++) { + let clone = this._windows[i]; + let icon = this._windowIcons[i]; + this._fadeInWindowIcon(clone, icon); + } + }, + + _hideAllIcons: function () { + for (let i = 1; i < this._windows.length; i++) { + let icon = this._windowIcons[i]; + icon.hide(); + } + }, + _windowRemoved : function(metaWorkspace, metaWin) { let global = Shell.Global.get(); let win = metaWin.get_compositor_private(); // find the position of the window in our list - let [index, clone] = this._lookupIndexAndClone (metaWin); + let index = this._lookupIndex (metaWin); if (index == -1) return; + let clone = this._windows[index]; + let icon = this._windowIcons[index]; + this._windows.splice(index, 1); + this._windowIcons.splice(index, 1); // If metaWin.get_compositor_private() returned non-NULL, that // means the window still exists (and is just being moved to @@ -490,6 +534,7 @@ Workspace.prototype = { }; } clone.destroy(); + icon.destroy(); this._positionWindows(false); this.updateRemovable(); @@ -559,8 +604,10 @@ Workspace.prototype = { // Animates the return from overlay mode zoomFromOverlay : function() { - this.leavingOverlay = true; - + this.leavingOverlay = true; + + this._hideAllIcons(); + Tweener.addTween(this.actor, { x: this.fullSizeX, y: this.fullSizeY, @@ -592,16 +639,18 @@ Workspace.prototype = { // Animates grid shrinking/expanding when a row or column // of workspaces is added or removed resizeToGrid : function (oldScale) { + this._hideAllIcons(); Tweener.addTween(this.actor, { x: this.gridX, y: this.gridY, scale_x: this.scale, scale_y: this.scale, time: Overlay.ANIMATION_TIME, - transition: "easeOutQuad" + transition: "easeOutQuad", + onComplete: Lang.bind(this, this._fadeInAllIcons) }); }, - + // Animates the addition of a new (empty) workspace slideIn : function(oldScale) { let global = Shell.Global.get(); @@ -630,6 +679,8 @@ Workspace.prototype = { let global = Shell.Global.get(); let destX = this.actor.x, destY = this.actor.y; + this._hideAllIcons(); + if (this.gridCol > this.gridRow) destX = global.screen_width; else @@ -682,16 +733,47 @@ Workspace.prototype = { return !win.is_override_redirect(); }, + _createWindowIcon: function(window) { + let appSys = Shell.AppSystem.get_default(); + let appMon = Shell.AppMonitor.get_default() + let appInfo = appMon.get_window_app(window.metaWindow); + let iconTexture = null; + // The design is application based, so prefer the application + // icon here if we have it. FIXME - should move this fallback code + // into ShellAppMonitor. + if (appInfo) { + iconTexture = appInfo.create_icon_texture(48); + } else { + let icon = window.metaWindow.icon; + iconTexture = new Clutter.Texture({ width: 48, + height: 48, + keep_aspect_ratio: true }); + Shell.clutter_texture_set_from_pixbuf(iconTexture, icon); + } + return iconTexture; + }, + // Create a clone of a (non-desktop) window and add it to the window list _addWindowClone : function(win) { + let icon = this._createWindowIcon(win); + this.parentActor.add_actor(icon); + let clone = new WindowClone(win); clone.connect('selected', Lang.bind(this, this._onCloneSelected)); - clone.connect('dragged', - Lang.bind(this, this._onCloneDragged)); + clone.connect('drag-begin', + Lang.bind(this, function() { + icon.hide(); + })); + clone.connect('drag-end', + Lang.bind(this, function() { + icon.show(); + })); this.actor.add_actor(clone.actor); + this._windows.push(clone); + this._windowIcons.push(icon); return clone; }, @@ -717,10 +799,6 @@ Workspace.prototype = { return [xCenter, yCenter, fraction]; }, - _onCloneDragged : function (clone, stageX, stageY, time) { - this.emit('window-dragged', clone, stageX, stageY, time); - }, - _onCloneSelected : function (clone, time) { Main.overlay.activateWindow(clone.metaWindow, time); }, @@ -1052,7 +1130,7 @@ Workspaces.prototype = { }, _addWorkspaceActor : function(workspaceNum) { - let workspace = new Workspace(workspaceNum); + let workspace = new Workspace(workspaceNum, this.actor); this._workspaces[workspaceNum] = workspace; this.actor.add_actor(workspace.actor); },