mirror of
https://github.com/zoriya/ags.git
synced 2026-06-09 04:46:08 +00:00
feature: add subprocess util
this would be the equivalent of deflisten in eww
This commit is contained in:
+40
-88
@@ -1,7 +1,6 @@
|
|||||||
import GLib from 'gi://GLib';
|
import GLib from 'gi://GLib';
|
||||||
import Gio from 'gi://Gio';
|
|
||||||
import Service from './service.js';
|
import Service from './service.js';
|
||||||
import { error, execAsync, warning } from '../utils.js';
|
import { error, execAsync, subprocess } from '../utils.js';
|
||||||
|
|
||||||
const HIS = GLib.getenv('HYPRLAND_INSTANCE_SIGNATURE');
|
const HIS = GLib.getenv('HYPRLAND_INSTANCE_SIGNATURE');
|
||||||
|
|
||||||
@@ -44,13 +43,6 @@ type Active = {
|
|||||||
workspace: ActiveWorkspace
|
workspace: ActiveWorkspace
|
||||||
}
|
}
|
||||||
|
|
||||||
type HyprlandState = {
|
|
||||||
active: Active
|
|
||||||
monitors: Map<string, Monitor>
|
|
||||||
workspaces: Map<number, Workspace>
|
|
||||||
clients: Map<string, Client>
|
|
||||||
}
|
|
||||||
|
|
||||||
class HyprlandService extends Service {
|
class HyprlandService extends Service {
|
||||||
static {
|
static {
|
||||||
Service.register(this, {
|
Service.register(this, {
|
||||||
@@ -59,55 +51,59 @@ class HyprlandService extends Service {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_state!: HyprlandState;
|
_active: Active;
|
||||||
|
_monitors: Map<string, Monitor>;
|
||||||
|
_workspaces: Map<number, Workspace>;
|
||||||
|
_clients: Map<string, Client>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (!HIS)
|
if (!HIS)
|
||||||
error('Hyprland is not running');
|
error('Hyprland is not running');
|
||||||
|
|
||||||
super();
|
super();
|
||||||
this._state = {
|
this._active = {
|
||||||
active: {
|
client: {
|
||||||
client: {
|
address: '',
|
||||||
address: '',
|
title: '',
|
||||||
title: '',
|
class: '',
|
||||||
class: '',
|
},
|
||||||
},
|
monitor: '',
|
||||||
monitor: '',
|
workspace: {
|
||||||
workspace: {
|
id: 0,
|
||||||
id: 0,
|
name: '',
|
||||||
name: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
monitors: new Map(),
|
|
||||||
workspaces: new Map(),
|
|
||||||
clients: new Map(),
|
|
||||||
};
|
};
|
||||||
|
this._monitors = new Map();
|
||||||
|
this._workspaces = new Map();
|
||||||
|
this._clients = new Map();
|
||||||
this._sync();
|
this._sync();
|
||||||
this._startSocat();
|
|
||||||
|
const socat = `socat -U - UNIX-CONNECT:/tmp/hypr/${HIS}/.socket2.sock`;
|
||||||
|
subprocess(['bash', '-c', socat], line => {
|
||||||
|
this._onEvent(line);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async _sync() {
|
async _sync() {
|
||||||
try {
|
try {
|
||||||
const monitors = await execAsync('hyprctl -j monitors');
|
const monitors = await execAsync('hyprctl -j monitors');
|
||||||
this._state.monitors = new Map();
|
this._monitors = new Map();
|
||||||
(JSON.parse(monitors as string) as Monitor[]).forEach(monitor => {
|
(JSON.parse(monitors as string) as Monitor[]).forEach(monitor => {
|
||||||
this._state.monitors.set(monitor.name, monitor);
|
this._monitors.set(monitor.name, monitor);
|
||||||
if (monitor.focused) {
|
if (monitor.focused) {
|
||||||
this._state.active.monitor = monitor.name;
|
this._active.monitor = monitor.name;
|
||||||
this._state.active.workspace = monitor.activeWorkspace;
|
this._active.workspace = monitor.activeWorkspace;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const workspaces = await execAsync('hyprctl -j workspaces');
|
const workspaces = await execAsync('hyprctl -j workspaces');
|
||||||
this._state.workspaces = new Map();
|
this._workspaces = new Map();
|
||||||
(JSON.parse(workspaces as string) as Workspace[]).forEach(ws => {
|
(JSON.parse(workspaces as string) as Workspace[]).forEach(ws => {
|
||||||
this._state.workspaces.set(ws.id, ws);
|
this._workspaces.set(ws.id, ws);
|
||||||
});
|
});
|
||||||
|
|
||||||
const clients = await execAsync('hyprctl -j clients');
|
const clients = await execAsync('hyprctl -j clients');
|
||||||
this._state.clients = new Map();
|
this._clients = new Map();
|
||||||
(JSON.parse(clients as string) as Client[]).forEach(c => {
|
(JSON.parse(clients as string) as Client[]).forEach(c => {
|
||||||
const {
|
const {
|
||||||
address,
|
address,
|
||||||
@@ -119,7 +115,7 @@ class HyprlandService extends Service {
|
|||||||
floating,
|
floating,
|
||||||
} = c;
|
} = c;
|
||||||
|
|
||||||
this._state.clients.set(address.substring(2), {
|
this._clients.set(address.substring(2), {
|
||||||
address,
|
address,
|
||||||
pid,
|
pid,
|
||||||
workspace,
|
workspace,
|
||||||
@@ -145,16 +141,16 @@ class HyprlandService extends Service {
|
|||||||
|
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case 'activewindow':
|
case 'activewindow':
|
||||||
this._state.active.client.class = argv[0];
|
this._active.client.class = argv[0];
|
||||||
this._state.active.client.title = argv[1];
|
this._active.client.title = argv[1];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'activewindowv2':
|
case 'activewindowv2':
|
||||||
this._state.active.client.address = argv[0];
|
this._active.client.address = argv[0];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'closewindow':
|
case 'closewindow':
|
||||||
this._state.active.client = {
|
this._active.client = {
|
||||||
class: '',
|
class: '',
|
||||||
title: '',
|
title: '',
|
||||||
address: '',
|
address: '',
|
||||||
@@ -172,7 +168,7 @@ class HyprlandService extends Service {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'changefloating': {
|
case 'changefloating': {
|
||||||
const client = this._state.clients.get(argv[0]);
|
const client = this._clients.get(argv[0]);
|
||||||
if (client)
|
if (client)
|
||||||
client.floating = argv[1] === '1';
|
client.floating = argv[1] === '1';
|
||||||
break;
|
break;
|
||||||
@@ -184,50 +180,6 @@ class HyprlandService extends Service {
|
|||||||
|
|
||||||
this.emit('changed');
|
this.emit('changed');
|
||||||
}
|
}
|
||||||
|
|
||||||
_startSocat() {
|
|
||||||
try {
|
|
||||||
const socat = `
|
|
||||||
socat -U - UNIX-CONNECT:/tmp/hypr/${HIS}/.socket2.sock | while read lines
|
|
||||||
do
|
|
||||||
echo $lines
|
|
||||||
done`;
|
|
||||||
|
|
||||||
const proc = Gio.Subprocess.new(
|
|
||||||
['bash', '-c', socat],
|
|
||||||
Gio.SubprocessFlags.STDOUT_PIPE,
|
|
||||||
);
|
|
||||||
|
|
||||||
const pipe = proc.get_stdout_pipe();
|
|
||||||
if (!pipe) {
|
|
||||||
warning('socat error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stdout = new Gio.DataInputStream({
|
|
||||||
base_stream: pipe,
|
|
||||||
close_base_stream: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
this._readSocat(stdout);
|
|
||||||
} catch (e) {
|
|
||||||
logError(e as Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_readSocat(stdout: Gio.DataInputStream) {
|
|
||||||
stdout.read_line_async(GLib.PRIORITY_LOW, null, (stdout, res) => {
|
|
||||||
try {
|
|
||||||
const line = stdout?.read_line_finish_utf8(res)[0];
|
|
||||||
if (line) {
|
|
||||||
this._onEvent(line);
|
|
||||||
this._readSocat(stdout);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
logError(e as Error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Hyprland {
|
export default class Hyprland {
|
||||||
@@ -239,10 +191,10 @@ export default class Hyprland {
|
|||||||
return Hyprland._instance;
|
return Hyprland._instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get active() { return Hyprland.instance._state.active; }
|
static get active() { return Hyprland.instance._active; }
|
||||||
static get monitors() { return Hyprland.instance._state.monitors; }
|
static get monitors() { return Hyprland.instance._monitors; }
|
||||||
static get workspaces() { return Hyprland.instance._state.workspaces; }
|
static get workspaces() { return Hyprland.instance._workspaces; }
|
||||||
static get clients() { return Hyprland.instance._state.clients; }
|
static get clients() { return Hyprland.instance._clients; }
|
||||||
|
|
||||||
static HyprctlGet(cmd: string): unknown | object {
|
static HyprctlGet(cmd: string): unknown | object {
|
||||||
const [success, out, err] =
|
const [success, out, err] =
|
||||||
|
|||||||
+42
-4
@@ -222,11 +222,8 @@ export function isRunning(dbusName: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function execAsync(cmd: string | string[]) {
|
export function execAsync(cmd: string | string[]) {
|
||||||
if (typeof cmd === 'string')
|
|
||||||
cmd = cmd.split(' ');
|
|
||||||
|
|
||||||
const proc = Gio.Subprocess.new(
|
const proc = Gio.Subprocess.new(
|
||||||
cmd,
|
typeof cmd === 'string' ? cmd.split(' ') : cmd,
|
||||||
Gio.SubprocessFlags.STDOUT_PIPE |
|
Gio.SubprocessFlags.STDOUT_PIPE |
|
||||||
Gio.SubprocessFlags.STDERR_PIPE,
|
Gio.SubprocessFlags.STDERR_PIPE,
|
||||||
);
|
);
|
||||||
@@ -258,3 +255,44 @@ export function exec(cmd: string) {
|
|||||||
|
|
||||||
return decoder.decode(out).trim();
|
return decoder.decode(out).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function subprocess(
|
||||||
|
cmd: string | string[],
|
||||||
|
callback: (out: string) => void,
|
||||||
|
onError = logError,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const read = (stdout: Gio.DataInputStream) => {
|
||||||
|
stdout.read_line_async(GLib.PRIORITY_LOW, null, (stdout, res) => {
|
||||||
|
try {
|
||||||
|
const output = stdout?.read_line_finish_utf8(res)[0];
|
||||||
|
if (output) {
|
||||||
|
callback(output);
|
||||||
|
read(stdout);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return onError(e as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const proc = Gio.Subprocess.new(
|
||||||
|
typeof cmd === 'string' ? cmd.split(' ') : cmd,
|
||||||
|
Gio.SubprocessFlags.STDOUT_PIPE |
|
||||||
|
Gio.SubprocessFlags.STDERR_PIPE,
|
||||||
|
);
|
||||||
|
|
||||||
|
const pipe = proc.get_stdout_pipe();
|
||||||
|
if (!pipe)
|
||||||
|
return onError(new Error(`subprocess ${cmd} stdout pipe is null`));
|
||||||
|
|
||||||
|
const stdout = new Gio.DataInputStream({
|
||||||
|
base_stream: pipe,
|
||||||
|
close_base_stream: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
read(stdout);
|
||||||
|
} catch (e) {
|
||||||
|
return onError(e as Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user