aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-03-15 17:26:13 +0100
committerLibravatar GitHub <noreply@github.com>2023-03-15 17:26:13 +0100
commitf1152d3dbb4c6deefea168d66f15f77b7155a5fe (patch)
tree22c27234b6e3a2dfe47ade037ece47b2533f7039 /src/lib
parent6.2.6-nightly.5 [skip ci] (diff)
downloadferdium-app-f1152d3dbb4c6deefea168d66f15f77b7155a5fe.tar.gz
ferdium-app-f1152d3dbb4c6deefea168d66f15f77b7155a5fe.tar.zst
ferdium-app-f1152d3dbb4c6deefea168d66f15f77b7155a5fe.zip
Basic D-Bus API (#866)
* feat: basic D-Bus API Expose muted state and the number of unread message over D-Bus when running on Linux. This is useful for, e.g., displaying notifications on a window manager status bar. Signed-off-by: Kristóf Marussy <kristof@marussy.com> * docs: create docs directory Move the documentation to a separate directory so that new documentation can be added into one place. We keep the following files still in the repository root by convention: * CHANGELOG.md * CODE_OF_CONDUCT.md * CONTRIBUTING.md * LICENSE.md * README.md * SECURITY.md Signed-off-by: Kristóf Marussy <kristof@marussy.com> * docs: D-Bus usage example Signed-off-by: Kristóf Marussy <kristof@marussy.com> * fix: remove unneeded D-Bus signals Only notify clients that the message counts or the mute status has changed if there actually was a change. Signed-off-by: Kristóf Marussy <kristof@marussy.com> * docs: rewrite sample bar client * docs: better unread --services help * docs: update dbus docs * docs: use ferdium-dbus in dbus bar example * docs: make command argument required in bar example --------- Signed-off-by: Kristóf Marussy <kristof@marussy.com> Co-authored-by: Victor Bonnelle <victor.bonnelle@protonmail.com>
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/DBus.ts69
-rw-r--r--src/lib/dbus/Ferdium.ts88
2 files changed, 155 insertions, 2 deletions
diff --git a/src/lib/DBus.ts b/src/lib/DBus.ts
index bbff405c4..530e30c85 100644
--- a/src/lib/DBus.ts
+++ b/src/lib/DBus.ts
@@ -1,28 +1,92 @@
1import { ipcMain } from 'electron';
2import { comparer } from 'mobx';
3
1import { MessageBus, sessionBus } from 'dbus-next'; 4import { MessageBus, sessionBus } from 'dbus-next';
2import { isLinux } from '../environment'; 5import { isLinux } from '../environment';
3import TrayIcon from './Tray'; 6import TrayIcon from './Tray';
7import Ferdium, { type UnreadServices } from './dbus/Ferdium';
4 8
5export default class DBus { 9export default class DBus {
6 bus: MessageBus | null = null; 10 private bus: MessageBus | null = null;
7 11
8 trayIcon: TrayIcon; 12 trayIcon: TrayIcon;
9 13
14 private ferdium: Ferdium | null = null;
15
16 muted = false;
17
18 unreadDirectMessageCount = 0;
19
20 unreadIndirectMessageCount = 0;
21
22 unreadServices: UnreadServices = [];
23
10 constructor(trayIcon: TrayIcon) { 24 constructor(trayIcon: TrayIcon) {
11 this.trayIcon = trayIcon; 25 this.trayIcon = trayIcon;
26 ipcMain.on('initialAppSettings', (_, appSettings) => {
27 this.updateSettings(appSettings);
28 });
29 ipcMain.on('updateAppSettings', (_, appSettings) => {
30 this.updateSettings(appSettings);
31 });
32 ipcMain.on(
33 'updateDBusUnread',
34 (
35 _,
36 unreadDirectMessageCount,
37 unreadIndirectMessageCount,
38 unreadServices,
39 ) => {
40 this.setUnread(
41 unreadDirectMessageCount,
42 unreadIndirectMessageCount,
43 unreadServices,
44 );
45 },
46 );
47 }
48
49 private updateSettings(appSettings): void {
50 const muted = !!appSettings.data.isAppMuted;
51 if (this.muted !== muted) {
52 this.muted = muted;
53 this.ferdium?.emitMutedChanged();
54 }
12 } 55 }
13 56
14 start() { 57 private setUnread(
58 unreadDirectMessageCount: number,
59 unreadIndirectMessageCount: number,
60 unreadServices: UnreadServices,
61 ): void {
62 if (
63 this.unreadDirectMessageCount !== unreadDirectMessageCount ||
64 this.unreadIndirectMessageCount !== unreadIndirectMessageCount ||
65 !comparer.structural(this.unreadServices, unreadServices)
66 ) {
67 this.unreadDirectMessageCount = unreadDirectMessageCount;
68 this.unreadIndirectMessageCount = unreadIndirectMessageCount;
69 this.unreadServices = unreadServices;
70 this.ferdium?.emitUnreadChanged();
71 }
72 }
73
74 async start() {
15 if (!isLinux || this.bus) { 75 if (!isLinux || this.bus) {
16 return; 76 return;
17 } 77 }
18 78
19 try { 79 try {
20 this.bus = sessionBus(); 80 this.bus = sessionBus();
81 await this.bus.requestName('org.ferdium.Ferdium', 0);
21 } catch { 82 } catch {
22 // Error connecting to the bus. 83 // Error connecting to the bus.
23 return; 84 return;
24 } 85 }
25 86
87 this.ferdium = new Ferdium(this);
88 this.bus.export('/org/ferdium', this.ferdium);
89
26 // HACK Hook onto the MessageBus to track StatusNotifierWatchers 90 // HACK Hook onto the MessageBus to track StatusNotifierWatchers
27 // @ts-expect-error Property '_addMatch' does not exist on type 'MessageBus'. 91 // @ts-expect-error Property '_addMatch' does not exist on type 'MessageBus'.
28 this.bus._addMatch( 92 this.bus._addMatch(
@@ -56,5 +120,6 @@ export default class DBus {
56 120
57 this.bus.disconnect(); 121 this.bus.disconnect();
58 this.bus = null; 122 this.bus = null;
123 this.ferdium = null;
59 } 124 }
60} 125}
diff --git a/src/lib/dbus/Ferdium.ts b/src/lib/dbus/Ferdium.ts
new file mode 100644
index 000000000..b2a9105f4
--- /dev/null
+++ b/src/lib/dbus/Ferdium.ts
@@ -0,0 +1,88 @@
1import * as dbus from 'dbus-next';
2
3import type DBus from '../DBus';
4
5export type UnreadServices = [string, number, number][];
6
7export default class Ferdium extends dbus.interface.Interface {
8 constructor(private readonly dbus: DBus) {
9 super('org.ferdium.Ferdium');
10 }
11
12 emitMutedChanged(): void {
13 Ferdium.emitPropertiesChanged(this, { Muted: this.dbus.muted }, []);
14 }
15
16 get Muted(): boolean {
17 return this.dbus.muted;
18 }
19
20 set Muted(muted: boolean) {
21 if (this.dbus.muted !== muted) {
22 this.ToggleMute();
23 }
24 }
25
26 ToggleMute(): void {
27 this.dbus.trayIcon.mainWindow?.webContents.send('muteApp');
28 }
29
30 ToggleWindow(): void {
31 this.dbus.trayIcon._toggleWindow();
32 }
33
34 emitUnreadChanged(): void {
35 Ferdium.emitPropertiesChanged(
36 this,
37 {
38 UnreadDirectMessageCount: this.dbus.unreadDirectMessageCount,
39 UnreadIndirectMessageCount: this.dbus.unreadIndirectMessageCount,
40 UnreadServices: this.dbus.unreadServices,
41 },
42 [],
43 );
44 }
45
46 get UnreadDirectMessageCount(): number {
47 return this.dbus.unreadDirectMessageCount;
48 }
49
50 get UnreadIndirectMessageCount(): number {
51 return this.dbus.unreadIndirectMessageCount;
52 }
53
54 get UnreadServices(): UnreadServices {
55 return this.dbus.unreadServices;
56 }
57}
58
59Ferdium.configureMembers({
60 methods: {
61 ToggleMute: {
62 inSignature: '',
63 outSignature: '',
64 },
65 ToggleWindow: {
66 inSignature: '',
67 outSignature: '',
68 },
69 },
70 properties: {
71 Muted: {
72 signature: 'b',
73 access: dbus.interface.ACCESS_READWRITE,
74 },
75 UnreadDirectMessageCount: {
76 signature: 'u',
77 access: dbus.interface.ACCESS_READ,
78 },
79 UnreadIndirectMessageCount: {
80 signature: 'u',
81 access: dbus.interface.ACCESS_READ,
82 },
83 UnreadServices: {
84 signature: 'a(suu)',
85 access: dbus.interface.ACCESS_READ,
86 },
87 },
88});