Skip to content

Events Module ​

The Events Module lets you emit and listen to events across windows and bridge components. All listener methods return a Promise that resolves to an unlisten function — call it when the listener is no longer needed to avoid memory leaks.

Methods ​

Emitting ​

MethodDescription
emit(event, payload?)Emits an event to the current window only.
emitToAll(event, payload?)Emits an event to all open windows.
emitTo(windowLabel, event, payload?)Emits an event to the window identified by windowLabel.

Listening ​

MethodHandler signatureReturn type
on(event, handler)(payload) => voidPromise<() => void>
once(event)
Promise<any>
onMany(events[], handler)(eventName, payload) => voidPromise<() => void>
onNetworkStatus(handler)(payload) => voidPromise<() => void>
onDeeplink(handler)(payload) => voidPromise<() => void>
onShortcut(handler)(payload) => voidPromise<() => void>
onDragDrop(handler, options?)(eventName, payload) => voidPromise<() => void>
onMenuEvent(handler)(payload) => voidPromise<() => void>
onTrayIconEvent(handler)(payload) => voidPromise<() => void>

Unsubscribing ​

Every listener method returns a Promise that resolves to an unlisten function. Always await the call — without await, you hold a Promise object, not the unlisten function.

js
// ✅ Correct
const unlisten = await Desktopr.events.on('data:refresh', (payload) => {
  console.log(payload);
});

// Later, when the component unmounts or the listener is no longer needed:
unlisten();
js
// ❌ Wrong — you need 'await' otherwise 'unlisten' is a Promise, not a function
const unlisten = Desktopr.events.on('data:refresh', handler);
unlisten(); // TypeError

Examples ​

on — persistent listener ​

js
const unlisten = await Desktopr.events.on('order:updated', (payload) => {
  console.log('Order updated:', payload);
});

// Remove the listener when done
unlisten();

once — wait for a single event ​

once returns a Promise that resolves with the event payload the first time the event fires. It automatically unsubscribes after the first occurrence — no unlisten needed.

js
const payload = await Desktopr.events.once('auth:token-ready');
console.log('Token received:', payload);

onMany — one handler for multiple events ​

The handler receives the event name as its first argument, so you can branch on it.

js
const unlisten = await Desktopr.events.onMany(
  ['cart:add', 'cart:remove', 'cart:clear'],
  (eventName, payload) => {
    if (eventName === 'cart:clear') resetCart();
    else updateCart(eventName, payload);
  }
);

onNetworkStatus — online/offline ​

js
const unlisten = await Desktopr.events.onNetworkStatus(({ online, reason, latency_ms }) => {
  console.log(online ? `Online (${latency_ms}ms)` : `Offline — ${reason}`);
});
js
const unlisten = await Desktopr.events.onDeeplink(({ scheme, segments, query, raw }) => {
  // e.g. myapp://reset-password?token=abc
  console.log(scheme, segments.list, query);
});

onShortcut — global keyboard shortcuts ​

Fires when a shortcut registered via Desktopr.globalShortcut.register() is triggered.

js
const unlisten = await Desktopr.events.onShortcut(({ accelerator, state }) => {
  if (state === 'Pressed') handleShortcut(accelerator);
});

onDragDrop — file drag and drop ​

By default listens to dragdrop:enter, dragdrop:drop, and dragdrop:cancel. Pass { includeHover: true } to also receive dragdrop:hover events while files are being dragged over the window.

js
const unlisten = await Desktopr.events.onDragDrop(
  (eventName, { kind, paths, position }) => {
    if (kind === 'drop') {
      console.log('Files dropped:', paths);
    }
  },
  { includeHover: true }
);

unlisten();

onMenuEvent / onTrayIconEvent ​

js
const unlistenMenu = await Desktopr.events.onMenuEvent((payload) => {
  console.log('Menu action:', payload);
});

const unlistenTray = await Desktopr.events.onTrayIconEvent((payload) => {
  console.log('Tray interaction:', payload);
});

Payload types ​

Event sourceRelevant fields
onNetworkStatusonline: boolean, reason: "ok" | "dns" | "timeout" | "unknown", latency_ms?: number
onDeeplinkscheme: string, segments: { first, last, list }, query: Record<string, string>, raw: string
onShortcutaccelerator: string, shortcut: string, id: number, state: "Pressed" | "Released"
onDragDropkind: "enter" | "hover" | "drop" | "cancel", paths: string[], position?: { x, y }

Notes ​

Cleanup pattern in components

If you are using a framework, store unlisten functions and call them on component teardown:

js
// Svelte
import { onDestroy } from 'svelte';

const unlisten = await Desktopr.events.on('my:event', handler);
onDestroy(unlisten);

// React
useEffect(() => {
  let unlisten;
  Desktopr.events.on('my:event', handler).then(fn => { unlisten = fn; });
  return () => unlisten?.();
}, []);

Forgetting to unlisten

Each call to on registers a new listener. If your component re-renders or re-mounts without cleaning up, the same event will be handled multiple times. Always pair each on call with a corresponding unlisten().