diff options
author | Kristóf Marussy <kristof@marussy.com> | 2020-05-17 15:17:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-17 13:17:07 +0000 |
commit | 4576a5080c51918907c89629cefe389945179d71 (patch) | |
tree | 614e278ac7a4b9f55ce393eba4d40b37bd3724f1 /src/lib | |
parent | Replace change server input with a dropdown menu (#717) (diff) | |
download | ferdium-app-4576a5080c51918907c89629cefe389945179d71.tar.gz ferdium-app-4576a5080c51918907c89629cefe389945179d71.tar.zst ferdium-app-4576a5080c51918907c89629cefe389945179d71.zip |
Make Tray icons more robust on Linux (#748)
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/DBus.js | 49 | ||||
-rw-r--r-- | src/lib/Tray.js | 43 |
2 files changed, 84 insertions, 8 deletions
diff --git a/src/lib/DBus.js b/src/lib/DBus.js new file mode 100644 index 000000000..957912efa --- /dev/null +++ b/src/lib/DBus.js | |||
@@ -0,0 +1,49 @@ | |||
1 | import { | ||
2 | sessionBus, | ||
3 | } from 'dbus-next'; | ||
4 | import { | ||
5 | isLinux, | ||
6 | } from '../environment'; | ||
7 | |||
8 | export default class DBus { | ||
9 | bus = null; | ||
10 | |||
11 | constructor(trayIcon) { | ||
12 | this.trayIcon = trayIcon; | ||
13 | } | ||
14 | |||
15 | start() { | ||
16 | if (!isLinux || this.bus) return; | ||
17 | |||
18 | try { | ||
19 | this.bus = sessionBus(); | ||
20 | } catch { | ||
21 | // Error connecting to the bus. | ||
22 | return; | ||
23 | } | ||
24 | |||
25 | // HACK Hook onto the MessageBus to track StatusNotifierWatchers | ||
26 | this.bus._addMatch("type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',path='/org/freedesktop/DBus',member='NameOwnerChanged'"); | ||
27 | const mangled = JSON.stringify({ | ||
28 | path: '/org/freedesktop/DBus', | ||
29 | interface: 'org.freedesktop.DBus', | ||
30 | member: 'NameOwnerChanged', | ||
31 | }); | ||
32 | this.bus._signals.on(mangled, (msg) => { | ||
33 | const [name, oldOwner, newOwner] = msg.body; | ||
34 | if (name === 'org.kde.StatusNotifierWatcher' && oldOwner !== newOwner && newOwner !== '') { | ||
35 | // Leave ample time for the StatusNotifierWatcher to be initialized | ||
36 | setTimeout(() => { | ||
37 | this.trayIcon.recreateIfVisible(); | ||
38 | }, 400); | ||
39 | } | ||
40 | }); | ||
41 | } | ||
42 | |||
43 | stop() { | ||
44 | if (!this.bus) return; | ||
45 | |||
46 | this.bus.disconnect(); | ||
47 | this.bus = null; | ||
48 | } | ||
49 | } | ||
diff --git a/src/lib/Tray.js b/src/lib/Tray.js index 0afb6289b..c6d9db004 100644 --- a/src/lib/Tray.js +++ b/src/lib/Tray.js | |||
@@ -22,6 +22,8 @@ export default class TrayIcon { | |||
22 | 22 | ||
23 | trayMenu = null; | 23 | trayMenu = null; |
24 | 24 | ||
25 | visible = false; | ||
26 | |||
25 | trayMenuTemplate = [ | 27 | trayMenuTemplate = [ |
26 | { | 28 | { |
27 | label: 'Show Ferdi', | 29 | label: 'Show Ferdi', |
@@ -50,7 +52,19 @@ export default class TrayIcon { | |||
50 | }, | 52 | }, |
51 | ]; | 53 | ]; |
52 | 54 | ||
55 | constructor() { | ||
56 | ipcMain.on('initialAppSettings', (event, appSettings) => { | ||
57 | this._updateTrayMenu(appSettings); | ||
58 | }); | ||
59 | |||
60 | ipcMain.on('updateAppSettings', (event, appSettings) => { | ||
61 | this._updateTrayMenu(appSettings); | ||
62 | }); | ||
63 | } | ||
64 | |||
53 | _updateTrayMenu(appSettings) { | 65 | _updateTrayMenu(appSettings) { |
66 | if (!this.trayIcon) return; | ||
67 | |||
54 | if (appSettings.type === 'app') { | 68 | if (appSettings.type === 'app') { |
55 | const { isAppMuted } = appSettings.data; | 69 | const { isAppMuted } = appSettings.data; |
56 | this.trayMenuTemplate[1].label = isAppMuted ? 'Enable Notifications && Audio' : 'Disable Notifications && Audio'; | 70 | this.trayMenuTemplate[1].label = isAppMuted ? 'Enable Notifications && Audio' : 'Disable Notifications && Audio'; |
@@ -62,6 +76,11 @@ export default class TrayIcon { | |||
62 | } | 76 | } |
63 | 77 | ||
64 | show() { | 78 | show() { |
79 | this.visible = true; | ||
80 | this._show(); | ||
81 | } | ||
82 | |||
83 | _show() { | ||
65 | if (this.trayIcon) return; | 84 | if (this.trayIcon) return; |
66 | 85 | ||
67 | this.trayIcon = new Tray(this._getAsset('tray', INDICATOR_TRAY_PLAIN)); | 86 | this.trayIcon = new Tray(this._getAsset('tray', INDICATOR_TRAY_PLAIN)); |
@@ -73,14 +92,6 @@ export default class TrayIcon { | |||
73 | this.trayIcon.setContextMenu(this.trayMenu); | 92 | this.trayIcon.setContextMenu(this.trayMenu); |
74 | } | 93 | } |
75 | 94 | ||
76 | ipcMain.on('initialAppSettings', (event, appSettings) => { | ||
77 | this._updateTrayMenu(appSettings); | ||
78 | }); | ||
79 | |||
80 | ipcMain.on('updateAppSettings', (event, appSettings) => { | ||
81 | this._updateTrayMenu(appSettings); | ||
82 | }); | ||
83 | |||
84 | this.trayIcon.on('click', () => { | 95 | this.trayIcon.on('click', () => { |
85 | if (app.mainWindow.isMinimized()) { | 96 | if (app.mainWindow.isMinimized()) { |
86 | app.mainWindow.restore(); | 97 | app.mainWindow.restore(); |
@@ -106,6 +117,11 @@ export default class TrayIcon { | |||
106 | } | 117 | } |
107 | 118 | ||
108 | hide() { | 119 | hide() { |
120 | this.visible = false; | ||
121 | this._hide(); | ||
122 | } | ||
123 | |||
124 | _hide() { | ||
109 | if (!this.trayIcon) return; | 125 | if (!this.trayIcon) return; |
110 | 126 | ||
111 | this.trayIcon.destroy(); | 127 | this.trayIcon.destroy(); |
@@ -117,6 +133,17 @@ export default class TrayIcon { | |||
117 | } | 133 | } |
118 | } | 134 | } |
119 | 135 | ||
136 | recreateIfVisible() { | ||
137 | if (this.visible) { | ||
138 | this._hide(); | ||
139 | setTimeout(() => { | ||
140 | if (this.visible) { | ||
141 | this._show(); | ||
142 | } | ||
143 | }, 100); | ||
144 | } | ||
145 | } | ||
146 | |||
120 | setIndicator(indicator) { | 147 | setIndicator(indicator) { |
121 | this.indicator = indicator; | 148 | this.indicator = indicator; |
122 | this._refreshIcon(); | 149 | this._refreshIcon(); |