237 lines
8.0 KiB
JavaScript
Executable File
237 lines
8.0 KiB
JavaScript
Executable File
import GLib from 'gi://GLib';
|
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
|
import * as Panel from 'resource:///org/gnome/shell/ui/panel.js';
|
|
import { Extension, gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js';
|
|
|
|
const _origAddToPanelBox = Panel.Panel.prototype._addToPanelBox;
|
|
|
|
let timeout_id = null;
|
|
let settings = null;
|
|
let order_arr_left = null;
|
|
let order_arr_center = null;
|
|
let order_arr_right = null;
|
|
let blacklist_array = null;
|
|
let order_arr = null;
|
|
|
|
export default class OrderIcons extends Extension {
|
|
enable() {
|
|
settings = this.getSettings()
|
|
order_arr_left = settings.get_value("order-icons-left").deep_unpack()
|
|
order_arr_center = settings.get_value("order-icons-center").deep_unpack()
|
|
order_arr_right = settings.get_value("order-icons-right").deep_unpack()
|
|
blacklist_array = settings.get_value("icons-blacklist").deep_unpack()
|
|
Panel.Panel.prototype._redrawIndicators = _redrawIndicators;
|
|
Panel.Panel.prototype._addToPanelBox = _addToPanelBox;
|
|
Main.panel._redrawIndicators();
|
|
this.settingsIDs = [];
|
|
this.settingsIDs.push(settings.connect('changed::order-icons-left', _ => {
|
|
Main.panel._redrawIndicators()
|
|
}));
|
|
this.settingsIDs.push(settings.connect('changed::order-icons-center', _ => {
|
|
Main.panel._redrawIndicators()
|
|
}));
|
|
this.settingsIDs.push(settings.connect('changed::order-icons-right', _ => {
|
|
Main.panel._redrawIndicators()
|
|
}));
|
|
this.settingsIDs.push(settings.connect('changed::icons-blacklist', _ => {
|
|
Main.panel._redrawIndicators()
|
|
}));
|
|
}
|
|
|
|
disable() {
|
|
Panel.Panel.prototype._redrawIndicators = undefined;
|
|
Panel.Panel.prototype._addToPanelBox = _origAddToPanelBox;
|
|
this.settingsIDs.forEach(id => settings.disconnect(id));
|
|
GLib.Source.remove(timeout_id);
|
|
timeout_id = null;
|
|
order_arr_left = null;
|
|
order_arr_center = null;
|
|
order_arr_right = null;
|
|
blacklist_array = null;
|
|
this.settingsIDs = null;
|
|
settings = null;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function _redrawIndicators() {
|
|
order_arr_left = settings.get_value("order-icons-left").deep_unpack()
|
|
order_arr_center = settings.get_value("order-icons-center").deep_unpack()
|
|
order_arr_right = settings.get_value("order-icons-right").deep_unpack()
|
|
blacklist_array = settings.get_value("icons-blacklist").deep_unpack()
|
|
for (const k in this.statusArea) {
|
|
const role = k;
|
|
const indicator = this.statusArea[k];
|
|
let box = indicator.get_parent().get_parent();
|
|
if (box == undefined) continue
|
|
this._addToPanelBox(role, indicator, 0, box)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
function _addToPanelBox(role, indicator, position, box) {
|
|
|
|
const container = indicator.container;
|
|
container.show();
|
|
const parent = container.get_parent();
|
|
if (parent) {
|
|
parent.remove_child(container);
|
|
}
|
|
|
|
this.statusArea[role] = indicator;
|
|
// not ideal, but due to recent changes in appindicator-extension we have to wait for the ID to become available
|
|
let in_blacklist = false;
|
|
waitForId(indicator, role).then(() => {
|
|
let position_corr = getRelativePosition(indicator, role, box.name, this.statusArea);
|
|
let testName = getTestName(indicator, role);
|
|
if (blacklist_array.includes(testName)) {
|
|
in_blacklist = true;
|
|
}
|
|
else {
|
|
setSettingValues(testName, box);
|
|
box.insert_child_at_index(container, position_corr ? position_corr : position);
|
|
}
|
|
}).catch((error) => { console.log(error) })
|
|
if (in_blacklist) {
|
|
delete this.statusArea[role];
|
|
}
|
|
else {
|
|
if (indicator.menu) {
|
|
this.menuManager.addMenu(indicator.menu);
|
|
}
|
|
const destroyId = indicator.connect('destroy', (emitter) => {
|
|
delete this.statusArea[role];
|
|
emitter.disconnect(destroyId);
|
|
});
|
|
indicator.connect('menu-set', this._onMenuSet.bind(this));
|
|
this._onMenuSet(indicator);
|
|
}
|
|
}
|
|
|
|
|
|
function setSettingValues(name, box) {
|
|
|
|
let index = null;
|
|
let index_arr = null;
|
|
|
|
if (box.name == "panelRight") {
|
|
index = getSettingsPosition(name, order_arr_right);
|
|
index_arr = order_arr_right.indexOf(name);
|
|
if (index_arr == -1) {
|
|
order_arr_right.splice(index, 0, name);
|
|
}
|
|
}
|
|
if (box.name == "panelCenter") {
|
|
index = getSettingsPosition(name, order_arr_center);
|
|
index_arr = order_arr_center.indexOf(name);
|
|
if (index_arr == -1) {
|
|
order_arr_center.splice(index, 0, name);
|
|
}
|
|
}
|
|
if (box.name == "panelLeft") {
|
|
index = getSettingsPosition(name, order_arr_left);
|
|
index_arr = order_arr_left.indexOf(name);
|
|
if (index_arr == -1) {
|
|
order_arr_left.splice(index, 0, name);
|
|
}
|
|
}
|
|
|
|
settings.set_value("order-icons-right", new GLib.Variant('as', order_arr_right))
|
|
settings.set_value("order-icons-center", new GLib.Variant('as', order_arr_center))
|
|
settings.set_value("order-icons-left", new GLib.Variant('as', order_arr_left))
|
|
}
|
|
|
|
|
|
function getRelativePosition(indicator, role, boxName, statusArea) {
|
|
const indicatorTestName = getTestName(indicator, role);
|
|
if (boxName == "panelRight")
|
|
order_arr = order_arr_right
|
|
else if (boxName == "panelCenter")
|
|
order_arr = order_arr_center
|
|
else if (boxName == "panelLeft")
|
|
order_arr = order_arr_left
|
|
const indicatorPosition = getSettingsPosition(indicatorTestName, order_arr);
|
|
|
|
let ctr = 0
|
|
for (const k in statusArea) {
|
|
if (k == role) continue
|
|
if (statusArea[k].get_parent().get_parent() != null && boxName === statusArea[k].get_parent().get_parent().get_name()) {
|
|
const toTest = getTestName(statusArea[k], k);
|
|
let setPosition = getSettingsPosition(toTest, order_arr);
|
|
if (setPosition == null) {
|
|
setPosition = 0;
|
|
}
|
|
if (setPosition < indicatorPosition) {
|
|
ctr = ctr + 1;
|
|
}
|
|
|
|
}
|
|
}
|
|
return ctr
|
|
}
|
|
|
|
|
|
function until(conditionFunction) {
|
|
const poll = resolve => {
|
|
if (conditionFunction()) {
|
|
resolve();
|
|
return GLib.G_SOURCE_REMOVE;
|
|
} else {
|
|
timeout_id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, _ => poll(resolve));
|
|
return GLib.G_SOURCE_REMOVE;
|
|
}
|
|
}
|
|
return new Promise(poll);
|
|
}
|
|
|
|
|
|
|
|
function getTestName(indicator, name) {
|
|
let toTest = name;
|
|
if (indicator._indicator) {
|
|
let id = indicator._indicator.id;
|
|
if (name.startsWith('appindicator-')) {
|
|
if (id.startsWith('chrome_status_icon')) {
|
|
// electron apps don't give a good ID with newer releases, so we have to revert to command line and try to get something useful
|
|
let commandLine = indicator._indicator._commandLine;
|
|
let commandLineSplit = commandLine.split('/');
|
|
toTest = commandLineSplit[commandLineSplit.length - 1];
|
|
}
|
|
else {
|
|
toTest = id;
|
|
}
|
|
}
|
|
}
|
|
if (toTest) {
|
|
const match = toTest.match(/appindicator-legacy:(.*?):/);
|
|
if (match && match.length > 1) {
|
|
return match[1];
|
|
}
|
|
if (toTest.includes('dropbox')) {
|
|
// dropbox needs special treatment because it appends the pid to the id.
|
|
// So we need to hardcode the name
|
|
return 'dropbox';
|
|
}
|
|
return toTest;
|
|
}
|
|
let ret = name.split("/")
|
|
return ret[ret.length - 1].replaceAll("_", "-")
|
|
}
|
|
|
|
async function waitForId(indicator, name) {
|
|
if (indicator._indicator && name.startsWith('appindicator-')) {
|
|
await until(_ => (indicator._indicator.id != undefined && indicator._indicator._commandLine != undefined));
|
|
}
|
|
return true
|
|
}
|
|
|
|
function getSettingsPosition(name, arr) {
|
|
if (arr == null) {
|
|
return 0;
|
|
}
|
|
let index = arr.indexOf(name);
|
|
return index != -1 ? index : 0;
|
|
}
|