P6
This commit is contained in:
@@ -8,6 +8,7 @@ import Gio from 'gi://Gio';
|
||||
import GLib from 'gi://GLib';
|
||||
import St from 'gi://St';
|
||||
import Clutter from 'gi://Clutter';
|
||||
import { installShellService } from './shell-dbus.js';
|
||||
|
||||
const BUS = 'io.qvac.Jarvis';
|
||||
const PATH = '/io/qvac/Jarvis';
|
||||
@@ -76,6 +77,7 @@ export default class JarvisExtension extends Extension {
|
||||
enable() {
|
||||
this._theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); this._stylesheet = Gio.File.new_for_path(`${this.path}/stylesheet.css`); try { this._theme.load_stylesheet(this._stylesheet); } catch (error) { log(`Jarvis stylesheet unavailable: ${error.message}`); }
|
||||
this.settings = this.getSettings(); this.proxy = new JarvisProxy(); this.overlay = new ArcOverlay(); this.overlay.attach(); this._applyAccessibility();
|
||||
this._removeShellService = installShellService();
|
||||
this._indicator = new PanelMenu.Button(0.0, 'Jarvis QVAC', true); this._indicator.accessible_name = 'Jarvis voice assistant';
|
||||
this._glyph = new St.Label({ text: '◯', style_class: 'jarvis-panel-glyph', y_align: Clutter.ActorAlign.CENTER }); this._glyph.accessible_name = 'Jarvis idle'; this._indicator.add_child(this._glyph);
|
||||
Main.panel.addToStatusArea('jarvis-qvac', this._indicator, 0, 'right');
|
||||
@@ -94,5 +96,5 @@ export default class JarvisExtension extends Extension {
|
||||
_applyAccent() { this.overlay.root.set_style(`--jarvis-accent: ${this.settings.get_string('accent-color')};`); }
|
||||
_applyAccessibility() { try { const desktop = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' }); this.overlay.reducedMotion = desktop.list_keys().includes('enable-animations') && !desktop.get_boolean('enable-animations'); const theme = desktop.list_keys().includes('gtk-theme') ? desktop.get_string('gtk-theme') : ''; if (/high.?contrast/i.test(theme)) this.overlay.root.add_style_class_name('jarvis-high-contrast'); } catch {} this.overlay.root.connect('key-press-event', (_actor, event) => { if (event.get_key_symbol() === Clutter.KEY_Escape) { this._call('Cancel'); this.overlay.hide(); return Clutter.EVENT_STOP; } return Clutter.EVENT_PROPAGATE; }); }
|
||||
_buildMenu() { const menu = this._indicator.menu; menu.removeAll(); for (const [label, action] of [['Open ARC', () => this.overlay.show()], ['Stop', () => this._call('Cancel')], ['Privacy mode', () => this._call('Sleep')], ['Settings', () => this.openPreferences()]]) { const item = new PopupMenu.PopupMenuItem(label); item.connect('activate', action); menu.addMenuItem(item); } menu.open(); }
|
||||
disable() { try { Main.wm.removeKeybinding(this._keyName); } catch {} if (this._settingsChanged) this.settings.disconnect(this._settingsChanged); this._signals?.forEach((id) => this.proxy?.proxy?.disconnect(id)); this.proxy?.close(); this.overlay?.destroy(); this._indicator?.destroy(); if (this._theme && this._stylesheet) { try { this._theme.unload_stylesheet(this._stylesheet); } catch {} } this.overlay = this._indicator = this._glyph = this.proxy = null; }
|
||||
disable() { this._removeShellService?.(); try { Main.wm.removeKeybinding(this._keyName); } catch {} if (this._settingsChanged) this.settings.disconnect(this._settingsChanged); this._signals?.forEach((id) => this.proxy?.proxy?.disconnect(id)); this.proxy?.close(); this.overlay?.destroy(); this._indicator?.destroy(); if (this._theme && this._stylesheet) { try { this._theme.unload_stylesheet(this._stylesheet); } catch {} } this.overlay = this._indicator = this._glyph = this.proxy = null; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import Gio from 'gi://Gio';
|
||||
import Meta from 'gi://Meta';
|
||||
|
||||
const BUS = 'io.qvac.Jarvis.Shell';
|
||||
const PATH = '/io/qvac/Jarvis/Shell';
|
||||
const XML = `<node><interface name="io.qvac.Jarvis.Shell"><method name="ListWindows"><arg type="s" direction="out"/></method><method name="FocusedWindow"><arg type="s" direction="out"/></method><method name="FocusWindow"><arg type="t" direction="in"/></method></interface></node>`;
|
||||
const describe = (window) => ({ id: Number(window.get_id?.() || 0), title: window.get_title?.() || '', wm_class: window.get_wm_class?.() || '', pid: Number(window.get_pid?.() || 0), rect: (() => { const r = window.get_frame_rect?.(); return r ? [r.x, r.y, r.width, r.height] : null; })(), focused: window === global.display.get_focus_window?.() });
|
||||
|
||||
export function installShellService() {
|
||||
const implementation = {
|
||||
ListWindows() { const windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).map(describe); return JSON.stringify(windows); },
|
||||
FocusedWindow() { const window = global.display.get_focus_window?.(); return JSON.stringify(window ? describe(window) : null); },
|
||||
FocusWindow(id) { const window = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).find((candidate) => Number(candidate.get_id?.()) === Number(id)); if (!window) throw new Error('window not found'); window.activate(global.get_current_time()); },
|
||||
};
|
||||
const ownerId = Gio.bus_own_name(Gio.BusType.SESSION, BUS, Gio.BusNameOwnerFlags.NONE, (connection) => { const exported = Gio.DBusExportedObject.wrapJSObject(XML, implementation); exported.export(connection, PATH); implementation._exported = exported; }, null, () => {});
|
||||
return () => { implementation._exported?.unexport(); Gio.bus_unown_name(ownerId); };
|
||||
}
|
||||
Reference in New Issue
Block a user