From 88525dcd8daa0c284592f40851d35fe0abef57d8 Mon Sep 17 00:00:00 2001 From: Leandro Rodrigues Date: Sat, 8 Aug 2026 18:10:34 -0300 Subject: [PATCH] fix(tray-icons): standardize missing icon fallback Use the generic executable symbolic icon for missing SNI, widget, and background application icons. Keep the fallback name in one shared constant so the paths cannot diverge. Validated with just validate, just test unit, just shexli, and the Tray Icons Shell integration test. --- src/desktop/trayIcons/backgroundAppsSource.ts | 4 ++-- src/desktop/trayIcons/sniHost.ts | 4 ++-- src/desktop/trayIcons/trayIconItem.ts | 4 ++-- src/desktop/trayIcons/trayState.ts | 2 ++ tests/unit/desktop/trayIcons/trayState.test.ts | 5 +++++ 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/desktop/trayIcons/backgroundAppsSource.ts b/src/desktop/trayIcons/backgroundAppsSource.ts index a791ced..4c561d3 100644 --- a/src/desktop/trayIcons/backgroundAppsSource.ts +++ b/src/desktop/trayIcons/backgroundAppsSource.ts @@ -5,7 +5,7 @@ import Gio from '@girs/gio-2.0'; import GLib from '@girs/glib-2.0'; import Shell from '@girs/shell-18'; -import type { TrayItem, TrayItemStatus } from './trayState.ts'; +import { TRAY_ICON_FALLBACK_NAME, type TrayItem, type TrayItemStatus } from './trayState.ts'; import { logger } from '~/core/logger.ts'; const DBUS_NAME = 'org.freedesktop.background.Monitor'; @@ -126,7 +126,7 @@ export class BackgroundAppsSource { return { id: `bg:${appId}`, get icon() { - return app.get_icon() || 'application-x-executable-symbolic'; + return app.get_icon() || TRAY_ICON_FALLBACK_NAME; }, get tooltip() { return message || ''; diff --git a/src/desktop/trayIcons/sniHost.ts b/src/desktop/trayIcons/sniHost.ts index 8a93a1e..1bf934e 100644 --- a/src/desktop/trayIcons/sniHost.ts +++ b/src/desktop/trayIcons/sniHost.ts @@ -5,7 +5,7 @@ import GLib from '@girs/glib-2.0'; import GdkPixbuf from '@girs/gdkpixbuf-2.0'; import St from '@girs/st-18'; -import type { TrayItem, TrayItemStatus } from './trayState.ts'; +import { TRAY_ICON_FALLBACK_NAME, type TrayItem, type TrayItemStatus } from './trayState.ts'; import type { SniWatcher } from './sniWatcher.ts'; import { sniIdentityMatchesAppId } from './appIdentity.ts'; import { isSymbolicSniArgb } from './sniIconState.ts'; @@ -231,7 +231,7 @@ export class SniHost { } logger.debug(`SNI icon ${itemId} reason=${reason} source=fallback`, { prefix: LOG_PREFIX }); - return 'image-missing-symbolic'; + return TRAY_ICON_FALLBACK_NAME; } refreshIcons(reason = 'theme-change'): void { diff --git a/src/desktop/trayIcons/trayIconItem.ts b/src/desktop/trayIcons/trayIconItem.ts index 146abd2..be195a0 100644 --- a/src/desktop/trayIcons/trayIconItem.ts +++ b/src/desktop/trayIcons/trayIconItem.ts @@ -9,7 +9,7 @@ import * as PopupMenu from '@girs/gnome-shell/ui/popupMenu'; import { PopupAnimation } from '@girs/gnome-shell/ui/boxpointer'; import { logger } from '~/core/logger.ts'; -import type { TrayItem } from './trayState.ts'; +import { TRAY_ICON_FALLBACK_NAME, type TrayItem } from './trayState.ts'; import { DBusMenuClient } from './dbusMenu.ts'; const BADGE_SIZE = 6; @@ -108,7 +108,7 @@ export const TrayIconItem = GObject.registerClass( this._iconWidget = new St.Icon({ icon_size: iconSize, - fallback_icon_name: 'image-missing-symbolic', + fallback_icon_name: TRAY_ICON_FALLBACK_NAME, reactive: false, }); box.add_child(this._iconWidget); diff --git a/src/desktop/trayIcons/trayState.ts b/src/desktop/trayIcons/trayState.ts index f349308..add9233 100644 --- a/src/desktop/trayIcons/trayState.ts +++ b/src/desktop/trayIcons/trayState.ts @@ -1,6 +1,8 @@ import type Gio from '@girs/gio-2.0'; import type GdkPixbuf from '@girs/gdkpixbuf-2.0'; +export const TRAY_ICON_FALLBACK_NAME = 'application-x-executable-symbolic'; + export type TrayItemStatus = 'Passive' | 'Active' | 'NeedsAttention'; export type TrayMenuItem = { label: string; action: () => void }; diff --git a/tests/unit/desktop/trayIcons/trayState.test.ts b/tests/unit/desktop/trayIcons/trayState.test.ts index 79cb144..b449991 100644 --- a/tests/unit/desktop/trayIcons/trayState.test.ts +++ b/tests/unit/desktop/trayIcons/trayState.test.ts @@ -6,9 +6,14 @@ import { applyScroll, addAttention, clearAttention, + TRAY_ICON_FALLBACK_NAME, } from '~/desktop/trayIcons/trayState.ts'; import type { TrayItem } from '~/desktop/trayIcons/trayState.ts'; +test('Tray Icons use the generic executable icon as their shared fallback', () => { + assert.strictEqual(TRAY_ICON_FALLBACK_NAME, 'application-x-executable-symbolic'); +}); + test('createTrayState returns collapsed=true, offset=0, empty attention set', () => { const state = createTrayState(); assert.strictEqual(state.collapsed, true);