Track window adds/removes in the overlay. #568983

svn path=/trunk/; revision=180
This commit is contained in:
Dan Winship 2009-02-04 14:50:50 +00:00
parent e9826ecb45
commit 4850ea608f

View File

@ -5,6 +5,7 @@ const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf; const GdkPixbuf = imports.gi.GdkPixbuf;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango; const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
@ -58,6 +59,7 @@ WindowClone.prototype = {
x: realWindow.x, x: realWindow.x,
y: realWindow.y }); y: realWindow.y });
this.realWindow = realWindow; this.realWindow = realWindow;
this.metaWindow = realWindow.meta_window;
this.origX = realWindow.x; this.origX = realWindow.x;
this.origY = realWindow.y; this.origY = realWindow.y;
@ -250,7 +252,7 @@ WindowClone.prototype = {
spacing: 4, spacing: 4,
orientation: Big.BoxOrientation.HORIZONTAL }); orientation: Big.BoxOrientation.HORIZONTAL });
let icon = window.meta_window.mini_icon; let icon = this.metaWindow.mini_icon;
let iconTexture = new Clutter.Texture({ x: this.actor.x, let iconTexture = new Clutter.Texture({ x: this.actor.x,
y: this.actor.y + this.actor.height - 16, y: this.actor.y + this.actor.height - 16,
width: 16, width: 16,
@ -261,7 +263,7 @@ WindowClone.prototype = {
let title = new Clutter.Label({ color: WINDOWCLONE_TITLE_COLOR, let title = new Clutter.Label({ color: WINDOWCLONE_TITLE_COLOR,
font_name: "Sans 12", font_name: "Sans 12",
text: window.meta_window.title, text: this.metaWindow.title,
ellipsize: Pango.EllipsizeMode.END ellipsize: Pango.EllipsizeMode.END
}); });
box.append(title, Big.BoxPackFlags.EXPAND); box.append(title, Big.BoxPackFlags.EXPAND);
@ -362,6 +364,8 @@ Workspace.prototype = {
let global = Shell.Global.get(); let global = Shell.Global.get();
this.workspaceNum = workspaceNum; this.workspaceNum = workspaceNum;
this._metaWorkspace = global.screen.get_workspace_by_index(workspaceNum);
this.actor = new Clutter.Group(); this.actor = new Clutter.Group();
this.scale = 1.0; this.scale = 1.0;
@ -378,12 +382,12 @@ Workspace.prototype = {
if (!this._desktop) if (!this._desktop)
this._desktop = new DesktopClone(); this._desktop = new DesktopClone();
let metaWorkspace = global.screen.get_workspace_by_index(workspaceNum);
this._desktop.connect('selected', this._desktop.connect('selected',
Lang.bind(this,
function(clone, time) { function(clone, time) {
metaWorkspace.activate(time); this._metaWorkspace.activate(time);
Main.hide_overlay(); Main.hide_overlay();
}); }));
this.actor.add_actor(this._desktop.actor); this.actor.add_actor(this._desktop.actor);
// Create clones for remaining windows that should be // Create clones for remaining windows that should be
@ -395,6 +399,12 @@ Workspace.prototype = {
} }
} }
// Track window changes
this._windowAddedId = this._metaWorkspace.connect('window-added',
Lang.bind(this, this._windowAdded));
this._windowRemovedId = this._metaWorkspace.connect('window-removed',
Lang.bind(this, this._windowRemoved));
this._removeButton = null; this._removeButton = null;
this._visible = false; this._visible = false;
@ -403,21 +413,18 @@ Workspace.prototype = {
this.leavingOverlay = false; this.leavingOverlay = false;
}, },
// Checks if the workspace is empty (ie, contains only a desktop window)
isEmpty : function() {
return this._windows.length == 1;
},
// Change Workspace's removability. updateRemovable : function() {
setRemovable : function(removable, buttonSize) {
let global = Shell.Global.get(); let global = Shell.Global.get();
let removable = (this._windows.length == 1 /* just desktop */ &&
this.workspaceNum == global.screen.n_workspaces - 1);
if (removable) { if (removable) {
if (this._removeButton) if (this._removeButton)
return; return;
this._removeButton = new Clutter.Texture({ width: buttonSize, this._removeButton = new Clutter.Texture({ width: Workspaces.buttonSize,
height: buttonSize, height: Workspaces.buttonSize,
reactive: true reactive: true
}); });
this._removeButton.set_from_file(global.imagedir + "remove-workspace.svg"); this._removeButton.set_from_file(global.imagedir + "remove-workspace.svg");
@ -539,39 +546,74 @@ Workspace.prototype = {
} }
}, },
// Remove a window from the workspace - this is called to fix up the visual _windowRemoved : function(metaWorkspace, metaWin) {
// display for changes to the window state that have already been made let global = Shell.Global.get();
removeWindow : function(win) { let win = metaWin.get_compositor_private();
// find the position of the window in our list // find the position of the window in our list
let index = - 1; let index = - 1, clone;
for (let i = 0; i < this._windows.length; i++) { for (let i = 0; i < this._windows.length; i++) {
if (this._windows[i].realWindow == win) { if (this._windows[i].metaWindow == metaWin) {
index = i; index = i;
clone = this._windows[index];
break; break;
} }
} }
if (index == -1) if (index == -1)
return; return;
let clone = this._windows[index];
this._windows.splice(index, 1); this._windows.splice(index, 1);
// If metaWin.get_compositor_private() returned non-NULL, that
// means the window still exists (and is just being moved to
// another workspace or something), so set its overlayHint
// accordingly. (If it returned NULL, then the window is being
// destroyed; we'd like to animate this, but it's too late at
// this point.)
if (win) {
let [stageX, stageY] = clone.actor.get_transformed_position();
let [stageWidth, stageHeight] = clone.actor.get_transformed_size();
win._overlayHint = {
x: stageX,
y: stageY,
scale: stageWidth / clone.actor.width
};
}
clone.destroy(); clone.destroy();
this._positionWindows(); this._positionWindows();
this.updateRemovable();
}, },
// Add a window from the workspace - this is called to fix up the visual _windowAdded : function(metaWorkspace, metaWin) {
// display for changes to the window state that have already been made. let win = metaWin.get_compositor_private();
// x/y/scale are used to give an initial position for the window (if the
// window was dropped on the workspace, say) - the window will then be if (!win) {
// animated to the final location. // Newly-created windows are added to a workspace before
addWindow : function(win, x, y, scale) { // the compositor finds out about them...
Mainloop.idle_add(Lang.bind(this,
function () {
if (metaWin.get_compositor_private())
this._windowAdded(metaWorkspace, metaWin);
return false;
}));
return;
}
let clone = this._addWindowClone(win); let clone = this._addWindowClone(win);
if (win._overlayHint) {
let x = (win._overlayHint.x - this.actor.x) / this.scale;
let y = (win._overlayHint.y - this.actor.y) / this.scale;
let scale = win._overlayHint.scale / this.scale;
delete win._overlayHint;
clone.actor.set_position (x, y); clone.actor.set_position (x, y);
clone.actor.set_scale (scale, scale); clone.actor.set_scale (scale, scale);
}
this._positionWindows(); this._positionWindows();
this.updateRemovable();
}, },
// Animate the full-screen to overlay transition. // Animate the full-screen to overlay transition.
@ -693,8 +735,13 @@ Workspace.prototype = {
}, },
destroy : function() { destroy : function() {
let global = Shell.Global.get();
this.actor.destroy(); this.actor.destroy();
this.actor = null; this.actor = null;
this._metaWorkspace.disconnect(this._windowAddedId);
this._metaWorkspace.disconnect(this._windowRemovedId);
}, },
// Tests if @win belongs to this workspaces // Tests if @win belongs to this workspaces
@ -756,14 +803,13 @@ Workspace.prototype = {
_onCloneSelected : function (clone, time) { _onCloneSelected : function (clone, time) {
let global = Shell.Global.get(); let global = Shell.Global.get();
let activeWorkspace = global.screen.get_active_workspace_index(); let activeWorkspace = global.screen.get_active_workspace_index();
let w = clone.realWindow; let windowWorkspace = clone.realWindow.get_workspace();
let windowWorkspace = w.get_workspace();
if (windowWorkspace != activeWorkspace) { if (windowWorkspace != activeWorkspace) {
let workspace = global.screen.get_workspace_by_index(windowWorkspace); let workspace = global.screen.get_workspace_by_index(windowWorkspace);
workspace.activate_with_focus(w.get_meta_window(), time); workspace.activate_with_focus(clone.metaWindow, time);
} else } else
w.get_meta_window().activate(time); clone.metaWindow.activate(time);
Main.hide_overlay(); Main.hide_overlay();
}, },
@ -838,14 +884,16 @@ Workspaces.prototype = {
}); });
// Create (+) and (-) buttons // Create (+) and (-) buttons
this._buttonSize = Math.floor(this._bottomHeight * 3/5); // FIXME: figure out a better way to communicate buttonSize
this._plusX = this._x + this._width - this._buttonSize; // to the Workspace
Workspaces.buttonSize = Math.floor(this._bottomHeight * 3/5);
this._plusX = this._x + this._width - Workspaces.buttonSize;
this._plusY = screenHeight - Math.floor(this._bottomHeight * 4/5); this._plusY = screenHeight - Math.floor(this._bottomHeight * 4/5);
let plus = new Clutter.Texture({ x: this._plusX, let plus = new Clutter.Texture({ x: this._plusX,
y: this._plusY, y: this._plusY,
width: this._buttonSize, width: Workspaces.buttonSize,
height: this._buttonSize, height: Workspaces.buttonSize,
reactive: true reactive: true
}); });
plus.set_from_file(global.imagedir + "add-workspace.svg"); plus.set_from_file(global.imagedir + "add-workspace.svg");
@ -854,8 +902,7 @@ Workspaces.prototype = {
plus.lower_bottom(); plus.lower_bottom();
let lastWorkspace = this._workspaces[this._workspaces.length - 1]; let lastWorkspace = this._workspaces[this._workspaces.length - 1];
if (lastWorkspace.isEmpty()) lastWorkspace.updateRemovable(true);
lastWorkspace.setRemovable(true, this._buttonSize);
// Position/scale the desktop windows and their children // Position/scale the desktop windows and their children
for (let w = 0; w < this._workspaces.length; w++) for (let w = 0; w < this._workspaces.length; w++)
@ -1039,7 +1086,7 @@ Workspaces.prototype = {
let lostWorkspaces = []; let lostWorkspaces = [];
// The old last workspace is no longer removable. // The old last workspace is no longer removable.
this._workspaces[oldNumWorkspaces - 1].setRemovable(false); this._workspaces[oldNumWorkspaces - 1].updateRemovable();
if (newNumWorkspaces > oldNumWorkspaces) { if (newNumWorkspaces > oldNumWorkspaces) {
// Create new workspace groups // Create new workspace groups
@ -1056,8 +1103,7 @@ Workspaces.prototype = {
// The new last workspace may be removable // The new last workspace may be removable
let newLastWorkspace = this._workspaces[this._workspaces.length - 1]; let newLastWorkspace = this._workspaces[this._workspaces.length - 1];
if (newLastWorkspace.isEmpty()) newLastWorkspace.updateRemovable();
newLastWorkspace.setRemovable(true, this._buttonSize);
// Figure out the new layout // Figure out the new layout
this._positionWorkspaces(global); this._positionWorkspaces(global);
@ -1080,6 +1126,7 @@ Workspaces.prototype = {
// Slide old workspaces out // Slide old workspaces out
for (let w = 0; w < lostWorkspaces.length; w++) { for (let w = 0; w < lostWorkspaces.length; w++) {
let workspace = lostWorkspaces[w]; let workspace = lostWorkspaces[w];
workspace.actor.raise(this._backdrop);
workspace.slideOut(function () { workspace.destroy(); }); workspace.slideOut(function () { workspace.destroy(); });
} }
@ -1135,17 +1182,17 @@ Workspaces.prototype = {
if (targetWorkspace == null || targetWorkspace == sourceWorkspace) if (targetWorkspace == null || targetWorkspace == sourceWorkspace)
return; return;
// Window position and scale relative to the new workspace // Set a hint on the Mutter.Window so its initial position in the
targetX = (windowX - myX - targetWorkspace.gridX) / targetWorkspace.scale; // overlay will be correct
targetY = (windowY - myY - targetWorkspace.gridY) / targetWorkspace.scale; clone.realWindow._overlayHint = {
targetScale = clone.actor.scale_x / targetWorkspace.scale; x: clone.actor.x,
y: clone.actor.y,
scale: clone.actor.scale_x
};
let metaWindow = clone.realWindow.get_meta_window(); clone.metaWindow.change_workspace_by_index(targetWorkspace.workspaceNum,
metaWindow.change_workspace_by_index(targetWorkspace.workspaceNum,
false, // don't create workspace false, // don't create workspace
time); time);
sourceWorkspace.removeWindow(clone.realWindow);
targetWorkspace.addWindow(clone.realWindow, targetX, targetY, targetScale);
} }
}; };