2010-01-22 02:33:48 +00:00
|
|
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
|
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
|
|
const Lang = imports.lang;
|
|
|
|
const Mainloop = imports.mainloop;
|
2011-01-30 21:38:13 +00:00
|
|
|
const Meta = imports.gi.Meta;
|
2010-01-22 02:33:48 +00:00
|
|
|
const Shell = imports.gi.Shell;
|
|
|
|
const St = imports.gi.St;
|
|
|
|
const Signals = imports.signals;
|
2010-05-13 18:29:00 +00:00
|
|
|
const Gettext = imports.gettext.domain('gnome-shell');
|
|
|
|
const _ = Gettext.gettext;
|
2010-01-22 02:33:48 +00:00
|
|
|
|
|
|
|
const DND = imports.ui.dnd;
|
|
|
|
const Main = imports.ui.main;
|
|
|
|
const Overview = imports.ui.overview;
|
|
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
const Workspace = imports.ui.workspace;
|
2011-01-31 02:18:12 +00:00
|
|
|
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
2010-01-22 02:33:48 +00:00
|
|
|
|
|
|
|
const WORKSPACE_SWITCH_TIME = 0.25;
|
|
|
|
// Note that mutter has a compile-time limit of 36
|
|
|
|
const MAX_WORKSPACES = 16;
|
|
|
|
|
2010-03-16 15:51:24 +00:00
|
|
|
|
2010-10-04 14:42:11 +00:00
|
|
|
const CONTROLS_POP_IN_FRACTION = 0.8;
|
|
|
|
const CONTROLS_POP_IN_TIME = 0.1;
|
2010-11-12 09:28:28 +00:00
|
|
|
|
|
|
|
|
2011-01-31 01:35:58 +00:00
|
|
|
function WorkspacesView(width, height, x, y, zoomScale, workspaces) {
|
|
|
|
this._init(width, height, x, y, zoomScale, workspaces);
|
2010-01-22 02:33:48 +00:00
|
|
|
}
|
|
|
|
|
2010-11-12 09:28:28 +00:00
|
|
|
WorkspacesView.prototype = {
|
2011-01-31 01:35:58 +00:00
|
|
|
_init: function(width, height, x, y, zoomScale, workspaces) {
|
2010-11-12 09:28:28 +00:00
|
|
|
this.actor = new St.Group({ style_class: 'workspaces-view' });
|
|
|
|
this.actor.set_clip(x, y, width, height);
|
2010-01-22 02:33:48 +00:00
|
|
|
|
2011-01-31 01:35:58 +00:00
|
|
|
// The actor itself isn't a drop target, so we don't want to pick on its area
|
|
|
|
this.actor.set_size(0, 0);
|
|
|
|
|
2010-02-18 15:43:58 +00:00
|
|
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
|
|
|
2010-02-10 06:00:02 +00:00
|
|
|
this.actor.connect('style-changed', Lang.bind(this,
|
|
|
|
function() {
|
|
|
|
let node = this.actor.get_theme_node();
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 21:38:36 +00:00
|
|
|
this._spacing = node.get_length('spacing');
|
2010-11-12 09:28:28 +00:00
|
|
|
this._computeWorkspacePositions();
|
2010-02-10 06:00:02 +00:00
|
|
|
}));
|
2011-01-21 18:47:54 +00:00
|
|
|
this.actor.connect('notify::mapped',
|
|
|
|
Lang.bind(this, this._onMappedChanged));
|
2010-01-22 02:33:48 +00:00
|
|
|
|
|
|
|
this._width = width;
|
|
|
|
this._height = height;
|
|
|
|
this._x = x;
|
|
|
|
this._y = y;
|
2011-01-31 01:35:58 +00:00
|
|
|
this._zoomScale = zoomScale;
|
2010-02-10 06:00:02 +00:00
|
|
|
this._spacing = 0;
|
2010-11-12 09:28:28 +00:00
|
|
|
this._activeWorkspaceX = 0; // x offset of active ws while dragging
|
|
|
|
this._activeWorkspaceY = 0; // y offset of active ws while dragging
|
|
|
|
this._lostWorkspaces = [];
|
|
|
|
this._animating = false; // tweening
|
2011-01-21 18:47:54 +00:00
|
|
|
this._scrolling = false; // swipe-scrolling
|
2010-11-12 09:28:28 +00:00
|
|
|
this._animatingScroll = false; // programatically updating the adjustment
|
2011-01-31 01:35:58 +00:00
|
|
|
this._zoomOut = false; // zoom to a larger area
|
2010-11-12 09:28:28 +00:00
|
|
|
this._inDrag = false; // dragging a window
|
2010-01-22 02:33:48 +00:00
|
|
|
|
|
|
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
2010-02-14 23:32:57 +00:00
|
|
|
this._workspaces = workspaces;
|
2010-01-22 02:33:48 +00:00
|
|
|
|
2010-02-14 23:32:57 +00:00
|
|
|
// Add workspace actors
|
2010-11-15 20:58:27 +00:00
|
|
|
for (let w = 0; w < global.screen.n_workspaces; w++)
|
2010-03-22 00:39:49 +00:00
|
|
|
this._workspaces[w].actor.reparent(this.actor);
|
2010-01-22 02:33:48 +00:00
|
|
|
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
|
|
|
|
|
|
|
// Position/scale the desktop windows and their children after the
|
|
|
|
// workspaces have been created. This cannot be done first because
|
|
|
|
// window movement depends on the Workspaces object being accessible
|
|
|
|
// as an Overview member.
|
|
|
|
this._overviewShowingId =
|
|
|
|
Main.overview.connect('showing',
|
|
|
|
Lang.bind(this, function() {
|
|
|
|
for (let w = 0; w < this._workspaces.length; w++)
|
2010-02-14 23:32:57 +00:00
|
|
|
this._workspaces[w].zoomToOverview();
|
2010-01-22 02:33:48 +00:00
|
|
|
}));
|
|
|
|
|
2010-11-12 09:28:28 +00:00
|
|
|
this._scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
|
|
|
|
lower: 0,
|
|
|
|
page_increment: 1,
|
|
|
|
page_size: 1,
|
|
|
|
step_increment: 0,
|
|
|
|
upper: this._workspaces.length });
|
|
|
|
this._scrollAdjustment.connect('notify::value',
|
|
|
|
Lang.bind(this, this._onScroll));
|
|
|
|
|
|
|
|
this._timeoutId = 0;
|
|
|
|
|
|
|
|
this._windowSelectionAppId = null;
|
|
|
|
this._highlightWindow = null;
|
|
|
|
|
2010-01-22 02:33:48 +00:00
|
|
|
this._switchWorkspaceNotifyId =
|
|
|
|
global.window_manager.connect('switch-workspace',
|
|
|
|
Lang.bind(this, this._activeWorkspaceChanged));
|
2010-11-12 09:28:28 +00:00
|
|
|
|
|
|
|
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
|
|
|
|
Lang.bind(this, this._dragBegin));
|
|
|
|
this._itemDragEndId = Main.overview.connect('item-drag-end',
|
|
|
|
Lang.bind(this, this._dragEnd));
|
2010-11-15 20:58:27 +00:00
|
|
|
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
|
|
|
|
Lang.bind(this, this._dragBegin));
|
|
|
|
this._windowDragEndId = Main.overview.connect('window-drag-end',
|
|
|
|
Lang.bind(this, this._dragEnd));
|
2011-01-21 18:47:54 +00:00
|
|
|
this._swipeScrollBeginId = 0;
|
|
|
|
this._swipeScrollEndId = 0;
|
2010-01-22 02:33:48 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_lookupWorkspaceForMetaWindow: function (metaWindow) {
|
|
|
|
for (let i = 0; i < this._workspaces.length; i++) {
|
|
|
|
if (this._workspaces[i].containsMetaWindow(metaWindow))
|
|
|
|
return this._workspaces[i];
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
|
|
|
|
setHighlightWindow: function (metaWindow) {
|
|
|
|
// Looping over all workspaces is easier than keeping track of the last
|
|
|
|
// highlighted window while trying to handle the window or workspace possibly
|
|
|
|
// going away.
|
|
|
|
for (let i = 0; i < this._workspaces.length; i++) {
|
|
|
|
this._workspaces[i].setHighlightWindow(null);
|
|
|
|
}
|
|
|
|
if (metaWindow != null) {
|
|
|
|
let workspace = this._lookupWorkspaceForMetaWindow(metaWindow);
|
|
|
|
workspace.setHighlightWindow(metaWindow);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-07-15 14:21:32 +00:00
|
|
|
getActiveWorkspace: function() {
|
|
|
|
let active = global.screen.get_active_workspace_index();
|
|
|
|
return this._workspaces[active];
|
|
|
|
},
|
|
|
|
|
2010-01-22 02:33:48 +00:00
|
|
|
_clearApplicationWindowSelection: function(reposition) {
|
|
|
|
if (this._windowSelectionAppId == null)
|
|
|
|
return;
|
|
|
|
this._windowSelectionAppId = null;
|
|
|
|
|
|
|
|
for (let i = 0; i < this._workspaces.length; i++) {
|
|
|
|
this._workspaces[i].setLightboxMode(false);
|
|
|
|
this._workspaces[i].setShowOnlyWindows(null, reposition);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* setApplicationWindowSelection:
|
|
|
|
* @appid: Application identifier string
|
|
|
|
*
|
|
|
|
* Enter a mode which shows only the windows owned by the
|
|
|
|
* given application, and allow highlighting of a specific
|
|
|
|
* window with setHighlightWindow().
|
|
|
|
*/
|
|
|
|
setApplicationWindowSelection: function (appId) {
|
|
|
|
if (appId == null) {
|
|
|
|
this._clearApplicationWindowSelection(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (appId == this._windowSelectionAppId)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._windowSelectionAppId = appId;
|
|
|
|
|
|
|
|
let appSys = Shell.AppSystem.get_default();
|
|
|
|
|
|
|
|
let showOnlyWindows = {};
|
|
|
|
let app = appSys.get_app(appId);
|
|
|
|
let windows = app.get_windows();
|
|
|
|
for (let i = 0; i < windows.length; i++) {
|
|
|
|
showOnlyWindows[windows[i]] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < this._workspaces.length; i++) {
|
|
|
|
this._workspaces[i].setLightboxMode(true);
|
|
|
|
this._workspaces[i].setShowOnlyWindows(showOnlyWindows, true);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
hide: function() {
|
|
|
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
|
|
|
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
|
|
|
|
2010-02-17 19:05:06 +00:00
|
|
|
if (this._windowSelectionAppId != null)
|
|
|
|
this._clearApplicationWindowSelection(false);
|
|
|
|
|
2010-01-22 02:33:48 +00:00
|
|
|
activeWorkspace.actor.raise_top();
|
|
|
|
|
|
|
|
for (let w = 0; w < this._workspaces.length; w++)
|
|
|
|
this._workspaces[w].zoomFromOverview();
|
|
|
|
},
|
|
|
|
|
|
|
|
destroy: function() {
|
2010-02-18 15:43:58 +00:00
|
|
|
this.actor.destroy();
|
|
|
|
},
|
|
|
|
|
2010-01-22 02:33:48 +00:00
|
|
|
getScale: function() {
|
|
|
|
return this._workspaces[0].scale;
|
|
|
|
},
|
|
|
|
|
2011-01-31 01:44:05 +00:00
|
|
|
syncStacking: function(stackIndices) {
|
2010-01-22 02:33:48 +00:00
|
|
|
for (let i = 0; i < this._workspaces.length; i++)
|
|
|
|
this._workspaces[i].syncStacking(stackIndices);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Get the grid position of the active workspace.
|
|
|
|
getActiveWorkspacePosition: function() {
|
|
|
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
|
|
|
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
|
|
|
|
2010-11-12 09:28:28 +00:00
|
|
|
return [activeWorkspace.x, activeWorkspace.y];
|
2010-01-23 11:24:49 +00:00
|
|
|
},
|
|
|
|
|
2011-01-31 01:35:58 +00:00
|
|
|
zoomOut: function() {
|
|
|
|
if (this._zoomOut)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._zoomOut = true;
|
|
|
|
this._computeWorkspacePositions();
|
|
|
|
this._updateWorkspaceActors(true);
|
|
|
|
},
|
|
|
|
|
|
|
|
zoomIn: function() {
|
|
|
|
if (!this._zoomOut)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._zoomOut = false;
|
|
|
|
this._computeWorkspacePositions();
|
|
|
|
this._updateWorkspaceActors(true);
|
|
|
|
},
|
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
// Compute the position, scale and opacity of the workspaces, but don't
|
|
|
|
// actually change the actors to match
|
|
|
|
_computeWorkspacePositions: function() {
|
|
|
|
let active = global.screen.get_active_workspace_index();
|
2011-01-31 01:35:58 +00:00
|
|
|
let zoomScale = this._zoomOut ? this._zoomScale : 1;
|
|
|
|
let scale = zoomScale * this._width / global.screen_width;
|
2010-01-22 02:33:48 +00:00
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
let _width = this._workspaces[0].actor.width * scale;
|
|
|
|
let _height = this._workspaces[0].actor.height * scale;
|
|
|
|
|
|
|
|
this._activeWorkspaceX = (this._width - _width) / 2;
|
|
|
|
this._activeWorkspaceY = (this._height - _height) / 2;
|
|
|
|
|
2010-01-22 02:33:48 +00:00
|
|
|
for (let w = 0; w < this._workspaces.length; w++) {
|
|
|
|
let workspace = this._workspaces[w];
|
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
workspace.opacity = (this._inDrag && w != active) ? 200 : 255;
|
2010-03-16 15:51:24 +00:00
|
|
|
|
2010-01-22 02:33:48 +00:00
|
|
|
workspace.scale = scale;
|
2011-01-30 23:21:31 +00:00
|
|
|
workspace.x = this._x + this._activeWorkspaceX;
|
2011-01-31 01:35:58 +00:00
|
|
|
|
|
|
|
// We adjust the center because the zoomScale is to leave space for
|
|
|
|
// the expanded workspace control so we want to zoom to either the
|
|
|
|
// left part of the area or the right part of the area
|
|
|
|
let offset = 0.5 * (1 - this._zoomScale) * this._width;
|
|
|
|
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
|
|
|
if (this._zoomOut)
|
|
|
|
workspace.x += rtl ? offset : - offset;
|
|
|
|
|
|
|
|
// We divide by zoomScale so that adjacent workspaces are always offscreen
|
|
|
|
// except when we are switching between workspaces
|
2011-01-30 23:21:31 +00:00
|
|
|
workspace.y = this._y + this._activeWorkspaceY
|
2011-01-31 01:35:58 +00:00
|
|
|
+ (w - active) * (_height + this._spacing) / zoomScale;
|
2010-02-15 13:29:34 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-02-10 05:56:36 +00:00
|
|
|
_scrollToActive: function(showAnimation) {
|
|
|
|
let active = global.screen.get_active_workspace_index();
|
|
|
|
|
2010-06-08 00:43:32 +00:00
|
|
|
this._computeWorkspacePositions();
|
2010-03-16 15:51:24 +00:00
|
|
|
this._updateWorkspaceActors(showAnimation);
|
2010-07-11 12:41:17 +00:00
|
|
|
this._updateScrollAdjustment(active, showAnimation);
|
2010-02-10 05:56:36 +00:00
|
|
|
},
|
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
// Update workspace actors parameters to the values calculated in
|
|
|
|
// _computeWorkspacePositions()
|
|
|
|
// @showAnimation: iff %true, transition between states
|
2010-03-16 15:51:24 +00:00
|
|
|
_updateWorkspaceActors: function(showAnimation) {
|
2010-02-10 05:56:36 +00:00
|
|
|
let active = global.screen.get_active_workspace_index();
|
2011-01-30 23:21:31 +00:00
|
|
|
let targetWorkspaceNewY = this._y + this._activeWorkspaceY;
|
|
|
|
let targetWorkspaceCurrentY = this._workspaces[active].y;
|
|
|
|
let dy = targetWorkspaceNewY - targetWorkspaceCurrentY;
|
2010-02-10 05:56:36 +00:00
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
this._animating = showAnimation;
|
|
|
|
|
2010-02-10 05:56:36 +00:00
|
|
|
for (let w = 0; w < this._workspaces.length; w++) {
|
|
|
|
let workspace = this._workspaces[w];
|
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
Tweener.removeTweens(workspace.actor);
|
|
|
|
|
2011-01-30 23:21:31 +00:00
|
|
|
workspace.y += dy;
|
2010-02-10 05:56:36 +00:00
|
|
|
|
|
|
|
if (showAnimation) {
|
2010-11-12 09:28:28 +00:00
|
|
|
let params = { x: workspace.x,
|
|
|
|
y: workspace.y,
|
2010-10-04 18:04:23 +00:00
|
|
|
scale_x: workspace.scale,
|
|
|
|
scale_y: workspace.scale,
|
|
|
|
opacity: workspace.opacity,
|
|
|
|
time: WORKSPACE_SWITCH_TIME,
|
|
|
|
transition: 'easeOutQuad'
|
|
|
|
};
|
|
|
|
// we have to call _updateVisibility() once before the
|
|
|
|
// animation and once afterwards - it does not really
|
|
|
|
// matter which tween we use, so we pick the first one ...
|
|
|
|
if (w == 0) {
|
|
|
|
this._updateVisibility();
|
|
|
|
params.onComplete = Lang.bind(this,
|
|
|
|
function() {
|
|
|
|
this._animating = false;
|
|
|
|
this._updateVisibility();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Tweener.addTween(workspace.actor, params);
|
2010-01-22 02:33:48 +00:00
|
|
|
} else {
|
2010-03-16 15:51:24 +00:00
|
|
|
workspace.actor.set_scale(workspace.scale, workspace.scale);
|
2010-11-12 09:28:28 +00:00
|
|
|
workspace.actor.set_position(workspace.x, workspace.y);
|
2010-03-16 15:51:24 +00:00
|
|
|
workspace.actor.opacity = workspace.opacity;
|
2010-10-04 18:04:23 +00:00
|
|
|
if (w == 0)
|
|
|
|
this._updateVisibility();
|
2010-01-22 02:33:48 +00:00
|
|
|
}
|
2010-03-16 15:51:24 +00:00
|
|
|
}
|
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
for (let l = 0; l < this._lostWorkspaces.length; l++) {
|
|
|
|
let workspace = this._lostWorkspaces[l];
|
2010-03-16 15:51:24 +00:00
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
Tweener.removeTweens(workspace.actor);
|
2010-03-16 15:51:24 +00:00
|
|
|
|
2011-01-30 23:21:31 +00:00
|
|
|
workspace.y += dy;
|
2010-03-22 23:01:44 +00:00
|
|
|
workspace.actor.show();
|
|
|
|
workspace.hideWindowsOverlays();
|
|
|
|
|
|
|
|
if (showAnimation) {
|
|
|
|
Tweener.addTween(workspace.actor,
|
2011-01-30 23:21:31 +00:00
|
|
|
{ y: workspace.x,
|
2010-03-22 23:01:44 +00:00
|
|
|
time: WORKSPACE_SWITCH_TIME,
|
|
|
|
transition: 'easeOutQuad',
|
|
|
|
onComplete: Lang.bind(this,
|
|
|
|
this._cleanWorkspaces)
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this._cleanWorkspaces();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2010-02-11 14:52:49 +00:00
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
_updateVisibility: function() {
|
|
|
|
let active = global.screen.get_active_workspace_index();
|
2010-02-11 14:52:49 +00:00
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
for (let w = 0; w < this._workspaces.length; w++) {
|
|
|
|
let workspace = this._workspaces[w];
|
|
|
|
if (this._animating || this._scrolling) {
|
|
|
|
workspace.hideWindowsOverlays();
|
|
|
|
workspace.actor.show();
|
2010-02-11 14:52:49 +00:00
|
|
|
} else {
|
2010-03-22 23:01:44 +00:00
|
|
|
workspace.showWindowsOverlays();
|
|
|
|
if (this._inDrag)
|
|
|
|
workspace.actor.visible = (Math.abs(w - active) <= 1);
|
|
|
|
else
|
|
|
|
workspace.actor.visible = (w == active);
|
2010-02-11 14:52:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_cleanWorkspaces: function() {
|
|
|
|
if (this._lostWorkspaces.length == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (let l = 0; l < this._lostWorkspaces.length; l++)
|
|
|
|
this._lostWorkspaces[l].destroy();
|
|
|
|
this._lostWorkspaces = [];
|
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
this._computeWorkspacePositions();
|
|
|
|
this._updateWorkspaceActors(false);
|
2010-01-22 02:33:48 +00:00
|
|
|
},
|
|
|
|
|
2010-07-11 12:41:17 +00:00
|
|
|
_updateScrollAdjustment: function(index, showAnimation) {
|
|
|
|
if (this._scrolling)
|
2010-02-10 05:56:36 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
this._animatingScroll = true;
|
|
|
|
|
|
|
|
if (showAnimation) {
|
2010-07-11 12:41:17 +00:00
|
|
|
Tweener.addTween(this._scrollAdjustment, {
|
2010-02-10 05:56:36 +00:00
|
|
|
value: index,
|
|
|
|
time: WORKSPACE_SWITCH_TIME,
|
|
|
|
transition: 'easeOutQuad',
|
|
|
|
onComplete: Lang.bind(this,
|
|
|
|
function() {
|
|
|
|
this._animatingScroll = false;
|
|
|
|
})
|
|
|
|
});
|
|
|
|
} else {
|
2010-07-11 12:41:17 +00:00
|
|
|
this._scrollAdjustment.value = index;
|
2010-02-10 05:56:36 +00:00
|
|
|
this._animatingScroll = false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-02-14 23:32:57 +00:00
|
|
|
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces, lostWorkspaces) {
|
2010-05-19 17:26:41 +00:00
|
|
|
let active = global.screen.get_active_workspace_index();
|
2010-01-22 02:33:48 +00:00
|
|
|
|
2010-03-22 19:52:50 +00:00
|
|
|
for (let l = 0; l < lostWorkspaces.length; l++)
|
|
|
|
lostWorkspaces[l].disconnectAll();
|
|
|
|
|
2010-07-11 12:41:17 +00:00
|
|
|
Tweener.addTween(this._scrollAdjustment,
|
|
|
|
{ upper: newNumWorkspaces,
|
|
|
|
time: WORKSPACE_SWITCH_TIME,
|
|
|
|
transition: 'easeOutQuad'
|
|
|
|
});
|
2010-01-22 02:33:48 +00:00
|
|
|
|
|
|
|
if (newNumWorkspaces > oldNumWorkspaces) {
|
2010-11-15 20:58:27 +00:00
|
|
|
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++)
|
2010-03-22 00:39:49 +00:00
|
|
|
this.actor.add_actor(this._workspaces[w].actor);
|
2010-02-14 23:32:57 +00:00
|
|
|
|
2010-03-22 23:01:44 +00:00
|
|
|
this._computeWorkspacePositions();
|
|
|
|
this._updateWorkspaceActors(false);
|
2010-01-22 02:33:48 +00:00
|
|
|
} else {
|
2010-02-14 23:32:57 +00:00
|
|
|
this._lostWorkspaces = lostWorkspaces;
|
2010-01-22 02:33:48 +00:00
|
|
|
}
|
|
|
|
|
2010-05-08 21:45:09 +00:00
|
|
|
this._scrollToActive(true);
|
2010-01-22 02:33:48 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_activeWorkspaceChanged: function(wm, from, to, direction) {
|
2010-02-10 05:56:36 +00:00
|
|
|
if (this._scrolling)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._scrollToActive(true);
|
2010-01-22 02:33:48 +00:00
|
|
|
},
|
|
|
|
|
2010-03-16 15:51:24 +00:00
|
|
|
_onDestroy: function() {
|
2011-01-28 02:41:57 +00:00
|
|
|
this._scrollAdjustment.run_dispose();
|
2010-11-12 09:28:28 +00:00
|
|
|
Main.overview.disconnect(this._overviewShowingId);
|
|
|
|
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
|
|
|
|
2010-03-16 15:51:24 +00:00
|
|
|
if (this._timeoutId) {
|
|
|
|
Mainloop.source_remove(this._timeoutId);
|
|
|
|
this._timeoutId = 0;
|
|
|
|
}
|
2010-05-08 14:06:28 +00:00
|
|
|
if (this._itemDragBeginId > 0) {
|
|
|
|
Main.overview.disconnect(this._itemDragBeginId);
|
|
|
|
this._itemDragBeginId = 0;
|
|
|
|
}
|
|
|
|
if (this._itemDragEndId > 0) {
|
|
|
|
Main.overview.disconnect(this._itemDragEndId);
|
|
|
|
this._itemDragEndId = 0;
|
|
|
|
}
|
2010-11-15 20:58:27 +00:00
|
|
|
if (this._windowDragBeginId > 0) {
|
|
|
|
Main.overview.disconnect(this._windowDragBeginId);
|
|
|
|
this._windowDragBeginId = 0;
|
|
|
|
}
|
|
|
|
if (this._windowDragEndId > 0) {
|
|
|
|
Main.overview.disconnect(this._windowDragEndId);
|
|
|
|
this._windowDragEndId = 0;
|
2010-03-22 19:52:50 +00:00
|
|
|
}
|
2010-03-16 15:51:24 +00:00
|
|
|
},
|
|
|
|
|
2011-01-21 18:47:54 +00:00
|
|
|
_onMappedChanged: function() {
|
|
|
|
if (this.actor.mapped) {
|
2011-01-30 23:21:31 +00:00
|
|
|
let direction = Overview.SwipeScrollDirection.VERTICAL;
|
2011-01-21 18:47:54 +00:00
|
|
|
Main.overview.setScrollAdjustment(this._scrollAdjustment,
|
|
|
|
direction);
|
|
|
|
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
|
|
|
|
Lang.bind(this, this._swipeScrollBegin));
|
|
|
|
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
|
|
|
|
Lang.bind(this, this._swipeScrollEnd));
|
|
|
|
} else {
|
|
|
|
Main.overview.disconnect(this._swipeScrollBeginId);
|
|
|
|
Main.overview.disconnect(this._swipeScrollEndId);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-05-08 14:06:28 +00:00
|
|
|
_dragBegin: function() {
|
2010-07-11 12:41:17 +00:00
|
|
|
if (this._scrolling)
|
2010-03-16 15:51:24 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
this._inDrag = true;
|
|
|
|
|
2010-06-06 15:24:51 +00:00
|
|
|
this._dragMonitor = {
|
|
|
|
dragMotion: Lang.bind(this, this._onDragMotion)
|
|
|
|
};
|
|
|
|
DND.addDragMonitor(this._dragMonitor);
|
2010-03-16 15:51:24 +00:00
|
|
|
},
|
|
|
|
|
2010-06-06 15:24:51 +00:00
|
|
|
_onDragMotion: function(dragEvent) {
|
2011-01-05 14:47:27 +00:00
|
|
|
if (Main.overview.animationInProgress)
|
|
|
|
return DND.DragMotionResult.CONTINUE;
|
|
|
|
|
2010-06-02 16:38:31 +00:00
|
|
|
let primary = global.get_primary_monitor();
|
|
|
|
|
2010-06-06 15:24:51 +00:00
|
|
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
2011-01-30 23:21:31 +00:00
|
|
|
let topWorkspace, bottomWorkspace;
|
|
|
|
topWorkspace = this._workspaces[activeWorkspaceIndex - 1];
|
|
|
|
bottomWorkspace = this._workspaces[activeWorkspaceIndex + 1];
|
2010-06-06 15:24:51 +00:00
|
|
|
let hoverWorkspace = null;
|
|
|
|
|
|
|
|
// reactive monitor edges
|
2011-01-30 23:21:31 +00:00
|
|
|
let topEdge = primary.y;
|
|
|
|
let switchTop = (dragEvent.y <= topEdge && topWorkspace);
|
|
|
|
if (switchTop && this._dragOverLastY != topEdge) {
|
|
|
|
topWorkspace.metaWorkspace.activate(global.get_current_time());
|
|
|
|
topWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
|
|
|
|
this._dragOverLastY = topEdge;
|
2010-06-06 15:24:51 +00:00
|
|
|
|
2010-09-10 02:00:28 +00:00
|
|
|
return DND.DragMotionResult.CONTINUE;
|
2010-03-16 15:51:24 +00:00
|
|
|
}
|
2011-01-30 23:21:31 +00:00
|
|
|
let bottomEdge = primary.y + primary.height - 1;
|
|
|
|
let switchBottom = (dragEvent.y >= bottomEdge && bottomWorkspace);
|
|
|
|
if (switchBottom && this._dragOverLastY != bottomEdge) {
|
|
|
|
bottomWorkspace.metaWorkspace.activate(global.get_current_time());
|
|
|
|
bottomWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
|
|
|
|
this._dragOverLastY = bottomEdge;
|
2010-06-06 15:24:51 +00:00
|
|
|
|
2010-09-10 02:00:28 +00:00
|
|
|
return DND.DragMotionResult.CONTINUE;
|
2010-03-16 15:51:24 +00:00
|
|
|
}
|
2011-01-30 23:21:31 +00:00
|
|
|
this._dragOverLastY = dragEvent.y;
|
2010-09-10 02:00:28 +00:00
|
|
|
let result = DND.DragMotionResult.CONTINUE;
|
2010-03-16 15:51:24 +00:00
|
|
|
|
2010-06-06 15:24:51 +00:00
|
|
|
// check hover state of new workspace area / inactive workspaces
|
2011-01-30 23:21:31 +00:00
|
|
|
if (topWorkspace) {
|
|
|
|
if (topWorkspace.actor.contains(dragEvent.targetActor)) {
|
|
|
|
hoverWorkspace = topWorkspace;
|
|
|
|
topWorkspace.opacity = topWorkspace.actor.opacity = 255;
|
|
|
|
result = topWorkspace.handleDragOver(dragEvent.source, dragEvent.dragActor);
|
2010-06-06 15:24:51 +00:00
|
|
|
} else {
|
2011-01-30 23:21:31 +00:00
|
|
|
topWorkspace.opacity = topWorkspace.actor.opacity = 200;
|
2010-06-06 15:24:51 +00:00
|
|
|
}
|
2010-03-16 15:51:24 +00:00
|
|
|
}
|
|
|
|
|
2011-01-30 23:21:31 +00:00
|
|
|
if (bottomWorkspace) {
|
|
|
|
if (bottomWorkspace.actor.contains(dragEvent.targetActor)) {
|
|
|
|
hoverWorkspace = bottomWorkspace;
|
|
|
|
bottomWorkspace.opacity = bottomWorkspace.actor.opacity = 255;
|
|
|
|
result = bottomWorkspace.handleDragOver(dragEvent.source, dragEvent.dragActor);
|
2010-06-06 15:24:51 +00:00
|
|
|
} else {
|
2011-01-30 23:21:31 +00:00
|
|
|
bottomWorkspace.opacity = bottomWorkspace.actor.opacity = 200;
|
2010-06-06 15:24:51 +00:00
|
|
|
}
|
2010-03-16 15:51:24 +00:00
|
|
|
}
|
2010-06-06 15:24:51 +00:00
|
|
|
|
|
|
|
// handle delayed workspace switches
|
|
|
|
if (hoverWorkspace) {
|
2010-03-16 15:51:24 +00:00
|
|
|
if (!this._timeoutId)
|
2010-06-06 15:24:51 +00:00
|
|
|
this._timeoutId = Mainloop.timeout_add_seconds(1,
|
|
|
|
Lang.bind(this, function() {
|
|
|
|
hoverWorkspace.metaWorkspace.activate(global.get_current_time());
|
|
|
|
hoverWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
|
|
|
|
return false;
|
|
|
|
}));
|
2010-03-16 15:51:24 +00:00
|
|
|
} else {
|
|
|
|
if (this._timeoutId) {
|
|
|
|
Mainloop.source_remove(this._timeoutId);
|
|
|
|
this._timeoutId = 0;
|
|
|
|
}
|
|
|
|
}
|
2010-06-06 15:24:51 +00:00
|
|
|
|
2010-09-10 02:00:28 +00:00
|
|
|
return result;
|
2010-03-16 15:51:24 +00:00
|
|
|
},
|
|
|
|
|
2010-05-08 14:06:28 +00:00
|
|
|
_dragEnd: function() {
|
2010-03-16 15:51:24 +00:00
|
|
|
if (this._timeoutId) {
|
|
|
|
Mainloop.source_remove(this._timeoutId);
|
|
|
|
this._timeoutId = 0;
|
|
|
|
}
|
2010-06-06 15:24:51 +00:00
|
|
|
DND.removeMonitor(this._dragMonitor);
|
2010-03-16 15:51:24 +00:00
|
|
|
this._inDrag = false;
|
|
|
|
|
|
|
|
for (let i = 0; i < this._workspaces.length; i++)
|
|
|
|
this._workspaces[i].setReservedSlot(null);
|
|
|
|
},
|
|
|
|
|
2011-01-21 18:47:54 +00:00
|
|
|
_swipeScrollBegin: function() {
|
|
|
|
this._scrolling = true;
|
|
|
|
},
|
|
|
|
|
|
|
|
_swipeScrollEnd: function(overview, result) {
|
|
|
|
this._scrolling = false;
|
|
|
|
|
|
|
|
if (result == Overview.SwipeScrollResult.CLICK) {
|
|
|
|
let [x, y, mod] = global.get_pointer();
|
|
|
|
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
|
|
|
|
x, y);
|
|
|
|
|
|
|
|
// Only switch to the workspace when there's no application
|
|
|
|
// windows open. The problem is that it's too easy to miss
|
|
|
|
// an app window and get the wrong one focused.
|
|
|
|
let active = global.screen.get_active_workspace_index();
|
|
|
|
if (this._workspaces[active].isEmpty() &&
|
|
|
|
this.actor.contains(actor))
|
|
|
|
Main.overview.hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == Overview.SwipeScrollResult.SWIPE)
|
|
|
|
// The active workspace has changed; while swipe-scrolling
|
|
|
|
// has already taken care of the positioning, the cached
|
|
|
|
// positions need to be updated
|
|
|
|
this._computeWorkspacePositions();
|
|
|
|
|
|
|
|
// Make sure title captions etc are shown as necessary
|
|
|
|
this._updateVisibility();
|
|
|
|
},
|
|
|
|
|
2010-07-11 12:41:17 +00:00
|
|
|
// sync the workspaces' positions to the value of the scroll adjustment
|
2010-02-10 05:56:36 +00:00
|
|
|
// and change the active workspace if appropriate
|
|
|
|
_onScroll: function(adj) {
|
|
|
|
if (this._animatingScroll)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let active = global.screen.get_active_workspace_index();
|
|
|
|
let current = Math.round(adj.value);
|
|
|
|
|
|
|
|
if (active != current) {
|
2010-02-14 23:32:57 +00:00
|
|
|
let metaWorkspace = this._workspaces[current].metaWorkspace;
|
2010-07-11 12:41:17 +00:00
|
|
|
metaWorkspace.activate(global.get_current_time());
|
2010-02-10 05:56:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let last = this._workspaces.length - 1;
|
2011-01-30 23:21:31 +00:00
|
|
|
let firstWorkspaceY = this._workspaces[0].actor.y;
|
|
|
|
let lastWorkspaceY = this._workspaces[last].actor.y;
|
|
|
|
let workspacesHeight = lastWorkspaceY - firstWorkspaceY;
|
2010-02-10 05:56:36 +00:00
|
|
|
|
|
|
|
if (adj.upper == 1)
|
|
|
|
return;
|
|
|
|
|
2011-01-30 23:21:31 +00:00
|
|
|
let currentY = firstWorkspaceY;
|
|
|
|
let newY = this._y - adj.value / (adj.upper - 1) * workspacesHeight;
|
2010-02-10 05:56:36 +00:00
|
|
|
|
2011-01-30 23:21:31 +00:00
|
|
|
let dy = newY - currentY;
|
2010-02-10 05:56:36 +00:00
|
|
|
|
|
|
|
for (let i = 0; i < this._workspaces.length; i++) {
|
2011-02-10 21:41:07 +00:00
|
|
|
this._workspaces[i].hideWindowsOverlays();
|
2010-03-16 15:51:24 +00:00
|
|
|
this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
|
2011-01-30 23:21:31 +00:00
|
|
|
this._workspaces[i].actor.y += dy;
|
2010-02-10 05:56:36 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-10-04 14:42:11 +00:00
|
|
|
_getWorkspaceIndexToRemove: function() {
|
|
|
|
return global.screen.get_active_workspace_index();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Signals.addSignalMethods(WorkspacesView.prototype);
|
|
|
|
|
|
|
|
|
2010-07-29 07:55:08 +00:00
|
|
|
function WorkspacesDisplay() {
|
|
|
|
this._init();
|
2010-02-14 23:32:57 +00:00
|
|
|
}
|
|
|
|
|
2010-10-04 14:42:11 +00:00
|
|
|
WorkspacesDisplay.prototype = {
|
2010-07-29 07:55:08 +00:00
|
|
|
_init: function() {
|
2011-01-31 03:54:05 +00:00
|
|
|
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));
|
2010-10-04 14:42:11 +00:00
|
|
|
|
|
|
|
let controls = new St.BoxLayout({ vertical: true,
|
|
|
|
style_class: 'workspace-controls' });
|
2011-01-31 01:35:58 +00:00
|
|
|
this._controls = controls;
|
|
|
|
this.actor.add_actor(controls);
|
|
|
|
|
|
|
|
controls.reactive = true;
|
|
|
|
controls.track_hover = true;
|
|
|
|
controls.connect('notify::hover',
|
|
|
|
Lang.bind(this, this._onControlsHoverChanged));
|
2010-10-04 14:42:11 +00:00
|
|
|
|
2011-01-31 02:18:12 +00:00
|
|
|
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);
|
|
|
|
});
|
|
|
|
|
2010-10-04 14:42:11 +00:00
|
|
|
this.workspacesView = null;
|
2011-01-31 01:35:58 +00:00
|
|
|
|
|
|
|
this._inDrag = false;
|
|
|
|
this._zoomOut = false;
|
2011-01-31 03:54:05 +00:00
|
|
|
this._zoomFraction = 0;
|
2011-01-31 01:35:58 +00:00
|
|
|
|
2010-07-29 07:55:08 +00:00
|
|
|
this._nWorkspacesNotifyId = 0;
|
2011-01-31 01:35:58 +00:00
|
|
|
this._switchWorkspaceNotifyId = 0;
|
|
|
|
|
|
|
|
this._itemDragBeginId = 0;
|
|
|
|
this._itemDragEndId = 0;
|
|
|
|
this._windowDragBeginId = 0;
|
|
|
|
this._windowDragEndId = 0;
|
2010-02-14 23:32:57 +00:00
|
|
|
},
|
|
|
|
|
2010-10-04 14:42:11 +00:00
|
|
|
show: function() {
|
2011-01-31 01:35:58 +00:00
|
|
|
this._controls.show();
|
2010-10-04 14:42:11 +00:00
|
|
|
|
2010-07-29 07:55:08 +00:00
|
|
|
this._workspaces = [];
|
2011-01-31 02:18:12 +00:00
|
|
|
this._workspaceThumbnails = [];
|
2010-07-29 07:55:08 +00:00
|
|
|
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);
|
2011-01-31 02:18:12 +00:00
|
|
|
|
|
|
|
let thumbnail = new WorkspaceThumbnail.WorkspaceThumbnail(metaWorkspace);
|
|
|
|
this._workspaceThumbnails[i] = thumbnail;
|
|
|
|
this._thumbnailsBox.add(thumbnail.actor);
|
2010-07-29 07:55:08 +00:00
|
|
|
}
|
|
|
|
|
2011-01-31 02:18:12 +00:00
|
|
|
// 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();
|
|
|
|
|
2011-01-31 01:35:58 +00:00
|
|
|
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
|
|
|
|
|
|
|
let totalAllocation = this.actor.allocation;
|
|
|
|
let totalWidth = totalAllocation.x2 - totalAllocation.x1;
|
2011-01-31 03:54:05 +00:00
|
|
|
let totalHeight = totalAllocation.y2 - totalAllocation.y1;
|
2011-01-31 01:35:58 +00:00
|
|
|
|
|
|
|
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(-1);
|
|
|
|
let controlsReserved = controlsNatural * (1 - CONTROLS_POP_IN_FRACTION);
|
|
|
|
|
|
|
|
totalWidth -= controlsReserved;
|
2010-07-29 07:55:08 +00:00
|
|
|
|
|
|
|
// Workspaces expect to have the same ratio as the screen, so take
|
2011-01-31 01:35:58 +00:00
|
|
|
// this into account when fitting the workspace into the available space
|
2010-07-29 07:55:08 +00:00
|
|
|
let width, height;
|
2011-01-31 01:35:58 +00:00
|
|
|
let totalRatio = totalWidth / totalHeight;
|
2010-07-29 07:55:08 +00:00
|
|
|
let wsRatio = global.screen_width / global.screen_height;
|
2011-01-31 01:35:58 +00:00
|
|
|
if (wsRatio > totalRatio) {
|
|
|
|
width = totalWidth;
|
|
|
|
height = Math.floor(totalWidth / wsRatio);
|
2010-07-29 07:55:08 +00:00
|
|
|
} else {
|
2011-01-31 01:35:58 +00:00
|
|
|
width = Math.floor(totalHeight * wsRatio);
|
|
|
|
height = totalHeight;
|
2010-07-29 07:55:08 +00:00
|
|
|
}
|
|
|
|
|
2011-01-31 01:35:58 +00:00
|
|
|
// Position workspaces in the available space
|
|
|
|
let [x, y] = this.actor.get_transformed_position();
|
|
|
|
x = Math.floor(x + Math.abs(totalWidth - width) / 2);
|
|
|
|
y = Math.floor(y + Math.abs(totalHeight - height) / 2);
|
|
|
|
|
|
|
|
if (rtl)
|
|
|
|
x += controlsReserved;
|
2010-07-29 07:55:08 +00:00
|
|
|
|
2011-01-31 01:35:58 +00:00
|
|
|
let zoomScale = (totalWidth - controlsNatural) / totalWidth;
|
|
|
|
let newView = new WorkspacesView(width, height, x, y, zoomScale, this._workspaces);
|
2010-11-12 09:28:28 +00:00
|
|
|
|
2010-02-14 23:32:57 +00:00
|
|
|
if (this.workspacesView)
|
|
|
|
this.workspacesView.destroy();
|
|
|
|
this.workspacesView = newView;
|
|
|
|
|
2010-10-04 14:42:11 +00:00
|
|
|
this._nWorkspacesNotifyId =
|
|
|
|
global.screen.connect('notify::n-workspaces',
|
|
|
|
Lang.bind(this, this._workspacesChanged));
|
2011-01-31 02:18:12 +00:00
|
|
|
this._switchWorkspaceNotifyId =
|
|
|
|
global.window_manager.connect('switch-workspace',
|
|
|
|
Lang.bind(this, this._activeWorkspaceChanged));
|
2011-01-31 01:35:58 +00:00
|
|
|
|
2011-01-31 01:44:05 +00:00
|
|
|
this._restackedNotifyId =
|
|
|
|
global.screen.connect('restacked',
|
|
|
|
Lang.bind(this, this._onRestacked));
|
|
|
|
|
2011-01-31 01:35:58 +00:00
|
|
|
if (this._itemDragBeginId == 0)
|
|
|
|
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
|
|
|
|
Lang.bind(this, this._dragBegin));
|
|
|
|
if (this._itemDragEndId == 0)
|
|
|
|
this._itemDragEndId = Main.overview.connect('item-drag-end',
|
|
|
|
Lang.bind(this, this._dragEnd));
|
|
|
|
if (this._windowDragBeginId == 0)
|
|
|
|
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
|
|
|
|
Lang.bind(this, this._dragBegin));
|
|
|
|
if (this._windowDragEndId == 0)
|
|
|
|
this._windowDragEndId = Main.overview.connect('window-drag-end',
|
|
|
|
Lang.bind(this, this._dragEnd));
|
2011-01-31 01:44:05 +00:00
|
|
|
|
|
|
|
this._onRestacked();
|
2011-01-31 02:18:12 +00:00
|
|
|
this._constrainThumbnailIndicator();
|
|
|
|
this._zoomOut = false;
|
2011-01-31 03:54:05 +00:00
|
|
|
this._zoomFraction = 0;
|
2011-01-31 02:18:12 +00:00
|
|
|
this._updateZoom();
|
2010-10-04 14:42:11 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
hide: function() {
|
2011-01-31 01:35:58 +00:00
|
|
|
this._controls.hide();
|
2010-10-04 14:42:11 +00:00
|
|
|
|
2011-01-31 01:35:58 +00:00
|
|
|
if (this._nWorkspacesNotifyId > 0) {
|
2010-10-04 14:42:11 +00:00
|
|
|
global.screen.disconnect(this._nWorkspacesNotifyId);
|
2011-01-31 01:35:58 +00:00
|
|
|
this._nWorkspacesNotifyId = 0;
|
|
|
|
}
|
2011-01-31 02:18:12 +00:00
|
|
|
if (this._switchWorkspaceNotifyId > 0) {
|
|
|
|
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
|
|
|
this._switchWorkspaceNotifyId = 0;
|
|
|
|
}
|
2011-01-31 01:44:05 +00:00
|
|
|
if (this._restackedNotifyId > 0){
|
|
|
|
global.screen.disconnect(this._restackedNotifyId);
|
|
|
|
this._restackedNotifyId = 0;
|
|
|
|
}
|
2011-01-31 01:35:58 +00:00
|
|
|
if (this._itemDragBeginId > 0) {
|
|
|
|
Main.overview.disconnect(this._itemDragBeginId);
|
|
|
|
this._itemDragBeginId = 0;
|
|
|
|
}
|
|
|
|
if (this._itemEndBeginId > 0) {
|
|
|
|
Main.overview.disconnect(this._itemDragEndId);
|
|
|
|
this._itemDragEndId = 0;
|
|
|
|
}
|
|
|
|
if (this._windowDragBeginId > 0) {
|
|
|
|
Main.overview.disconnect(this._windowDragBeginId);
|
|
|
|
this._windowDragBeginId = 0;
|
|
|
|
}
|
|
|
|
if (this._windowDragEndId > 0) {
|
|
|
|
Main.overview.disconnect(this._windowDragEndId);
|
|
|
|
this._windowDragEndId = 0;
|
|
|
|
}
|
|
|
|
|
2010-10-04 14:42:11 +00:00
|
|
|
this.workspacesView.destroy();
|
|
|
|
this.workspacesView = null;
|
2011-01-31 02:18:12 +00:00
|
|
|
this._unconstrainThumbnailIndicator();
|
2010-10-04 14:42:11 +00:00
|
|
|
for (let w = 0; w < this._workspaces.length; w++) {
|
|
|
|
this._workspaces[w].disconnectAll();
|
|
|
|
this._workspaces[w].destroy();
|
2011-01-31 02:18:12 +00:00
|
|
|
this._workspaceThumbnails[w].destroy();
|
2010-10-04 14:42:11 +00:00
|
|
|
}
|
2010-02-14 23:32:57 +00:00
|
|
|
},
|
|
|
|
|
2011-01-31 03:54:05 +00:00
|
|
|
// 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;
|
|
|
|
},
|
|
|
|
|
|
|
|
_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 controlsReserved = controlsNatural * (1 - (1 - this._zoomFraction) * CONTROLS_POP_IN_FRACTION);
|
|
|
|
|
|
|
|
let rtl = (St.Widget.get_default_direction () == St.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);
|
|
|
|
},
|
|
|
|
|
2011-01-31 02:18:12 +00:00
|
|
|
_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)
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2011-01-31 01:44:05 +00:00
|
|
|
_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.workspacesView.syncStacking(stackIndices);
|
2011-01-31 02:18:12 +00:00
|
|
|
for (let i = 0; i < this._workspaceThumbnails.length; i++)
|
|
|
|
this._workspaceThumbnails[i].syncStacking(stackIndices);
|
2011-01-31 01:44:05 +00:00
|
|
|
},
|
|
|
|
|
2010-02-14 23:32:57 +00:00
|
|
|
_workspacesChanged: function() {
|
|
|
|
let oldNumWorkspaces = this._workspaces.length;
|
|
|
|
let newNumWorkspaces = global.screen.n_workspaces;
|
|
|
|
let active = global.screen.get_active_workspace_index();
|
|
|
|
|
|
|
|
if (oldNumWorkspaces == newNumWorkspaces)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let lostWorkspaces = [];
|
|
|
|
if (newNumWorkspaces > oldNumWorkspaces) {
|
|
|
|
// Assume workspaces are only added at the end
|
|
|
|
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
|
|
|
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
|
|
|
this._workspaces[w] = new Workspace.Workspace(metaWorkspace);
|
2011-01-31 02:18:12 +00:00
|
|
|
|
|
|
|
let thumbnail = new WorkspaceThumbnail.WorkspaceThumbnail(metaWorkspace);
|
|
|
|
this._workspaceThumbnails[w] = thumbnail;
|
|
|
|
this._thumbnailsBox.add(thumbnail.actor);
|
2010-02-14 23:32:57 +00:00
|
|
|
}
|
2011-01-31 02:18:12 +00:00
|
|
|
this._thumbnailIndicator.raise_top();
|
2010-02-14 23:32:57 +00:00
|
|
|
} else {
|
|
|
|
// Assume workspaces are only removed sequentially
|
|
|
|
// (e.g. 2,3,4 - not 2,4,7)
|
|
|
|
let removedIndex;
|
|
|
|
let removedNum = oldNumWorkspaces - newNumWorkspaces;
|
|
|
|
for (let w = 0; w < oldNumWorkspaces; w++) {
|
|
|
|
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
|
|
|
if (this._workspaces[w].metaWorkspace != metaWorkspace) {
|
|
|
|
removedIndex = w;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lostWorkspaces = this._workspaces.splice(removedIndex,
|
|
|
|
removedNum);
|
|
|
|
|
|
|
|
// Don't let the user try to select this workspace as it's
|
|
|
|
// making its exit.
|
|
|
|
for (let l = 0; l < lostWorkspaces.length; l++)
|
|
|
|
lostWorkspaces[l].setReactive(false);
|
2011-01-31 02:18:12 +00:00
|
|
|
|
|
|
|
for (let k = removedIndex; k < removedIndex + removedNum; k++)
|
|
|
|
this._workspaceThumbnails[k].destroy();
|
|
|
|
this._workspaceThumbnails.splice(removedIndex, removedNum);
|
2010-02-14 23:32:57 +00:00
|
|
|
}
|
|
|
|
|
2011-01-25 21:29:45 +00:00
|
|
|
// If we removed the current workspace, then metacity will have already
|
|
|
|
// switched to an adjacent workspace. Leaving the animation we
|
|
|
|
// started in response to that around will look funny because it's an
|
|
|
|
// animation for the *old* workspace configuration. So, kill it.
|
|
|
|
// If we animate the workspace removal in the future, we should animate
|
|
|
|
// the indicator as part of that.
|
|
|
|
Tweener.removeTweens(this._thumbnailIndicator);
|
|
|
|
this._constrainThumbnailIndicator();
|
|
|
|
|
2010-02-14 23:32:57 +00:00
|
|
|
this.workspacesView.updateWorkspaces(oldNumWorkspaces,
|
|
|
|
newNumWorkspaces,
|
|
|
|
lostWorkspaces);
|
2011-01-31 01:35:58 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_updateZoom : function() {
|
|
|
|
if (Main.overview.animationInProgress)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let shouldZoom = this._controls.hover || this._inDrag;
|
|
|
|
if (shouldZoom != this._zoomOut) {
|
|
|
|
this._zoomOut = shouldZoom;
|
|
|
|
|
|
|
|
if (!this.workspacesView)
|
|
|
|
return;
|
|
|
|
|
2011-01-31 03:54:05 +00:00
|
|
|
Tweener.addTween(this,
|
|
|
|
{ zoomFraction: this._zoomOut ? 1 : 0,
|
2011-01-31 01:35:58 +00:00
|
|
|
time: WORKSPACE_SWITCH_TIME,
|
|
|
|
transition: 'easeOutQuad' });
|
|
|
|
|
|
|
|
if (shouldZoom)
|
|
|
|
this.workspacesView.zoomOut();
|
|
|
|
else
|
|
|
|
this.workspacesView.zoomIn();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_onControlsHoverChanged: function() {
|
|
|
|
this._updateZoom();
|
|
|
|
},
|
|
|
|
|
|
|
|
_dragBegin: function() {
|
|
|
|
this._inDrag = true;
|
|
|
|
this._updateZoom();
|
|
|
|
},
|
|
|
|
|
|
|
|
_dragEnd: function() {
|
|
|
|
this._inDrag = false;
|
2011-01-30 21:38:13 +00:00
|
|
|
|
|
|
|
// 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));
|
2010-02-14 23:32:57 +00:00
|
|
|
}
|
|
|
|
};
|
2010-10-04 14:42:11 +00:00
|
|
|
Signals.addSignalMethods(WorkspacesDisplay.prototype);
|