Fix: Support AppIndicator/KStatusNotifierItem item addition again

Do this by not acting upon a new AppIndicator/KStatusNotifierItem item
immediately (as in trying to position it properly and maybe saving it to
settings), but rather act once the app indicators "ready" signal emits
by simply saving new items to settings and ordering the top bar boxes.
This commit is contained in:
Julian 2023-01-28 08:38:27 +01:00
parent 644656d93a
commit 843c5f0e1c
Signed by: julian
GPG Key ID: 094C2AC34192FA11
2 changed files with 61 additions and 11 deletions

View File

@ -43,6 +43,15 @@ class Extension {
addConfiguredBoxOrderChangeHandler("left");
addConfiguredBoxOrderChangeHandler("center");
addConfiguredBoxOrderChangeHandler("right");
// Handle AppIndicators getting ready.
this._boxOrderManager.connect("appIndicatorReady", () => {
this._boxOrderManager.saveNewTopBarItems();
this.#orderTopBarItems("left");
this.#orderTopBarItems("center");
this.#orderTopBarItems("right");
});
}
disable() {
@ -55,8 +64,10 @@ class Extension {
for (const handlerId of this._settingsHandlerIds) {
this.settings.disconnect(handlerId);
}
this._boxOrderManager.disconnectSignals();
this.settings = null;
this._boxOrderManager = null;
}
////////////////////////////////////////////////////////////////////////////
@ -88,12 +99,6 @@ class Extension {
// Overwrite `Panel._addToPanelBox`.
Panel.Panel.prototype._addToPanelBox = function (role, indicator, position, box) {
// Handle the case where the new item is a
// AppIndicator/KStatusNotifierItem.
if (role.startsWith("appindicator-")) {
// Just throw an error for now.
throw new Error("AppIndicator/KStatusNotifierItem addition is currently broken/not implemented.");
}
// Simply call the original `_addToPanelBox` and order the top bar
// and handle new items afterwards.
this._originalAddToPanelBox(role, indicator, position, box);

View File

@ -1,6 +1,8 @@
"use strict";
/* exported BoxOrderManager */
const GObject = imports.gi.GObject;
const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
@ -20,8 +22,15 @@ const Main = imports.ui.main;
* what is really useable by the other extension code.
* It's basically a heavy wrapper around the box orders stored in the settings.
*/
var BoxOrderManager = class BoxOrderManager {
constructor() {
var BoxOrderManager = GObject.registerClass({
Signals: {
"appIndicatorReady": {}
}
}, class BoxOrderManager extends GObject.Object {
constructor(params = {}) {
super(params);
this._appIndicatorReadyHandlerIdMap = new Map();
this._appIndicatorItemApplicationRoleMap = new Map();
this._settings = ExtensionUtils.getSettings();
@ -31,6 +40,10 @@ var BoxOrderManager = class BoxOrderManager {
* Handles an AppIndicator/KStatusNotifierItem item by associating the role
* of the given item with the application of the
* AppIndicator/KStatusNotifier item and returning a placeholder role.
* In the case, where the application can't be determined, this method
* throws an error. However it also makes sure that once the app indicators
* "ready" signal emits, this classes "appIndicatorReady" signal emits as
* well.
* @param {string} indicatorContainer - The container of the indicator of the
* AppIndicator/KStatusNotifierItem item.
* @param {string} role - The role of the AppIndicator/KStatusNotifierItem
@ -38,7 +51,18 @@ var BoxOrderManager = class BoxOrderManager {
* @returns {string} The placeholder role.
*/
#handleAppIndicatorItem(indicatorContainer, role) {
let application = indicatorContainer.get_child()._indicator.id;
const appIndicator = indicatorContainer.get_child()._indicator;
let application = appIndicator.id;
if (!application && this._appIndicatorReadyHandlerIdMap) {
const handlerId = appIndicator.connect("ready", () => {
this.emit("appIndicatorReady");
appIndicator.disconnect(handlerId);
this._appIndicatorReadyHandlerIdMap.delete(handlerId);
});
this._appIndicatorReadyHandlerIdMap.set(handlerId, appIndicator);
throw new Error("Application can't be determined.");
}
// Since the Dropbox client appends its PID to the id, drop the PID and
// the hyphen before it.
@ -101,6 +125,20 @@ var BoxOrderManager = class BoxOrderManager {
return resolvedBoxOrder;
}
/**
* Disconnects all signals (and disables future signal connection).
* This is typically used before nulling an instance of this class to make
* sure all signals are disconnected.
*/
disconnectSignals() {
for (const [handlerId, appIndicator] of this._appIndicatorReadyHandlerIdMap) {
if (handlerId && appIndicator) {
appIndicator.disconnect(handlerId);
}
}
this._appIndicatorReadyHandlerIdMap = null;
}
/**
* This method returns a valid box order for the given top bar box.
* This means it returns a box order, where only roles are included, which
@ -184,7 +222,14 @@ var BoxOrderManager = class BoxOrderManager {
// Handle an AppIndicator/KStatusNotifierItem item differently.
if (role.startsWith("appindicator-")) {
role = this.#handleAppIndicatorItem(indicatorContainer, role);
try {
role = this.#handleAppIndicatorItem(indicatorContainer, role);
} catch (e) {
if (e.message !== "Application can't be determined.") {
throw(e);
}
continue;
}
}
// Add the role to the box order, if it isn't in in one already.
@ -220,4 +265,4 @@ var BoxOrderManager = class BoxOrderManager {
saveBoxOrderToSettings(boxOrders.center, "center");
saveBoxOrderToSettings(boxOrders.right, "right");
}
};
});