aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2020-05-17 15:17:07 +0200
committerLibravatar GitHub <noreply@github.com>2020-05-17 13:17:07 +0000
commit4576a5080c51918907c89629cefe389945179d71 (patch)
tree614e278ac7a4b9f55ce393eba4d40b37bd3724f1 /src
parentReplace change server input with a dropdown menu (#717) (diff)
downloadferdium-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')
-rw-r--r--src/index.js8
-rw-r--r--src/lib/DBus.js49
-rw-r--r--src/lib/Tray.js43
3 files changed, 92 insertions, 8 deletions
diff --git a/src/index.js b/src/index.js
index 484191f2e..9dfbb4d8f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -35,6 +35,7 @@ import {
35import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; 35import { mainIpcHandler as basicAuthHandler } from './features/basicAuth';
36import ipcApi from './electron/ipc-api'; 36import ipcApi from './electron/ipc-api';
37import Tray from './lib/Tray'; 37import Tray from './lib/Tray';
38import DBus from './lib/DBus';
38import Settings from './electron/Settings'; 39import Settings from './electron/Settings';
39import handleDeepLink from './electron/deepLinking'; 40import handleDeepLink from './electron/deepLinking';
40import { isPositionValid } from './electron/windowUtils'; 41import { isPositionValid } from './electron/windowUtils';
@@ -213,6 +214,9 @@ const createWindow = () => {
213 // Initialize System Tray 214 // Initialize System Tray
214 const trayIcon = new Tray(); 215 const trayIcon = new Tray();
215 216
217 // Initialize DBus interface
218 const dbus = new DBus(trayIcon);
219
216 // Initialize ipcApi 220 // Initialize ipcApi
217 ipcApi({ 221 ipcApi({
218 mainWindow, 222 mainWindow,
@@ -223,6 +227,9 @@ const createWindow = () => {
223 trayIcon, 227 trayIcon,
224 }); 228 });
225 229
230 // Connect to the DBus after ipcApi took care of the System Tray
231 dbus.start();
232
226 // Manage Window State 233 // Manage Window State
227 mainWindowState.manage(mainWindow); 234 mainWindowState.manage(mainWindow);
228 235
@@ -265,6 +272,7 @@ const createWindow = () => {
265 mainWindow.hide(); 272 mainWindow.hide();
266 } 273 }
267 } else { 274 } else {
275 dbus.stop();
268 app.quit(); 276 app.quit();
269 } 277 }
270 }); 278 });
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 @@
1import {
2 sessionBus,
3} from 'dbus-next';
4import {
5 isLinux,
6} from '../environment';
7
8export 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();