@@ -1,7 +1,55 @@
|
||||
export class ShellProvider {
|
||||
constructor({ listWindows, focusedWindow, focusWindow, proxy } = {}) { this.listWindowsImpl = listWindows; this.focusedWindowImpl = focusedWindow; this.focusWindowImpl = focusWindow; this.proxy = proxy; }
|
||||
async connect() { if (this.proxy) return this; const dbus = await import('dbus-next'); const bus = dbus.sessionBus(); const object = await bus.getProxyObject('io.qvac.Jarvis.Shell', '/io/qvac/Jarvis/Shell'); this.proxy = object.getInterface('io.qvac.Jarvis.Shell'); return this; }
|
||||
async windows() { if (this.proxy) return { available: true, windows: JSON.parse(await this.proxy.ListWindows()) }; if (!this.listWindowsImpl) return { available: false, reason: 'GNOME Shell helper is not connected', windows: [] }; return { available: true, windows: await this.listWindowsImpl() }; }
|
||||
async focused() { if (this.proxy) return JSON.parse(await this.proxy.FocusedWindow()); if (!this.focusedWindowImpl) return null; return this.focusedWindowImpl(); }
|
||||
async focus(id) { if (this.proxy) return this.proxy.FocusWindow(BigInt(id)); if (!this.focusWindowImpl) throw new Error('GNOME Shell focus helper is unavailable'); return this.focusWindowImpl(id); }
|
||||
import { spawn } from 'node:child_process';
|
||||
|
||||
const DEST = 'io.qvac.Jarvis.Shell';
|
||||
const PATH = '/io/qvac/Jarvis/Shell';
|
||||
const IFACE = 'io.qvac.Jarvis.Shell';
|
||||
|
||||
function parseGdbusString(out) {
|
||||
const match = String(out).match(/'((?:\\.|[^'\\])*)'/);
|
||||
if (!match) throw new Error('GNOME Shell helper returned no string');
|
||||
return match[1].replace(/\\(.)/g, '$1');
|
||||
}
|
||||
|
||||
export class ShellProvider {
|
||||
constructor({ listWindows, focusedWindow, focusWindow, proxy, spawnImpl = spawn, timeoutMs = 2000 } = {}) {
|
||||
this.listWindowsImpl = listWindows; this.focusedWindowImpl = focusedWindow; this.focusWindowImpl = focusWindow; this.proxy = proxy;
|
||||
this.spawnImpl = spawnImpl; this.timeoutMs = timeoutMs;
|
||||
}
|
||||
|
||||
_call(method, args = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = this.spawnImpl('gdbus', ['call', '--session', '--dest', DEST, '--object-path', PATH, '--method', `${IFACE}.${method}`, ...args], { stdio: ['ignore', 'pipe', 'pipe'] });
|
||||
let out = ''; let err = ''; let settled = false;
|
||||
const timer = setTimeout(() => { if (settled) return; settled = true; child.kill('SIGTERM'); reject(new Error('GNOME Shell helper timed out')); }, this.timeoutMs);
|
||||
const done = (fn) => (value) => { if (settled) return; settled = true; clearTimeout(timer); fn(value); };
|
||||
child.stdout.on('data', (d) => { out += d; });
|
||||
child.stderr.on('data', (d) => { err += d; });
|
||||
child.on('error', done(reject));
|
||||
child.on('close', (code) => done(code === 0 ? resolve : reject)(code === 0 ? parseGdbusString(out) : new Error(err.trim() || `GNOME Shell helper exited ${code}`)));
|
||||
});
|
||||
}
|
||||
|
||||
async connect() {
|
||||
if (this.proxy || this.listWindowsImpl) return this;
|
||||
await this._call('ListWindows');
|
||||
return this;
|
||||
}
|
||||
|
||||
async windows() {
|
||||
if (this.proxy) return { available: true, windows: JSON.parse(await this.proxy.ListWindows()) };
|
||||
if (this.listWindowsImpl) return { available: true, windows: await this.listWindowsImpl() };
|
||||
try { return { available: true, windows: JSON.parse(await this._call('ListWindows')) }; } catch (error) { return { available: false, reason: error.message, windows: [] }; }
|
||||
}
|
||||
|
||||
async focused() {
|
||||
if (this.proxy) return JSON.parse(await this.proxy.FocusedWindow());
|
||||
if (this.focusedWindowImpl) return this.focusedWindowImpl();
|
||||
try { return JSON.parse(await this._call('FocusedWindow')); } catch { return null; }
|
||||
}
|
||||
|
||||
async focus(id) {
|
||||
if (this.proxy) return this.proxy.FocusWindow(BigInt(id));
|
||||
if (this.focusWindowImpl) return this.focusWindowImpl(id);
|
||||
await this._call('FocusWindow', [String(id)]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user