aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/DBus.ts
blob: 70c8132a325c6a17abd2e9a153ad592b94440a19 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { ipcMain } from 'electron';
import { comparer } from 'mobx';

import { type MessageBus, sessionBus } from 'dbus-next';
import { isLinux } from '../environment';
import type TrayIcon from './Tray';
import Ferdium, { type UnreadServices } from './dbus/Ferdium';

export default class DBus {
  private bus: MessageBus | null = null;

  trayIcon: TrayIcon;

  private ferdium: Ferdium | null = null;

  muted = false;

  unreadDirectMessageCount = 0;

  unreadIndirectMessageCount = 0;

  unreadServices: UnreadServices = [];

  constructor(trayIcon: TrayIcon) {
    this.trayIcon = trayIcon;
    ipcMain.on('initialAppSettings', (_, appSettings) => {
      this.updateSettings(appSettings);
    });
    ipcMain.on('updateAppSettings', (_, appSettings) => {
      this.updateSettings(appSettings);
    });
    ipcMain.on(
      'updateDBusUnread',
      (
        _,
        unreadDirectMessageCount,
        unreadIndirectMessageCount,
        unreadServices,
      ) => {
        this.setUnread(
          unreadDirectMessageCount,
          unreadIndirectMessageCount,
          unreadServices,
        );
      },
    );
  }

  private updateSettings(appSettings): void {
    const muted = !!appSettings.data.isAppMuted;
    if (this.muted !== muted) {
      this.muted = muted;
      this.ferdium?.emitMutedChanged();
    }
  }

  private setUnread(
    unreadDirectMessageCount: number,
    unreadIndirectMessageCount: number,
    unreadServices: UnreadServices,
  ): void {
    if (
      this.unreadDirectMessageCount !== unreadDirectMessageCount ||
      this.unreadIndirectMessageCount !== unreadIndirectMessageCount ||
      !comparer.structural(this.unreadServices, unreadServices)
    ) {
      this.unreadDirectMessageCount = unreadDirectMessageCount;
      this.unreadIndirectMessageCount = unreadIndirectMessageCount;
      this.unreadServices = unreadServices;
      this.ferdium?.emitUnreadChanged();
    }
  }

  async start() {
    if (!isLinux || this.bus) {
      return;
    }

    try {
      this.bus = sessionBus();
      await this.bus.requestName('org.ferdium.Ferdium', 0);
    } catch {
      // Error connecting to the bus.
      return;
    }

    this.ferdium = new Ferdium(this);
    this.bus.export('/org/ferdium', this.ferdium);

    // HACK Hook onto the MessageBus to track StatusNotifierWatchers
    // @ts-expect-error Property '_addMatch' does not exist on type 'MessageBus'.
    this.bus._addMatch(
      "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',path='/org/freedesktop/DBus',member='NameOwnerChanged'",
    );
    const mangled = JSON.stringify({
      path: '/org/freedesktop/DBus',
      interface: 'org.freedesktop.DBus',
      member: 'NameOwnerChanged',
    });
    // @ts-expect-error Property '_signals' does not exist on type 'MessageBus'.
    this.bus._signals.on(mangled, (msg: { body: [any, any, any] }) => {
      const [name, oldOwner, newOwner] = msg.body;
      if (
        name === 'org.kde.StatusNotifierWatcher' &&
        oldOwner !== newOwner &&
        newOwner !== ''
      ) {
        // Leave ample time for the StatusNotifierWatcher to be initialized
        setTimeout(() => {
          this.trayIcon.recreateIfVisible();
        }, 400);
      }
    });
  }

  stop() {
    if (!this.bus) {
      return;
    }

    this.bus.disconnect();
    this.bus = null;
    this.ferdium = null;
  }
}