diff --git a/apps/desktop/electron/tray-host.test.ts b/apps/desktop/electron/tray-host.test.ts index 2f704df62c..761f216727 100644 --- a/apps/desktop/electron/tray-host.test.ts +++ b/apps/desktop/electron/tray-host.test.ts @@ -40,6 +40,15 @@ test('a registered host is required, and losing its owner reports loss exactly o dispose() }) +test('dbus-native 0.15 returns the registered flag as a bare boolean', async () => { + const instance = bus(true) + instance.invoke.mockResolvedValue(true) + const lost = vi.fn() + const dispose = await watchLinuxTrayHost(lost) + expect(lost).not.toHaveBeenCalled() + dispose() +}) + test('a missing host and a failed query reject without leaving an open bus connection', async () => { const lost = vi.fn() const absent = bus(false) diff --git a/apps/desktop/electron/tray-host.ts b/apps/desktop/electron/tray-host.ts index 3a730c1eeb..5a2aed29a4 100644 --- a/apps/desktop/electron/tray-host.ts +++ b/apps/desktop/electron/tray-host.ts @@ -1,5 +1,15 @@ import { createClient, type Message, type Variant } from 'dbus-native' +// dbus-native 0.15 defaults plainValues to true, so a property Get returns the +// bare boolean. Older builds still wrap it as { value }. +function statusNotifierHostRegistered(value: unknown): boolean { + if (value === true) { + return true + } + + return typeof value === 'object' && value !== null && (value as { value?: unknown }).value === true +} + // Electron can construct a Linux Tray even when the desktop has no tray host // (notably stock GNOME). Never use that object alone as proof of a restore path. export async function watchLinuxTrayHost(onLost: () => void): Promise<() => void> { @@ -93,7 +103,7 @@ export async function watchLinuxTrayHost(onLost: () => void): Promise<() => void options ) - if (disposed || value.value !== true) { + if (disposed || !statusNotifierHostRegistered(value)) { throw new Error('No system tray host is available') }