476816732f
The different units - seconds for Tweener and milliseconds for timeouts - are not a big issue currently, as there is little overlap. However this will change when we start using Clutter's own animation framework (which uses milliseconds as well), in particular where constants are shared between modules. In order to prepare for the transition, define all animation times as milliseconds and adjust them when passing them to Tweener. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/663
227 lines
8.7 KiB
JavaScript
227 lines
8.7 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
/* exported WorkspaceSwitcherPopup */
|
|
|
|
const { Clutter, GLib, GObject, Meta, St } = imports.gi;
|
|
const Mainloop = imports.mainloop;
|
|
|
|
const Main = imports.ui.main;
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
var ANIMATION_TIME = 100;
|
|
var DISPLAY_TIMEOUT = 600;
|
|
|
|
var WorkspaceSwitcherPopupList = GObject.registerClass(
|
|
class WorkspaceSwitcherPopupList extends St.Widget {
|
|
_init() {
|
|
super._init({ style_class: 'workspace-switcher' });
|
|
|
|
this._itemSpacing = 0;
|
|
this._childHeight = 0;
|
|
this._childWidth = 0;
|
|
this._orientation = global.workspace_manager.layout_rows == -1
|
|
? Clutter.Orientation.VERTICAL
|
|
: Clutter.Orientation.HORIZONTAL;
|
|
|
|
this.connect('style-changed', () => {
|
|
this._itemSpacing = this.get_theme_node().get_length('spacing');
|
|
});
|
|
}
|
|
|
|
_getPreferredSizeForOrientation(_forSize) {
|
|
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
|
let themeNode = this.get_theme_node();
|
|
|
|
let availSize;
|
|
if (this._orientation == Clutter.Orientation.HORIZONTAL)
|
|
availSize = workArea.width - themeNode.get_horizontal_padding();
|
|
else
|
|
availSize = workArea.height - themeNode.get_vertical_padding();
|
|
|
|
let size = 0;
|
|
for (let child of this.get_children()) {
|
|
let [, childNaturalHeight] = child.get_preferred_height(-1);
|
|
let height = childNaturalHeight * workArea.width / workArea.height;
|
|
|
|
if (this._orientation == Clutter.Orientation.HORIZONTAL)
|
|
size += height * workArea.width / workArea.height;
|
|
else
|
|
size += height;
|
|
}
|
|
|
|
let workspaceManager = global.workspace_manager;
|
|
let spacing = this._itemSpacing * (workspaceManager.n_workspaces - 1);
|
|
size += spacing;
|
|
size = Math.min(size, availSize);
|
|
|
|
if (this._orientation == Clutter.Orientation.HORIZONTAL) {
|
|
this._childWidth = (size - spacing) / workspaceManager.n_workspaces;
|
|
return themeNode.adjust_preferred_width(size, size);
|
|
} else {
|
|
this._childHeight = (size - spacing) / workspaceManager.n_workspaces;
|
|
return themeNode.adjust_preferred_height(size, size);
|
|
}
|
|
}
|
|
|
|
_getSizeForOppositeOrientation() {
|
|
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
|
|
|
if (this._orientation == Clutter.Orientation.HORIZONTAL) {
|
|
this._childHeight = Math.round(this._childWidth * workArea.height / workArea.width);
|
|
return [this._childHeight, this._childHeight];
|
|
} else {
|
|
this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
|
|
return [this._childWidth, this._childWidth];
|
|
}
|
|
}
|
|
|
|
vfunc_get_preferred_height(forWidth) {
|
|
if (this._orientation == Clutter.Orientation.HORIZONTAL)
|
|
return this._getSizeForOppositeOrientation();
|
|
else
|
|
return this._getPreferredSizeForOrientation(forWidth);
|
|
}
|
|
|
|
vfunc_get_preferred_width(forHeight) {
|
|
if (this._orientation == Clutter.Orientation.HORIZONTAL)
|
|
return this._getPreferredSizeForOrientation(forHeight);
|
|
else
|
|
return this._getSizeForOppositeOrientation();
|
|
}
|
|
|
|
vfunc_allocate(box, flags) {
|
|
this.set_allocation(box, flags);
|
|
|
|
let themeNode = this.get_theme_node();
|
|
box = themeNode.get_content_box(box);
|
|
|
|
let childBox = new Clutter.ActorBox();
|
|
|
|
let rtl = this.text_direction == Clutter.TextDirection.RTL;
|
|
let x = rtl ? box.x2 - this._childWidth : box.x1;
|
|
let y = box.y1;
|
|
for (let child of this.get_children()) {
|
|
childBox.x1 = Math.round(x);
|
|
childBox.x2 = Math.round(x + this._childWidth);
|
|
childBox.y1 = Math.round(y);
|
|
childBox.y2 = Math.round(y + this._childHeight);
|
|
|
|
if (this._orientation == Clutter.Orientation.HORIZONTAL) {
|
|
if (rtl)
|
|
x -= this._childWidth + this._itemSpacing;
|
|
else
|
|
x += this._childWidth + this._itemSpacing;
|
|
} else {
|
|
y += this._childHeight + this._itemSpacing;
|
|
}
|
|
child.allocate(childBox, flags);
|
|
}
|
|
}
|
|
});
|
|
|
|
var WorkspaceSwitcherPopup = GObject.registerClass(
|
|
class WorkspaceSwitcherPopup extends St.Widget {
|
|
_init() {
|
|
super._init({ x: 0,
|
|
y: 0,
|
|
width: global.screen_width,
|
|
height: global.screen_height,
|
|
style_class: 'workspace-switcher-group' });
|
|
|
|
Main.uiGroup.add_actor(this);
|
|
|
|
this._timeoutId = 0;
|
|
|
|
this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' });
|
|
this.add_child(this._container);
|
|
|
|
this._list = new WorkspaceSwitcherPopupList();
|
|
this._container.add_child(this._list);
|
|
|
|
this._redisplay();
|
|
|
|
this.hide();
|
|
|
|
let workspaceManager = global.workspace_manager;
|
|
this._workspaceManagerSignals = [];
|
|
this._workspaceManagerSignals.push(workspaceManager.connect('workspace-added',
|
|
this._redisplay.bind(this)));
|
|
this._workspaceManagerSignals.push(workspaceManager.connect('workspace-removed',
|
|
this._redisplay.bind(this)));
|
|
|
|
this.connect('destroy', this._onDestroy.bind(this));
|
|
}
|
|
|
|
_redisplay() {
|
|
let workspaceManager = global.workspace_manager;
|
|
|
|
this._list.destroy_all_children();
|
|
|
|
for (let i = 0; i < workspaceManager.n_workspaces; i++) {
|
|
let indicator = null;
|
|
|
|
if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.UP)
|
|
indicator = new St.Bin({ style_class: 'ws-switcher-active-up' });
|
|
else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.DOWN)
|
|
indicator = new St.Bin({ style_class: 'ws-switcher-active-down' });
|
|
else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.LEFT)
|
|
indicator = new St.Bin({ style_class: 'ws-switcher-active-left' });
|
|
else if (i == this._activeWorkspaceIndex && this._direction == Meta.MotionDirection.RIGHT)
|
|
indicator = new St.Bin({ style_class: 'ws-switcher-active-right' });
|
|
else
|
|
indicator = new St.Bin({ style_class: 'ws-switcher-box' });
|
|
|
|
this._list.add_actor(indicator);
|
|
|
|
}
|
|
|
|
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
|
let [, containerNatHeight] = this._container.get_preferred_height(global.screen_width);
|
|
let [, containerNatWidth] = this._container.get_preferred_width(containerNatHeight);
|
|
this._container.x = workArea.x + Math.floor((workArea.width - containerNatWidth) / 2);
|
|
this._container.y = workArea.y + Math.floor((workArea.height - containerNatHeight) / 2);
|
|
}
|
|
|
|
_show() {
|
|
Tweener.addTween(this._container, { opacity: 255,
|
|
time: ANIMATION_TIME / 1000,
|
|
transition: 'easeOutQuad'
|
|
});
|
|
this.show();
|
|
}
|
|
|
|
display(direction, activeWorkspaceIndex) {
|
|
this._direction = direction;
|
|
this._activeWorkspaceIndex = activeWorkspaceIndex;
|
|
|
|
this._redisplay();
|
|
if (this._timeoutId != 0)
|
|
Mainloop.source_remove(this._timeoutId);
|
|
this._timeoutId = Mainloop.timeout_add(DISPLAY_TIMEOUT, this._onTimeout.bind(this));
|
|
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._onTimeout');
|
|
this._show();
|
|
}
|
|
|
|
_onTimeout() {
|
|
Mainloop.source_remove(this._timeoutId);
|
|
this._timeoutId = 0;
|
|
Tweener.addTween(this._container, { opacity: 0.0,
|
|
time: ANIMATION_TIME / 1000,
|
|
transition: 'easeOutQuad',
|
|
onComplete: () => this.destroy()
|
|
});
|
|
return GLib.SOURCE_REMOVE;
|
|
}
|
|
|
|
_onDestroy() {
|
|
if (this._timeoutId)
|
|
Mainloop.source_remove(this._timeoutId);
|
|
this._timeoutId = 0;
|
|
|
|
let workspaceManager = global.workspace_manager;
|
|
for (let i = 0; i < this._workspaceManagerSignals.length; i++)
|
|
workspaceManager.disconnect(this._workspaceManagerSignals[i]);
|
|
|
|
this._workspaceManagerSignals = [];
|
|
}
|
|
});
|