193 lines
4.8 KiB
JavaScript
193 lines
4.8 KiB
JavaScript
const { GObject, Clutter, St, GLib } = imports.gi;
|
|
const { panelMenu, popupMenu } = imports.ui;
|
|
const { getCurrentExtension, getSettings } = imports.misc.extensionUtils;
|
|
const AppManager = getCurrentExtension().imports.AppManager;
|
|
|
|
var TrayIndicator = GObject.registerClass(
|
|
class TrayIndicator extends panelMenu.Button {
|
|
_init() {
|
|
this._icons = [];
|
|
|
|
super._init(0.0, null, false);
|
|
this._overflow = false;
|
|
|
|
this._indicators = new St.BoxLayout();
|
|
this.add_child(this._indicators);
|
|
|
|
this._icon = new St.Icon({
|
|
icon_name: "view-more-horizontal",
|
|
style_class: "system-status-icon",
|
|
reactive: true,
|
|
track_hover: true,
|
|
});
|
|
this._indicators.add_child(this._icon);
|
|
|
|
this._menuItem = new popupMenu.PopupBaseMenuItem({
|
|
reactive: false,
|
|
can_focus: true,
|
|
});
|
|
this.menu.addMenuItem(this._menuItem);
|
|
this.menu.actor.add_style_class_name("TrayIndicatorPopup");
|
|
this.hide();
|
|
}
|
|
|
|
get size() {
|
|
const context = St.ThemeContext.get_for_stage(global.stage);
|
|
return this._size * context.scale_factor;
|
|
}
|
|
|
|
setSize(size, margin, padding) {
|
|
this._size = size;
|
|
this._margin = margin;
|
|
this._padding = padding;
|
|
|
|
this._icons.forEach((icon) => {
|
|
icon.get_parent().style = this._getButtonStyle();
|
|
icon.set_size(this._size, this._size);
|
|
});
|
|
}
|
|
|
|
addIcon(icon) {
|
|
const isHidden = AppManager.getAppSetting(icon, "hidden");
|
|
if (isHidden) return;
|
|
|
|
const button = new St.Button({
|
|
child: icon,
|
|
button_mask:
|
|
St.ButtonMask.ONE | St.ButtonMask.TWO | St.ButtonMask.THREE,
|
|
style: this._getButtonStyle(),
|
|
style_class: "panel-button",
|
|
});
|
|
icon.opacity = 0;
|
|
icon.set_x_align(Clutter.ActorAlign.CENTER);
|
|
icon.set_y_align(Clutter.ActorAlign.CENTER);
|
|
icon.inOverflow = this._overflow;
|
|
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => {
|
|
icon.set_size(this.size, this.size);
|
|
icon.ease({
|
|
opacity: 255,
|
|
duration: 400,
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
});
|
|
this._addEffectIcon(icon);
|
|
return GLib.SOURCE_REMOVE;
|
|
});
|
|
icon.connect("destroy", () => {
|
|
button.destroy();
|
|
});
|
|
|
|
button.connect("button-release-event", (actor, event) => {
|
|
switch (event.get_button()) {
|
|
case 1:
|
|
AppManager.leftClick(icon, event);
|
|
break;
|
|
case 2:
|
|
AppManager.middleClick(icon, event);
|
|
break;
|
|
case 3:
|
|
icon.click(event);
|
|
break;
|
|
}
|
|
if (AppManager.isWine(icon)) {
|
|
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1, () => {
|
|
this.menu.close();
|
|
return GLib.SOURCE_REMOVE;
|
|
});
|
|
} else {
|
|
this.menu.close();
|
|
}
|
|
});
|
|
|
|
this._icons.push(icon);
|
|
|
|
if (this._overflow) {
|
|
this._menuItem.actor.add(button);
|
|
} else {
|
|
this._indicators.insert_child_at_index(button, 0);
|
|
}
|
|
|
|
this.checkOverflow();
|
|
}
|
|
|
|
removeIcon(icon, ignoreCheckOverflow) {
|
|
const index = this._icons.indexOf(icon);
|
|
this._icons.splice(index, 1);
|
|
|
|
const actor = icon.get_parent();
|
|
actor.remove_actor(icon);
|
|
actor.destroy();
|
|
|
|
if (!ignoreCheckOverflow) {
|
|
this.checkOverflow();
|
|
}
|
|
}
|
|
|
|
checkOverflow() {
|
|
if (this._icons.length >= getSettings().get_int("icons-limit")) {
|
|
this._overflow = true;
|
|
this._icon.visible = true;
|
|
this.reactive = true;
|
|
this.style_class = "panel-button TrayIndicator";
|
|
} else {
|
|
this._overflow = false;
|
|
this._icon.visible = false;
|
|
this.reactive = false;
|
|
this.style_class = "TrayIndicator";
|
|
}
|
|
|
|
if (this._icons.length) {
|
|
this.show();
|
|
} else {
|
|
this.hide();
|
|
}
|
|
|
|
this._refreshIcons(this._overflow);
|
|
}
|
|
|
|
_refreshIcons(overflow) {
|
|
this._icons.forEach((icon) => {
|
|
if (icon.inOverflow != overflow) {
|
|
this.removeIcon(icon, true);
|
|
this.addIcon(icon);
|
|
}
|
|
});
|
|
}
|
|
|
|
_getButtonStyle() {
|
|
let style;
|
|
if (!this._overflow) {
|
|
style = `margin: ${this._margin.vertical}px ${this._margin.horizontal}px; padding: ${this._padding.vertical}px ${this._padding.horizontal}px`;
|
|
}
|
|
return `width: ${this.size}px; height: ${this.size}px;${style}`;
|
|
}
|
|
|
|
_addEffectIcon(icon) {
|
|
let brightnessContrast = new Clutter.BrightnessContrastEffect({});
|
|
brightnessContrast.set_contrast(
|
|
getSettings().get_int("icon-contrast") / 100
|
|
);
|
|
brightnessContrast.set_brightness(
|
|
getSettings().get_int("icon-brightness") / 100
|
|
);
|
|
icon.add_effect_with_name("brightnessContrast", brightnessContrast);
|
|
icon.add_effect_with_name(
|
|
"desaturate",
|
|
new Clutter.DesaturateEffect({
|
|
factor: getSettings().get_int("icon-saturation") / 100,
|
|
})
|
|
);
|
|
}
|
|
|
|
setEffect(contrast, saturation, brightness) {
|
|
this._icons.forEach((icon) => {
|
|
let brightnessContrast = icon.get_effect("brightnessContrast");
|
|
brightnessContrast.set_contrast(contrast / 100);
|
|
brightnessContrast.set_brightness(brightness / 100);
|
|
|
|
let desaturate = icon.get_effect("desaturate");
|
|
desaturate.set_factor(saturation / 100);
|
|
});
|
|
}
|
|
}
|
|
);
|