"use strict"; /* exported init */ const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Main = imports.ui.main; const Panel = imports.ui.panel; const BoxOrderManager = Me.imports.extensionModules.BoxOrderManager; class Extension { constructor() { } enable() { this.settings = ExtensionUtils.getSettings(); this._boxOrderManager = new BoxOrderManager.BoxOrderManager(); // 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"); // Handle AppIndicators getting ready. this._boxOrderManager.connect("appIndicatorReady", () => { this._boxOrderManager.saveNewTopBarItems(); this.#orderTopBarItems("left"); this.#orderTopBarItems("center"); this.#orderTopBarItems("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._boxOrderManager.disconnectSignals(); this.settings = null; this._boxOrderManager = 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) { // 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. /// //////////////////////////////////////////////////////////////////////////// /** * 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); if (box === "right") { // If the target panel box is the right panel box, insert the // indicator container at index `-1`, which just adds it to the // end (correct order is ensured, since `validBoxOrder` is // sorted correctly and we're looping over it in order). // This way unaccounted-for indicator containers will be at the // left, which is preferred, since the box is logically // right-to-left. // The same applies for indicator containers, which are just // temporarily unaccounted for (like for indicator containers of // not yet ready app indicators), since them being at the right // for a probably temporary stay causes all the indicator // containers to shift. panelBox.insert_child_at_index(associatedIndicatorContainer, -1); } else { 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(); }