gnome-shell/js/ui/workspaceSwitcherPopup.js
Florian Müllner 476816732f cleanup: Use milliseconds for animation times
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
2019-08-05 21:55:20 +00:00

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 = [];
}
});