aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-client
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-client')
-rw-r--r--packages/meshbay-client/src/main.js99
-rw-r--r--packages/meshbay-client/src/tray-icon.pngbin415 -> 504 bytes
-rw-r--r--packages/meshbay-client/src/tray-icon@2x.pngbin755 -> 967 bytes
3 files changed, 77 insertions, 22 deletions
diff --git a/packages/meshbay-client/src/main.js b/packages/meshbay-client/src/main.js
index 71b56be..273d151 100644
--- a/packages/meshbay-client/src/main.js
+++ b/packages/meshbay-client/src/main.js
@@ -339,6 +339,19 @@ let mainWindow = null;
// files are the interface's, the main process has no i18n, and a second string
// table is how two of them start disagreeing.
let tray = null;
+let trayLabels = null;
+let trayTimer = null;
+let nodeService = null; // assigned by registerBridge()
+
+const TRAY_FALLBACK = {
+ show: 'Show MeshBay', quit: 'Quit',
+ start_node: 'Start the node', stop_node: 'Stop the node',
+};
+
+// libappindicator offers no "menu is about to open" event, so a menu built once
+// would show a stale Start/Stop for as long as the app runs. `systemctl --user
+// show` is a few milliseconds and this only ticks while an indicator exists.
+const TRAY_POLL_MS = 5000;
function showFromTray() {
if (!mainWindow) return;
@@ -347,18 +360,51 @@ function showFromTray() {
mainWindow.focus();
}
+async function buildTrayMenu() {
+ const text = { ...TRAY_FALLBACK, ...(trayLabels || {}) };
+ const items = [{ label: text.show, click: showFromTray }];
+
+ // Only when there is a daemon to act on: not installed means no entry at all,
+ // rather than a control that reports failure when used.
+ let status = null;
+ try {
+ status = nodeService ? await nodeService.status() : null;
+ } catch {
+ status = null; // unreadable state is the same as no control
+ }
+ if (status && status.supported && status.installed) {
+ const running = status.activeState === 'active';
+ items.push({ type: 'separator' });
+ items.push({
+ label: running ? text.stop_node : text.start_node,
+ click: async () => {
+ try {
+ // `restart` starts a stopped unit, which is what systemd's restart
+ // means; there is no separate start verb to call.
+ if (running) await nodeService.stop();
+ else await nodeService.restart();
+ } catch (err) {
+ console.error('[MeshBay] tray: node action failed', err);
+ }
+ refreshTrayMenu(); // reflect the new state without waiting a tick
+ },
+ });
+ }
+
+ items.push({ type: 'separator' },
+ { label: text.quit, click: () => app.quit() });
+ return Menu.buildFromTemplate(items);
+}
+
+async function refreshTrayMenu() {
+ if (!tray) return;
+ tray.setContextMenu(await buildTrayMenu());
+}
+
function ensureTray(labels) {
- const text = {
- show: (labels && labels.show) || 'Show MeshBay',
- quit: (labels && labels.quit) || 'Quit',
- };
+ if (labels) trayLabels = labels; // the person may have changed language
if (tray) {
- // Relabel in place: the person may have changed language since it was made.
- tray.setContextMenu(Menu.buildFromTemplate([
- { label: text.show, click: showFromTray },
- { type: 'separator' },
- { label: text.quit, click: () => app.quit() },
- ]));
+ refreshTrayMenu();
return tray;
}
// In src/, not build/: electron-builder packages only `src/**` and `ui/**`
@@ -366,17 +412,13 @@ function ensureTray(labels) {
// missing from every installed one.
tray = new Tray(path.join(__dirname, 'tray-icon.png'));
tray.setToolTip('MeshBay');
- tray.setContextMenu(Menu.buildFromTemplate([
- { label: text.show, click: showFromTray },
- { type: 'separator' },
- { label: text.quit, click: () => app.quit() },
- ]));
+ refreshTrayMenu();
// Harmless where it does nothing (GNOME), useful on desktops that do send it.
tray.on('click', showFromTray);
+ if (!trayTimer) trayTimer = setInterval(refreshTrayMenu, TRAY_POLL_MS);
return tray;
}
-
function createWindow() {
const bounds = (config.window && config.window.width) ? config.window : {
width: 1200, height: 800,
@@ -1073,7 +1115,16 @@ function registerBridge() {
// of the Node page. Deliberately not `probeNode()`: that asks the daemon's
// own HTTP API, which cannot answer while the daemon is stopped or crash-
// looping — exactly the states this panel exists to show and act on.
- ipcMain.handle('node:service-status', async () => {
+ // The tray menu drives the same daemon controls as the Node page. Declared
+ // here because these close over registerBridge's helpers; the tray is created
+ // long after, so it reads them through this binding rather than duplicating
+ // the systemctl and Task Scheduler branches.
+ nodeService = { status: nodeServiceStatus, stop: nodeServiceStop,
+ restart: nodeServiceRestart };
+
+ ipcMain.handle('node:service-status', () => nodeServiceStatus());
+
+ async function nodeServiceStatus() {
if (process.platform === 'win32') {
const svc = await winServiceTaskStatus();
if (svc.installed) {
@@ -1133,9 +1184,11 @@ function registerBridge() {
});
});
});
- });
+ }
- ipcMain.handle('node:service-stop', async () => {
+ ipcMain.handle('node:service-stop', () => nodeServiceStop());
+
+ async function nodeServiceStop() {
if (process.platform === 'win32') {
const svc = await winServiceTaskStatus();
if (svc.installed) await winServiceTaskEnd();
@@ -1154,9 +1207,11 @@ function registerBridge() {
});
});
return { stopped: true };
- });
+ }
- ipcMain.handle('node:service-restart', async () => {
+ ipcMain.handle('node:service-restart', () => nodeServiceRestart());
+
+ async function nodeServiceRestart() {
if (process.platform === 'win32') {
const svc = await winServiceTaskStatus();
if (svc.installed) await winServiceTaskEnd();
@@ -1181,7 +1236,7 @@ function registerBridge() {
});
});
return { restarted: true };
- });
+ }
// Install / remove the Windows Startup-folder launcher, and query it.
ipcMain.handle('node:autostart', async (_e, action) => {
diff --git a/packages/meshbay-client/src/tray-icon.png b/packages/meshbay-client/src/tray-icon.png
index 394604d..98fd63b 100644
--- a/packages/meshbay-client/src/tray-icon.png
+++ b/packages/meshbay-client/src/tray-icon.png
Binary files differ
diff --git a/packages/meshbay-client/src/tray-icon@2x.png b/packages/meshbay-client/src/tray-icon@2x.png
index 3e533fb..9cf613d 100644
--- a/packages/meshbay-client/src/tray-icon@2x.png
+++ b/packages/meshbay-client/src/tray-icon@2x.png
Binary files differ