Add workspace thumbnails to the overview

Add workspace thumbnails to the workspace controls area. The user can
click on the thumbnail to switch workspaces and can also drag windows
out of the thumbnail to other workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
This commit is contained in:
Owen W. Taylor
2011-01-30 21:18:12 -05:00
parent eda12542c0
commit 6514bc845f
4 changed files with 399 additions and 4 deletions

View File

@ -14,6 +14,7 @@ const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
const WORKSPACE_SWITCH_TIME = 0.25;
// Note that mutter has a compile-time limit of 36
@ -725,6 +726,25 @@ WorkspacesDisplay.prototype = {
}));
controls.add(this._removeButton);
this._thumbnailsBox = new St.BoxLayout({ vertical: true,
style_class: 'workspace-thumbnails' });
controls.add(this._thumbnailsBox, { expand: false });
let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator',
fixed_position_set: true });
// We don't want the indicator to affect drag-and-drop
Shell.util_set_hidden_from_pick(indicator, true);
this._thumbnailIndicator = indicator;
this._thumbnailsBox.add(this._thumbnailIndicator);
this._thumbnailIndicatorConstraints = [];
this._thumbnailIndicatorConstraints.push(new Clutter.BindConstraint({ coordinate: Clutter.BindCoordinate.POSITION }));
this._thumbnailIndicatorConstraints.push(new Clutter.BindConstraint({ coordinate: Clutter.BindCoordinate.SIZE }));
this._thumbnailIndicatorConstraints.forEach(function(constraint) {
indicator.add_constraint(constraint);
});
this._addButton = new St.Button({ label: '+',
style_class: 'add-workspace' });
this._addButton.connect('clicked', Lang.bind(this, function() {
@ -759,11 +779,22 @@ WorkspacesDisplay.prototype = {
this._controls.show();
this._workspaces = [];
this._workspaceThumbnails = [];
for (let i = 0; i < global.screen.n_workspaces; i++) {
let metaWorkspace = global.screen.get_workspace_by_index(i);
this._workspaces[i] = new Workspace.Workspace(metaWorkspace);
let thumbnail = new WorkspaceThumbnail.WorkspaceThumbnail(metaWorkspace);
this._workspaceThumbnails[i] = thumbnail;
this._thumbnailsBox.add(thumbnail.actor);
}
// The thumbnails indicator actually needs to be on top of the thumbnails, but
// there is also something more subtle going on as well - actors in a StBoxLayout
// are allocated from bottom to top (start to end), and we need the
// thumnail indicator to be allocated after the actors it is constrained to.
this._thumbnailIndicator.raise_top();
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
let totalAllocation = this.actor.allocation;
@ -810,6 +841,9 @@ WorkspacesDisplay.prototype = {
this._nWorkspacesNotifyId =
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace',
Lang.bind(this, this._activeWorkspaceChanged));
this._restackedNotifyId =
global.screen.connect('restacked',
@ -829,6 +863,9 @@ WorkspacesDisplay.prototype = {
Lang.bind(this, this._dragEnd));
this._onRestacked();
this._constrainThumbnailIndicator();
this._zoomOut = false;
this._updateZoom();
},
hide: function() {
@ -838,6 +875,10 @@ WorkspacesDisplay.prototype = {
global.screen.disconnect(this._nWorkspacesNotifyId);
this._nWorkspacesNotifyId = 0;
}
if (this._switchWorkspaceNotifyId > 0) {
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._switchWorkspaceNotifyId = 0;
}
if (this._restackedNotifyId > 0){
global.screen.disconnect(this._restackedNotifyId);
this._restackedNotifyId = 0;
@ -861,12 +902,51 @@ WorkspacesDisplay.prototype = {
this.workspacesView.destroy();
this.workspacesView = null;
this._unconstrainThumbnailIndicator();
for (let w = 0; w < this._workspaces.length; w++) {
this._workspaces[w].disconnectAll();
this._workspaces[w].destroy();
this._workspaceThumbnails[w].destroy();
}
},
_constrainThumbnailIndicator: function() {
let active = global.screen.get_active_workspace_index();
let thumbnail = this._workspaceThumbnails[active];
this._thumbnailIndicatorConstraints.forEach(function(constraint) {
constraint.set_source(thumbnail.actor);
constraint.set_enabled(true);
});
},
_unconstrainThumbnailIndicator: function() {
this._thumbnailIndicatorConstraints.forEach(function(constraint) {
constraint.set_enabled(false);
});
},
_activeWorkspaceChanged: function(wm, from, to, direction) {
let active = global.screen.get_active_workspace_index();
let thumbnail = this._workspaceThumbnails[active];
this._unconstrainThumbnailIndicator();
let oldAllocation = this._thumbnailIndicator.allocation;
this._thumbnailIndicator.x = oldAllocation.x1;
this._thumbnailIndicator.y = oldAllocation.y1;
this._thumbnailIndicator.width = oldAllocation.x2 - oldAllocation.x1;
this._thumbnailIndicator.height = oldAllocation.y2 - oldAllocation.y1;
Tweener.addTween(this._thumbnailIndicator,
{ x: thumbnail.actor.allocation.x1,
y: thumbnail.actor.allocation.y1,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
this._constrainThumbnailIndicator)
});
},
_onRestacked: function() {
let stack = global.get_window_actors();
let stackIndices = {};
@ -877,6 +957,8 @@ WorkspacesDisplay.prototype = {
}
this.workspacesView.syncStacking(stackIndices);
for (let i = 0; i < this._workspaceThumbnails.length; i++)
this._workspaceThumbnails[i].syncStacking(stackIndices);
},
_workspacesChanged: function() {
@ -893,7 +975,12 @@ WorkspacesDisplay.prototype = {
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
this._workspaces[w] = new Workspace.Workspace(metaWorkspace);
let thumbnail = new WorkspaceThumbnail.WorkspaceThumbnail(metaWorkspace);
this._workspaceThumbnails[w] = thumbnail;
this._thumbnailsBox.add(thumbnail.actor);
}
this._thumbnailIndicator.raise_top();
} else {
// Assume workspaces are only removed sequentially
// (e.g. 2,3,4 - not 2,4,7)
@ -914,6 +1001,10 @@ WorkspacesDisplay.prototype = {
// making its exit.
for (let l = 0; l < lostWorkspaces.length; l++)
lostWorkspaces[l].setReactive(false);
for (let k = removedIndex; k < removedIndex + removedNum; k++)
this._workspaceThumbnails[k].destroy();
this._workspaceThumbnails.splice(removedIndex, removedNum);
}
this.workspacesView.updateWorkspaces(oldNumWorkspaces,