Review of "Better Tray Icons" version 2

Details Page Preview

Brings tray icons back to the GNOME panel. Supports the StatusNotifierItem (SNI) and KStatusNotifierItem specs, so apps like Discord, Steam, Telegram, Signal and Nextcloud show up in the panel like they used to. A configurable number of icons stays inline, the rest are tucked away into an overflow popup behind a toggle button, in row or grid layout. Every icon can be renamed, hidden, reordered or swapped out for a custom one on a per-app basis. Left, middle and right click, plus double-click and long-press, are independently bindable. Spacing, padding, radius, hover background and the toggle styling are all up to you. Settings can be exported, imported and synced across devices through a shared JSON file with rotated backups. Wayland only, X11 sessions are not supported. Conflicts with other tray and AppIndicator extensions, so disable those before enabling this one.

Extension Homepage
https://github.com/nexaknight/BetterTrayIcons

No comments.

Diff Against

Files

Note: Binary files aren't shown on the web site. To see all files, please download the extension zipfile.

Shexli (experimental) warning 3

Shexli found 3 issues that may need reviewer attention.

EGO-X-004 warning

extensions should avoid synchronous file IO in shell code

Shell code should avoid synchronous file IO APIs like `GLib.file_get_contents()` and `Gio.File.load_contents()`.

File Operations

  • src/shell/utils/dbus.js:34
    interfaceFile.load_contents(null)

EGO-L-003 warning

signals connected by extension should be disconnected in disable()

Signals assigned in `enable()` are missing matching disconnect calls in `disable()` or its helper methods.

Disconnect all signals

  • extension.js:126
            this._autoPushSignalId = this._settings.connect('changed', (_s, key) => {
                if (key === 'sync-file-path' || key === 'enable-auto-sync')
                    return;
                if (this._lastImportAt && Date.now() - this._lastImportAt < AUTO_PUSH_GUARD_AFTER_IMPORT_MS)
                    r
  • extension.js:73
                this._fileMonitorSignalId = this._fileMonitor.connect('changed', (_monitor, f, _other, eventType) => {
                    if (eventType === Gio.FileMonitorEvent.CHANGED || eventType === Gio.FileMonitorEvent.CREATED)
                        this._queueSyncImport(f);
                })
  • extension.js:144
    this._settings.connect(`changed::${key}`, handler)
  • src/shell/xembedBridge.js:302
            this._sigIconDestroy = this._icon.connect('destroy', () => {
                this._sigIconDestroy = 0;
                this.destroy();
            })
  • src/shell/xembedBridge.js:283
                this.actor.connect('button-press-event', () => {
                    this.actor.add_style_pseudo_class('active');
                    return Clutter.EVENT_PROPAGATE;
                })
  • src/shell/xembedBridge.js:332
    this._settings.connect(`changed::${key}`, () => {
                    this._draggable?.setEnabled(isDragEnabledFromSettings(this._settings));
                })

EGO-L-004 warning

main loop sources should be removed in disable()

Main loop sources assigned in `enable()` are missing matching removals in `disable()` or its helper methods.

Remove main loop sources

  • extension.js:133
                this._autoPushDebounceId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, AUTO_PUSH_DEBOUNCE_MS, () => {
                    this._autoPushDebounceId = 0;
                    saveSettingsToFile(this._settings, this._settings.get_string('sync-file-path'))
                        .catch(e => warn(`Auto-push 
  • extension.js:20
            this._enableTimeoutId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
                this._enableTimeoutId = 0;
                this._realEnable();
                return GLib.SOURCE_REMOVE;
            })
  • extension.js:86
            this._syncDebounceId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, AUTO_SYNC_DEBOUNCE_MS, () => {
                this._syncDebounceId = 0;
    
                // Cancellable lets disable() abort the read before it touches
                // a nulled `this._settings`.
                disposeAll(this, 'cancel', '_s
  • src/shell/xembedBridge.js:348
            this._pendingClickId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
                this._pendingClickId = 0;
                if (!this._isDestroyed && this._icon)
                    this._icon.click(eventCopy);
                return GLib.SOURCE_REMOVE;
            })

All Versions

Version Status
2 Unreviewed
1 Rejected