Track window adds/removes in the overlay. #568983
svn path=/trunk/; revision=180
This commit is contained in:
parent
e9826ecb45
commit
4850ea608f
@ -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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user