diff --git a/.editorconfig b/.editorconfig index e948b32..572b7d2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,7 +6,7 @@ insert_final_newline = true indent_style = space charset = utf-8 -[*.{js,ts,json}] +[*.{js,json}] indent_size = 4 trim_trailing_whitespace = true diff --git a/.eslintignore b/.eslintignore index 524273b..2af37ff 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,7 +1 @@ -/docs/panel_master_2021-04-21.js -/docs/panel_42.5_2022-10-22.js -/docs/panel_43.2_2023-01-24.js -/docs/panel_45.0_2023-09-26.js -/docs/panel_46.4_2024-09-11.js -/docs/panel_47.rc_2024-09-12.js -/docs/panel_48.2_2025-06-08.js +/docs/panel.js diff --git a/.eslintrc.yml b/.eslintrc.yml index caf7992..12f1a2e 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -2,8 +2,7 @@ env: es2021: true extends: 'eslint:recommended' parserOptions: - ecmaVersion: 2022 - sourceType: module + ecmaVersion: 12 rules: indent: - error @@ -18,43 +17,5 @@ rules: semi: - error - always - no-unused-vars: - - error - - argsIgnorePattern: "^_" - curly: - - error - - all - brace-style: - - error - - 1tbs - # Rules from GJS Style Guide regarding whitespace. - # See here: https://gjs.guide/guides/gjs/style-guide.html#whitespace - func-call-spacing: - - error - - never - array-bracket-spacing: - - error - - never - space-before-function-paren: - - error - - never - space-before-blocks: - - error - - always - key-spacing: - - error - - beforeColon: false - afterColon: true - mode: strict - object-curly-spacing: - - error - - always - comma-dangle: - - error - - arrays: always-multiline - objects: always-multiline - imports: always-multiline - exports: always-multiline - functions: never globals: - log: readonly + imports: readonly diff --git a/.gitignore b/.gitignore index 9bb16b5..eb99e38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /node_modules/ -/dist/ -top-bar-organizer@julian.gse.jsts.xyz.shell-extension.zip +gschemas.compiled +top-bar-organizer@julian.gse.jsts.xyz.zip diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md deleted file mode 100644 index 2caef4d..0000000 --- a/.gitlab/issue_templates/Bug.md +++ /dev/null @@ -1,49 +0,0 @@ -### Bug Description - - - -### Steps to Reproduce - - - -### What behavior did you observe? - - - -### What behavior did you expect? - - - -### Further Information - - - - - -### System Information - -- Operating System: -- GNOME Version: - -Enabled Extensions: - - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3df8919..72a8f7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,22 +9,22 @@ For code of this repo in `.js` files, stick to a textwidth of 80. The commit message format is as follows: ``` -tag: short description +Tag: Short description Longer description here if necessary ``` -The `tag` should be one of the following: +The `Tag` should be one of the following: -- `fix` - for a bug fix. -- `update` - for a backwards compatible enhancement. -- `feature` (formerly also `New`) - for a new feature. -- `breaking` - for a backwards-incompatible enhancement or feature. -- `perf` - for a code change that improves performance. -- `refactor` - for a code change that neither fixes a bug nor adds a feature (nor is `perf`). -- `build` - for changes that affect the build system or external dependencies. -- `test` - for adding or correcting tests. -- `docs` - for changes to documentation only. -- `other` - for anything that isn't covered by the tags above. +- `Fix` - for a bug fix. +- `Update` - for a backwards compatible enhancement. +- `Feature` (formerly also `New`) - for a new feature. +- `Breaking` - for a backwards-incompatible enhancement or feature. +- `Perf` - for a code change that improves performance. +- `Refactor` - for a code change that neither fixes a bug nor adds a feature (nor is `Perf`). +- `Build` - for changes that affect the build system or external dependencies. +- `Test` - for adding or correcting tests. +- `Docs` - for changes to documentation only. +- `Other` - for anything that isn't covered by the tags above. Those tags are an adapted version of the tags eslint () and of the tags Angular () uses. diff --git a/README.md b/README.md deleted file mode 100644 index 91ea15c..0000000 --- a/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Top Bar Organizer - -![Screenshot of GNOME Shell 43 with Top Bar Organizer v6 running and its preferences open. The GNOME Shell top bar items aren't all in their default location.](./res/Screenshot%20of%20GNOME%20Shell%2043%20with%20Top%20Bar%20Organizer%20v6%20and%20its%20preferences%20in%20light%20theme%202023-01-30.jpg) - -Top Bar Organizer allows you to organize the items of the GNOME Shell top (menu)bar. - -## Installation - -The extension is available on the [GNOME Extensions website](https://extensions.gnome.org/extension/4356/top-bar-organizer/). -Or you can also manually install a release from the [releases page](https://gitlab.gnome.org/june/top-bar-organizer/-/releases). - -There's also a community-maintained [AUR package](https://aur.archlinux.org/packages/gnome-shell-extension-top-bar-organizer) available. diff --git a/ambient.d.ts b/ambient.d.ts deleted file mode 100644 index 842985c..0000000 --- a/ambient.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import "@girs/gjs" -import "@girs/gjs/dom" -import "@girs/gnome-shell/ambient" -import "@girs/gnome-shell/extensions/global" diff --git a/data/css/prefs.css b/data/css/prefs.css deleted file mode 100644 index 5cafea5..0000000 --- a/data/css/prefs.css +++ /dev/null @@ -1,9 +0,0 @@ -/* Taken from: https://gitlab.gnome.org/GNOME/gnome-control-center/-/blob/43.5/shell/style.css */ - -.drag-handle { - color: alpha(@theme_fg_color, 0.4); -} - -.drag-handle:backdrop { - color: alpha(@theme_unfocused_fg_color, 0.4); -} diff --git a/data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml b/data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml deleted file mode 100644 index 8b143e7..0000000 --- a/data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - Order of items in the left box of the top bar. - [] - - - Order of items in the center box of the top bar. - [] - - - Order of items in the right box of the top bar. - [] - - - Top bar items to (forcefully) hide. - [] - - - Top bar items to (forcefully) show. - [] - - - diff --git a/data/ui/prefs-box-order-item-options-dialog.ui b/data/ui/prefs-box-order-item-options-dialog.ui deleted file mode 100644 index d953d24..0000000 --- a/data/ui/prefs-box-order-item-options-dialog.ui +++ /dev/null @@ -1,38 +0,0 @@ - - - - diff --git a/data/ui/prefs-box-order-item-row.ui b/data/ui/prefs-box-order-item-row.ui deleted file mode 100644 index dd06b32..0000000 --- a/data/ui/prefs-box-order-item-row.ui +++ /dev/null @@ -1,62 +0,0 @@ - - - - -
- - Move Up - row.move-up - - - Move Down - row.move-down - -
-
- - Options - row.options - -
-
- - Forget - row.forget - -
-
-
diff --git a/data/ui/prefs-box-order-list-box.ui b/data/ui/prefs-box-order-list-box.ui deleted file mode 100644 index 46c77d2..0000000 --- a/data/ui/prefs-box-order-list-box.ui +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/data/ui/prefs-page.ui b/data/ui/prefs-page.ui deleted file mode 100644 index 7eca8d0..0000000 --- a/data/ui/prefs-page.ui +++ /dev/null @@ -1,52 +0,0 @@ - - - - diff --git a/docs/Creating_a_New_Release.md b/docs/Creating_a_New_Release.md deleted file mode 100644 index 049afd2..0000000 --- a/docs/Creating_a_New_Release.md +++ /dev/null @@ -1,51 +0,0 @@ -# Creating a Release - -## Create a Tag - -To create a new tag, do the following: - -1. Fill out `git_annotated_tag_template`. -2. Run the following command to tag the current commit with `vX`: - - ``` - git tag -a -F git_annotated_tag_template -s --cleanup=verbatim vX - ``` - -3. Restore `git_annotated_tag_template` to its original state: - - ``` - git restore git_annotated_tag_template - ``` - -4. Push the tag: - - ``` - git push --tags - ``` - -## Build a Release-ZIP - -1. Build the release-ZIP: - - ``` - ./package.sh - ``` - -2. Name the release-ZIP after the current version: - - ``` - mv top-bar-organizer@julian.gse.jsts.xyz.shell-extension.zip top-bar-organizer@julian.gse.jsts.xyz.shell-extension_vX.zip - ``` - -## Create a GitLab Release - -1. Go to the [Releases section of the repo](https://gitlab.gnome.org/june/top-bar-organizer/-/releases) and click on the "New Release" button. -2. Select the corresponding tag created earlier. -3. Name the release "Top Bar Organizer vX". -4. Copy the [release notes template](./release_notes_template.md) and fill it out. -5. Drop the release-ZIP created in the previous step at the end of the release notes. -6. Create the release. - -## Uploading to the GNOME Extensions Website - -1. Go to the [upload page of the GNOME extensions website](https://extensions.gnome.org/upload/) and upload the release-ZIP. diff --git a/docs/Gnome_Shell_Extensions_Development_VM.md b/docs/Gnome_Shell_Extensions_Development_VM.md deleted file mode 100644 index 76ca83e..0000000 --- a/docs/Gnome_Shell_Extensions_Development_VM.md +++ /dev/null @@ -1,91 +0,0 @@ -# Gnome Shell Extensions Development VM - -This document holds some setup instructions and tips for getting the most of your Gnome Shell Extensions Development VM. - -Note on commands in this document: - -- `$` indicates that a command should be run as your normal user. -- `#` indicates that a command should be run as root. - -## GTKInspector - -Enable GTKInspector by running the following command: - -``` -$ gsettings set org.gtk.Settings.Debug enable-inspector-keybinding true -``` - -Now you can inspect GTK Apps by pressing `Ctrl + Shift + D`. - -### Links and Sources - -- - -## Looking Glass - -Looking Glass is Gnome Shells integrated debugger and inspector tool. -You can use it by pressing `Alt + F2`, typing `lg` and pressing Enter. - -If you want to exit Looking Glass, press `Esc` in the Evaluator pane. - -### Links and Sources - -- - -## Sharing a Directory Between the Host and the Guest - -To share a directory between the host and the Gnome Shell Extensions Development VM, do the following. -Note that this guide assumes you're using Virtual Machine Manager (virt-manager) and at least v4.0.0 of it. - -1. Shut down the VM. -2. Go to your VMs hardware details and then to `Memory`. - Check the `Enable shared memory` checkbox there. -3. Go to your VMs hardware details and then to `Add Hardware -> Filesystem`. - Then select `virtiofs` for the driver and an appropriate source path (like `/home/user/gse_dev_vm_shared_folder`) and target path (like `shared_folder`). - Finally click on `Finish`. -4. Power on the VM. -5. Create a mountpoint by running: - - ``` - # mkdir /mnt/shared_host_folder - ``` - -6. Edit `/etc/fstab` and add the following line at the end: - - ``` - TARGET_PATH_YOU_SET_IN_VIRT_MANAGER /mnt/shared_host_folder virtiofs rw,noatime,_netdev 0 0 - ``` - -7. Reboot the VM. - -Now you have a shared folder between your host and your VM, which you can access on your host at the specified source path and in the VM at `/mnt/shared_host_folder`. - -### Links and Sources - -- -- -- - -## Enabling Automatic Login - -Enabling Automatic Login in the Gnome Settings under `Users -> Unlock... -> Automatic Login` saves you from inserting the VM users password after VM startups. - -## Disabling Automatic Screen Lock - -Disabling Automatic Screen Lock in the Gnome Settings under `Privacy -> Screen Lock -> Automatic Screen Lock` saves you from Gnome locking the VM and you having to insert the VM users password. - -## Running Applications Providing Tray Icons Automatically on Startup - -Especially for the development of this extension it is useful to have some applications, which provide tray icons (e.g. Element, Telegram) run automatically on startup. -To make this happen (nicely), you need to do the following: - -1. Make sure the applications get started automatically on log in by using Gnome Tweaks, going to `Startup Applications` and adding them there. -2. If you're using Automatic Login, use the Password and Keys application (seahorse) to set the Login keyrings password to a blank one. - Do this to avoid the Login keyring password prompt after log in, which is triggered by some applications like Element. - Note that this leaves the keyring unencrypted, but since you're in a Dev VM, no important things should be stored in there anyway (hopefully). -3. Use the "Auto Move Windows" extension to move the windows of your applications to a different workspace, so your main one doesn't get cluttered. -4. To see tray icons, install the "AppIndicator and KStatusNotifierItem Support" extension. - -### Links and Sources - -- diff --git a/docs/panel_master_2021-04-21.js b/docs/panel.js similarity index 100% rename from docs/panel_master_2021-04-21.js rename to docs/panel.js diff --git a/docs/panel_42.5_2022-10-22.js b/docs/panel_42.5_2022-10-22.js deleted file mode 100644 index 9c96e7a..0000000 --- a/docs/panel_42.5_2022-10-22.js +++ /dev/null @@ -1,318 +0,0 @@ -// My annotated and cut down `js/ui/panel.js` from gnome-shell/42.5. -// All annotations are what I guessed, interpreted and copied while reading the -// code and comparing to other `panel.js` versions and might be wrong. They are -// prefixed with "Annotation:" to indicate that they're my comments, not -// comments that orginally existed. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/42.5/js/ui/panel.js -// On: 2022-10-22 -// License: This code is licensed under GPLv2. - -// Parts taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/42.5/js/ui/sessionMode.js -// On: 2022-10-22 -// License: This code is licensed under GPLv2. - -// I'm using the word "item" to refer to the thing, which gets added to the top -// (menu)bar / panel, where an item has a role/name and an indicator. - - -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported Panel */ - -const { Atk, Clutter, GLib, GObject, Meta, Shell, St } = imports.gi; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. -const CtrlAltTab = imports.ui.ctrlAltTab; -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. -const PopupMenu = imports.ui.popupMenu; -const PanelMenu = imports.ui.panelMenu; -const Main = imports.ui.main; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -// Compared to panel_master_2021-04-21.js: -// The "screenRecording" entry got added. -const PANEL_ITEM_IMPLEMENTATIONS = { - 'activities': ActivitiesButton, - 'aggregateMenu': AggregateMenu, - 'appMenu': AppMenuButton, - 'dateMenu': imports.ui.dateMenu.DateMenuButton, - 'a11y': imports.ui.status.accessibility.ATIndicator, - 'keyboard': imports.ui.status.keyboard.InputSourceIndicator, - 'dwellClick': imports.ui.status.dwellClick.DwellClickIndicator, - 'screenRecording': imports.ui.status.remoteAccess.ScreenRecordingIndicator, -}; - -var Panel = GObject.registerClass( -class Panel extends St.Widget { - // Annotation: Initializes the top (menu)bar / panel. - // Does relevant stuff like: - // - Defining `this._leftBox`, `this._centerBox` and `this._rightBox`. - // - Finally calling `this._updatePanel()`. - // Compared to panel_master_2021-04-21.js: - // Didn't really change, except for two events getting connected, which we - // probably don't care about, the corners being gone and some reformatting. - _init() { - super._init({ - name: 'panel', - reactive: true, - }); - - this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); - - this._sessionStyle = null; - - this.statusArea = {}; - - this.menuManager = new PopupMenu.PopupMenuManager(this); - - this._leftBox = new St.BoxLayout({ name: 'panelLeft' }); - this.add_child(this._leftBox); - this._centerBox = new St.BoxLayout({ name: 'panelCenter' }); - this.add_child(this._centerBox); - this._rightBox = new St.BoxLayout({ name: 'panelRight' }); - this.add_child(this._rightBox); - - this.connect('button-press-event', this._onButtonPress.bind(this)); - this.connect('touch-event', this._onTouchEvent.bind(this)); - - Main.overview.connect('showing', () => { - this.add_style_pseudo_class('overview'); - }); - Main.overview.connect('hiding', () => { - this.remove_style_pseudo_class('overview'); - }); - - Main.layoutManager.panelBox.add(this); - Main.ctrlAltTabManager.addGroup(this, _("Top Bar"), 'focus-top-bar-symbolic', - { sortGroup: CtrlAltTab.SortGroup.TOP }); - - Main.sessionMode.connect('updated', this._updatePanel.bind(this)); - - global.display.connect('workareas-changed', () => this.queue_relayout()); - this._updatePanel(); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. - - // Annotation: Gets called by `this._init()` to populate the top (menu)bar / - // panel initially. - // - // It does the following relevant stuff: - // - Calls `this._hideIndicators()` - // - Calls `this._updateBox()` for `this._leftBox`, `this._centerBox` and - // `this._rightBox` with `panel.left`, `panel.center` and `panel.right` to - // populate the boxes with items defined in `panel.left`, `panel.center` - // and `panel.right`. - // - // `panel.left`, `panel.center` and `panel.right` get set via the line - // `let panel = Main.sessionMode.panel`, which uses the pnale of Mains - // (`js/ui/main.js`) instance of SessionMode (`js/ui/sessionMode.js`). - // - // And in `js/ui/sessionMode.js` (42.5, 2022-10-22) you have different - // modes with different panel configuration. For example the "user" mode - // with: - // ``` - // panel: { - // left: ['activities', 'appMenu'], - // center: ['dateMenu'], - // right: ['screenRecording', 'dwellClick', 'a11y', 'keyboard', 'aggregateMenu'], - // }, - // ``` - // - // This way this function populates the top (menu)bar / panel with the - // default stuff you see on a fresh Gnome. - // - // Compared to panel_master_2021-04-21.js: - // Corner-related code is gone and some function name casing got changed. - _updatePanel() { - let panel = Main.sessionMode.panel; - this._hideIndicators(); - this._updateBox(panel.left, this._leftBox); - this._updateBox(panel.center, this._centerBox); - this._updateBox(panel.right, this._rightBox); - - if (panel.left.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; - else if (panel.right.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; - // Default to center if there is no dateMenu - else - Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; - - if (this._sessionStyle) - this.remove_style_class_name(this._sessionStyle); - - this._sessionStyle = Main.sessionMode.panelStyle; - if (this._sessionStyle) - this.add_style_class_name(this._sessionStyle); - } - - // Annotation: This function hides all items, which are in the top (menu)bar - // panel and in PANEL_ITEM_IMPLEMENTATIONS. - // - // Compared to panel_master_2021-04-21.js: Nothing changed. - _hideIndicators() { - for (let role in PANEL_ITEM_IMPLEMENTATIONS) { - let indicator = this.statusArea[role]; - if (!indicator) - continue; - indicator.container.hide(); - } - } - - // Annotation: This function takes a role (of an item) and returns a - // corresponding indicator, if either of two things are true: - // - The indicator is already in `this.statusArea`. - // Then it just returns the indicator by using `this.statusArea`. - // - The role is in PANEL_ITEM_IMPLEMENTATIONS. - // Then it creates a new indicator, adds it to `this.statusArea` and - // returns it. - // - // Compared to panel_master_2021-04-21.js: Nothing changed. - _ensureIndicator(role) { - let indicator = this.statusArea[role]; - if (!indicator) { - let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; - if (!constructor) { - // This icon is not implemented (this is a bug) - return null; - } - indicator = new constructor(this); - this.statusArea[role] = indicator; - } - return indicator; - } - - // Annotation: This function takes a list of items (or rather their roles) - // and adds the indicators of those items to a box (like `this._leftBox`) - // using `this._ensureIndicator()` to get the indicator corresponding to the - // given role. - // So only items with roles `this._ensureIndicator()` knows, get added. - // - // Compared to panel_master_2021-04-21.js: Nothing changed. - _updateBox(elements, box) { - let nChildren = box.get_n_children(); - - for (let i = 0; i < elements.length; i++) { - let role = elements[i]; - let indicator = this._ensureIndicator(role); - if (indicator == null) - continue; - - this._addToPanelBox(role, indicator, i + nChildren, box); - } - } - - // Annotation: This function adds the given item to the specified top - // (menu)bar / panel box and connects to "destroy" and "menu-set" events. - // - // It takes the following arguments: - // - role: The name of the item to add. - // - indicator: The indicator of the item to add. - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - `this._leftBox` - // - `this._centerBox` - // - `this._rightBox` - // - // Compared to panel_master_2021-04-21.js: Nothing changed. - _addToPanelBox(role, indicator, position, box) { - let container = indicator.container; - container.show(); - - let parent = container.get_parent(); - if (parent) - parent.remove_actor(container); - - - box.insert_child_at_index(container, position); - if (indicator.menu) - this.menuManager.addMenu(indicator.menu); - this.statusArea[role] = indicator; - let destroyId = indicator.connect('destroy', emitter => { - delete this.statusArea[role]; - emitter.disconnect(destroyId); - }); - indicator.connect('menu-set', this._onMenuSet.bind(this)); - this._onMenuSet(indicator); - } - - // Annotation: This function allows you to add an item to the top (menu)bar - // / panel. - // While per default it adds the item to the status area (the right box of - // the top bar), you can specify the box and add the item to any of the - // three boxes of the top bar. - // To add an item to the top bar, you need to give its role and indicator. - // - // This function takes the following arguments: - // - role: A name for the item to add. - // - indicator: The indicator for the item to add (must be an instance of - // PanelMenu.Button). - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - "left": referring to `this._leftBox` - // - "center": referring to `this._centerBox` - // - "right": referring to `this._rightBox` - // These boxes are what you see in the top bar as the left, right and - // center sections. - // - // Finally this function just calls `this._addToPanelBox()` for the actual - // work, so it basically just makes sure the input to - // `this._addToPanelBox()` is correct. - // - // Compared to panel_master_2021-04-21.js: - // Some syntax changes (usage of syntactic sugar). - addToStatusArea(role, indicator, position, box) { - if (this.statusArea[role]) - throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); - - if (!(indicator instanceof PanelMenu.Button)) - throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); - - position ??= 0; - let boxes = { - left: this._leftBox, - center: this._centerBox, - right: this._rightBox, - }; - let boxContainer = boxes[box] || this._rightBox; - this.statusArea[role] = indicator; - this._addToPanelBox(role, indicator, position, boxContainer); - return indicator; - } - - // Annotation: - // Compared to panel_master_2021-04-21.js: - // `_addStyleClassName(className)` and `_removeStyleClassName(className)` - // are gone, since they apparently only existed to handle stuff related to - // the corners, which are gone. - - _onMenuSet(indicator) { - if (!indicator.menu || indicator.menu._openChangedId) - return; - - indicator.menu._openChangedId = indicator.menu.connect('open-state-changed', - (menu, isOpen) => { - let boxAlignment; - if (this._leftBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.START; - else if (this._centerBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.CENTER; - else if (this._rightBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.END; - - if (boxAlignment == Main.messageTray.bannerAlignment) - Main.messageTray.bannerBlocked = isOpen; - }); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. -}); diff --git a/docs/panel_43.2_2023-01-24.js b/docs/panel_43.2_2023-01-24.js deleted file mode 100644 index 85f0a1c..0000000 --- a/docs/panel_43.2_2023-01-24.js +++ /dev/null @@ -1,317 +0,0 @@ -// My annotated and cut down `js/ui/panel.js` from gnome-shell/43.2. -// All annotations are what I guessed, interpreted and copied while reading the -// code and comparing to other `panel.js` versions and might be wrong. They are -// prefixed with "Annotation:" to indicate that they're my comments, not -// comments that orginally existed. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/43.2/js/ui/panel.js -// On: 2023-01-24 -// License: This code is licensed under GPLv2. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/43.2/js/ui/sessionMode.js -// On: 2023-01-24 -// License: This code is licensed under GPLv2. - -// I'm using the word "item" to refer to the thing, which gets added to the top -// (menu)bar / panel, where an item has a role/name and an indicator. - - -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported Panel */ - -const { Atk, Clutter, GLib, GObject, Meta, Shell, St } = imports.gi; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. -const CtrlAltTab = imports.ui.ctrlAltTab; -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. -const PopupMenu = imports.ui.popupMenu; -const PanelMenu = imports.ui.panelMenu; -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. -const Main = imports.ui.main; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -// Compared to panel_42.5_2022-10-22.js: -// "aggregateMenu" is gone with "quickSettings" replacing it. -// "screenSharing" got added. -const PANEL_ITEM_IMPLEMENTATIONS = { - 'activities': ActivitiesButton, - 'appMenu': AppMenuButton, - 'quickSettings': QuickSettings, - 'dateMenu': imports.ui.dateMenu.DateMenuButton, - 'a11y': imports.ui.status.accessibility.ATIndicator, - 'keyboard': imports.ui.status.keyboard.InputSourceIndicator, - 'dwellClick': imports.ui.status.dwellClick.DwellClickIndicator, - 'screenRecording': imports.ui.status.remoteAccess.ScreenRecordingIndicator, - 'screenSharing': imports.ui.status.remoteAccess.ScreenSharingIndicator, -}; - -var Panel = GObject.registerClass( -class Panel extends St.Widget { - // Annotation: Initializes the top (menu)bar / panel. - // Does relevant stuff like: - // - Defining `this._leftBox`, `this._centerBox` and `this._rightBox`. - // - Finally calling `this._updatePanel()`. - // Compared to panel_42.5_2022-10-22.js: Nothing changed. - _init() { - super._init({ - name: 'panel', - reactive: true, - }); - - this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); - - this._sessionStyle = null; - - this.statusArea = {}; - - this.menuManager = new PopupMenu.PopupMenuManager(this); - - this._leftBox = new St.BoxLayout({ name: 'panelLeft' }); - this.add_child(this._leftBox); - this._centerBox = new St.BoxLayout({ name: 'panelCenter' }); - this.add_child(this._centerBox); - this._rightBox = new St.BoxLayout({ name: 'panelRight' }); - this.add_child(this._rightBox); - - this.connect('button-press-event', this._onButtonPress.bind(this)); - this.connect('touch-event', this._onTouchEvent.bind(this)); - - Main.overview.connect('showing', () => { - this.add_style_pseudo_class('overview'); - }); - Main.overview.connect('hiding', () => { - this.remove_style_pseudo_class('overview'); - }); - - Main.layoutManager.panelBox.add(this); - Main.ctrlAltTabManager.addGroup(this, _("Top Bar"), 'focus-top-bar-symbolic', - { sortGroup: CtrlAltTab.SortGroup.TOP }); - - Main.sessionMode.connect('updated', this._updatePanel.bind(this)); - - global.display.connect('workareas-changed', () => this.queue_relayout()); - this._updatePanel(); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. - - // Annotation: Gets called by `this._init()` to populate the top (menu)bar / - // panel initially. - // - // It does the following relevant stuff: - // - Calls `this._hideIndicators()` - // - Calls `this._updateBox()` for `this._leftBox`, `this._centerBox` and - // `this._rightBox` with `panel.left`, `panel.center` and `panel.right` to - // populate the boxes with items defined in `panel.left`, `panel.center` - // and `panel.right`. - // - // `panel.left`, `panel.center` and `panel.right` get set via the line - // `let panel = Main.sessionMode.panel`, which uses the panel of Mains - // (`js/ui/main.js`) instance of SessionMode (`js/ui/sessionMode.js`). - // - // And in `js/ui/sessionMode.js` (43.2, 2023-01-24) you have different - // modes with different panel configuration. For example the "user" mode - // with: - // ``` - // panel: { - // left: ['activities', 'appMenu'], - // center: ['dateMenu'], - // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], - // }, - // ``` - // - // This way this function populates the top (menu)bar / panel with the - // default stuff you see on a fresh Gnome. - // - // Compared to panel_42.5_2022-10-22.js: Nothing changed. - _updatePanel() { - let panel = Main.sessionMode.panel; - this._hideIndicators(); - this._updateBox(panel.left, this._leftBox); - this._updateBox(panel.center, this._centerBox); - this._updateBox(panel.right, this._rightBox); - - if (panel.left.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; - else if (panel.right.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; - // Default to center if there is no dateMenu - else - Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; - - if (this._sessionStyle) - this.remove_style_class_name(this._sessionStyle); - - this._sessionStyle = Main.sessionMode.panelStyle; - if (this._sessionStyle) - this.add_style_class_name(this._sessionStyle); - } - - // Annotation: This function hides all items, which are in the top (menu)bar - // panel and in PANEL_ITEM_IMPLEMENTATIONS. - // - // Compared to panel_42.5_2022-10-22.js: Nothing changed. - _hideIndicators() { - for (let role in PANEL_ITEM_IMPLEMENTATIONS) { - let indicator = this.statusArea[role]; - if (!indicator) - continue; - indicator.container.hide(); - } - } - - // Annotation: This function takes a role (of an item) and returns a - // corresponding indicator, if either of two things are true: - // - The indicator is already in `this.statusArea`. - // Then it just returns the indicator by using `this.statusArea`. - // - The role is in PANEL_ITEM_IMPLEMENTATIONS. - // Then it creates a new indicator, adds it to `this.statusArea` and - // returns it. - // - // Compared to panel_42.5_2022-10-22.js: Nothing changed. - _ensureIndicator(role) { - let indicator = this.statusArea[role]; - if (!indicator) { - let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; - if (!constructor) { - // This icon is not implemented (this is a bug) - return null; - } - indicator = new constructor(this); - this.statusArea[role] = indicator; - } - return indicator; - } - - // Annotation: This function takes a list of items (or rather their roles) - // and adds the indicators of those items to a box (like `this._leftBox`) - // using `this._ensureIndicator()` to get the indicator corresponding to the - // given role. - // So only items with roles `this._ensureIndicator()` knows, get added. - // - // Compared to panel_42.5_2022-10-22.js: Nothing changed. - _updateBox(elements, box) { - let nChildren = box.get_n_children(); - - for (let i = 0; i < elements.length; i++) { - let role = elements[i]; - let indicator = this._ensureIndicator(role); - if (indicator == null) - continue; - - this._addToPanelBox(role, indicator, i + nChildren, box); - } - } - - // Annotation: This function adds the given item to the specified top - // (menu)bar / panel box and connects to "destroy" and "menu-set" events. - // - // It takes the following arguments: - // - role: The name of the item to add. - // - indicator: The indicator of the item to add. - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - `this._leftBox` - // - `this._centerBox` - // - `this._rightBox` - // - // Compared to panel_42.5_2022-10-22.js: - // Code for adding indicator menu to a menu manager got moved to - // `_onMenuSet` method without the if clause. - _addToPanelBox(role, indicator, position, box) { - let container = indicator.container; - container.show(); - - let parent = container.get_parent(); - if (parent) - parent.remove_actor(container); - - - box.insert_child_at_index(container, position); - this.statusArea[role] = indicator; - let destroyId = indicator.connect('destroy', emitter => { - delete this.statusArea[role]; - emitter.disconnect(destroyId); - }); - indicator.connect('menu-set', this._onMenuSet.bind(this)); - this._onMenuSet(indicator); - } - - // Annotation: This function allows you to add an item to the top (menu)bar - // / panel. - // While per default it adds the item to the status area (the right box of - // the top bar), you can specify the box and add the item to any of the - // three boxes of the top bar. - // To add an item to the top bar, you need to give its role and indicator. - // - // This function takes the following arguments: - // - role: A name for the item to add. - // - indicator: The indicator for the item to add (must be an instance of - // PanelMenu.Button). - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - "left": referring to `this._leftBox` - // - "center": referring to `this._centerBox` - // - "right": referring to `this._rightBox` - // These boxes are what you see in the top bar as the left, right and - // center sections. - // - // Finally this function just calls `this._addToPanelBox()` for the actual - // work, so it basically just makes sure the input to - // `this._addToPanelBox()` is correct. - // - // Compared to panel_42.5_2022-10-22.js: Nothing changed. - addToStatusArea(role, indicator, position, box) { - if (this.statusArea[role]) - throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); - - if (!(indicator instanceof PanelMenu.Button)) - throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); - - position ??= 0; - let boxes = { - left: this._leftBox, - center: this._centerBox, - right: this._rightBox, - }; - let boxContainer = boxes[box] || this._rightBox; - this.statusArea[role] = indicator; - this._addToPanelBox(role, indicator, position, boxContainer); - return indicator; - } - - // Compared to panel_42.5_2022-10-22.js: - // Code for adding indicator menu to a menu manager got moved to here from - // `_addToPanelBox` method without the if clause. - _onMenuSet(indicator) { - if (!indicator.menu || indicator.menu._openChangedId) - return; - - this.menuManager.addMenu(indicator.menu); - - indicator.menu._openChangedId = indicator.menu.connect('open-state-changed', - (menu, isOpen) => { - let boxAlignment; - if (this._leftBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.START; - else if (this._centerBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.CENTER; - else if (this._rightBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.END; - - if (boxAlignment == Main.messageTray.bannerAlignment) - Main.messageTray.bannerBlocked = isOpen; - }); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. -}); diff --git a/docs/panel_45.0_2023-09-26.js b/docs/panel_45.0_2023-09-26.js deleted file mode 100644 index bb44a90..0000000 --- a/docs/panel_45.0_2023-09-26.js +++ /dev/null @@ -1,344 +0,0 @@ -// My annotated and cut down `js/ui/panel.js` from gnome-shell/45.0. -// All annotations are what I guessed, interpreted and copied while reading the -// code and comparing to other `panel.js` versions and might be wrong. They are -// prefixed with "Annotation:" to indicate that they're my comments, not -// comments that orginally existed. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/45.0/js/ui/panel.js -// On: 2023-09-26 -// License: This code is licensed under GPLv2. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/45.0/js/ui/sessionMode.js -// On: 2023-09-26 -// License: This code is licensed under GPLv2. - -// I'm using the word "item" to refer to the thing, which gets added to the top -// (menu)bar / panel, where an item has a role/name and an indicator. - - -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import Clutter from 'gi://Clutter'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import GObject from 'gi://GObject'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import St from 'gi://St'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as CtrlAltTab from './ctrlAltTab.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as PopupMenu from './popupMenu.js'; -import * as PanelMenu from './panelMenu.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as Main from './main.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import {DateMenuButton} from './dateMenu.js'; -import {ATIndicator} from './status/accessibility.js'; -import {InputSourceIndicator} from './status/keyboard.js'; -import {DwellClickIndicator} from './status/dwellClick.js'; -import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. -// Of note (for PANEL_ITEM_IMPLEMENTATIONS): -// const AppMenuButton = [...] -// const ActivitiesButton = [...] -// const QuickSettings = [...] - -const PANEL_ITEM_IMPLEMENTATIONS = { - 'activities': ActivitiesButton, - 'appMenu': AppMenuButton, - 'quickSettings': QuickSettings, - 'dateMenu': DateMenuButton, - 'a11y': ATIndicator, - 'keyboard': InputSourceIndicator, - 'dwellClick': DwellClickIndicator, - 'screenRecording': ScreenRecordingIndicator, - 'screenSharing': ScreenSharingIndicator, -}; - -// Annotation: Uses ESM export now. -export const Panel = GObject.registerClass( -class Panel extends St.Widget { - // Annotation: Initializes the top (menu)bar / panel. - // Does relevant stuff like: - // - Defining `this._leftBox`, `this._centerBox` and `this._rightBox`. - // - Finally calling `this._updatePanel()`. - // Compared to panel_43.2_2023-01-24.js: Nothing changed (except for - // formatting). - _init() { - super._init({ - name: 'panel', - reactive: true, - }); - - this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); - - this._sessionStyle = null; - - this.statusArea = {}; - - this.menuManager = new PopupMenu.PopupMenuManager(this); - - this._leftBox = new St.BoxLayout({name: 'panelLeft'}); - this.add_child(this._leftBox); - this._centerBox = new St.BoxLayout({name: 'panelCenter'}); - this.add_child(this._centerBox); - this._rightBox = new St.BoxLayout({name: 'panelRight'}); - this.add_child(this._rightBox); - - this.connect('button-press-event', this._onButtonPress.bind(this)); - this.connect('touch-event', this._onTouchEvent.bind(this)); - - Main.overview.connect('showing', () => { - this.add_style_pseudo_class('overview'); - }); - Main.overview.connect('hiding', () => { - this.remove_style_pseudo_class('overview'); - }); - - Main.layoutManager.panelBox.add(this); - Main.ctrlAltTabManager.addGroup(this, - _('Top Bar'), 'focus-top-bar-symbolic', - {sortGroup: CtrlAltTab.SortGroup.TOP}); - - Main.sessionMode.connect('updated', this._updatePanel.bind(this)); - - global.display.connect('workareas-changed', () => this.queue_relayout()); - this._updatePanel(); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. - - // Annotation: Gets called by `this._init()` to populate the top (menu)bar / - // panel initially. - // - // It does the following relevant stuff: - // - Calls `this._hideIndicators()` - // - Calls `this._updateBox()` for `this._leftBox`, `this._centerBox` and - // `this._rightBox` with `panel.left`, `panel.center` and `panel.right` to - // populate the boxes with items defined in `panel.left`, `panel.center` - // and `panel.right`. - // - // `panel.left`, `panel.center` and `panel.right` get set via the line - // `let panel = Main.sessionMode.panel`, which uses the panel of Mains - // (`js/ui/main.js`) instance of SessionMode (`js/ui/sessionMode.js`). - // - // And in `js/ui/sessionMode.js` (45.0, 2023-09-26) you have different - // modes with different panel configuration. For example the "user" mode - // with: - // ``` - // panel: { - // left: ['activities'], - // center: ['dateMenu'], - // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], - // }, - // ``` - // - // This way this function populates the top (menu)bar / panel with the - // default stuff you see on a fresh Gnome. - // - // Compared to panel_43.2_2023-01-24.js: Nothing changed. - _updatePanel() { - let panel = Main.sessionMode.panel; - this._hideIndicators(); - this._updateBox(panel.left, this._leftBox); - this._updateBox(panel.center, this._centerBox); - this._updateBox(panel.right, this._rightBox); - - if (panel.left.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; - else if (panel.right.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; - // Default to center if there is no dateMenu - else - Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; - - if (this._sessionStyle) - this.remove_style_class_name(this._sessionStyle); - - this._sessionStyle = Main.sessionMode.panelStyle; - if (this._sessionStyle) - this.add_style_class_name(this._sessionStyle); - } - - // Annotation: This function hides all items, which are in the top (menu)bar - // panel and in PANEL_ITEM_IMPLEMENTATIONS. - // - // Compared to panel_43.2_2023-01-24.js: Nothing changed. - _hideIndicators() { - for (let role in PANEL_ITEM_IMPLEMENTATIONS) { - let indicator = this.statusArea[role]; - if (!indicator) - continue; - indicator.container.hide(); - } - } - - // Annotation: This function takes a role (of an item) and returns a - // corresponding indicator, if either of two things are true: - // - The indicator is already in `this.statusArea`. - // Then it just returns the indicator by using `this.statusArea`. - // - The role is in PANEL_ITEM_IMPLEMENTATIONS. - // Then it creates a new indicator, adds it to `this.statusArea` and - // returns it. - // - // Compared to panel_43.2_2023-01-24.js: Nothing changed. - _ensureIndicator(role) { - let indicator = this.statusArea[role]; - if (!indicator) { - let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; - if (!constructor) { - // This icon is not implemented (this is a bug) - return null; - } - indicator = new constructor(this); - this.statusArea[role] = indicator; - } - return indicator; - } - - // Annotation: This function takes a list of items (or rather their roles) - // and adds the indicators of those items to a box (like `this._leftBox`) - // using `this._ensureIndicator()` to get the indicator corresponding to the - // given role. - // So only items with roles `this._ensureIndicator()` knows, get added. - // - // Compared to panel_43.2_2023-01-24.js: Nothing changed. - _updateBox(elements, box) { - let nChildren = box.get_n_children(); - - for (let i = 0; i < elements.length; i++) { - let role = elements[i]; - let indicator = this._ensureIndicator(role); - if (indicator == null) - continue; - - this._addToPanelBox(role, indicator, i + nChildren, box); - } - } - - // Annotation: This function adds the given item to the specified top - // (menu)bar / panel box and connects to "destroy" and "menu-set" events. - // - // It takes the following arguments: - // - role: The name of the item to add. - // - indicator: The indicator of the item to add. - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - `this._leftBox` - // - `this._centerBox` - // - `this._rightBox` - // - // Compared to panel_43.2_2023-01-24.js: Nothing changed. - _addToPanelBox(role, indicator, position, box) { - let container = indicator.container; - container.show(); - - let parent = container.get_parent(); - if (parent) - parent.remove_actor(container); - - - box.insert_child_at_index(container, position); - this.statusArea[role] = indicator; - let destroyId = indicator.connect('destroy', emitter => { - delete this.statusArea[role]; - emitter.disconnect(destroyId); - }); - indicator.connect('menu-set', this._onMenuSet.bind(this)); - this._onMenuSet(indicator); - } - - // Annotation: This function allows you to add an item to the top (menu)bar - // / panel. - // While per default it adds the item to the status area (the right box of - // the top bar), you can specify the box and add the item to any of the - // three boxes of the top bar. - // To add an item to the top bar, you need to give its role and indicator. - // - // This function takes the following arguments: - // - role: A name for the item to add. - // - indicator: The indicator for the item to add (must be an instance of - // PanelMenu.Button). - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - "left": referring to `this._leftBox` - // - "center": referring to `this._centerBox` - // - "right": referring to `this._rightBox` - // These boxes are what you see in the top bar as the left, right and - // center sections. - // - // Finally this function just calls `this._addToPanelBox()` for the actual - // work, so it basically just makes sure the input to - // `this._addToPanelBox()` is correct. - // - // Compared to panel_43.2_2023-01-24.js: Nothing changed. - addToStatusArea(role, indicator, position, box) { - if (this.statusArea[role]) - throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); - - if (!(indicator instanceof PanelMenu.Button)) - throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); - - position ??= 0; - let boxes = { - left: this._leftBox, - center: this._centerBox, - right: this._rightBox, - }; - let boxContainer = boxes[box] || this._rightBox; - this.statusArea[role] = indicator; - this._addToPanelBox(role, indicator, position, boxContainer); - return indicator; - } - - // Compared to panel_43.2_2023-01-24.js: Nothing changed, except for the - // usage of === instead of ==. - _onMenuSet(indicator) { - if (!indicator.menu || indicator.menu._openChangedId) - return; - - this.menuManager.addMenu(indicator.menu); - - indicator.menu._openChangedId = indicator.menu.connect('open-state-changed', - (menu, isOpen) => { - let boxAlignment; - if (this._leftBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.START; - else if (this._centerBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.CENTER; - else if (this._rightBox.contains(indicator.container)) - boxAlignment = Clutter.ActorAlign.END; - - if (boxAlignment === Main.messageTray.bannerAlignment) - Main.messageTray.bannerBlocked = isOpen; - }); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. -}); diff --git a/docs/panel_46.4_2024-09-11.js b/docs/panel_46.4_2024-09-11.js deleted file mode 100644 index 76c2640..0000000 --- a/docs/panel_46.4_2024-09-11.js +++ /dev/null @@ -1,322 +0,0 @@ -// My annotated and cut down js/ui/panel.js from gnome-shell/46.4. -// All annotations are what I guessed, interpreted and copied while reading the -// code and comparing to other panel.js versions and might be wrong. They are -// prefixed with "Annotation:" to indicate that they're my comments, not -// comments that orginally existed. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/46.4/js/ui/panel.js -// On: 2024-09-11 -// License: This code is licensed under GPLv2. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/46.4/js/ui/sessionMode.js -// On: 2023-09-11 -// License: This code is licensed under GPLv2. - -// I'm using the word "item" to refer to the thing, which gets added to the top -// (menu)bar / panel, where an item has a role/name and an indicator. - - -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import Clutter from 'gi://Clutter'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import GObject from 'gi://GObject'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import St from 'gi://St'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as CtrlAltTab from './ctrlAltTab.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as PopupMenu from './popupMenu.js'; -import * as PanelMenu from './panelMenu.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as Main from './main.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import {DateMenuButton} from './dateMenu.js'; -import {ATIndicator} from './status/accessibility.js'; -import {InputSourceIndicator} from './status/keyboard.js'; -import {DwellClickIndicator} from './status/dwellClick.js'; -import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -// Of note (for PANEL_ITEM_IMPLEMENTATIONS): -// const AppMenuButton = [...] -// const ActivitiesButton = [...] -// const QuickSettings = [...] - -const PANEL_ITEM_IMPLEMENTATIONS = { - 'activities': ActivitiesButton, - 'appMenu': AppMenuButton, - 'quickSettings': QuickSettings, - 'dateMenu': DateMenuButton, - 'a11y': ATIndicator, - 'keyboard': InputSourceIndicator, - 'dwellClick': DwellClickIndicator, - 'screenRecording': ScreenRecordingIndicator, - 'screenSharing': ScreenSharingIndicator, -}; - -export const Panel = GObject.registerClass( -class Panel extends St.Widget { - // Annotation: Initializes the top (menu)bar / panel. - // Does relevant stuff like: - // - Defining this._leftBox, this._centerBox and this._rightBox. - // - Finally calling this._updatePanel(). - // Compared to panel_45.0_2023-09-26.js: Not much changed except from some - // slightly different function names/calls. - _init() { - super._init({ - name: 'panel', - reactive: true, - }); - - this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); - - this._sessionStyle = null; - - this.statusArea = {}; - - this.menuManager = new PopupMenu.PopupMenuManager(this); - - this._leftBox = new St.BoxLayout({name: 'panelLeft'}); - this.add_child(this._leftBox); - this._centerBox = new St.BoxLayout({name: 'panelCenter'}); - this.add_child(this._centerBox); - this._rightBox = new St.BoxLayout({name: 'panelRight'}); - this.add_child(this._rightBox); - - this.connect('button-press-event', this._onButtonPress.bind(this)); - this.connect('touch-event', this._onTouchEvent.bind(this)); - - Main.overview.connectObject('showing', - () => this.add_style_pseudo_class('overview'), - this); - Main.overview.connectObject('hiding', - () => this.remove_style_pseudo_class('overview'), - this); - - Main.layoutManager.panelBox.add_child(this); - Main.ctrlAltTabManager.addGroup(this, - _('Top Bar'), 'shell-focus-top-bar-symbolic', - {sortGroup: CtrlAltTab.SortGroup.TOP}); - - Main.sessionMode.connect('updated', this._updatePanel.bind(this)); - - global.display.connect('workareas-changed', () => this.queue_relayout()); - this._updatePanel(); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. - - // Annotation: Gets called by this._init() to populate the top (menu)bar / - // panel initially. - // - // It does the following relevant stuff: - // - Calls this._hideIndicators() - // - Calls this._updateBox() for this._leftBox, this._centerBox and - // this._rightBox with panel.left, panel.center and panel.right to - // populate the boxes with items defined in panel.left, panel.center and - // panel.right. - // - // panel.left, panel.center and panel.right get set via the line let panel - // = Main.sessionMode.panel, which uses the panel of Mains (js/ui/main.js) - // instance of SessionMode (js/ui/sessionMode.js). - // - // And in js/ui/sessionMode.js (46.4, 2024-09-11) you have different modes - // with different panel configuration. For example the "user" mode with: - // panel: { - // left: ['activities'], - // center: ['dateMenu'], - // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], - // } - // - // This way this function populates the top (menu)bar / panel with the - // default stuff you see on a fresh Gnome. - // - // Compared to panel_45.0_2023-09-26.js: Nothing changed. - _updatePanel() { - let panel = Main.sessionMode.panel; - this._hideIndicators(); - this._updateBox(panel.left, this._leftBox); - this._updateBox(panel.center, this._centerBox); - this._updateBox(panel.right, this._rightBox); - - if (panel.left.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; - else if (panel.right.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; - // Default to center if there is no dateMenu - else - Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; - - if (this._sessionStyle) - this.remove_style_class_name(this._sessionStyle); - - this._sessionStyle = Main.sessionMode.panelStyle; - if (this._sessionStyle) - this.add_style_class_name(this._sessionStyle); - } - - // Annotation: This function hides all items, which are in the top (menu)bar - // panel and in PANEL_ITEM_IMPLEMENTATIONS. - // - // Compared to panel_45.0_2023-09-26.js: Nothing changed. - _hideIndicators() { - for (let role in PANEL_ITEM_IMPLEMENTATIONS) { - let indicator = this.statusArea[role]; - if (!indicator) - continue; - indicator.container.hide(); - } - } - - // Annotation: This function takes a role (of an item) and returns a - // corresponding indicator, if either of two things are true: - // - The indicator is already in this.statusArea. - // Then it just returns the indicator by using this.statusArea. - // - The role is in PANEL_ITEM_IMPLEMENTATIONS. - // Then it creates a new indicator, adds it to this.statusArea and returns - // it. - // - // Compared to panel_45.0_2023-09-26.js: Nothing changed. - _ensureIndicator(role) { - let indicator = this.statusArea[role]; - if (!indicator) { - let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; - if (!constructor) { - // This icon is not implemented (this is a bug) - return null; - } - indicator = new constructor(this); - this.statusArea[role] = indicator; - } - return indicator; - } - - // Annotation: This function takes a list of items (or rather their roles) - // and adds the indicators of those items to a box (like this._leftBox) - // using this._ensureIndicator() to get the indicator corresponding to the - // given role. - // So only items with roles this._ensureIndicator() knows, get added. - // - // Compared to panel_45.0_2023-09-26.js: Nothing changed. - _updateBox(elements, box) { - let nChildren = box.get_n_children(); - - for (let i = 0; i < elements.length; i++) { - let role = elements[i]; - let indicator = this._ensureIndicator(role); - if (indicator == null) - continue; - - this._addToPanelBox(role, indicator, i + nChildren, box); - } - } - - // Annotation: This function adds the given item to the specified top - // (menu)bar / panel box and connects to "destroy" and "menu-set" events. - // - // It takes the following arguments: - // - role: The name of the item to add. - // - indicator: The indicator of the item to add. - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - this._leftBox - // - this._centerBox - // - this._rightBox - // - // Compared to panel_45.0_2023-09-26.js: The call of - // parent.remove_actor(container) changed to parent.remove_child(container). - _addToPanelBox(role, indicator, position, box) { - let container = indicator.container; - container.show(); - - let parent = container.get_parent(); - if (parent) - parent.remove_child(container); - - - box.insert_child_at_index(container, position); - this.statusArea[role] = indicator; - let destroyId = indicator.connect('destroy', emitter => { - delete this.statusArea[role]; - emitter.disconnect(destroyId); - }); - indicator.connect('menu-set', this._onMenuSet.bind(this)); - this._onMenuSet(indicator); - } - - // Annotation: This function allows you to add an item to the top (menu)bar - // / panel. - // While per default it adds the item to the status area (the right box of - // the top bar), you can specify the box and add the item to any of the - // three boxes of the top bar. - // To add an item to the top bar, you need to give its role and indicator. - // - // This function takes the following arguments: - // - role: A name for the item to add. - // - indicator: The indicator for the item to add (must be an instance of - // PanelMenu.Button). - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - "left": referring to this._leftBox - // - "center": referring to this._centerBox - // - "right": referring to this._rightBox - // These boxes are what you see in the top bar as the left, right and - // center sections. - // - // Finally this function just calls this._addToPanelBox() for the actual - // work, so it basically just makes sure the input to this._addToPanelBox() - // is correct. - // - // Compared to panel_45.0_2023-09-26.js: Nothing changed. - addToStatusArea(role, indicator, position, box) { - if (this.statusArea[role]) - throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); - - if (!(indicator instanceof PanelMenu.Button)) - throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); - - position ??= 0; - let boxes = { - left: this._leftBox, - center: this._centerBox, - right: this._rightBox, - }; - let boxContainer = boxes[box] || this._rightBox; - this.statusArea[role] = indicator; - this._addToPanelBox(role, indicator, position, boxContainer); - return indicator; - } - - // Of note: - // _onMenuSet(indicator) { [...] } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. -}); diff --git a/docs/panel_47.rc_2024-09-12.js b/docs/panel_47.rc_2024-09-12.js deleted file mode 100644 index 504cbb6..0000000 --- a/docs/panel_47.rc_2024-09-12.js +++ /dev/null @@ -1,317 +0,0 @@ -// My annotated and cut down js/ui/panel.js from gnome-shell/47.rc. -// All annotations are what I guessed, interpreted and copied while reading the -// code and comparing to other panel.js versions and might be wrong. They are -// prefixed with "Annotation:" to indicate that they're my comments, not -// comments that orginally existed. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/47.rc/js/ui/panel.js -// On: 2024-09-12 -// License: This code is licensed under GPLv2. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/47.rc/js/ui/sessionMode.js -// On: 2023-09-12 -// License: This code is licensed under GPLv2. - -// I'm using the word "item" to refer to the thing, which gets added to the top -// (menu)bar / panel, where an item has a role/name and an indicator. - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import Clutter from 'gi://Clutter'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import GObject from 'gi://GObject'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import St from 'gi://St'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as CtrlAltTab from './ctrlAltTab.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as PopupMenu from './popupMenu.js'; -import * as PanelMenu from './panelMenu.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as Main from './main.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import {DateMenuButton} from './dateMenu.js'; -import {ATIndicator} from './status/accessibility.js'; -import {InputSourceIndicator} from './status/keyboard.js'; -import {DwellClickIndicator} from './status/dwellClick.js'; -import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -// Of note (for PANEL_ITEM_IMPLEMENTATIONS): -// const AppMenuButton = [...] -// const ActivitiesButton = [...] -// const QuickSettings = [...] - -const PANEL_ITEM_IMPLEMENTATIONS = { - 'activities': ActivitiesButton, - 'appMenu': AppMenuButton, - 'quickSettings': QuickSettings, - 'dateMenu': DateMenuButton, - 'a11y': ATIndicator, - 'keyboard': InputSourceIndicator, - 'dwellClick': DwellClickIndicator, - 'screenRecording': ScreenRecordingIndicator, - 'screenSharing': ScreenSharingIndicator, -}; - -export const Panel = GObject.registerClass( -class Panel extends St.Widget { - // Annotation: Initializes the top (menu)bar / panel. - // Does relevant stuff like: - // - Defining this._leftBox, this._centerBox and this._rightBox. - // - Finally calling this._updatePanel(). - // Compared to panel_46.4_2024-09-11.js: Nothing changed. - _init() { - super._init({ - name: 'panel', - reactive: true, - }); - - this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); - - this._sessionStyle = null; - - this.statusArea = {}; - - this.menuManager = new PopupMenu.PopupMenuManager(this); - - this._leftBox = new St.BoxLayout({name: 'panelLeft'}); - this.add_child(this._leftBox); - this._centerBox = new St.BoxLayout({name: 'panelCenter'}); - this.add_child(this._centerBox); - this._rightBox = new St.BoxLayout({name: 'panelRight'}); - this.add_child(this._rightBox); - - this.connect('button-press-event', this._onButtonPress.bind(this)); - this.connect('touch-event', this._onTouchEvent.bind(this)); - - Main.overview.connectObject('showing', - () => this.add_style_pseudo_class('overview'), - this); - Main.overview.connectObject('hiding', - () => this.remove_style_pseudo_class('overview'), - this); - - Main.layoutManager.panelBox.add_child(this); - Main.ctrlAltTabManager.addGroup(this, - _('Top Bar'), 'shell-focus-top-bar-symbolic', - {sortGroup: CtrlAltTab.SortGroup.TOP}); - - Main.sessionMode.connect('updated', this._updatePanel.bind(this)); - - global.display.connect('workareas-changed', () => this.queue_relayout()); - this._updatePanel(); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. - - // Annotation: Gets called by this._init() to populate the top (menu)bar / - // panel initially. - // - // It does the following relevant stuff: - // - Calls this._hideIndicators() - // - Calls this._updateBox() for this._leftBox, this._centerBox and - // this._rightBox with panel.left, panel.center and panel.right to - // populate the boxes with items defined in panel.left, panel.center and - // panel.right. - // - // panel.left, panel.center and panel.right get set via the line let panel - // = Main.sessionMode.panel, which uses the panel of Mains (js/ui/main.js) - // instance of SessionMode (js/ui/sessionMode.js). - // - // And in js/ui/sessionMode.js (47.rc, 2024-09-12) you have different modes - // with different panel configuration. For example the "user" mode with: - // panel: { - // left: ['activities'], - // center: ['dateMenu'], - // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], - // } - // - // This way this function populates the top (menu)bar / panel with the - // default stuff you see on a fresh Gnome. - // - // Compared to panel_46.4_2024-09-11.js: Nothing changed. - _updatePanel() { - let panel = Main.sessionMode.panel; - this._hideIndicators(); - this._updateBox(panel.left, this._leftBox); - this._updateBox(panel.center, this._centerBox); - this._updateBox(panel.right, this._rightBox); - - if (panel.left.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; - else if (panel.right.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; - // Default to center if there is no dateMenu - else - Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; - - if (this._sessionStyle) - this.remove_style_class_name(this._sessionStyle); - - this._sessionStyle = Main.sessionMode.panelStyle; - if (this._sessionStyle) - this.add_style_class_name(this._sessionStyle); - } - - // Annotation: This function hides all items, which are in the top (menu)bar - // panel and in PANEL_ITEM_IMPLEMENTATIONS. - // - // Compared to panel_46.4_2024-09-11.js: Nothing changed. - _hideIndicators() { - for (let role in PANEL_ITEM_IMPLEMENTATIONS) { - let indicator = this.statusArea[role]; - if (!indicator) - continue; - indicator.container.hide(); - } - } - - // Annotation: This function takes a role (of an item) and returns a - // corresponding indicator, if either of two things are true: - // - The indicator is already in this.statusArea. - // Then it just returns the indicator by using this.statusArea. - // - The role is in PANEL_ITEM_IMPLEMENTATIONS. - // Then it creates a new indicator, adds it to this.statusArea and returns - // it. - // - // Compared to panel_46.4_2024-09-11.js: Nothing changed. - _ensureIndicator(role) { - let indicator = this.statusArea[role]; - if (!indicator) { - let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; - if (!constructor) { - // This icon is not implemented (this is a bug) - return null; - } - indicator = new constructor(this); - this.statusArea[role] = indicator; - } - return indicator; - } - - // Annotation: This function takes a list of items (or rather their roles) - // and adds the indicators of those items to a box (like this._leftBox) - // using this._ensureIndicator() to get the indicator corresponding to the - // given role. - // So only items with roles this._ensureIndicator() knows, get added. - // - // Compared to panel_46.4_2024-09-11.js: Nothing changed. - _updateBox(elements, box) { - let nChildren = box.get_n_children(); - - for (let i = 0; i < elements.length; i++) { - let role = elements[i]; - let indicator = this._ensureIndicator(role); - if (indicator == null) - continue; - - this._addToPanelBox(role, indicator, i + nChildren, box); - } - } - - // Annotation: This function adds the given item to the specified top - // (menu)bar / panel box and connects to "destroy" and "menu-set" events. - // - // It takes the following arguments: - // - role: The name of the item to add. - // - indicator: The indicator of the item to add. - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - this._leftBox - // - this._centerBox - // - this._rightBox - // - // Compared to panel_46.4_2024-09-11.js: Nothing changed. - _addToPanelBox(role, indicator, position, box) { - let container = indicator.container; - container.show(); - - let parent = container.get_parent(); - if (parent) - parent.remove_child(container); - - - box.insert_child_at_index(container, position); - this.statusArea[role] = indicator; - let destroyId = indicator.connect('destroy', emitter => { - delete this.statusArea[role]; - emitter.disconnect(destroyId); - }); - indicator.connect('menu-set', this._onMenuSet.bind(this)); - this._onMenuSet(indicator); - } - - // Annotation: This function allows you to add an item to the top (menu)bar - // / panel. - // While per default it adds the item to the status area (the right box of - // the top bar), you can specify the box and add the item to any of the - // three boxes of the top bar. - // To add an item to the top bar, you need to give its role and indicator. - // - // This function takes the following arguments: - // - role: A name for the item to add. - // - indicator: The indicator for the item to add (must be an instance of - // PanelMenu.Button). - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - "left": referring to this._leftBox - // - "center": referring to this._centerBox - // - "right": referring to this._rightBox - // These boxes are what you see in the top bar as the left, right and - // center sections. - // - // Finally this function just calls this._addToPanelBox() for the actual - // work, so it basically just makes sure the input to this._addToPanelBox() - // is correct. - // - // Compared to panel_46.4_2024-09-11.js: Nothing changed. - addToStatusArea(role, indicator, position, box) { - if (this.statusArea[role]) - throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); - - if (!(indicator instanceof PanelMenu.Button)) - throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); - - position ??= 0; - let boxes = { - left: this._leftBox, - center: this._centerBox, - right: this._rightBox, - }; - let boxContainer = boxes[box] || this._rightBox; - this.statusArea[role] = indicator; - this._addToPanelBox(role, indicator, position, boxContainer); - return indicator; - } - - // Of note: - // _onMenuSet(indicator) { [...] } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. -}); diff --git a/docs/panel_48.2_2025-06-08.js b/docs/panel_48.2_2025-06-08.js deleted file mode 100644 index 7becfb8..0000000 --- a/docs/panel_48.2_2025-06-08.js +++ /dev/null @@ -1,322 +0,0 @@ -// My annotated and cut down js/ui/panel.js from gnome-shell/48.2. -// All annotations are what I guessed, interpreted and copied while reading the -// code and comparing to other panel.js versions and might be wrong. They are -// prefixed with "Annotation:" to indicate that they're my comments, not -// comments that orginally existed. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/48.2/js/ui/panel.js -// On: 2025-06-08 -// License: This code is licensed under GPLv2. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/48.2/js/ui/sessionMode.js -// On: 2025-06-08 -// License: This code is licensed under GPLv2. - -// I'm using the word "item" to refer to the thing, which gets added to the top -// (menu)bar / panel, where an item has a role/name and an indicator. - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import Clutter from 'gi://Clutter'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import GObject from 'gi://GObject'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import St from 'gi://St'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as CtrlAltTab from './ctrlAltTab.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as PopupMenu from './popupMenu.js'; -import * as PanelMenu from './panelMenu.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as Main from './main.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import {DateMenuButton} from './dateMenu.js'; -import {ATIndicator} from './status/accessibility.js'; -import {InputSourceIndicator} from './status/keyboard.js'; -import {DwellClickIndicator} from './status/dwellClick.js'; -import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -// Of note (for PANEL_ITEM_IMPLEMENTATIONS): -// const AppMenuButton = [...] -// const ActivitiesButton = [...] -// const QuickSettings = [...] - -const PANEL_ITEM_IMPLEMENTATIONS = { - 'activities': ActivitiesButton, - 'appMenu': AppMenuButton, - 'quickSettings': QuickSettings, - 'dateMenu': DateMenuButton, - 'a11y': ATIndicator, - 'keyboard': InputSourceIndicator, - 'dwellClick': DwellClickIndicator, - 'screenRecording': ScreenRecordingIndicator, - 'screenSharing': ScreenSharingIndicator, -}; - -export const Panel = GObject.registerClass( -class Panel extends St.Widget { - // Annotation: Initializes the top (menu)bar / panel. - // Does relevant stuff like: - // - Defining this._leftBox, this._centerBox and this._rightBox. - // - Finally calling this._updatePanel(). - // Compared to panel_47.rc_2024-09-12.js: connectObject instead of connect - // gets used, which shouldn't be relevant for this extension. - _init() { - super._init({ - name: 'panel', - reactive: true, - }); - - this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); - - this._sessionStyle = null; - - this.statusArea = {}; - - this.menuManager = new PopupMenu.PopupMenuManager(this); - - this._leftBox = new St.BoxLayout({name: 'panelLeft'}); - this.add_child(this._leftBox); - this._centerBox = new St.BoxLayout({name: 'panelCenter'}); - this.add_child(this._centerBox); - this._rightBox = new St.BoxLayout({name: 'panelRight'}); - this.add_child(this._rightBox); - - this.connect('button-press-event', this._onButtonPress.bind(this)); - this.connect('touch-event', this._onTouchEvent.bind(this)); - - Main.overview.connectObject('showing', - () => this.add_style_pseudo_class('overview'), - this); - Main.overview.connectObject('hiding', - () => this.remove_style_pseudo_class('overview'), - this); - - Main.layoutManager.panelBox.add_child(this); - Main.ctrlAltTabManager.addGroup(this, - _('Top Bar'), 'shell-focus-top-bar-symbolic', - {sortGroup: CtrlAltTab.SortGroup.TOP}); - - Main.sessionMode.connectObject('updated', - this._updatePanel.bind(this), - this); - - global.display.connectObject('workareas-changed', - () => this.queue_relayout(), - this); - this._updatePanel(); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. - - // Annotation: Gets called by this._init() to populate the top (menu)bar / - // panel initially. - // - // It does the following relevant stuff: - // - Calls this._hideIndicators() - // - Calls this._updateBox() for this._leftBox, this._centerBox and - // this._rightBox with panel.left, panel.center and panel.right to - // populate the boxes with items defined in panel.left, panel.center and - // panel.right. - // - // panel.left, panel.center and panel.right get set via the line let panel - // = Main.sessionMode.panel, which uses the panel of Mains (js/ui/main.js) - // instance of SessionMode (js/ui/sessionMode.js). - // - // And in js/ui/sessionMode.js (48.2, 2025-06-08) you have different modes - // with different panel configuration. For example the "user" mode with: - // panel: { - // left: ['activities'], - // center: ['dateMenu'], - // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], - // } - // - // This way this function populates the top (menu)bar / panel with the - // default stuff you see on a fresh Gnome. - // - // Compared to panel_47.rc_2024-09-12.js: Nothing changed. - _updatePanel() { - let panel = Main.sessionMode.panel; - this._hideIndicators(); - this._updateBox(panel.left, this._leftBox); - this._updateBox(panel.center, this._centerBox); - this._updateBox(panel.right, this._rightBox); - - if (panel.left.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; - else if (panel.right.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; - // Default to center if there is no dateMenu - else - Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; - - if (this._sessionStyle) - this.remove_style_class_name(this._sessionStyle); - - this._sessionStyle = Main.sessionMode.panelStyle; - if (this._sessionStyle) - this.add_style_class_name(this._sessionStyle); - } - - // Annotation: This function hides all items, which are in the top (menu)bar - // panel and in PANEL_ITEM_IMPLEMENTATIONS. - // - // Compared to panel_47.rc_2024-09-12.js: Nothing changed. - _hideIndicators() { - for (let role in PANEL_ITEM_IMPLEMENTATIONS) { - let indicator = this.statusArea[role]; - if (!indicator) - continue; - indicator.container.hide(); - } - } - - // Annotation: This function takes a role (of an item) and returns a - // corresponding indicator, if either of two things are true: - // - The indicator is already in this.statusArea. - // Then it just returns the indicator by using this.statusArea. - // - The role is in PANEL_ITEM_IMPLEMENTATIONS. - // Then it creates a new indicator, adds it to this.statusArea and returns - // it. - // - // Compared to panel_47.rc_2024-09-12.js: Nothing changed. - _ensureIndicator(role) { - let indicator = this.statusArea[role]; - if (!indicator) { - let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; - if (!constructor) { - // This icon is not implemented (this is a bug) - return null; - } - indicator = new constructor(this); - this.statusArea[role] = indicator; - } - return indicator; - } - - // Annotation: This function takes a list of items (or rather their roles) - // and adds the indicators of those items to a box (like this._leftBox) - // using this._ensureIndicator() to get the indicator corresponding to the - // given role. - // So only items with roles this._ensureIndicator() knows, get added. - // - // Compared to panel_47.rc_2024-09-12.js: Nothing changed. - _updateBox(elements, box) { - let nChildren = box.get_n_children(); - - for (let i = 0; i < elements.length; i++) { - let role = elements[i]; - let indicator = this._ensureIndicator(role); - if (indicator == null) - continue; - - this._addToPanelBox(role, indicator, i + nChildren, box); - } - } - - // Annotation: This function adds the given item to the specified top - // (menu)bar / panel box and connects to "destroy" and "menu-set" events. - // - // It takes the following arguments: - // - role: The name of the item to add. - // - indicator: The indicator of the item to add. - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - this._leftBox - // - this._centerBox - // - this._rightBox - // - // Compared to panel_47.rc_2024-09-12.js: Nothing changed. - _addToPanelBox(role, indicator, position, box) { - let container = indicator.container; - container.show(); - - let parent = container.get_parent(); - if (parent) - parent.remove_child(container); - - - box.insert_child_at_index(container, position); - this.statusArea[role] = indicator; - let destroyId = indicator.connect('destroy', emitter => { - delete this.statusArea[role]; - emitter.disconnect(destroyId); - }); - indicator.connect('menu-set', this._onMenuSet.bind(this)); - this._onMenuSet(indicator); - } - - // Annotation: This function allows you to add an item to the top (menu)bar - // / panel. - // While per default it adds the item to the status area (the right box of - // the top bar), you can specify the box and add the item to any of the - // three boxes of the top bar. - // To add an item to the top bar, you need to give its role and indicator. - // - // This function takes the following arguments: - // - role: A name for the item to add. - // - indicator: The indicator for the item to add (must be an instance of - // PanelMenu.Button). - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - "left": referring to this._leftBox - // - "center": referring to this._centerBox - // - "right": referring to this._rightBox - // These boxes are what you see in the top bar as the left, right and - // center sections. - // - // Finally this function just calls this._addToPanelBox() for the actual - // work, so it basically just makes sure the input to this._addToPanelBox() - // is correct. - // - // Compared to panel_47.rc_2024-09-12.js: Nothing changed. - addToStatusArea(role, indicator, position, box) { - if (this.statusArea[role]) - throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); - - if (!(indicator instanceof PanelMenu.Button)) - throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); - - position ??= 0; - let boxes = { - left: this._leftBox, - center: this._centerBox, - right: this._rightBox, - }; - let boxContainer = boxes[box] || this._rightBox; - this.statusArea[role] = indicator; - this._addToPanelBox(role, indicator, position, boxContainer); - return indicator; - } - - // Of note: - // _onMenuSet(indicator) { [...] } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. -}); diff --git a/docs/panel_49.0_2025-10-03.js b/docs/panel_49.0_2025-10-03.js deleted file mode 100644 index 449c038..0000000 --- a/docs/panel_49.0_2025-10-03.js +++ /dev/null @@ -1,321 +0,0 @@ -// My annotated and cut down js/ui/panel.js from gnome-shell/49.0. -// All annotations are what I guessed, interpreted and copied while reading the -// code and comparing to other panel.js versions and might be wrong. They are -// prefixed with "Annotation:" to indicate that they're my comments, not -// comments that orginally existed. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/49.0/js/ui/panel.js -// On: 2025-10-03 -// License: This code is licensed under GPLv2. - -// Taken from: https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/49.0/js/ui/sessionMode.js -// On: 2025-10-03 -// License: This code is licensed under GPLv2. - -// I'm using the word "item" to refer to the thing, which gets added to the top -// (menu)bar / panel, where an item has a role/name and an indicator. - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import Clutter from 'gi://Clutter'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import GObject from 'gi://GObject'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import St from 'gi://St'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as CtrlAltTab from './ctrlAltTab.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as PopupMenu from './popupMenu.js'; -import * as PanelMenu from './panelMenu.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import * as Main from './main.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -import {DateMenuButton} from './dateMenu.js'; -import {ATIndicator} from './status/accessibility.js'; -import {InputSourceIndicator} from './status/keyboard.js'; -import {DwellClickIndicator} from './status/dwellClick.js'; -import {ScreenRecordingIndicator, ScreenSharingIndicator} from './status/remoteAccess.js'; - -// Annotation: [...] Cut out bunch of stuff here, which isn't relevant for this -// Extension. - -// Of note (for PANEL_ITEM_IMPLEMENTATIONS): -// const ActivitiesButton = [...] -// const QuickSettings = [...] -// Compared to panel_48.2_2025-06-08.js: AppMenuButton got removed. - -// Compared to panel_48.2_2025-06-08.js: AppMenuButton got removed. -const PANEL_ITEM_IMPLEMENTATIONS = { - 'activities': ActivitiesButton, - 'quickSettings': QuickSettings, - 'dateMenu': DateMenuButton, - 'a11y': ATIndicator, - 'keyboard': InputSourceIndicator, - 'dwellClick': DwellClickIndicator, - 'screenRecording': ScreenRecordingIndicator, - 'screenSharing': ScreenSharingIndicator, -}; - -export const Panel = GObject.registerClass( -class Panel extends St.Widget { - // Annotation: Initializes the top (menu)bar / panel. - // Does relevant stuff like: - // - Defining this._leftBox, this._centerBox and this._rightBox. - // - Finally calling this._updatePanel(). - // Compared to panel_48.2_2025-06-08.js: Nothing changed. - _init() { - super._init({ - name: 'panel', - reactive: true, - }); - - this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); - - this._sessionStyle = null; - - this.statusArea = {}; - - this.menuManager = new PopupMenu.PopupMenuManager(this); - - this._leftBox = new St.BoxLayout({name: 'panelLeft'}); - this.add_child(this._leftBox); - this._centerBox = new St.BoxLayout({name: 'panelCenter'}); - this.add_child(this._centerBox); - this._rightBox = new St.BoxLayout({name: 'panelRight'}); - this.add_child(this._rightBox); - - this.connect('button-press-event', this._onButtonPress.bind(this)); - this.connect('touch-event', this._onTouchEvent.bind(this)); - - Main.overview.connectObject('showing', - () => this.add_style_pseudo_class('overview'), - this); - Main.overview.connectObject('hiding', - () => this.remove_style_pseudo_class('overview'), - this); - - Main.layoutManager.panelBox.add_child(this); - Main.ctrlAltTabManager.addGroup(this, - _('Top Bar'), 'shell-focus-top-bar-symbolic', - {sortGroup: CtrlAltTab.SortGroup.TOP}); - - Main.sessionMode.connectObject('updated', - this._updatePanel.bind(this), - this); - - global.display.connectObject('workareas-changed', - () => this.queue_relayout(), - this); - this._updatePanel(); - } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. - - // Annotation: Gets called by this._init() to populate the top (menu)bar / - // panel initially. - // - // It does the following relevant stuff: - // - Calls this._hideIndicators() - // - Calls this._updateBox() for this._leftBox, this._centerBox and - // this._rightBox with panel.left, panel.center and panel.right to - // populate the boxes with items defined in panel.left, panel.center and - // panel.right. - // - // panel.left, panel.center and panel.right get set via the line let panel - // = Main.sessionMode.panel, which uses the panel of Mains (js/ui/main.js) - // instance of SessionMode (js/ui/sessionMode.js). - // - // And in js/ui/sessionMode.js (49.0, 2025-10-03) you have different modes - // with different panel configuration. For example the "user" mode with: - // panel: { - // left: ['activities'], - // center: ['dateMenu'], - // right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'], - // } - // - // This way this function populates the top (menu)bar / panel with the - // default stuff you see on a fresh Gnome. - // - // Compared to panel_48.2_2025-06-08.js: Nothing changed. - _updatePanel() { - let panel = Main.sessionMode.panel; - this._hideIndicators(); - this._updateBox(panel.left, this._leftBox); - this._updateBox(panel.center, this._centerBox); - this._updateBox(panel.right, this._rightBox); - - if (panel.left.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.START; - else if (panel.right.includes('dateMenu')) - Main.messageTray.bannerAlignment = Clutter.ActorAlign.END; - // Default to center if there is no dateMenu - else - Main.messageTray.bannerAlignment = Clutter.ActorAlign.CENTER; - - if (this._sessionStyle) - this.remove_style_class_name(this._sessionStyle); - - this._sessionStyle = Main.sessionMode.panelStyle; - if (this._sessionStyle) - this.add_style_class_name(this._sessionStyle); - } - - // Annotation: This function hides all items, which are in the top (menu)bar - // panel and in PANEL_ITEM_IMPLEMENTATIONS. - // - // Compared to panel_48.2_2025-06-08.js: Nothing changed. - _hideIndicators() { - for (let role in PANEL_ITEM_IMPLEMENTATIONS) { - let indicator = this.statusArea[role]; - if (!indicator) - continue; - indicator.container.hide(); - } - } - - // Annotation: This function takes a role (of an item) and returns a - // corresponding indicator, if either of two things are true: - // - The indicator is already in this.statusArea. - // Then it just returns the indicator by using this.statusArea. - // - The role is in PANEL_ITEM_IMPLEMENTATIONS. - // Then it creates a new indicator, adds it to this.statusArea and returns - // it. - // - // Compared to panel_48.2_2025-06-08.js: Nothing changed. - _ensureIndicator(role) { - let indicator = this.statusArea[role]; - if (!indicator) { - let constructor = PANEL_ITEM_IMPLEMENTATIONS[role]; - if (!constructor) { - // This icon is not implemented (this is a bug) - return null; - } - indicator = new constructor(this); - this.statusArea[role] = indicator; - } - return indicator; - } - - // Annotation: This function takes a list of items (or rather their roles) - // and adds the indicators of those items to a box (like this._leftBox) - // using this._ensureIndicator() to get the indicator corresponding to the - // given role. - // So only items with roles this._ensureIndicator() knows, get added. - // - // Compared to panel_48.2_2025-06-08.js: Nothing changed. - _updateBox(elements, box) { - let nChildren = box.get_n_children(); - - for (let i = 0; i < elements.length; i++) { - let role = elements[i]; - let indicator = this._ensureIndicator(role); - if (indicator == null) - continue; - - this._addToPanelBox(role, indicator, i + nChildren, box); - } - } - - // Annotation: This function adds the given item to the specified top - // (menu)bar / panel box and connects to "destroy" and "menu-set" events. - // - // It takes the following arguments: - // - role: The name of the item to add. - // - indicator: The indicator of the item to add. - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - this._leftBox - // - this._centerBox - // - this._rightBox - // - // Compared to panel_48.2_2025-06-08.js: Nothing changed. - _addToPanelBox(role, indicator, position, box) { - let container = indicator.container; - container.show(); - - let parent = container.get_parent(); - if (parent) - parent.remove_child(container); - - - box.insert_child_at_index(container, position); - this.statusArea[role] = indicator; - let destroyId = indicator.connect('destroy', emitter => { - delete this.statusArea[role]; - emitter.disconnect(destroyId); - }); - indicator.connect('menu-set', this._onMenuSet.bind(this)); - this._onMenuSet(indicator); - } - - // Annotation: This function allows you to add an item to the top (menu)bar - // / panel. - // While per default it adds the item to the status area (the right box of - // the top bar), you can specify the box and add the item to any of the - // three boxes of the top bar. - // To add an item to the top bar, you need to give its role and indicator. - // - // This function takes the following arguments: - // - role: A name for the item to add. - // - indicator: The indicator for the item to add (must be an instance of - // PanelMenu.Button). - // - position: Where in the box to add the item. - // - box: The box to add the item to. - // Can be one of the following: - // - "left": referring to this._leftBox - // - "center": referring to this._centerBox - // - "right": referring to this._rightBox - // These boxes are what you see in the top bar as the left, right and - // center sections. - // - // Finally this function just calls this._addToPanelBox() for the actual - // work, so it basically just makes sure the input to this._addToPanelBox() - // is correct. - // - // Compared to panel_48.2_2025-06-08.js: Nothing changed. - addToStatusArea(role, indicator, position, box) { - if (this.statusArea[role]) - throw new Error(`Extension point conflict: there is already a status indicator for role ${role}`); - - if (!(indicator instanceof PanelMenu.Button)) - throw new TypeError('Status indicator must be an instance of PanelMenu.Button'); - - position ??= 0; - let boxes = { - left: this._leftBox, - center: this._centerBox, - right: this._rightBox, - }; - let boxContainer = boxes[box] || this._rightBox; - this.statusArea[role] = indicator; - this._addToPanelBox(role, indicator, position, boxContainer); - return indicator; - } - - // Of note: - // _onMenuSet(indicator) { [...] } - - // Annotation: [...] Cut out bunch of stuff here, which isn't relevant for - // this Extension. -}); diff --git a/docs/release_notes_template.md b/docs/release_notes_template.md deleted file mode 100644 index 66ac266..0000000 --- a/docs/release_notes_template.md +++ /dev/null @@ -1,26 +0,0 @@ -Top Bar Organizer vX includes the following changes: - -# Relevant and/or Breaking Changes - -The following relevant and/or breaking changes of this version: - -## Breaking Change - -Description - -## Relevant Change - -Description - -# Other Changes - -- a change -- another change - -# `git shortlog` - -The git shortlog for this version: - -``` -git shortlog vX-1..vX -``` diff --git a/git_annotated_tag_template b/git_annotated_tag_template deleted file mode 100644 index 2c66d8d..0000000 --- a/git_annotated_tag_template +++ /dev/null @@ -1,9 +0,0 @@ -Top Bar Organizer vX - -Relevant and/or Breaking Changes: -- breaking change: description -- relevant change: description - -Other Changes: -- a change -- another change diff --git a/package-lock.json b/package-lock.json index 2ca458a..b039aa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2020 +1,974 @@ { "name": "top-bar-organizer", "version": "1.0.0", - "lockfileVersion": 3, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "top-bar-organizer", - "version": "1.0.0", - "license": "GPL-3.0-or-later", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gnome-shell": "^48.0.2" + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", + "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" }, - "devDependencies": { - "eslint": "^8.57.1", - "eslint-plugin-jsdoc": "^50.7.1", - "typescript": "^5.8.3" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.50.2", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", - "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", - "dev": true, - "license": "MIT", "dependencies": { - "@types/estree": "^1.0.6", - "@typescript-eslint/types": "^8.11.0", - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.1.0" - }, - "engines": { - "node": ">=18" + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "@eslint/eslintrc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", + "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", - "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "dependencies": { + "requires": { "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@girs/accountsservice-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/accountsservice-1.0/-/accountsservice-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-QR7xfIvNbovmhNzzma+NxIMsQR8zgTaYk16Dqa/4YD8XBWrAgWuQhwEKKibG9KbQe5+YSUDUxJlbkSeOb3S5mg==", - "license": "MIT", "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + } } }, - "node_modules/@girs/adw-1": { - "version": "1.8.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/adw-1/-/adw-1-1.8.0-4.0.0-beta.23.tgz", - "integrity": "sha512-yDhOFc7qHTvIXo5naYuljtmpipP+z0JCyw6qw+mGEwyh0PXF9VA7MOUu5lUVQAsJgwUD5hLsWmqhd/JxnaXf7Q==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gdk-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/gsk-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gtk-4.0": "^4.18.3-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/pangocairo-1.0": "^1.0.0-4.0.0-beta.23" - } + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true }, - "node_modules/@girs/atk-1.0": { - "version": "2.56.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/atk-1.0/-/atk-1.0-2.56.0-4.0.0-beta.23.tgz", - "integrity": "sha512-5kFs//8rkORYMJh0FQNeNciEQmbMNfA4Jo8AV9du8WiWGAdFzkPLH9o3eQrqRGIqZBsbqiEy3FS+R9P7+bn/UA==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true }, - "node_modules/@girs/cairo-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/cairo-1.0/-/cairo-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-t5fADO+9TmZy8Xzk6Fqk23B3bmakzhNQxa3kFERzy2cL8p1q1pAWm1ARNcadIsl2IbflS4Hbn5sAwRwOm8W67A==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/clutter-16": { - "version": "16.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/clutter-16/-/clutter-16-16.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-dQ0cfxSa4E0AAfsFhs8Yd/eFHv7286c5oo7cku13nlEYBFQpyfUfa+CMSclAbUBUxM35PseXGXEy0jegkKpbXQ==", - "license": "MIT", - "dependencies": { - "@girs/atk-1.0": "^2.56.0-4.0.0-beta.23", - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/cogl-16": "^16.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gl-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/mtk-16": "^16.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/xlib-2.0": "^2.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/cogl-16": { - "version": "16.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/cogl-16/-/cogl-16-16.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-0UxbYg0gk0lcGnAwArY0Gq6ljfpzTUcnlyn1iCVI51nvFTyVCIRk4e89PM30aE/QN0daeFs/4+fjEsYUhHKNjA==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gl-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/mtk-16": "^16.0.0-4.0.0-beta.23", - "@girs/xlib-2.0": "^2.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/cogl-2.0": { - "version": "2.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/cogl-2.0/-/cogl-2.0-2.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-OSFZav9AiarIY5YuTEjOAG1IghHMuz/E+ZroPtuuI4Nhjp5AGVj7OevVw6QOVzhrGY95a3/ZhSP5sSpI8EdWyA==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gl-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/freetype2-2.0": { - "version": "2.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/freetype2-2.0/-/freetype2-2.0-2.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-DpMJET2s2ZXmGjScv+tu8tyEDIT6mIEWgY/Lp5HaXTUkKpw+LdtVV0bEwiXMYn3TSs6QYJZyBxNlwTSD3qb+Ww==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gck-2": { - "version": "4.4.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gck-2/-/gck-2-4.4.0-4.0.0-beta.23.tgz", - "integrity": "sha512-PY1yLymRxNDnUMrLAvu6dAImoUco4RpkFv+u72AUGXcgbmvPNcRwBC/11TcLHlqnzOzy31QjWZBYsbUE89jWiA==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gcr-4": { - "version": "4.4.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gcr-4/-/gcr-4-4.4.0-4.0.0-beta.23.tgz", - "integrity": "sha512-Oo6/wDbbAq+ytfFGhOHFjOjfVdhTkE0EvdvTLSa31qNfCEI+0I0OwL1gG35DoUCKeESqd6WgpqMXmMnop3/yIg==", - "license": "MIT", - "dependencies": { - "@girs/gck-2": "^4.4.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gdesktopenums-3.0": { - "version": "3.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gdesktopenums-3.0/-/gdesktopenums-3.0-3.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-T2LpS68w/HtOH1Cd/RGWOXrqPJEsUNOhUOpjwZhH6lu3Ey1IYEq5yyyIeWi3ts9QS4SjbhZvqMTJKFwA5xywMw==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gdk-4.0": { - "version": "4.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gdk-4.0/-/gdk-4.0-4.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-esdIxWgxyKQKYAsQBnTZPHocf5CXwEovt6Xp2aIVxbATLzzd0x35194PPjq51IbZ7eRi/XnBC9yTlNI5JYVNog==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/pangocairo-1.0": "^1.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gdkpixbuf-2.0": { - "version": "2.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gdkpixbuf-2.0/-/gdkpixbuf-2.0-2.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-Apku+aCEsosPXdEOnDtI3GPdX2Seo2rWUm10aY3ijGOnvafjmsJkHwWlThHzV850Ygi7dw3hBBys0z8hG6Cf1A==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gdm-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gdm-1.0/-/gdm-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-mKsmZTShn6xh0yzFcgzCddG3X2oXQi0nc5Q3AR3TPk+UURbREBdJwzeoIKI3Uqi03gwaRQVtFopHQ1B5IRSTAg==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gio-2.0": { - "version": "2.84.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gio-2.0/-/gio-2.0-2.84.0-4.0.0-beta.23.tgz", - "integrity": "sha512-FcGgYQ96KhdeFJvUYsIm0XmOYaYnTfpHKzPUOW4IcJm5q38RNDKgoijBMfedv3fMxnPDtpMb08ZFD6P1GjJY8A==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gjs": { - "version": "4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gjs/-/gjs-4.0.0-beta.23.tgz", - "integrity": "sha512-Yz1s23WaGAsVHetWFReVxeYDJbVFtJ6KZ7u+qzWa/B3P2mB+5aXpGc7nV6Bx7GbRc48FuGgtbKxVo0rq26Ug/Q==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gl-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gl-1.0/-/gl-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-OaaqoeoZG2ovpf0SrDXDVNZOGk5Ay+tdw6M+sAsqjI+02epWgItWvdl3HfGd/82ENviIufw3s+vtWKodNUoWFw==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/glib-2.0": { - "version": "2.84.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/glib-2.0/-/glib-2.0-2.84.0-4.0.0-beta.23.tgz", - "integrity": "sha512-epQae3f9rDeIrEgA9hOEiNAppJYQAfVRZ4Uh/0yO9NtAQR6PTfXUpjotw9ndjVxsHpEmRODoM2t/kytCYqKmVg==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gmodule-2.0": { - "version": "2.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gmodule-2.0/-/gmodule-2.0-2.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-Dc+Pq1peNlwQ0o/WFsUzT1qt3oqgMLBhzjEfOTGAD0Jw1Ut3QCoBuryVFFNMIruOKnSSBoBnQO7Qelly5aSd2w==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gnome-shell": { - "version": "48.0.2", - "resolved": "https://registry.npmjs.org/@girs/gnome-shell/-/gnome-shell-48.0.2.tgz", - "integrity": "sha512-hrlnTCc6y9O7GTn7M7YAufKdmIF8Et7ZFTRRUVXyv3hBHAor0bUFDrHdmVD+D7KdMHCJrtaLW6EtUCRQyovU2A==", - "license": "MIT", - "dependencies": { - "@girs/accountsservice-1.0": "1.0.0-4.0.0-beta.23", - "@girs/adw-1": "^1.8.0-4.0.0-beta.23", - "@girs/atk-1.0": "^2.56.0-4.0.0-beta.23", - "@girs/clutter-16": "^16.0.0-4.0.0-beta.23", - "@girs/cogl-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gcr-4": "^4.4.0-4.0.0-beta.23", - "@girs/gdm-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gnomebg-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gnomebluetooth-3.0": "^3.0.0-4.0.0-beta.23", - "@girs/gnomedesktop-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gtk-4.0": "^4.18.3-4.0.0-beta.23", - "@girs/gvc-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/meta-16": "^16.0.0-4.0.0-beta.23", - "@girs/mtk-16": "^16.0.0-4.0.0-beta.23", - "@girs/polkit-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/shell-16": "^16.0.0-4.0.0-beta.23", - "@girs/shew-0": "^0.0.0-4.0.0-beta.23", - "@girs/st-16": "^16.0.0-4.0.0-beta.23", - "@girs/upowerglib-1.0": "^0.99.1-4.0.0-beta.23" - } - }, - "node_modules/@girs/gnomebg-4.0": { - "version": "4.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gnomebg-4.0/-/gnomebg-4.0-4.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-mXipjnVd+lUSMhUeugo49TXo32ihlKiN2ggpGDLIcD6ZfGe644DSgxoHFeYkn44HmNW39DvSqF9AcSvLP0cZJA==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gdesktopenums-3.0": "^3.0.0-4.0.0-beta.23", - "@girs/gdk-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gnomedesktop-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/pangocairo-1.0": "^1.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gnomebluetooth-3.0": { - "version": "3.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gnomebluetooth-3.0/-/gnomebluetooth-3.0-3.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-nLpLGgJwqaxtrie//bodjb9+CnELo6AqXM6QDi13C2pDlfMZGeCdLZj3kRvqqCLnPRJybIUVEjRLSEloZUHJnQ==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gnomedesktop-4.0": { - "version": "4.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gnomedesktop-4.0/-/gnomedesktop-4.0-4.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-pkH6574kp371HH0F/M77lz7e8fK4hzpxaOz5w2cNoYdU3sMqUgET0nak0gxOsjuTBzd2gPZm3gQHhOz/J4AEtw==", - "license": "MIT", - "dependencies": { - "@girs/gdesktopenums-3.0": "^3.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gobject-2.0": { - "version": "2.84.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gobject-2.0/-/gobject-2.0-2.84.0-4.0.0-beta.23.tgz", - "integrity": "sha512-GNWQDLo+Nmq2FQNPljKKh4Zplp8vZwwr0hj1sf4lbJ36zbVsovrhfNozqaph0XNjv8vtHeTcXUocGQprM9FHCg==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/graphene-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/graphene-1.0/-/graphene-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-C6HAR88uCAi6xCKip208tPdzYUBFICiCyBSBm+gVzniEfikNM4CVN7+tHHwp4Gd1FKixK5EMVDIYs5sCfToNWQ==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gsk-4.0": { - "version": "4.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gsk-4.0/-/gsk-4.0-4.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-zLjklfxLjef6SV5VEQ2+52G/d+hQqmp6HbBu0/Jn5CLFFYe22LmDQWSEtGOn0NwKDL7XltXaxKoT/JBHEQsgcg==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gdk-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/pangocairo-1.0": "^1.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gtk-4.0": { - "version": "4.18.3-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gtk-4.0/-/gtk-4.0-4.18.3-4.0.0-beta.23.tgz", - "integrity": "sha512-CsMPZLHQz+kWP81zR8AfPRpqUh9g1i5QNG08E9shj3Z9hvbR3goXmQXCSjgVxkcD40YsFn2tlc5FF/aztwY45Q==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gdk-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/gsk-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/pangocairo-1.0": "^1.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/gvc-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/gvc-1.0/-/gvc-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-Pzx/2KP0wBBMLmLcpwyVN6HE6SCPjlOqI2GCM81ztfb/EABAxAgq7liMua9RbIlo+eKj7e+GBb3rq8mEphgvcg==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/harfbuzz-0.0": { - "version": "9.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/harfbuzz-0.0/-/harfbuzz-0.0-9.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-9uWYDEUhkyoClR4GHv69AMHRDtcNSwidtA8MG8c1rMDT5qWNWkwfQK5hwX8/oBCbL0LqJNeMfJByIQ3yLfgQGg==", - "license": "MIT", - "dependencies": { - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/meta-16": { - "version": "16.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/meta-16/-/meta-16-16.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-qKto7mjzIS3D/uFRJxVWUFAV7VD0H2sbW3FDU9pvyVM++mtnrBnSi3SeTBJhIVFOhFCurcyn4SpqSoD7XkZ0uw==", - "license": "MIT", - "dependencies": { - "@girs/atk-1.0": "^2.56.0-4.0.0-beta.23", - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/clutter-16": "^16.0.0-4.0.0-beta.23", - "@girs/cogl-16": "^16.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gdesktopenums-3.0": "^3.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gl-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/mtk-16": "^16.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/xfixes-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/xlib-2.0": "^2.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/mtk-16": { - "version": "16.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/mtk-16/-/mtk-16-16.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-nLiqoarVgY4nPl6aBsuxzRdiRMGwyXmzlbLSTtCPUsK73QeKWfsdNtU4xDeC3WkBNtYM8mnosF/sqBodbR+lrg==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/nm-1.0": { - "version": "1.49.4-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/nm-1.0/-/nm-1.0-1.49.4-4.0.0-beta.23.tgz", - "integrity": "sha512-N0TCk6b0KDH4p/h91+aiusSHdJ4986vjkc5NFKEPS+QHBUyqHU4nf/+RAU1bfII/KU2rQejJfx/yDRGc6PwyIw==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/pango-1.0": { - "version": "1.56.4-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/pango-1.0/-/pango-1.0-1.56.4-4.0.0-beta.23.tgz", - "integrity": "sha512-gezMBRQerPUt7xLGzx34W0UFK+AVf2S7GPKm1LK8dGGq4qnjkkEdf1w2wcN/iV3lLCxz1+4U0MmBArrqcSe2hQ==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/pangocairo-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/pangocairo-1.0/-/pangocairo-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-8omT0HAxzj+IDLIYLv08GjXc43yRs5QXxttEtV+/0aDWX0XOyaenuWg9cNS8lwBKPIa5tW9lcdLCudyBJ2xcqA==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23" - } - }, - "node_modules/@girs/polkit-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/polkit-1.0/-/polkit-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-jayhgMeindShO2SMbEZduYcFrU5GaHjgJWK7zGdkg3QDSKhy1pZJwxmDJcq/yvNtMmcGsws7aTrLcnAYrhjg0w==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/polkitagent-1.0": { - "version": "1.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/polkitagent-1.0/-/polkitagent-1.0-1.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-LAwHOtoaWJ1SuAKBKXeTa2pgHZGUyN6X9qujHpnzVDpli1gawlY7irb7fk/sCkc/Nxt4IgN2YfCE+BENi3726Q==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/polkit-1.0": "^1.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/shell-16": { - "version": "16.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/shell-16/-/shell-16-16.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-Gynf4hxPnbuzW6FkmMIay1ky//tmAIWaOvXgV1So+i2BlyglJXCo2WYSCxjEtp0+JrNvSWBnKf7Hnh9S++30dQ==", - "license": "MIT", - "dependencies": { - "@girs/atk-1.0": "^2.56.0-4.0.0-beta.23", - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/clutter-16": "^16.0.0-4.0.0-beta.23", - "@girs/cogl-16": "^16.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gck-2": "^4.4.0-4.0.0-beta.23", - "@girs/gcr-4": "^4.4.0-4.0.0-beta.23", - "@girs/gdesktopenums-3.0": "^3.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gl-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/gvc-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/meta-16": "^16.0.0-4.0.0-beta.23", - "@girs/mtk-16": "^16.0.0-4.0.0-beta.23", - "@girs/nm-1.0": "^1.49.4-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/polkit-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/polkitagent-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/st-16": "^16.0.0-4.0.0-beta.23", - "@girs/xfixes-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/xlib-2.0": "^2.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/shew-0": { - "version": "0.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/shew-0/-/shew-0-0.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-voxcO7uev7ZnrPfGoz9y0HV3fToXe5Q/Dzn1uKDVmebFKlcl8Oznr/zbPEuym+K7lKc4LVMos+f7HelxVfD27w==", - "license": "MIT", - "dependencies": { - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gdk-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/gsk-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/gtk-4.0": "^4.18.3-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/pangocairo-1.0": "^1.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/st-16": { - "version": "16.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/st-16/-/st-16-16.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-eVaxgQZzwTyhKSv5OD9phI2c8SzKVnMA6b2SahJ4V/PR6pC65JsGZFmJE6WdtU23XKdFEoMnG/CKegKKyaw0eg==", - "license": "MIT", - "dependencies": { - "@girs/atk-1.0": "^2.56.0-4.0.0-beta.23", - "@girs/cairo-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/clutter-16": "^16.0.0-4.0.0-beta.23", - "@girs/cogl-16": "^16.0.0-4.0.0-beta.23", - "@girs/freetype2-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gdesktopenums-3.0": "^3.0.0-4.0.0-beta.23", - "@girs/gdkpixbuf-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gl-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/graphene-1.0": "^1.0.0-4.0.0-beta.23", - "@girs/harfbuzz-0.0": "^9.0.0-4.0.0-beta.23", - "@girs/meta-16": "^16.0.0-4.0.0-beta.23", - "@girs/mtk-16": "^16.0.0-4.0.0-beta.23", - "@girs/pango-1.0": "^1.56.4-4.0.0-beta.23", - "@girs/xfixes-4.0": "^4.0.0-4.0.0-beta.23", - "@girs/xlib-2.0": "^2.0.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/upowerglib-1.0": { - "version": "0.99.1-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/upowerglib-1.0/-/upowerglib-1.0-0.99.1-4.0.0-beta.23.tgz", - "integrity": "sha512-GpWzIVdXSK2dhk1I7utZIzao7NLSIP4iZ/EOXUUV7HSaDeNW/1orR5jUZMJOQhfH8w0JiFsfaoZTm/7TTZlUPg==", - "license": "MIT", - "dependencies": { - "@girs/gio-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gjs": "^4.0.0-beta.23", - "@girs/glib-2.0": "^2.84.0-4.0.0-beta.23", - "@girs/gmodule-2.0": "^2.0.0-4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/xfixes-4.0": { - "version": "4.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/xfixes-4.0/-/xfixes-4.0-4.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-66pjrl+5kXurr1NRBE6rFBixQp3F15HvYrWkzXzrTJABTt3H1it82jsJkprA1h3Z7Z8ucxx/u3fEWMJGY5xUjQ==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@girs/xlib-2.0": { - "version": "2.0.0-4.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@girs/xlib-2.0/-/xlib-2.0-2.0.0-4.0.0-beta.23.tgz", - "integrity": "sha512-FETH5hCvxs45ZonJ948nosy0tXAIZPTyrtF0r6TwVvjMHSHuINXsU4ylxM7Uc0xeuFh5KL+3ShAPXzwi9FynVg==", - "license": "MIT", - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gobject-2.0": "^2.84.0-4.0.0-beta.23" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/types": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz", - "integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { + "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", - "dependencies": { + "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "engines": { - "node": ">=8" + "requires": { + "color-convert": "^1.9.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "requires": { + "sprintf-js": "~1.0.2" } }, - "node_modules/are-docs-informative": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { + "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/brace-expansion": { + "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "dependencies": { + "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/callsites": { + "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "dev": true }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dev": true, - "dependencies": { + "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "node_modules/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/concat-map": { + "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/cross-spawn": { + "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, - "dependencies": { + "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" } }, - "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "requires": { + "ms": "2.1.2" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "node_modules/doctrine": { + "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "dependencies": { + "requires": { "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "requires": { + "ansi-colors": "^4.1.1" } }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz", + "integrity": "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==", "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.1", + "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.3.2", + "debug": "^4.0.1", "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "lodash": "^4.17.21", + "minimatch": "^3.0.4", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" } }, - "node_modules/eslint-plugin-jsdoc": { - "version": "50.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.7.1.tgz", - "integrity": "sha512-XBnVA5g2kUVokTNUiE1McEPse5n9/mNUmuJcx52psT6zBs2eVcXSmQBvjfa7NZdfLVSy3u1pEDDUxoxpwy89WA==", + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@es-joy/jsdoccomment": "~0.50.2", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.4.1", - "escape-string-regexp": "^4.0.0", - "espree": "^10.3.0", - "esquery": "^1.6.0", - "parse-imports-exports": "^0.2.4", - "semver": "^7.7.2", - "spdx-expression-parse": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { + "requires": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "estraverse": "^4.1.1" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "requires": { + "eslint-visitor-keys": "^1.1.0" }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, - "license": "BSD-3-Clause", + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { "estraverse": "^5.1.0" }, - "engines": { - "node": ">=0.10" + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, - "node_modules/esrecurse": { + "esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "dependencies": { + "requires": { "estraverse": "^5.2.0" }, - "engines": { - "node": ">=4.0" + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true }, - "node_modules/esutils": { + "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "dev": true }, - "node_modules/fast-deep-equal": { + "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" + "dev": true }, - "node_modules/fast-json-stable-stringify": { + "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true }, - "node_modules/file-entry-cache": { + "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "dependencies": { + "requires": { "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", - "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", - "dev": true, - "dependencies": { - "flatted": "^3.2.7", - "keyv": "^4.5.3", + "requires": { + "flatted": "^3.1.0", "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=12.0.0" } }, - "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, - "node_modules/fs.realpath": { + "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, - "dependencies": { + "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.1.1", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" + "requires": { + "is-glob": "^4.0.1" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "globals": { + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", + "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", "dev": true, - "license": "MIT", - "dependencies": { + "requires": { "type-fest": "^0.20.2" }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { + "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/imurmurhash": { + "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, - "node_modules/inflight": { + "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, - "dependencies": { + "requires": { "once": "^1.3.0", "wrappy": "1" } }, - "node_modules/inherits": { + "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/is-extglob": { + "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, - "dependencies": { + "requires": { "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { + "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", - "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "node_modules/json-schema-traverse": { + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true }, - "node_modules/levn": { + "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "dependencies": { + "requires": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "requires": { + "yallist": "^4.0.0" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "license": "MIT" + "requires": { + "brace-expansion": "^1.1.7" + } }, - "node_modules/natural-compare": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/once": { + "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "dependencies": { + "requires": { "wrappy": "1" } }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", + "requires": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { + "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "license": "MIT", - "dependencies": { + "requires": { "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" } }, - "node_modules/parse-imports-exports": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", - "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parse-statements": "1.0.11" - } - }, - "node_modules/parse-statements": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", - "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { + "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, - "node_modules/path-key": { + "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } + "dev": true }, - "node_modules/prelude-ls": { + "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } + "dev": true }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, - "node_modules/resolve-from": { + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } + "dev": true }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { + "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, - "dependencies": { + "requires": { "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" + "requires": { + "lru-cache": "^6.0.0" } }, - "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { + "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "dependencies": { + "requires": { "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" } }, - "node_modules/shebang-regex": { + "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } + "dev": true }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { + "slice-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", - "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, - "engines": { - "node": ">=8" + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, - "node_modules/strip-json-comments": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/type-check": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.4.0.tgz", + "integrity": "sha512-7QD2l6+KBSLwf+7MuYocbWvRPdOu63/trReTLu2KFwkgctnub1auoF+Y1WYcm09CTM7quuscrzqmASaLHC/K4Q==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "dependencies": { + "requires": { "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uri-js": { + "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { + "requires": { "punycode": "^2.1.0" } }, - "node_modules/which": { + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "dependencies": { + "requires": { "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } } diff --git a/package.json b/package.json index c4d4367..7bb10a3 100644 --- a/package.json +++ b/package.json @@ -2,23 +2,16 @@ "name": "top-bar-organizer", "version": "1.0.0", "description": "A Gnome Shell Extension for organizing your Gnome Shell top bar.", - "type": "module", "directories": { "doc": "docs" }, "repository": { "type": "git", - "url": "git@gitlab.gnome.org:june/top-bar-organizer.git" + "url": "git@gitlab.gnome.org:julianschacher/top-bar-organizer.git" }, - "author": "June", + "author": "Julian Schacher", "license": "GPL-3.0-or-later", "devDependencies": { - "eslint": "^8.57.1", - "eslint-plugin-jsdoc": "^50.7.1", - "typescript": "^5.8.3" - }, - "dependencies": { - "@girs/gjs": "^4.0.0-beta.23", - "@girs/gnome-shell": "^48.0.2" + "eslint": "^7.26.0" } } diff --git a/package.sh b/package.sh index 63497dc..bc05fc0 100755 --- a/package.sh +++ b/package.sh @@ -4,14 +4,8 @@ set -e REAL_BASE_DIR=$( dirname $( readlink -f "$0" )) -rm -rf "$REAL_BASE_DIR/dist" -cd "$REAL_BASE_DIR" -npx tsc -cp "$REAL_BASE_DIR/src/metadata.json" "$REAL_BASE_DIR/dist/metadata.json" -gnome-extensions pack "$REAL_BASE_DIR/dist" \ - --force \ - --extra-source extensionModules \ - --extra-source prefsModules \ - --extra-source ../data/ui \ - --extra-source ../data/css \ - --schema ../data/org.gnome.shell.extensions.top-bar-organizer.gschema.xml +glib-compile-schemas "$REAL_BASE_DIR/src/schemas" +rm "$REAL_BASE_DIR/top-bar-organizer@julian.gse.jsts.xyz.zip" || true +cd "$REAL_BASE_DIR/src" +zip -r "$REAL_BASE_DIR/top-bar-organizer@julian.gse.jsts.xyz.zip" * +zip -d "$REAL_BASE_DIR/top-bar-organizer@julian.gse.jsts.xyz.zip" "schemas/org.gnome.shell.extensions.top-bar-organizer.gschema.xml" diff --git a/res/Screenshot of GNOME Shell 43 with Top Bar Organizer v6 and its preferences in light theme 2023-01-30.jpg b/res/Screenshot of GNOME Shell 43 with Top Bar Organizer v6 and its preferences in light theme 2023-01-30.jpg deleted file mode 100644 index bb9594d..0000000 Binary files a/res/Screenshot of GNOME Shell 43 with Top Bar Organizer v6 and its preferences in light theme 2023-01-30.jpg and /dev/null differ diff --git a/src/extension.js b/src/extension.js new file mode 100644 index 0000000..7740169 --- /dev/null +++ b/src/extension.js @@ -0,0 +1,451 @@ +/* + * This file is part of Top-Bar-Organizer (a Gnome Shell Extension for + * organizing your Gnome Shell top bar). + * Copyright (C) 2021 Julian Schacher + * + * Top-Bar-Organizer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* exported init */ +"use strict"; + +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 BoxOrderCreator = Me.imports.extensionModules.BoxOrderCreator; + +class Extension { + constructor() { + this.settings = ExtensionUtils.getSettings(); + } + + enable() { + // Create an instance of AppIndicatorKStatusNotifierItemManager to handle AppIndicator/KStatusNotifierItem items. + this._appIndicatorKStatusNotifierItemManager = new AppIndicatorKStatusNotifierItemManager.AppIndicatorKStatusNotifierItemManager(); + + // Create an instance of BoxOrderCreator for the creation of special box + // orders. + this._boxOrderCreator = new BoxOrderCreator.BoxOrderCreator(this._appIndicatorKStatusNotifierItemManager); + + this._addNewItemsToBoxOrders(); + this._orderTopBarItemsOfAllBoxes(); + 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, get an updated + /// box order and save it, if needed. + let updatedBoxOrder; + switch (box) { + case "left": + updatedBoxOrder = this._createUpdatedBoxOrders().left; + break; + case "center": + updatedBoxOrder = this._createUpdatedBoxOrders().center; + break; + case "right": + updatedBoxOrder = this._createUpdatedBoxOrders().right; + break; + } + // Only save the updated box order to settings, if it is + // different, to avoid looping. + const currentBoxOrder = this.settings.get_strv(`${box}-box-order`); + if (JSON.stringify(currentBoxOrder) !== JSON.stringify(updatedBoxOrder)) { + this.settings.set_strv(`${box}-box-order`, updatedBoxOrder); + } + }); + 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); + } + } + + //////////////////////////////////////////////////////////////////////////// + /// Methods used on extension enable. /// + //////////////////////////////////////////////////////////////////////////// + + /** + * This method adds all new items currently present in the Gnome Shell top + * bar to the box orders. + */ + _addNewItemsToBoxOrders() { + const boxOrders = this._createUpdatedBoxOrders(); + this.settings.set_strv("left-box-order", boxOrders.left); + this.settings.set_strv("center-box-order", boxOrders.center); + this.settings.set_strv("right-box-order", boxOrders.right); + } + + /** + * This methods orders the top bar items of all boxes according to the + * configured box orders using `this._orderTopBarItems`. + */ + _orderTopBarItemsOfAllBoxes() { + this._orderTopBarItems("left"); + this._orderTopBarItems("center"); + this._orderTopBarItems("right"); + } + + /** + * 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 handles top + * bar item additions to make sure that they are added in the correct + * position and box. + */ + _overwritePanelAddToPanelBox() { + // Add the original `Panel._addToPanelBox` method as + // `Panel._originalAddToPanelBox`. + Panel.Panel.prototype._originalAddToPanelBox = Panel.Panel.prototype._addToPanelBox; + + // This function gets used by the `Panel._addToPanelBox` overwrite to + // determine the position and box for a new item. + // It also adds the new item to the relevant box order, if it isn't in + // it already. + const getPositionAndBoxOverwrite = (role, box, indicator) => { + const boxOrders = { + left: this.settings.get_strv("left-box-order"), + center: this.settings.get_strv("center-box-order"), + right: this.settings.get_strv("right-box-order"), + }; + let boxOrder; + + // Handle the case where the new item is a + // AppIndicator/KStatusNotifierItem. + if (role.startsWith("appindicator-")) { + switch (box) { + case "left": + boxOrder = this.settings.get_strv("left-box-order"); + this._appIndicatorKStatusNotifierItemManager.handleAppIndicatorKStatusNotifierItemItem(indicator.container, role, boxOrder, boxOrders); + this.settings.set_strv("left-box-order", boxOrder); + break; + case "center": + boxOrder = this.settings.get_strv("center-box-order"); + this._appIndicatorKStatusNotifierItemManager.handleAppIndicatorKStatusNotifierItemItem(indicator.container, role, boxOrder, boxOrders); + this.settings.set_strv("center-box-order", boxOrder); + break; + case "right": + boxOrder = this.settings.get_strv("right-box-order"); + this._appIndicatorKStatusNotifierItemManager.handleAppIndicatorKStatusNotifierItemItem(indicator.container, role, boxOrder, boxOrders, true); + this.settings.set_strv("right-box-order", boxOrder); + break; + } + } + + // Get the resolved box orders for all boxes. + const resolvedBoxOrders = { + left: this._appIndicatorKStatusNotifierItemManager.createResolvedBoxOrder(this.settings.get_strv("left-box-order")), + center: this._appIndicatorKStatusNotifierItemManager.createResolvedBoxOrder(this.settings.get_strv("center-box-order")), + right: this._appIndicatorKStatusNotifierItemManager.createResolvedBoxOrder(this.settings.get_strv("right-box-order")), + }; + // Also get the restricted valid box order of the target box. + const restrictedValidBoxOrderOfTargetBox = this._boxOrderCreator.createRestrictedValidBoxOrder(box); + + // Get the index of the role for each box order. + const indices = { + left: resolvedBoxOrders.left.indexOf(role), + center: resolvedBoxOrders.center.indexOf(role), + right: resolvedBoxOrders.right.indexOf(role), + }; + + // If the role is not already configured in one of the box orders, + // just add it to the target box order at the end/beginning, save + // the updated box order and return the relevant position and box. + if (indices.left === -1 + && indices.center === -1 + && indices.right === -1) { + switch (box) { + // For the left and center box, insert the role at the end, + // since they're LTR. + case "left": + boxOrders["left"].push(role); + this.settings.set_strv("left-box-order", boxOrders["left"]); + return { + position: restrictedValidBoxOrderOfTargetBox.length - 1, + box: box + }; + case "center": + boxOrders["center"].push(role); + this.settings.set_strv("center-box-order", boxOrders["center"]); + return { + position: restrictedValidBoxOrderOfTargetBox.length - 1, + box: box + }; + // For the right box, insert the role at the beginning, + // since it's RTL. + case "right": + boxOrders["right"].unshift(role); + this.settings.set_strv("right-box-order", boxOrders["right"]); + return { + position: 0, + box: box + }; + } + } + + /// Since the role is already configured in one of the box orders, + /// determine the correct insertion index for the position. + const determineInsertionIndex = (index, restrictedValidBoxOrder, boxOrder) => { + // Set the insertion index initially to 0, so that if no closest + // item can be found, the new item just gets inserted at the + // beginning. + let insertionIndex = 0; + + // Find the index of the closest item, which is also in the + // valid box order and before the new item. + // This way, we can insert the new item just after the index of + // this closest item. + for (let i = index - 1; i >= 0; i--) { + let potentialClosestItemIndex = restrictedValidBoxOrder.indexOf(boxOrder[i]); + if (potentialClosestItemIndex !== -1) { + insertionIndex = potentialClosestItemIndex + 1; + break; + } + } + + return insertionIndex; + }; + + if (indices.left !== -1) { + return { + position: determineInsertionIndex(indices.left, this._boxOrderCreator.createRestrictedValidBoxOrder("left"), boxOrders.left), + box: "left" + }; + } + + if (indices.center !== -1) { + return { + position: determineInsertionIndex(indices.center, this._boxOrderCreator.createRestrictedValidBoxOrder("center"), boxOrders.center), + box: "center" + }; + } + + if (indices.right !== -1) { + return { + position: determineInsertionIndex(indices.right, this._boxOrderCreator.createRestrictedValidBoxOrder("right"), boxOrders.right), + box: "right" + }; + } + }; + + // Overwrite `Panel._addToPanelBox`. + Panel.Panel.prototype._addToPanelBox = function (role, indicator, position, box) { + // Get the position and box overwrite. + let positionBoxOverwrite; + switch (box) { + case this._leftBox: + positionBoxOverwrite = getPositionAndBoxOverwrite(role, "left", indicator); + break; + case this._centerBox: + positionBoxOverwrite = getPositionAndBoxOverwrite(role, "center", indicator); + break; + case this._rightBox: + positionBoxOverwrite = getPositionAndBoxOverwrite(role, "right", indicator); + break; + } + + // Call the original `Panel._addToPanelBox` with the position + // overwrite as the position argument and the box determined by the + // box overwrite as the box argument. + switch (positionBoxOverwrite.box) { + case "left": + this._originalAddToPanelBox(role, indicator, positionBoxOverwrite.position, Main.panel._leftBox); + break; + case "center": + this._originalAddToPanelBox(role, indicator, positionBoxOverwrite.position, Main.panel._centerBox); + break; + case "right": + this._originalAddToPanelBox(role, indicator, positionBoxOverwrite.position, Main.panel._rightBox); + break; + } + }; + } + + //////////////////////////////////////////////////////////////////////////// + /// 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 adds all new items currently present in the Gnome Shell top + * bar to the correct box order and returns the new box orders. + * @returns {BoxOrders} - The updated box orders. + */ + _createUpdatedBoxOrders() { + // Load the configured box orders from settings. + const boxOrders = { + left: this.settings.get_strv("left-box-order"), + center: this.settings.get_strv("center-box-order"), + right: this.settings.get_strv("right-box-order"), + }; + + // Get items (or rather their roles) currently present in the Gnome + // Shell top bar and index them using their associated indicator + // container. + let indicatorContainerRoleMap = new Map(); + for (const role in Main.panel.statusArea) { + indicatorContainerRoleMap.set(Main.panel.statusArea[role].container, role); + } + + // Get the indicator containers (of the items) currently present in the + // Gnome Shell top bar boxes. + const boxOrderIndicatorContainers = { + left: Main.panel._leftBox.get_children(), + center: Main.panel._centerBox.get_children(), + // Reverse this array, since the items in the left and center box + // are logically LTR, while the items in the right box are RTL. + right: Main.panel._rightBox.get_children().reverse() + }; + + // This function goes through the items (or rather their indicator + // containers) of the given box and adds new items (or rather their + // roles) to the box order. + const addNewItemsToBoxOrder = (boxIndicatorContainers, boxOrder, box) => { + for (const indicatorContainer of boxIndicatorContainers) { + // First get the role associated with the current indicator + // container. + const associatedRole = indicatorContainerRoleMap.get(indicatorContainer); + + // Handle an AppIndicator/KStatusNotifierItem item differently. + if (associatedRole.startsWith("appindicator-")) { + this._appIndicatorKStatusNotifierItemManager.handleAppIndicatorKStatusNotifierItemItem(indicatorContainer, associatedRole, boxOrder, boxOrders, box === "right"); + continue; + } + + // Add the role to the box order, if it isn't in in one already. + if (!boxOrders.left.includes(associatedRole) + && !boxOrders.center.includes(associatedRole) + && !boxOrders.right.includes(associatedRole)) { + if (box === "right") { + // Add the items to the beginning for this array, since + // its RTL. + boxOrder.unshift(associatedRole); + } else { + boxOrder.push(associatedRole); + } + } + } + }; + + addNewItemsToBoxOrder(boxOrderIndicatorContainers.left, boxOrders.left, "left"); + addNewItemsToBoxOrder(boxOrderIndicatorContainers.center, boxOrders.center, "center"); + addNewItemsToBoxOrder(boxOrderIndicatorContainers.right, boxOrders.right, "right"); + + return boxOrders; + } + + /** + * 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._boxOrderCreator.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. + // Declare panelBoxChildCount here, because we might need it later. + let panelBoxChildCount; + switch (box) { + // If the left or center box is the target box, order form left to + // right. + case "left": + case "center": + 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); + } + break; + // If the right box is the target box, order from right to left. + // The order direction is important for the case, where the box + // order got set to a box order, which doesn't include all the roles + // to cover all items of the respective box. + // This could happen, when the box order gets set to a permutation + // of an outdated box order. + case "right": + panelBoxChildCount = panelBox.get_children().length; + for (let i = 0; i < validBoxOrder.length; i++) { + const role = validBoxOrder[validBoxOrder.length - 1 - 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, panelBoxChildCount - 1 -i); + } + break; + } + // 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(); +} diff --git a/src/extension.ts b/src/extension.ts deleted file mode 100644 index 026de7e..0000000 --- a/src/extension.ts +++ /dev/null @@ -1,200 +0,0 @@ -"use strict"; - -import St from "gi://St" -import type Gio from "gi://Gio" - -import * as Main from "resource:///org/gnome/shell/ui/main.js"; -import * as Panel from "resource:///org/gnome/shell/ui/panel.js"; -import { Extension } from "resource:///org/gnome/shell/extensions/extension.js"; - -import BoxOrderManager from "./extensionModules/BoxOrderManager.js"; -import type { Box } from "./extensionModules/BoxOrderManager.js"; - -export interface CustomPanel extends Panel.Panel { - _leftBox: St.BoxLayout; - _centerBox: St.BoxLayout; - _rightBox: St.BoxLayout; -} - -export default class TopBarOrganizerExtension extends Extension { - _settings!: Gio.Settings; - _boxOrderManager!: BoxOrderManager; - _settingsHandlerIds!: number[]; - - enable(): void { - this._settings = this.getSettings(); - - this._boxOrderManager = new BoxOrderManager({}, this._settings); - - /// Stuff to do on startup(extension enable). - // Initially handle new top bar items and order top bar boxes. - this.#handleNewItemsAndOrderTopBar(); - - // Overwrite the `Panel._addToPanelBox` method with one handling new - // items. - this.#overwritePanelAddToPanelBox(); - // Handle AppIndicators getting ready, to handle new AppIndicator items. - this._boxOrderManager.connect("appIndicatorReady", () => { - this.#handleNewItemsAndOrderTopBar(); - }); - - // Handle changes of settings. - this._settingsHandlerIds = []; - const addSettingsChangeHandler = (settingsName: string) => { - const handlerId = this._settings.connect(`changed::${settingsName}`, () => { - this.#handleNewItemsAndOrderTopBar(); - }); - this._settingsHandlerIds.push(handlerId); - }; - addSettingsChangeHandler("left-box-order"); - addSettingsChangeHandler("center-box-order"); - addSettingsChangeHandler("right-box-order"); - addSettingsChangeHandler("hide"); - addSettingsChangeHandler("show"); - } - - disable(): void { - // Revert the overwrite of `Panel._addToPanelBox`. - // @ts-ignore - Panel.Panel.prototype._addToPanelBox = Panel.Panel.prototype._originalAddToPanelBox; - // Set `Panel._originalAddToPanelBox` to `undefined`. - // @ts-ignore - Panel.Panel.prototype._originalAddToPanelBox = undefined; - - // Disconnect signals. - for (const handlerId of this._settingsHandlerIds) { - this._settings.disconnect(handlerId); - } - this._boxOrderManager.disconnectSignals(); - - // @ts-ignore - this._settings = null; - // @ts-ignore - this._boxOrderManager = null; - } - - //////////////////////////////////////////////////////////////////////////// - /// Methods used on extension enable. /// - //////////////////////////////////////////////////////////////////////////// - - /** - * Overwrite `Panel._addToPanelBox` with a custom method, which simply calls - * the original one and handles new items and orders the top bar afterwards. - */ - #overwritePanelAddToPanelBox(): void { - // Add the original `Panel._addToPanelBox` method as - // `Panel._originalAddToPanelBox`. - // @ts-ignore - Panel.Panel.prototype._originalAddToPanelBox = Panel.Panel.prototype._addToPanelBox; - - const handleNewItemsAndOrderTopBar = () => { - this.#handleNewItemsAndOrderTopBar(); - }; - - // 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. - // @ts-ignore - this._originalAddToPanelBox(role, indicator, position, box); - handleNewItemsAndOrderTopBar(); - }; - } - - //////////////////////////////////////////////////////////////////////////// - /// 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 {Box} box - The box to order. - */ - #orderTopBarItems(box: Box): void { - // Only run, when the session mode is "user" or the parent session mode - // is "user". - if(Main.sessionMode.currentMode !== "user" && Main.sessionMode.parentMode !== "user") { - return; - } - - // Get the valid box order. - const validBoxOrder = this._boxOrderManager.getValidBoxOrder(box); - - // Get the relevant box of `Main.panel`. - let panelBox = (Main.panel as CustomPanel)[`_${box}Box`]; - - /// Go through the items of the validBoxOrder and order the GNOME Shell - /// top bar box accordingly. - for (let i = 0; i < validBoxOrder.length; i++) { - const item = validBoxOrder[i]; - // Get the indicator container associated with the current role. - const associatedIndicatorContainer = (Main.panel.statusArea as any)[item.role]?.container; - if (!(associatedIndicatorContainer instanceof St.Bin)) { - // TODO: maybe add logging - continue; - } - - // Save whether or not the indicator container is visible. - const isVisible = associatedIndicatorContainer.visible; - - const parent = associatedIndicatorContainer.get_parent(); - if (parent !== null) { - 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); - } - - // Hide the indicator container... - // - ...if it wasn't visible before and the hide property of the - // item is "default". - // - if the hide property of the item is "hide". - // In all other cases have the item show. - // An e.g. screen recording indicator still wouldn't show tho, since - // this here acts on the indicator container, but a screen recording - // indicator is hidden on the indicator level. - if ((!isVisible && item.hide === "default") || - item.hide === "hide") { - associatedIndicatorContainer.hide(); - } - } - // 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. - } - - /** - * This method handles all new items currently present in the top bar and - * orders the items of all top bar boxes. - */ - #handleNewItemsAndOrderTopBar(): void { - // Only run, when the session mode is "user" or the parent session mode - // is "user". - if(Main.sessionMode.currentMode !== "user" && Main.sessionMode.parentMode !== "user") { - return; - } - - this._boxOrderManager.saveNewTopBarItems(); - this.#orderTopBarItems("left"); - this.#orderTopBarItems("center"); - this.#orderTopBarItems("right"); - // In `this.#orderTopBarItems` it says to update the box orders to - // include potentially new items, since the ordering might have been - // based on an outdated box order. However, since we already handle new - // top bar items at the beginning of this method, this isn't a concern. - } -} diff --git a/src/extensionModules/AppIndicatorKStatusNotifierItemManager.js b/src/extensionModules/AppIndicatorKStatusNotifierItemManager.js new file mode 100644 index 0000000..e4c3e85 --- /dev/null +++ b/src/extensionModules/AppIndicatorKStatusNotifierItemManager.js @@ -0,0 +1,121 @@ +/* + * This file is part of Top-Bar-Organizer (a Gnome Shell Extension for + * organizing your Gnome Shell top bar). + * Copyright (C) 2021 Julian Schacher + * + * Top-Bar-Organizer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* exported AppIndicatorKStatusNotifierItemManager */ +"use strict"; + +var AppIndicatorKStatusNotifierItemManager = class AppIndicatorKStatusNotifierItemManager { + constructor() { + // Create an application-role map for associating roles with + // applications. + // This is needed so that this class can handle/manage + // AppIndicator/KStatusNotifierItem items. + this._applicationRoleMap = new Map(); + } + + /** + * Handle an AppIndicator/KStatusNotifierItem item. + * + * This function basically does the following two things: + * - Associate the role of the given item with the application of the + * AppIndicator/KStatusNotifierItem. + * - Add a placeholder for the roles associated with the application of the + * AppIndiciator/KStatusNotifierItem to the box order, if needed. + * + * Note: The caller is responsible for saving the updated box order to + * settings. + * @param {} indicatorContainer - The container of the indicator of the + * AppIndicator/KStatusNotifierItem item. + * @param {string} role - The role of the AppIndicator/KStatusNotifierItem + * item. + * @param {string[]} - The box order the placeholder should be added to, if + * needed. + * @param {BoxOrders} boxOrders - An object containing the box orders, which + * is currently getting worked on. + * @param {boolean} - Whether to add the placeholder to the beginning of the + * box order. + */ + handleAppIndicatorKStatusNotifierItemItem(indicatorContainer, role, boxOrder, boxOrders, atToBeginning = false) { + // Get the application the AppIndicator/KStatusNotifierItem is + // associated with. + const application = indicatorContainer.get_child()._indicator.id; + + // Associate the role with the application. + let roles = this._applicationRoleMap.get(application); + if (roles) { + // If the application already has an array of associated roles, just + // add the role to it, if needed. + if (!roles.includes(role)) roles.push(role); + } else { + // Otherwise create a new array. + this._applicationRoleMap.set(application, [ role ]); + } + + // Store a placeholder for the roles associated with the application in + // the box order, if needed. + // (Then later the `this.createResolvedBoxOrder` method can be used to + // get a box order, where the placeholder/s get/s replaced with the + // relevant roles (by using `this._applicationRoleMap`).) + const placeholder = `appindicator-kstatusnotifieritem-${application}`; + if (!boxOrders.left.includes(placeholder) + && !boxOrders.center.includes(placeholder) + && !boxOrders.right.includes(placeholder)) { + if (atToBeginning) { + boxOrder.unshift(placeholder); + } else { + boxOrder.push(placeholder); + } + } + } + + /** + * This function takes a box order and returns a box order, where all + * placeholders got replaced with their relevant roles. + * @param {string[]} boxOrder - The box order of which to replace the + * placeholders. + * @returns {string[]} A resolved box order, where all placeholders got + * replaced with their relevant roles. + */ + createResolvedBoxOrder(boxOrder) { + let resolvedBoxOrder = [ ]; + for (const item of boxOrder) { + // If the item isn't a placeholder, just add it to the new resolved + // box order. + if (!item.startsWith("appindicator-kstatusnotifieritem-")) { + resolvedBoxOrder.push(item); + continue; + } + + /// If the item is a placeholder, replace it. + // First get the application this placeholder is associated with. + const application = item.replace("appindicator-kstatusnotifieritem-", ""); + + // Then get the roles associated with the application. + let roles = this._applicationRoleMap.get(application); + + // Continue, if there are no roles. + if (!roles) continue; + // Otherwise add the roles + for (const role of roles) { + resolvedBoxOrder.push(role); + } + } + + return resolvedBoxOrder; + } +}; diff --git a/src/extensionModules/BoxOrderCreator.js b/src/extensionModules/BoxOrderCreator.js new file mode 100644 index 0000000..228bea9 --- /dev/null +++ b/src/extensionModules/BoxOrderCreator.js @@ -0,0 +1,137 @@ +/* + * This file is part of Top-Bar-Organizer (a Gnome Shell Extension for + * organizing your Gnome Shell top bar). + * Copyright (C) 2021 Julian Schacher + * + * Top-Bar-Organizer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* exported BoxOrderCreator */ +"use strict"; + +const ExtensionUtils = imports.misc.extensionUtils; + +const Main = imports.ui.main; + +/** + * A class exposing methods, which create special box orders. + */ +var BoxOrderCreator = class BoxOrderCreator { + /** + * @param {AppIndicatorKStatusNotifierItemManager} + * appIndicatorKStatusNotifierItemManager - An instance of + * AppIndicatorKStatusNotifierItemManager to be used in the methods of + * `this`. + */ + constructor(appIndicatorKStatusNotifierItemManager) { + this._appIndicatorKStatusNotifierItemManager = appIndicatorKStatusNotifierItemManager; + + this._settings = ExtensionUtils.getSettings(); + } + + /** + * This function creates a valid box order for the given box. + * This means it returns a box order for the box, where only roles are + * included, which have their associated indicator container already in some + * box of the Gnome Shell top bar. + * @param {string} box - The box to return the valid box order for. + * Must be one of the following values: + * - "left" + * - "center" + * - "right" + * @returns {string[]} - The valid box order. + */ + createValidBoxOrder(box) { + // Get a resolved box order. + let boxOrder = this._appIndicatorKStatusNotifierItemManager.createResolvedBoxOrder(this._settings.get_strv(`${box}-box-order`)); + + // Get the indicator containers (of the items) currently present in the + // Gnome Shell top bar. + const boxIndicatorContainers = [ ]; + + const addIndicatorContainersOfBox = (panelBox) => { + for (const indicatorContainer of panelBox.get_children()) { + boxIndicatorContainers.push(indicatorContainer); + } + }; + + addIndicatorContainersOfBox(Main.panel._leftBox); + addIndicatorContainersOfBox(Main.panel._centerBox); + addIndicatorContainersOfBox(Main.panel._rightBox); + + // Create an indicator containers set from the indicator containers for + // fast easy access. + const boxIndicatorContainersSet = new Set(boxIndicatorContainers); + + // Go through the box order and only add items to the valid box order, + // where their indicator is present in the Gnome Shell top bar + // currently. + let validBoxOrder = [ ]; + for (const role of boxOrder) { + // Get the indicator container associated with the current role. + const associatedIndicatorContainer = Main.panel.statusArea[role]?.container; + + if (boxIndicatorContainersSet.has(associatedIndicatorContainer)) validBoxOrder.push(role); + } + + return validBoxOrder; + } + + /** + * This function creates a restricted valid box order for the given box. + * This means it returns a box order for the box, where only roles are + * included, which have their associated indicator container already in the + * specified box. + * @param {string} box - The box to return the valid box order for. + * Must be one of the following values: + * - "left" + * - "center" + * - "right" + * @returns {string[]} - The restricted valid box order. + */ + createRestrictedValidBoxOrder(box) { + // Get a resolved box order and get the indicator containers (of the + // items) which are currently present in the Gnome Shell top bar in the + // specified box. + let boxOrder = this._appIndicatorKStatusNotifierItemManager.createResolvedBoxOrder(this._settings.get_strv(`${box}-box-order`)); + let boxIndicatorContainers; + switch (box) { + case "left": + boxIndicatorContainers = Main.panel._leftBox.get_children(); + break; + case "center": + boxIndicatorContainers = Main.panel._centerBox.get_children(); + break; + case "right": + boxIndicatorContainers = Main.panel._rightBox.get_children(); + break; + } + + // Create an indicator containers set from the indicator containers for + // fast easy access. + const boxIndicatorContainersSet = new Set(boxIndicatorContainers); + + // Go through the box order and only add items to the restricted valid + // box order, where their indicator is present in the Gnome Shell top + // bar in the specified box currently. + let restrictedValidBoxOrder = [ ]; + for (const role of boxOrder) { + // Get the indicator container associated with the current role. + const associatedIndicatorContainer = Main.panel.statusArea[role]?.container; + + if (boxIndicatorContainersSet.has(associatedIndicatorContainer)) restrictedValidBoxOrder.push(role); + } + + return restrictedValidBoxOrder; + } +}; diff --git a/src/extensionModules/BoxOrderManager.ts b/src/extensionModules/BoxOrderManager.ts deleted file mode 100644 index cfb4dbe..0000000 --- a/src/extensionModules/BoxOrderManager.ts +++ /dev/null @@ -1,388 +0,0 @@ -"use strict"; - -import GObject from "gi://GObject"; -import St from "gi://St"; -import type Gio from "gi://Gio"; - -import * as Main from "resource:///org/gnome/shell/ui/main.js"; - -import type { CustomPanel } from "../extension.js" - -export type Box = "left" | "center" | "right"; -type Hide = "hide" | "show" | "default"; -/** - * A resolved box order item containing the items role, settings identifier and - * additional information. - */ -interface ResolvedBoxOrderItem { - settingsId: string // The settings identifier of the item. - role: string // The role of the item. - hide: Hide // Whether the item should be (forcefully) hidden, (forcefully) shown or just be left as is. -} - -/** - * This class provides an interfaces to the box orders stored in settings. - * It takes care of handling AppIndicator and Task Up UltraLite items and - * resolving from the internal item settings identifiers to roles. - * In the end this results in convenient functions, which are directly useful in - * other extension code. - */ -export default class BoxOrderManager extends GObject.Object { - static { - GObject.registerClass({ - Signals: { - "appIndicatorReady": {}, - }, - }, this); - } - - // Can't have type guarantees here, since this is working with types from - // the KStatusNotifier/AppIndicator extension. - #appIndicatorReadyHandlerIdMap: Map; - #appIndicatorItemSettingsIdToRolesMap: Map; - #taskUpUltraLiteItemRoles: string[]; - #settings: Gio.Settings; - - constructor(params = {}, settings: Gio.Settings) { - // @ts-ignore Params should be passed, see: https://gjs.guide/guides/gobject/subclassing.html#subclassing-gobject - super(params); - - this.#appIndicatorReadyHandlerIdMap = new Map(); - this.#appIndicatorItemSettingsIdToRolesMap = new Map(); - this.#taskUpUltraLiteItemRoles = []; - - this.#settings = settings; - } - - /** - * Gets a box order for the given top bar box from settings. - * @param {Box} box - The top bar box for which to get the box order. - * @returns {string[]} - The box order consisting of an array of item - * settings identifiers. - */ - #getBoxOrder(box: Box): string[] { - return this.#settings.get_strv(`${box}-box-order`); - } - - /** - * Save the given box order to settings, making sure to only save a changed - * box order, to avoid loops when listening on settings changes. - * @param {Box} box - The top bar box for which to save the box order. - * @param {string[]} boxOrder - The box order to save. Must be an array of - * item settings identifiers. - */ - #saveBoxOrder(box: Box, boxOrder: string[]): void { - const currentBoxOrder = this.#getBoxOrder(box); - - // Only save the given box order to settings, if it is different, to - // avoid loops when listening on settings changes. - if (JSON.stringify(boxOrder) !== JSON.stringify(currentBoxOrder)) { - this.#settings.set_strv(`${box}-box-order`, boxOrder); - } - } - - /** - * Handles an AppIndicator/KStatusNotifierItem item by deriving a settings - * identifier and then associating the role of the given item to the items - * settings identifier. - * It then returns the derived settings identifier. - * In the case, where the settings identifier can't be derived, because the - * application can't be determined, this method throws an error. However it - * then also makes sure that once the app indicators "ready" signal emits, - * this classes "appIndicatorReady" signal emits as well, such that it and - * other methods can be called again to properly handle the item. - * @param {St.Bin} indicatorContainer - The container of the indicator of the - * AppIndicator/KStatusNotifierItem item. - * @param {string} role - The role of the AppIndicator/KStatusNotifierItem - * item. - * @returns {string} The derived items settings identifier. - */ - #handleAppIndicatorItem(indicatorContainer: St.Bin, role: string): string { - // Since this is working with types from the - // AppIndicator/KStatusNotifierItem extension, we loose a bunch of type - // safety here. - // https://github.com/ubuntu/gnome-shell-extension-appindicator - const appIndicator = (indicatorContainer.get_child() as any)._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. - if (application.startsWith("dropbox-client-")) { - application = "dropbox-client"; - } - - // Derive the items settings identifier from the application name. - const itemSettingsId = `appindicator-kstatusnotifieritem-${application}`; - - // Associate the role with the items settings identifier. - let roles = this.#appIndicatorItemSettingsIdToRolesMap.get(itemSettingsId); - if (roles) { - // If the settings identifier already has an array of associated - // roles, just add the role to it, if needed. - if (!roles.includes(role)) { - roles.push(role); - } - } else { - // Otherwise create a new array. - this.#appIndicatorItemSettingsIdToRolesMap.set(itemSettingsId, [role]); - } - - // Return the item settings identifier. - return itemSettingsId; - } - - /** - * Handles a Task Up UltraLite item by storing its role and returning the - * Task Up UltraLite settings identifier. - * This is needed since the Task Up UltraLite extension creates a bunch of - * top bar items as part of its functionality, so we want to group them - * under one identifier in the settings. - * https://extensions.gnome.org/extension/7700/task-up-ultralite/ - * @param {string} role - The role of the Task Up UltraLite item. - * @returns {string} The settings identifier to use. - */ - #handleTaskUpUltraLiteItem(role: string): string { - const roles = this.#taskUpUltraLiteItemRoles; - - if (!roles.includes(role)) { - roles.push(role); - } - - return "item-role-group-task-up-ultralite"; - } - - /** - * Gets a resolved box order for the given top bar box, where all - * AppIndicator and Task Up UltraLite items got resolved using their roles, - * meaning they might be present multiple times or not at all depending on - * the roles stored. - * The items of the box order also have additional information stored. - * @param {Box} box - The top bar box for which to get the resolved box order. - * @returns {ResolvedBoxOrderItem[]} - The resolved box order. - */ - #getResolvedBoxOrder(box: Box): ResolvedBoxOrderItem[] { - let boxOrder = this.#getBoxOrder(box); - - const itemsToHide = this.#settings.get_strv("hide"); - const itemsToShow = this.#settings.get_strv("show"); - - let resolvedBoxOrder = []; - for (const itemSettingsId of boxOrder) { - const resolvedBoxOrderItem = { - settingsId: itemSettingsId, - role: "", - hide: "", - }; - - // Set the hide state of the item. - if (itemsToHide.includes(resolvedBoxOrderItem.settingsId)) { - resolvedBoxOrderItem.hide = "hide"; - } else if (itemsToShow.includes(resolvedBoxOrderItem.settingsId)) { - resolvedBoxOrderItem.hide = "show"; - } else { - resolvedBoxOrderItem.hide = "default"; - } - - // If the items settings identifier doesn't indicate that the item - // is an AppIndicator/KStatusNotifierItem item or the Task Up - // UltraLite item role group, then its identifier is the role and it - // can just be added to the resolved box order. - if (!itemSettingsId.startsWith("appindicator-kstatusnotifieritem-") && - itemSettingsId !== "item-role-group-task-up-ultralite") { - resolvedBoxOrderItem.role = resolvedBoxOrderItem.settingsId; - resolvedBoxOrder.push(resolvedBoxOrderItem); - continue; - } - - // If the items settings identifier indicates otherwise, then handle - // the item specially. - - // Get the roles associated with the items settings id. - let roles: string[] = []; - if (itemSettingsId.startsWith("appindicator-kstatusnotifieritem-")) { - roles = this.#appIndicatorItemSettingsIdToRolesMap.get(resolvedBoxOrderItem.settingsId) ?? []; - } else if (itemSettingsId === "item-role-group-task-up-ultralite") { - roles = this.#taskUpUltraLiteItemRoles; - } - - // Create a new resolved box order item for each role and add it to - // the resolved box order. - for (const role of roles) { - const newResolvedBoxOrderItem = JSON.parse(JSON.stringify(resolvedBoxOrderItem)); - newResolvedBoxOrderItem.role = role; - resolvedBoxOrder.push(newResolvedBoxOrderItem); - } - } - - 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(): void { - for (const [handlerId, appIndicator] of this.#appIndicatorReadyHandlerIdMap) { - if (handlerId && appIndicator?.signalHandlerIsConnected(handlerId)) { - appIndicator.disconnect(handlerId); - } - } - // @ts-ignore - this.#appIndicatorReadyHandlerIdMap = null; - } - - /** - * Gets a valid box order for the given top bar box, where all AppIndicator - * and Task Up UltraLite items got resolved and where only items are - * included, which are in some GNOME Shell top bar box. - * The items of the box order also have additional information stored. - * @param {Box} box - The top bar box to return the valid box order for. - * @returns {ResolvedBoxOrderItem[]} - The valid box order. - */ - getValidBoxOrder(box: Box): ResolvedBoxOrderItem[] { - // Get a resolved box order. - let resolvedBoxOrder = this.#getResolvedBoxOrder(box); - - // Get the indicator containers (of the items) currently present in the - // GNOME Shell top bar. - // They should be St.Bins (see link), so ensure that using a filter. - // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/48.2/js/ui/panelMenu.js?ref_type=tags#L21 - const indicatorContainers = new Set([ - (Main.panel as CustomPanel)._leftBox.get_children(), - (Main.panel as CustomPanel)._centerBox.get_children(), - (Main.panel as CustomPanel)._rightBox.get_children(), - ].flat().filter(ic => ic instanceof St.Bin)); - - // Go through the resolved box order and only add items to the valid box - // order, where their indicator is currently present in the GNOME Shell - // top bar. - let validBoxOrder: ResolvedBoxOrderItem[] = []; - for (const item of resolvedBoxOrder) { - const associatedIndicatorContainer = (Main.panel.statusArea as any)[item.role]?.container; - if (!(associatedIndicatorContainer instanceof St.Bin)) { - // TODO: maybe add logging - continue; - } - - if (indicatorContainers.has(associatedIndicatorContainer)) { - validBoxOrder.push(item); - } - } - - return validBoxOrder; - } - - /** - * This method saves all new items currently present in the GNOME Shell top - * bar to the settings. - */ - saveNewTopBarItems(): void { - // Only run, when the session mode is "user" or the parent session mode - // is "user". - if (Main.sessionMode.currentMode !== "user" && Main.sessionMode.parentMode !== "user") { - return; - } - - // Get the box orders. - const boxOrders = { - left: this.#getBoxOrder("left"), - center: this.#getBoxOrder("center"), - right: this.#getBoxOrder("right"), - }; - - // Get roles (of items) currently present in the GNOME Shell top bar and - // index them using their associated indicator container. - let indicatorContainerRoleMap = new Map(); - for (const role in (Main.panel.statusArea as any)) { - const associatedIndicatorContainer = (Main.panel.statusArea as any)[role]?.container; - if (!(associatedIndicatorContainer instanceof St.Bin)) { - // TODO: maybe add logging - continue; - } - indicatorContainerRoleMap.set(associatedIndicatorContainer, role); - } - - // Get the indicator containers (of the items) currently present in the - // GNOME Shell top bar boxes. - // They should be St.Bins (see link), so ensure that using a filter. - // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/48.2/js/ui/panelMenu.js?ref_type=tags#L21 - const boxIndicatorContainers = { - left: (Main.panel as CustomPanel)._leftBox.get_children().filter(ic => ic instanceof St.Bin), - center: (Main.panel as CustomPanel)._centerBox.get_children().filter(ic => ic instanceof St.Bin), - // Reverse this array, since the items in the left and center box - // are logically LTR, while the items in the right box are RTL. - right: (Main.panel as CustomPanel)._rightBox.get_children().filter(ic => ic instanceof St.Bin).reverse(), - }; - - // This function goes through the indicator containers of the given box - // and adds new item settings identifiers to the given box order. - const addNewItemSettingsIdsToBoxOrder = (indicatorContainers: St.Bin[], boxOrder: string[], box: Box) => { - for (const indicatorContainer of indicatorContainers) { - // First get the role associated with the current indicator - // container. - let role = indicatorContainerRoleMap.get(indicatorContainer); - if (!role) { - continue; - } - - // Then get a settings identifier for the item. - let itemSettingsId; - if (role.startsWith("appindicator-")) { - // If the role indicates that the item is an - // AppIndicator/KStatusNotifierItem item, then handle it - // differently. - try { - itemSettingsId = this.#handleAppIndicatorItem(indicatorContainer, role); - } catch (e) { - if (!(e instanceof Error)) { - throw(e); - } - if (e.message !== "Application can't be determined.") { - throw(e); - } - continue; - } - } else if (role.startsWith("task-button-")) { - // If the role indicates that the item is a Task Up - // UltraLite item, then handle it differently. - itemSettingsId = this.#handleTaskUpUltraLiteItem(role); - } else { // Otherwise just use the role as the settings identifier. - itemSettingsId = role; - } - - // Add the items settings identifier to the box order, if it - // isn't in in one already. - if (!boxOrders.left.includes(itemSettingsId) - && !boxOrders.center.includes(itemSettingsId) - && !boxOrders.right.includes(itemSettingsId)) { - if (box === "right") { - // Add the items to the beginning for this array, since - // its RTL. - boxOrder.unshift(itemSettingsId); - } else { - boxOrder.push(itemSettingsId); - } - } - } - }; - - addNewItemSettingsIdsToBoxOrder(boxIndicatorContainers.left, boxOrders.left, "left"); - addNewItemSettingsIdsToBoxOrder(boxIndicatorContainers.center, boxOrders.center, "center"); - addNewItemSettingsIdsToBoxOrder(boxIndicatorContainers.right, boxOrders.right, "right"); - - this.#saveBoxOrder("left", boxOrders.left); - this.#saveBoxOrder("center", boxOrders.center); - this.#saveBoxOrder("right", boxOrders.right); - } -} diff --git a/src/metadata.json b/src/metadata.json index 11b0cce..3c0e438 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -2,8 +2,8 @@ "uuid": "top-bar-organizer@julian.gse.jsts.xyz", "name": "Top Bar Organizer", "description": "Organize the items of the top (menu)bar.", - "version": 15, - "shell-version": [ "45", "46", "47", "48", "49" ], + "version": 1, + "shell-version": [ "40" ], "settings-schema": "org.gnome.shell.extensions.top-bar-organizer", - "url": "https://gitlab.gnome.org/june/top-bar-organizer" + "url": "https://gitlab.gnome.org/julianschacher/top-bar-organizer" } diff --git a/src/prefs-box-order-item-row.ui b/src/prefs-box-order-item-row.ui new file mode 100644 index 0000000..a82e225 --- /dev/null +++ b/src/prefs-box-order-item-row.ui @@ -0,0 +1,40 @@ + + + + + diff --git a/data/ui/prefs-box-order-list-empty-placeholder.ui b/src/prefs-box-order-list-empty-placeholder.ui similarity index 54% rename from data/ui/prefs-box-order-list-empty-placeholder.ui rename to src/prefs-box-order-list-empty-placeholder.ui index d113107..11803f8 100644 --- a/data/ui/prefs-box-order-list-empty-placeholder.ui +++ b/src/prefs-box-order-list-empty-placeholder.ui @@ -1,4 +1,22 @@ + diff --git a/src/prefs-widget.ui b/src/prefs-widget.ui new file mode 100644 index 0000000..a153981 --- /dev/null +++ b/src/prefs-widget.ui @@ -0,0 +1,101 @@ + + + + + diff --git a/src/prefs.js b/src/prefs.js new file mode 100644 index 0000000..d13c132 --- /dev/null +++ b/src/prefs.js @@ -0,0 +1,89 @@ +/* + * This file is part of Top-Bar-Organizer (a Gnome Shell Extension for + * organizing your Gnome Shell top bar). + * Copyright (C) 2021 Julian Schacher + * + * Top-Bar-Organizer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* exported buildPrefsWidget, init */ +"use strict"; + +const Gtk = imports.gi.Gtk; +const GObject = imports.gi.GObject; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +const PrefsBoxOrderListEmptyPlaceholder = Me.imports.prefsModules.PrefsBoxOrderListEmptyPlaceholder; +const PrefsBoxOrderItemRow = Me.imports.prefsModules.PrefsBoxOrderItemRow; + +var PrefsWidget = GObject.registerClass({ + GTypeName: "PrefsWidget", + Template: Me.dir.get_child("prefs-widget.ui").get_uri(), + InternalChildren: [ + "left-box-order", + "center-box-order", + "right-box-order" + ] +}, class PrefsWidget extends Gtk.Box { + _init(params = {}) { + super._init(params); + + this._settings = ExtensionUtils.getSettings(); + + // Initialize the given `gtkListBox`. + const initializeGtkListBox = (boxOrder, gtkListBox) => { + // Add the items of the given configured box order as + // GtkListBoxRows. + for (const item of boxOrder) { + const listBoxRow = new PrefsBoxOrderItemRow.PrefsBoxOrderItemRow(); + + listBoxRow.item = item; + if (item.startsWith("appindicator-kstatusnotifieritem-")) { + // Set `item_name_display_label` of the `listBoxRow` to + // something nicer, if the associated item is an + // AppIndicator/KStatusNotifierItem item. + listBoxRow.item_name_display_label.set_label(item.replace("appindicator-kstatusnotifieritem-", "")); + } else { + // Otherwise just set the `item_name_display_label` of the + // `listBoxRow` to `item`. + listBoxRow.item_name_display_label.set_label(item); + } + gtkListBox.append(listBoxRow); + } + + // Add a placeholder widget for the case, where `gtkListBox` doesn't + // have any GtkListBoxRows. + gtkListBox.set_placeholder(new PrefsBoxOrderListEmptyPlaceholder.PrefsBoxOrderListEmptyPlaceholder()); + }; + + initializeGtkListBox(this._settings.get_strv("left-box-order"), this._left_box_order); + initializeGtkListBox(this._settings.get_strv("center-box-order"), this._center_box_order); + initializeGtkListBox(this._settings.get_strv("right-box-order"), this._right_box_order); + + // Set the box order each GtkListBox is associated with. + // This is needed by the reordering of the GtkListBoxRows, so that the + // updated box orders can be saved. + this._left_box_order.boxOrder = "left-box-order"; + this._center_box_order.boxOrder = "center-box-order"; + this._right_box_order.boxOrder = "right-box-order"; + } +}); + +function buildPrefsWidget() { + return new PrefsWidget(); +} + +function init() { +} diff --git a/src/prefs.ts b/src/prefs.ts deleted file mode 100644 index 76718ba..0000000 --- a/src/prefs.ts +++ /dev/null @@ -1,32 +0,0 @@ -"use strict"; - -import Gtk from "gi://Gtk"; -import Gdk from "gi://Gdk"; - -import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js"; - -import PrefsPage from "./prefsModules/PrefsPage.js"; - -export default class TopBarOrganizerPreferences extends ExtensionPreferences { - getPreferencesWidget() { - const provider = new Gtk.CssProvider(); - provider.load_from_path(this.metadata.dir.get_path() + "/css/prefs.css"); - const defaultGdkDisplay = Gdk.Display.get_default(); - Gtk.StyleContext.add_provider_for_display( - (defaultGdkDisplay as Gdk.Display), - provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - - const prefsPage = new PrefsPage(); - - prefsPage.connect("destroy", () => { - Gtk.StyleContext.remove_provider_for_display( - (defaultGdkDisplay as Gdk.Display), - provider - ); - }); - - return prefsPage; - } -} diff --git a/src/prefsModules/PrefsBoxOrderItemOptionsDialog.ts b/src/prefsModules/PrefsBoxOrderItemOptionsDialog.ts deleted file mode 100644 index 736a773..0000000 --- a/src/prefsModules/PrefsBoxOrderItemOptionsDialog.ts +++ /dev/null @@ -1,69 +0,0 @@ -"use strict"; - -import GObject from "gi://GObject"; -import Adw from "gi://Adw"; -import GLib from "gi://GLib"; -import type Gio from "gi://Gio"; -import type Gtk from "gi://Gtk"; - -import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js"; - -export default class PrefsBoxOrderItemOptionsDialog extends Adw.Dialog { - static { - GObject.registerClass({ - GTypeName: "PrefsBoxOrderItemOptionsDialog", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-item-options-dialog.ui", GLib.UriFlags.NONE), - InternalChildren: [ - "visibility-row", - ], - }, this); - } - - declare _visibility_row: Adw.ComboRow; - #settings: Gio.Settings; - item: string; - - constructor(params = {}, item: string) { - super(params); - - // Associate `this` with an item. - this.item = item; - // Load the settings. - this.#settings = ExtensionPreferences.lookupByURL(import.meta.url)!.getSettings(); - - // Set the selected visibility row choice to the settings value. - const itemsToHide = new Set(this.#settings.get_strv("hide")); - const itemsToShow = new Set(this.#settings.get_strv("show")); - if (itemsToHide.has(this.item)) { - this._visibility_row.set_selected(1); - } else if (itemsToShow.has(this.item)) { - this._visibility_row.set_selected(2); - } else { - this._visibility_row.set_selected(0); - } - } - - onVisibilityRowSelectionChanged(): void { - const visibility = (this._visibility_row.get_selected_item() as Gtk.StringObject).get_string(); - const itemsToHide = new Set(this.#settings.get_strv("hide")); - const itemsToShow = new Set(this.#settings.get_strv("show")); - - switch (visibility) { - case "Forcefully Hide": - itemsToHide.add(this.item) - itemsToShow.delete(this.item); - break; - case "Forcefully Show": - itemsToHide.delete(this.item) - itemsToShow.add(this.item); - break; - case "Default": - itemsToHide.delete(this.item) - itemsToShow.delete(this.item); - break; - } - - this.#settings.set_strv("hide", Array.from(itemsToHide)); - this.#settings.set_strv("show", Array.from(itemsToShow)); - } -} diff --git a/src/prefsModules/PrefsBoxOrderItemRow.js b/src/prefsModules/PrefsBoxOrderItemRow.js new file mode 100644 index 0000000..9914f79 --- /dev/null +++ b/src/prefsModules/PrefsBoxOrderItemRow.js @@ -0,0 +1,132 @@ +/* + * This file is part of Top-Bar-Organizer (a Gnome Shell Extension for + * organizing your Gnome Shell top bar). + * Copyright (C) 2021 Julian Schacher + * + * Top-Bar-Organizer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* exported PrefsBoxOrderItemRow */ +"use strict"; + +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; +const GObject = imports.gi.GObject; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +var PrefsBoxOrderItemRow = GObject.registerClass({ + GTypeName: "PrefsBoxOrderItemRow", + Template: Me.dir.get_child("prefs-box-order-item-row.ui").get_uri(), + Children: ["item-name-display-label"] +}, class PrefsBoxOrderItemRow extends Gtk.ListBoxRow { + _init(params = {}) { + super._init(params); + + // Make `this` draggable by creating a drag source and adding it to + // `this`. + let dragSource = new Gtk.DragSource(); + dragSource.set_actions(Gdk.DragAction.MOVE); + dragSource.connect("prepare", () => { + return Gdk.ContentProvider.new_for_value(this); + }); + this.add_controller(dragSource); + + /// Make `this` accept drops by creating a drop target and adding it to + /// `this`. + let dropTarget = new Gtk.DropTarget(); + dropTarget.set_gtypes([this.constructor.$gtype]); + dropTarget.set_actions(Gdk.DragAction.MOVE); + // Handle a new drop on `this` properly. + // `value` is the thing getting dropped. + dropTarget.connect("drop", (target, value) => { + // If `this` got dropped onto itself, do nothing. + if (value === this) { + return; + } + + // Get the GtkListBoxes of `this` and the drop value. + const ownListBox = this.get_parent(); + const valueListBox = value.get_parent(); + + // Get the position of `this` and the drop value. + const ownPosition = this.get_index(); + const valuePosition = value.get_index(); + + // Remove the drop value from its list box. + valueListBox.remove(value); + + // Since an element got potentially removed from the list of `this`, + // get the position of `this` again. + const updatedOwnPosition = this.get_index(); + + if (ownListBox !== valueListBox) { + // First handle the case where `this` and the drop value are in + // different list boxes. + if ((ownListBox.boxOrder === "right-box-order" && valueListBox.boxOrder === "left-box-order") + || (ownListBox.boxOrder === "right-box-order" && valueListBox.boxOrder === "center-box-order") + || (ownListBox.boxOrder === "center-box-order" && valueListBox.boxOrder === "left-box-order")) { + // If the list box of the drop value comes before the list + // box of `this`, add the drop value after `this`. + ownListBox.insert(value, updatedOwnPosition + 1); + } else { + // Otherwise, add the drop value where `this` currently is. + ownListBox.insert(value, updatedOwnPosition); + } + } else { + if (valuePosition < ownPosition) { + // If the drop value was before `this`, add the drop value + // after `this`. + ownListBox.insert(value, updatedOwnPosition + 1); + } else { + // Otherwise, add the drop value where `this` currently is. + ownListBox.insert(value, updatedOwnPosition); + } + } + + /// Finally save the box orders to settings. + const settings = ExtensionUtils.getSettings(); + + let updatedBoxOrder = [ ]; + for (let potentialListBoxRow of ownListBox) { + // Only process PrefsBoxOrderItemRows. + if (potentialListBoxRow.constructor.$gtype.name !== "PrefsBoxOrderItemRow") { + continue; + } + + const item = potentialListBoxRow.item; + updatedBoxOrder.push(item); + } + settings.set_strv(ownListBox.boxOrder, updatedBoxOrder); + + // If the list boxes of `this` and the drop value were different, + // save an updated box order for the list were the drop value was in + // as well. + if (ownListBox !== valueListBox) { + let updatedBoxOrder = [ ]; + for (let potentialListBoxRow of valueListBox) { + // Only process PrefsBoxOrderItemRows. + if (potentialListBoxRow.constructor.$gtype.name !== "PrefsBoxOrderItemRow") { + continue; + } + + const item = potentialListBoxRow.item; + updatedBoxOrder.push(item); + } + settings.set_strv(valueListBox.boxOrder, updatedBoxOrder); + } + }); + this.add_controller(dropTarget); + } +}); diff --git a/src/prefsModules/PrefsBoxOrderItemRow.ts b/src/prefsModules/PrefsBoxOrderItemRow.ts deleted file mode 100644 index 3da4d6b..0000000 --- a/src/prefsModules/PrefsBoxOrderItemRow.ts +++ /dev/null @@ -1,161 +0,0 @@ -"use strict"; - -import Gtk from "gi://Gtk"; -import Gdk from "gi://Gdk"; -import GObject from "gi://GObject"; -import Adw from "gi://Adw"; -import GLib from "gi://GLib"; - -import PrefsBoxOrderItemOptionsDialog from "./PrefsBoxOrderItemOptionsDialog.js"; -import type PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js"; - -export default class PrefsBoxOrderItemRow extends Adw.ActionRow { - static { - GObject.registerClass({ - GTypeName: "PrefsBoxOrderItemRow", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-item-row.ui", GLib.UriFlags.NONE), - Signals: { - "move": { - param_types: [GObject.TYPE_STRING], - }, - }, - }, this); - this.install_action("row.forget", null, (self, _actionName, _param) => { - const parentListBox = self.get_parent() as PrefsBoxOrderListBox; - parentListBox.removeRow(self as PrefsBoxOrderItemRow); - parentListBox.saveBoxOrderToSettings(); - parentListBox.determineRowMoveActionEnable(); - }); - this.install_action("row.options", null, (self, _actionName, _param) => { - const itemOptionsDialog = new PrefsBoxOrderItemOptionsDialog({ - // Get the title from self as the constructor of - // PrefsBoxOrderItemRow already processes the item name into a - // nice title. - title: (self as PrefsBoxOrderItemRow).get_title() - }, (self as PrefsBoxOrderItemRow).item); - itemOptionsDialog.present(self); - }); - this.install_action("row.move-up", null, (self, _actionName, _param) => self.emit("move", "up")); - this.install_action("row.move-down", null, (self, _actionName, _param) => self.emit("move", "down")); - } - - item: string; - #drag_starting_point_x?: number; - #drag_starting_point_y?: number; - - constructor(params = {}, item: string) { - super(params); - - // Associate `this` with an item. - this.item = item; - if (this.item.startsWith("appindicator-kstatusnotifieritem-")) { - // Set the title to something nicer, if the associated item is an - // AppIndicator/KStatusNotifierItem item. - this.set_title(this.item.replace("appindicator-kstatusnotifieritem-", "")); - } else if (this.item === "item-role-group-task-up-ultralite") { - // Set the title to something nicer, if the item in question is the - // Task Up UltraLite item role group. - this.set_title("Task Up UltraLite Items"); - } else { - // Otherwise just set it to `item`. - this.set_title(this.item); - } - } - - onDragPrepare(_source: Gtk.DragSource, x: number, y: number): Gdk.ContentProvider { - const value = new GObject.Value(); - value.init(PrefsBoxOrderItemRow.$gtype); - value.set_object(this); - - this.#drag_starting_point_x = x; - this.#drag_starting_point_y = y; - return Gdk.ContentProvider.new_for_value(value); - } - - onDragBegin(_source: Gtk.DragSource, drag: Gdk.Drag): void { - let dragWidget = new Gtk.ListBox(); - let allocation = this.get_allocation(); - dragWidget.set_size_request(allocation.width, allocation.height); - - let dragPrefsBoxOrderItemRow = new PrefsBoxOrderItemRow({}, this.item); - dragWidget.append(dragPrefsBoxOrderItemRow); - dragWidget.drag_highlight_row(dragPrefsBoxOrderItemRow); - - let currentDragIcon = Gtk.DragIcon.get_for_drag(drag); - currentDragIcon.set_child(dragWidget); - // Even tho this should always be the case, ensure the values for the hotspot aren't undefined. - if (typeof this.#drag_starting_point_x !== "undefined" && - typeof this.#drag_starting_point_y !== "undefined") { - drag.set_hotspot(this.#drag_starting_point_x, this.#drag_starting_point_y); - } - } - - // Handle a new drop on `this` properly. - // `value` is the thing getting dropped. - onDrop(_target: Gtk.DropTarget, value: any, _x: number, _y: number): boolean { - // According to the type annotations of Gtk.DropTarget, value is of type - // GObject.Value, so ensure the one we work with is of type - // PrefsBoxOrderItemRow. - if (!(value instanceof PrefsBoxOrderItemRow)) { - // TODO: maybe add logging - return false; - } - - // If `this` got dropped onto itself, do nothing. - if (value === this) { - return false; - } - - // Get the GtkListBoxes of `this` and the drop value. - const ownListBox = this.get_parent() as PrefsBoxOrderListBox; - const valueListBox = value.get_parent() as PrefsBoxOrderListBox; - - // Get the position of `this` and the drop value. - const ownPosition = this.get_index(); - const valuePosition = value.get_index(); - - // Remove the drop value from its list box. - valueListBox.removeRow(value); - - // Since an element got potentially removed from the list of `this`, - // get the position of `this` again. - const updatedOwnPosition = this.get_index(); - - if (ownListBox !== valueListBox) { - // First handle the case where `this` and the drop value are in - // different list boxes. - if ((ownListBox.boxOrder === "right-box-order" && valueListBox.boxOrder === "left-box-order") - || (ownListBox.boxOrder === "right-box-order" && valueListBox.boxOrder === "center-box-order") - || (ownListBox.boxOrder === "center-box-order" && valueListBox.boxOrder === "left-box-order")) { - // If the list box of the drop value comes before the list - // box of `this`, add the drop value after `this`. - ownListBox.insertRow(value, updatedOwnPosition + 1); - } else { - // Otherwise, add the drop value where `this` currently is. - ownListBox.insertRow(value, updatedOwnPosition); - } - } else { - if (valuePosition < ownPosition) { - // If the drop value was before `this`, add the drop value - // after `this`. - ownListBox.insertRow(value, updatedOwnPosition + 1); - } else { - // Otherwise, add the drop value where `this` currently is. - ownListBox.insertRow(value, updatedOwnPosition); - } - } - - /// Finally save the box order(/s) to settings and make sure move - /// actions are correctly enabled/disabled. - ownListBox.saveBoxOrderToSettings(); - ownListBox.determineRowMoveActionEnable(); - // If the list boxes of `this` and the drop value were different, handle - // the former list box of the drop value as well. - if (ownListBox !== valueListBox) { - valueListBox.saveBoxOrderToSettings(); - valueListBox.determineRowMoveActionEnable(); - } - - return true; - } -} diff --git a/src/prefsModules/PrefsBoxOrderListBox.ts b/src/prefsModules/PrefsBoxOrderListBox.ts deleted file mode 100644 index f2b5c98..0000000 --- a/src/prefsModules/PrefsBoxOrderListBox.ts +++ /dev/null @@ -1,152 +0,0 @@ -"use strict"; - -import Gtk from "gi://Gtk"; -import GObject from "gi://GObject"; -import GLib from "gi://GLib"; -import type Gio from "gi://Gio"; - -import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js"; - -import PrefsBoxOrderItemRow from "./PrefsBoxOrderItemRow.js"; -import PrefsBoxOrderListEmptyPlaceholder from "./PrefsBoxOrderListEmptyPlaceholder.js"; - -export default class PrefsBoxOrderListBox extends Gtk.ListBox { - static { - GObject.registerClass({ - GTypeName: "PrefsBoxOrderListBox", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-box.ui", GLib.UriFlags.NONE), - Properties: { - BoxOrder: GObject.ParamSpec.string( - "box-order", - "Box Order", - "The box order this PrefsBoxOrderListBox is associated with.", - GObject.ParamFlags.READWRITE, - "" - ), - }, - Signals: { - "row-move": { - param_types: [PrefsBoxOrderItemRow.$gtype, GObject.TYPE_STRING], - }, - }, - }, this); - } - - _boxOrder!: string; - #settings: Gio.Settings; - #rowSignalHandlerIds = new Map(); - - /** - * @param {Object} params - */ - constructor(params = {}) { - super(params); - - // Load the settings. - this.#settings = ExtensionPreferences.lookupByURL(import.meta.url)!.getSettings(); - - // Add a placeholder widget for the case, where no GtkListBoxRows are - // present. - this.set_placeholder(new PrefsBoxOrderListEmptyPlaceholder()); - } - - get boxOrder(): string { - return this._boxOrder; - } - - set boxOrder(value: string) { - this._boxOrder = value; - - // Get the actual box order for the given box order name from settings. - const boxOrder = this.#settings.get_strv(this._boxOrder); - // Populate this GtkListBox with GtkListBoxRows for the items of the - // given configured box order. - for (const item of boxOrder) { - const row = new PrefsBoxOrderItemRow({}, item); - this.insertRow(row, -1); - } - - this.determineRowMoveActionEnable(); - this.notify("box-order"); - } - - /** - * Inserts the given PrefsBoxOrderItemRow to this list box at the given - * position. - * Also handles stuff like connecting signals. - */ - insertRow(row: PrefsBoxOrderItemRow, position: number): void { - this.insert(row, position); - - const signalHandlerIds: number[] = []; - signalHandlerIds.push(row.connect("move", (row, direction) => { - this.emit("row-move", row, direction); - })); - - this.#rowSignalHandlerIds.set(row, signalHandlerIds); - } - - /** - * Removes the given PrefsBoxOrderItemRow from this list box. - * Also handles stuff like disconnecting signals. - */ - removeRow(row: PrefsBoxOrderItemRow): void { - const signalHandlerIds = this.#rowSignalHandlerIds.get(row) ?? []; - - for (const id of signalHandlerIds) { - row.disconnect(id); - } - - this.remove(row); - } - - /** - * Saves the box order represented by `this` (and its - * `PrefsBoxOrderItemRows`) to settings. - */ - saveBoxOrderToSettings(): void { - let currentBoxOrder: string[] = []; - for (let potentialPrefsBoxOrderItemRow of this) { - // Only process PrefsBoxOrderItemRows. - if (!(potentialPrefsBoxOrderItemRow instanceof PrefsBoxOrderItemRow)) { - continue; - } - - const item = potentialPrefsBoxOrderItemRow.item; - currentBoxOrder.push(item); - } - this.#settings.set_strv(this.boxOrder, currentBoxOrder); - } - - /** - * Determines whether or not each move action of each PrefsBoxOrderItemRow - * should be enabled or disabled. - */ - determineRowMoveActionEnable(): void { - for (let potentialPrefsBoxOrderItemRow of this) { - // Only process PrefsBoxOrderItemRows. - if (!(potentialPrefsBoxOrderItemRow instanceof PrefsBoxOrderItemRow)) { - continue; - } - - const row = potentialPrefsBoxOrderItemRow; - - // If the current row is the topmost row in the topmost list box, - // then disable the move-up action. - if (row.get_index() === 0 && this.boxOrder === "left-box-order") { - row.action_set_enabled("row.move-up", false); - } else { // Else enable it. - row.action_set_enabled("row.move-up", true); - } - - // If the current row is the bottommost row in the bottommost list - // box, then disable the move-down action. - const rowNextSibling = row.get_next_sibling(); - if ((rowNextSibling instanceof PrefsBoxOrderListEmptyPlaceholder || rowNextSibling === null) && this.boxOrder === "right-box-order") { - row.action_set_enabled("row.move-down", false); - } else { // Else enable it. - row.action_set_enabled("row.move-down", true); - } - } - } -} diff --git a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js new file mode 100644 index 0000000..f1cde8f --- /dev/null +++ b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.js @@ -0,0 +1,73 @@ +/* + * This file is part of Top-Bar-Organizer (a Gnome Shell Extension for + * organizing your Gnome Shell top bar). + * Copyright (C) 2021 Julian Schacher + * + * Top-Bar-Organizer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* exported PrefsBoxOrderListEmptyPlaceholder */ +"use strict"; + +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; +const GObject = imports.gi.GObject; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); + +var PrefsBoxOrderListEmptyPlaceholder = GObject.registerClass({ + GTypeName: "PrefsBoxOrderListEmptyPlaceholder", + Template: Me.dir.get_child("prefs-box-order-list-empty-placeholder.ui").get_uri() +}, class PrefsBoxOrderListEmptyPlaceholder extends Gtk.Box { + _init(params = {}) { + super._init(params); + + /// Make `this` accept drops by creating a drop target and adding it to + /// `this`. + let dropTarget = new Gtk.DropTarget(); + dropTarget.set_gtypes([GObject.type_from_name("PrefsBoxOrderItemRow")]); + dropTarget.set_actions(Gdk.DragAction.MOVE); + // Handle a new drop on `this` properly. + // `value` is the thing getting dropped. + dropTarget.connect("drop", (target, value) => { + // Get the GtkListBoxes of `this` and the drop value. + const ownListBox = this.get_parent(); + const valueListBox = value.get_parent(); + + // Remove the drop value from its list box. + valueListBox.remove(value); + + // Insert the drop value into the list box of `this`. + ownListBox.insert(value, 0); + + /// Finally save the box orders to settings. + const settings = ExtensionUtils.getSettings(); + + settings.set_strv(ownListBox.boxOrder, [value.item]); + + let updatedBoxOrder = [ ]; + for (let potentialListBoxRow of valueListBox) { + // Only process PrefsBoxOrderItemRows. + if (potentialListBoxRow.constructor.$gtype.name !== "PrefsBoxOrderItemRow") { + continue; + } + + const item = potentialListBoxRow.item; + updatedBoxOrder.push(item); + } + settings.set_strv(valueListBox.boxOrder, updatedBoxOrder); + }); + this.add_controller(dropTarget); + } +}); diff --git a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.ts b/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.ts deleted file mode 100644 index dae599b..0000000 --- a/src/prefsModules/PrefsBoxOrderListEmptyPlaceholder.ts +++ /dev/null @@ -1,48 +0,0 @@ -"use strict"; - -import Gtk from "gi://Gtk"; -import GObject from "gi://GObject"; -import GLib from "gi://GLib"; - -import PrefsBoxOrderItemRow from "./PrefsBoxOrderItemRow.js"; -import type PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js"; - -export default class PrefsBoxOrderListEmptyPlaceholder extends Gtk.Box { - static { - GObject.registerClass({ - GTypeName: "PrefsBoxOrderListEmptyPlaceholder", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-box-order-list-empty-placeholder.ui", GLib.UriFlags.NONE), - }, this); - } - - // Handle a new drop on `this` properly. - // `value` is the thing getting dropped. - onDrop(_target: Gtk.DropTarget, value: any, _x: number, _y: number): boolean { - // According to the type annotations of Gtk.DropTarget, value is of type - // GObject.Value, so ensure the one we work with is of type - // PrefsBoxOrderItemRow. - if (!(value instanceof PrefsBoxOrderItemRow)) { - // TODO: maybe add logging - return false; - } - - // Get the GtkListBoxes of `this` and the drop value. - const ownListBox = this.get_parent() as PrefsBoxOrderListBox; - const valueListBox = value.get_parent() as PrefsBoxOrderListBox; - - // Remove the drop value from its list box. - valueListBox.removeRow(value); - - // Insert the drop value into the list box of `this`. - ownListBox.insertRow(value, 0); - - /// Finally save the box orders to settings and make sure move actions - /// are correctly enabled/disabled. - ownListBox.saveBoxOrderToSettings(); - ownListBox.determineRowMoveActionEnable(); - valueListBox.saveBoxOrderToSettings(); - valueListBox.determineRowMoveActionEnable(); - - return true; - } -} diff --git a/src/prefsModules/PrefsPage.ts b/src/prefsModules/PrefsPage.ts deleted file mode 100644 index 6c22d8f..0000000 --- a/src/prefsModules/PrefsPage.ts +++ /dev/null @@ -1,196 +0,0 @@ -"use strict"; - -import Gdk from "gi://Gdk"; -import Gtk from "gi://Gtk"; -import GObject from "gi://GObject"; -import Adw from "gi://Adw"; -import GLib from "gi://GLib"; - -import ScrollManager from "./ScrollManager.js"; -import PrefsBoxOrderListEmptyPlaceholder from "./PrefsBoxOrderListEmptyPlaceholder.js"; -import type PrefsBoxOrderItemRow from "./PrefsBoxOrderItemRow.js"; - -// Imports to make UI file work. -// eslint-disable-next-line -import PrefsBoxOrderListBox from "./PrefsBoxOrderListBox.js"; - -export default class PrefsPage extends Adw.PreferencesPage { - static { - GObject.registerClass({ - GTypeName: "PrefsPage", - Template: GLib.uri_resolve_relative(import.meta.url, "../ui/prefs-page.ui", GLib.UriFlags.NONE), - InternalChildren: [ - "left-box-order-list-box", - "center-box-order-list-box", - "right-box-order-list-box", - ], - }, this); - } - - _dndEnded?: boolean; - declare _left_box_order_list_box: PrefsBoxOrderListBox; - declare _center_box_order_list_box: PrefsBoxOrderListBox; - declare _right_box_order_list_box: PrefsBoxOrderListBox; - - constructor(params = {}) { - super(params); - - this.#setupDNDScroll(); - } - - /** - * This function sets up Drag-and-Drop scrolling. - * This means that scroll up or down is happening when a Drag-and-Drop - * operation is in progress and the user has their cursor either in the - * upper or lower 10% of this widget respectively. - */ - #setupDNDScroll(): void { - // Pass `this.get_first_child()` to the ScrollManager, since this - // `PrefsPage` extends an `Adw.PreferencesPage` and the first child of - // an `Adw.PreferencesPage` is the built-in `Gtk.ScrolledWindow`. - const scrollManager = new ScrollManager(this.get_first_child() as Gtk.ScrolledWindow); - - /// Setup GtkDropControllerMotion event controller and make use of its - /// events. - let controller = new Gtk.DropControllerMotion(); - - // Make sure scrolling stops, when DND operation ends. - this._dndEnded = true; - - // Scroll, when the pointer is in the right places and a DND operation - // is properly set up (this._dndEnded is false). - controller.connect("motion", (_, _x, y) => { - if ((y <= this.get_allocated_height() * 0.1) && !this._dndEnded) { - // If the pointer is currently in the upper ten percent of this - // widget, then scroll up. - scrollManager.startScrollUp(); - } else if ((y >= this.get_allocated_height() * 0.9) && !this._dndEnded) { - // If the pointer is currently in the lower ten percent of this - // widget, then scroll down. - scrollManager.startScrollDown(); - } else { - // Otherwise stop scrolling. - scrollManager.stopScrollAll(); - } - }); - - const stopScrollAllAtDNDEnd = () => { - this._dndEnded = true; - scrollManager.stopScrollAll(); - }; - controller.connect("leave", () => { - stopScrollAllAtDNDEnd(); - }); - controller.connect("enter", () => { - // Make use of `this._dndEnded` to setup stopScrollAtDNDEnd only - // once per DND operation. - if (this._dndEnded) { - const drag = controller.get_drop()?.get_drag() ?? null; - // Ensure we have a Gdk.Drag. - // If this is not the case for whatever reason, then don't start - // DND scrolling and just return. - if (!(drag instanceof Gdk.Drag)) { - // TODO: maybe add logging - return; - } - drag.connect("drop-performed", () => { - stopScrollAllAtDNDEnd(); - }); - drag.connect("dnd-finished", () => { - stopScrollAllAtDNDEnd(); - }); - drag.connect("cancel", () => { - stopScrollAllAtDNDEnd(); - }); - this._dndEnded = false; - } - }); - - this.add_controller(controller); - } - - onRowMove(listBox: PrefsBoxOrderListBox, row: PrefsBoxOrderItemRow, direction: string): void { - const rowPosition = row.get_index(); - - if (direction === "up") { // If the direction of the move is up. - // Handle the case, where the row is the topmost row in the list box. - if (rowPosition === 0) { - switch (listBox.boxOrder) { - // If the row is also in the topmost list box, then do - // nothing and return. - case "left-box-order": - log("The row is already the topmost row in the topmost box order."); - return; - // If the row is in the center list box, then move it up to - // the left one. - case "center-box-order": - listBox.removeRow(row); - this._left_box_order_list_box.insertRow(row, -1); - // First save the box order of the destination, then do - // "a save for clean up". - this._left_box_order_list_box.saveBoxOrderToSettings(); - this._left_box_order_list_box.determineRowMoveActionEnable(); - listBox.saveBoxOrderToSettings(); - listBox.determineRowMoveActionEnable(); - return; - // If the row is in the right list box, then move it up to - // the center one. - case "right-box-order": - listBox.removeRow(row); - this._center_box_order_list_box.insertRow(row, -1); - this._center_box_order_list_box.saveBoxOrderToSettings(); - this._center_box_order_list_box.determineRowMoveActionEnable(); - listBox.saveBoxOrderToSettings(); - listBox.determineRowMoveActionEnable(); - return; - } - } - - // Else just move the row up in the box. - listBox.removeRow(row); - listBox.insertRow(row, rowPosition - 1); - listBox.saveBoxOrderToSettings(); - listBox.determineRowMoveActionEnable(); - return; - } else { // Else the direction of the move must be down. - // Handle the case, where the row is the bottommost row in the list box. - const rowNextSibling = row.get_next_sibling(); - if (rowNextSibling instanceof PrefsBoxOrderListEmptyPlaceholder || rowNextSibling === null) { - switch (listBox.boxOrder) { - // If the row is also in the bottommost list box, then do - // nothing and return. - case "right-box-order": - log("The row is already the bottommost row in the bottommost box order."); - return; - // If the row is in the center list box, then move it down - // to the right one. - case "center-box-order": - listBox.removeRow(row); - this._right_box_order_list_box.insertRow(row, 0); - this._right_box_order_list_box.saveBoxOrderToSettings(); - this._right_box_order_list_box.determineRowMoveActionEnable(); - listBox.saveBoxOrderToSettings(); - listBox.determineRowMoveActionEnable(); - return; - // If the row is in the left list box, then move it down to - // the center one. - case "left-box-order": - listBox.removeRow(row); - this._center_box_order_list_box.insertRow(row, 0); - this._center_box_order_list_box.saveBoxOrderToSettings(); - this._center_box_order_list_box.determineRowMoveActionEnable(); - listBox.saveBoxOrderToSettings(); - listBox.determineRowMoveActionEnable(); - return; - } - } - - // Else just move the row down in the box. - listBox.removeRow(row); - listBox.insertRow(row, rowPosition + 1); - listBox.saveBoxOrderToSettings(); - listBox.determineRowMoveActionEnable(); - return; - } - } -} diff --git a/src/prefsModules/ScrollManager.ts b/src/prefsModules/ScrollManager.ts deleted file mode 100644 index 1d9a8f8..0000000 --- a/src/prefsModules/ScrollManager.ts +++ /dev/null @@ -1,87 +0,0 @@ -"use strict"; - -import GLib from "gi://GLib"; -import type Gtk from "gi://Gtk"; - -export default class ScrollManager { - #gtkScrolledWindow: Gtk.ScrolledWindow; - #scrollUp: boolean; - #scrollDown: boolean; - - constructor(gtkScrolledWindow: Gtk.ScrolledWindow) { - this.#gtkScrolledWindow = gtkScrolledWindow; - - this.#scrollUp = false; - this.#scrollDown = false; - } - - startScrollUp(): void { - // If the scroll up is already started, don't do anything. - if (this.#scrollUp) { - return; - } - - // Make sure scroll down is stopped. - this.stopScrollDown(); - - this.#scrollUp = true; - - GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => { - // Set the new vadjustment value to either the current value minus a - // step increment or to 0. - const newVAdjustementValue = Math.max(this.#gtkScrolledWindow.vadjustment.get_value() - this.#gtkScrolledWindow.vadjustment.get_step_increment(), 0); - - // If the new value is the old one, return and stop this interval. - if (newVAdjustementValue === this.#gtkScrolledWindow.vadjustment.get_value()) { - this.#scrollUp = false; - return this.#scrollUp; - } - // Otherwise, update the value. - this.#gtkScrolledWindow.vadjustment.set_value(newVAdjustementValue); - return this.#scrollUp; - }); - } - - startScrollDown(): void { - // If the scroll down is already started, don't do anything. - if (this.#scrollDown) { - return; - } - - // Make sure scroll up is stopped. - this.stopScrollUp(); - - this.#scrollDown = true; - - GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => { - // Set the new vadjusment value either to the curent value plus a - // step increment or to the upper value minus the page size. - const newVAdjustementValue = Math.min( - this.#gtkScrolledWindow.vadjustment.get_value() + this.#gtkScrolledWindow.vadjustment.get_step_increment(), - this.#gtkScrolledWindow.vadjustment.get_upper() - this.#gtkScrolledWindow.vadjustment.get_page_size() - ); - - // If the new value is the old one, return and stop this interval. - if (newVAdjustementValue === this.#gtkScrolledWindow.vadjustment.get_value()) { - this.#scrollDown = false; - return this.#scrollDown; - } - // Otherwise, update the value. - this.#gtkScrolledWindow.vadjustment.set_value(newVAdjustementValue); - return this.#scrollDown; - }); - } - - stopScrollUp(): void { - this.#scrollUp = false; - } - - stopScrollDown(): void { - this.#scrollDown = false; - } - - stopScrollAll(): void { - this.stopScrollUp(); - this.stopScrollDown(); - } -} diff --git a/src/schemas/org.gnome.shell.extensions.top-bar-organizer.gschema.xml b/src/schemas/org.gnome.shell.extensions.top-bar-organizer.gschema.xml new file mode 100644 index 0000000..b4b03a4 --- /dev/null +++ b/src/schemas/org.gnome.shell.extensions.top-bar-organizer.gschema.xml @@ -0,0 +1,35 @@ + + + + + + Order of items in the left box of the top bar. + [] + + + Order of items in the center box of the top bar. + [] + + + Order of items in the right box of the top bar. + [] + + + diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index ea2c80f..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "module": "NodeNext", - "moduleResolution": "NodeNext", - "outDir": "./dist", - "sourceMap": false, - "strict": true, - // To preserve imports for UI files. - "verbatimModuleSyntax": true, - "target": "es2022", - "lib": [ - "ES2022" - ], - }, - "include": [ - "ambient.d.ts", - ], - "files": [ - "src/extension.ts", - "src/prefs.ts" - ] -}