gnome-shell/js/ui/osdWindow.js
Florian Müllner fd50b9a45e cleanup: Use destructuring for imports from GI
This is *much* nicer than repetitive "imports.gi" lines ...

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/399
2019-02-09 07:39:20 +01:00

279 lines
8.6 KiB
JavaScript

// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
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 = 0.1;
var LEVEL_ANIMATION_TIME = 0.1;
var LevelBar = class extends BarLevel.BarLevel {
constructor() {
super(0, { styleClass: 'level' });
this._level = 0;
this._maxLevel = 100;
this.actor.accessible_name = _("Volume");
this.actor.connect('notify::width', () => { this.level = this.level; });
}
get level() {
return this._level;
}
set level(value) {
this._level = Math.max(0, Math.min(value, this._maxLevel));
this.setValue(this._level / 100);
}
get maxLevel() {
return this._maxLevel;
}
set maxLevel(value) {
this._maxLevel = Math.max(100, value);
this.setMaximumValue(this._maxLevel / 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 LevelBar();
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(level) {
this._level.actor.visible = (level != undefined);
if (level != undefined) {
if (this.actor.visible)
Tweener.addTween(this._level,
{ level: level,
time: LEVEL_ANIMATION_TIME,
transition: 'easeOutQuad' });
else
this._level.level = level;
}
}
setMaxLevel(maxLevel) {
if (maxLevel === undefined)
maxLevel = 100;
this._level.maxLevel = 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,
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,
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();
}
};