"use strict"; /* exported init */ const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Main = imports.ui.main; const Panel = imports.ui.panel; const AppIndicatorKStatusNotifierItemManager = Me.imports.extensionModules.AppIndicatorKStatusNotifierItemManager; const BoxOrderManager = Me.imports.extensionModules.BoxOrderManager; class Extension { constructor() { } enable() { this.settings = ExtensionUtils.getSettings(); // Create an instance of AppIndicatorKStatusNotifierItemManager to // handle AppIndicator/KStatusNotifierItem items. this._appIndicatorKStatusNotifierItemManager = new AppIndicatorKStatusNotifierItemManager.AppIndicatorKStatusNotifierItemManager(); this._boxOrderManager = new BoxOrderManager.BoxOrderManager(this._appIndicatorKStatusNotifierItemManager); // Stuff to do on startup(extension enable). this._boxOrderManager.saveNewTopBarItems(); this.#orderTopBarItems("left"); this.#orderTopBarItems("center"); this.#orderTopBarItems("right"); this.#overwritePanelAddToPanelBox(); // Handle changes of configured box orders. this._settingsHandlerIds = [ ]; const addConfiguredBoxOrderChangeHandler = (box) => { let handlerId = this.settings.connect(`changed::${box}-box-order`, () => { this.#orderTopBarItems(box); // For the case, where the currently saved box order is based on // a permutation of an outdated box order, save new top bar // items. this._boxOrderManager.saveNewTopBarItems(); }); this._settingsHandlerIds.push(handlerId); }; addConfiguredBoxOrderChangeHandler("left"); addConfiguredBoxOrderChangeHandler("center"); addConfiguredBoxOrderChangeHandler("right"); } disable() { // Revert the overwrite of `Panel._addToPanelBox`. Panel.Panel.prototype._addToPanelBox = Panel.Panel.prototype._originalAddToPanelBox; // Set `Panel._originalAddToPanelBox` to `undefined`. Panel._originalAddToPanelBox = undefined; // Disconnect signals. for (const handlerId of this._settingsHandlerIds) { this.settings.disconnect(handlerId); } this.settings = null; } //////////////////////////////////////////////////////////////////////////// /// Methods used on extension enable. /// //////////////////////////////////////////////////////////////////////////// /** * An object containing a position and box overwrite. * @typedef PositionAndBoxOverwrite * @property {Number} position - The position overwrite. * @property {string} box - The position box overwrite. */ /** * Overwrite `Panel._addToPanelBox` with a custom method, which simply calls * the original one and orders the top bar and handles new items afterwards. */ #overwritePanelAddToPanelBox() { // Add the original `Panel._addToPanelBox` method as // `Panel._originalAddToPanelBox`. Panel.Panel.prototype._originalAddToPanelBox = Panel.Panel.prototype._addToPanelBox; const orderTopBarAndHandleNewItems = () => { this.#orderTopBarItems("left"); this.#orderTopBarItems("center"); this.#orderTopBarItems("right"); this._boxOrderManager.saveNewTopBarItems(); }; // 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); orderTopBarAndHandleNewItems(); }; } //////////////////////////////////////////////////////////////////////////// /// Helper methods holding logic needed by other methods. /// //////////////////////////////////////////////////////////////////////////// /** * An object containing a box order for the left, center and right top bar * box. * @typedef {Object} BoxOrders * @property {string[]} left - The box order for the left top bar box. * @property {string[]} center - The box order for the center top bar box. * @property {string[]} right - The box order for the right top bar box. */ /** * This method orders the top bar items of the specified box according to * the configured box orders. * @param {string} box - The box to order. */ #orderTopBarItems(box) { // Get the valid box order. const validBoxOrder = this._boxOrderManager.createValidBoxOrder(box); // Get the relevant box of `Main.panel`. let panelBox; switch (box) { case "left": panelBox = Main.panel._leftBox; break; case "center": panelBox = Main.panel._centerBox; break; case "right": panelBox = Main.panel._rightBox; break; } /// Go through the items (or rather their roles) of the validBoxOrder /// and order the panelBox accordingly. for (let i = 0; i < validBoxOrder.length; i++) { const role = validBoxOrder[i]; // Get the indicator container associated with the current role. const associatedIndicatorContainer = Main.panel.statusArea[role].container; associatedIndicatorContainer.get_parent().remove_child(associatedIndicatorContainer); panelBox.insert_child_at_index(associatedIndicatorContainer, i); } // To handle the case, where the box order got set to a permutation // of an outdated box order, it would be wise, if the caller updated the // box order now to include the items present in the top bar. } } function init() { return new Extension(); }