gnome-shell/js/ui/osdWindow.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

245 lines
7.9 KiB
JavaScript

// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported OsdWindowManager */
const { Clutter, GLib, GObject, Meta, St } = imports.gi;
const Mainloop = imports.mainloop;
const BarLevel = imports.ui.barLevel;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var HIDE_TIMEOUT = 1500;
var FADE_TIME = 100;
var LEVEL_ANIMATION_TIME = 100;
var OsdWindowConstraint = GObject.registerClass(
class OsdWindowConstraint extends Clutter.Constraint {
_init(props) {
this._minSize = 0;
super._init(props);
}
set minSize(v) {
this._minSize = v;
if (this.actor)
this.actor.queue_relayout();
}
vfunc_update_allocation(actor, actorBox) {
// Clutter will adjust the allocation for margins,
// so add it to our minimum size
let minSize = this._minSize + actor.margin_top + actor.margin_bottom;
let [width, height] = actorBox.get_size();
// Enforce a ratio of 1
let size = Math.ceil(Math.max(minSize, height));
actorBox.set_size(size, size);
// Recenter
let [x, y] = actorBox.get_origin();
actorBox.set_origin(Math.ceil(x + width / 2 - size / 2),
Math.ceil(y + height / 2 - size / 2));
}
});
var OsdWindow = class {
constructor(monitorIndex) {
this.actor = new St.Widget({ x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER });
this._monitorIndex = monitorIndex;
let constraint = new Layout.MonitorConstraint({ index: monitorIndex });
this.actor.add_constraint(constraint);
this._boxConstraint = new OsdWindowConstraint();
this._box = new St.BoxLayout({ style_class: 'osd-window',
vertical: true });
this._box.add_constraint(this._boxConstraint);
this.actor.add_actor(this._box);
this._icon = new St.Icon();
this._box.add(this._icon, { expand: true });
this._label = new St.Label();
this._box.add(this._label);
this._level = new BarLevel.BarLevel(0, { styleClass: 'level' });
this._box.add(this._level.actor);
this._hideTimeoutId = 0;
this._reset();
this.actor.connect('destroy', this._onDestroy.bind(this));
this._monitorsChangedId =
Main.layoutManager.connect('monitors-changed',
this._relayout.bind(this));
let themeContext = St.ThemeContext.get_for_stage(global.stage);
this._scaleChangedId =
themeContext.connect('notify::scale-factor',
this._relayout.bind(this));
this._relayout();
Main.uiGroup.add_child(this.actor);
}
_onDestroy() {
if (this._monitorsChangedId)
Main.layoutManager.disconnect(this._monitorsChangedId);
this._monitorsChangedId = 0;
let themeContext = St.ThemeContext.get_for_stage(global.stage);
if (this._scaleChangedId)
themeContext.disconnect(this._scaleChangedId);
this._scaleChangedId = 0;
}
setIcon(icon) {
this._icon.gicon = icon;
}
setLabel(label) {
this._label.visible = (label != undefined);
if (label)
this._label.text = label;
}
setLevel(value) {
this._level.actor.visible = (value != undefined);
if (value != undefined) {
if (this.actor.visible)
Tweener.addTween(this._level,
{ value: value,
time: LEVEL_ANIMATION_TIME / 1000,
transition: 'easeOutQuad' });
else
this._level.value = value;
}
}
setMaxLevel(maxLevel = 1) {
this._level.maximum_value = maxLevel;
}
show() {
if (!this._icon.gicon)
return;
if (!this.actor.visible) {
Meta.disable_unredirect_for_display(global.display);
this.actor.show();
this.actor.opacity = 0;
this.actor.get_parent().set_child_above_sibling(this.actor, null);
Tweener.addTween(this.actor,
{ opacity: 255,
time: FADE_TIME / 1000,
transition: 'easeOutQuad' });
}
if (this._hideTimeoutId)
Mainloop.source_remove(this._hideTimeoutId);
this._hideTimeoutId = Mainloop.timeout_add(HIDE_TIMEOUT,
this._hide.bind(this));
GLib.Source.set_name_by_id(this._hideTimeoutId, '[gnome-shell] this._hide');
}
cancel() {
if (!this._hideTimeoutId)
return;
Mainloop.source_remove(this._hideTimeoutId);
this._hide();
}
_hide() {
this._hideTimeoutId = 0;
Tweener.addTween(this.actor,
{ opacity: 0,
time: FADE_TIME / 1000,
transition: 'easeOutQuad',
onComplete: () => {
this._reset();
Meta.enable_unredirect_for_display(global.display);
}
});
return GLib.SOURCE_REMOVE;
}
_reset() {
this.actor.hide();
this.setLabel(null);
this.setMaxLevel(null);
this.setLevel(null);
}
_relayout() {
/* assume 110x110 on a 640x480 display and scale from there */
let monitor = Main.layoutManager.monitors[this._monitorIndex];
if (!monitor)
return; // we are about to be removed
let scalew = monitor.width / 640.0;
let scaleh = monitor.height / 480.0;
let scale = Math.min(scalew, scaleh);
let popupSize = 110 * Math.max(1, scale);
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._icon.icon_size = popupSize / (2 * scaleFactor);
this._box.translation_y = Math.round(monitor.height / 4);
this._boxConstraint.minSize = popupSize;
}
};
var OsdWindowManager = class {
constructor() {
this._osdWindows = [];
Main.layoutManager.connect('monitors-changed',
this._monitorsChanged.bind(this));
this._monitorsChanged();
}
_monitorsChanged() {
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
if (this._osdWindows[i] == undefined)
this._osdWindows[i] = new OsdWindow(i);
}
for (let i = Main.layoutManager.monitors.length; i < this._osdWindows.length; i++) {
this._osdWindows[i].actor.destroy();
this._osdWindows[i] = null;
}
this._osdWindows.length = Main.layoutManager.monitors.length;
}
_showOsdWindow(monitorIndex, icon, label, level, maxLevel) {
this._osdWindows[monitorIndex].setIcon(icon);
this._osdWindows[monitorIndex].setLabel(label);
this._osdWindows[monitorIndex].setMaxLevel(maxLevel);
this._osdWindows[monitorIndex].setLevel(level);
this._osdWindows[monitorIndex].show();
}
show(monitorIndex, icon, label, level, maxLevel) {
if (monitorIndex != -1) {
for (let i = 0; i < this._osdWindows.length; i++) {
if (i == monitorIndex)
this._showOsdWindow(i, icon, label, level, maxLevel);
else
this._osdWindows[i].cancel();
}
} else {
for (let i = 0; i < this._osdWindows.length; i++)
this._showOsdWindow(i, icon, label, level, maxLevel);
}
}
hideAll() {
for (let i = 0; i < this._osdWindows.length; i++)
this._osdWindows[i].cancel();
}
};