feature: add subprocess util

this would be the equivalent of deflisten in eww
This commit is contained in:
Aylur
2023-08-12 23:46:45 +02:00
parent a3f717ed50
commit 9d7be06ea8
2 changed files with 82 additions and 92 deletions
+40 -88
View File
@@ -1,7 +1,6 @@
import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
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');
@@ -44,13 +43,6 @@ type Active = {
workspace: ActiveWorkspace
}
type HyprlandState = {
active: Active
monitors: Map<string, Monitor>
workspaces: Map<number, Workspace>
clients: Map<string, Client>
}
class HyprlandService extends Service {
static {
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() {
if (!HIS)
error('Hyprland is not running');
super();
this._state = {
active: {
client: {
address: '',
title: '',
class: '',
},
monitor: '',
workspace: {
id: 0,
name: '',
},
this._active = {
client: {
address: '',
title: '',
class: '',
},
monitor: '',
workspace: {
id: 0,
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._startSocat();
const socat = `socat -U - UNIX-CONNECT:/tmp/hypr/${HIS}/.socket2.sock`;
subprocess(['bash', '-c', socat], line => {
this._onEvent(line);
});
}
async _sync() {
try {
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 => {
this._state.monitors.set(monitor.name, monitor);
this._monitors.set(monitor.name, monitor);
if (monitor.focused) {
this._state.active.monitor = monitor.name;
this._state.active.workspace = monitor.activeWorkspace;
this._active.monitor = monitor.name;
this._active.workspace = monitor.activeWorkspace;
}
});
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 => {
this._state.workspaces.set(ws.id, ws);
this._workspaces.set(ws.id, ws);
});
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 => {
const {
address,
@@ -119,7 +115,7 @@ class HyprlandService extends Service {
floating,
} = c;
this._state.clients.set(address.substring(2), {
this._clients.set(address.substring(2), {
address,
pid,
workspace,
@@ -145,16 +141,16 @@ class HyprlandService extends Service {
switch (e) {
case 'activewindow':
this._state.active.client.class = argv[0];
this._state.active.client.title = argv[1];
this._active.client.class = argv[0];
this._active.client.title = argv[1];
break;
case 'activewindowv2':
this._state.active.client.address = argv[0];
this._active.client.address = argv[0];
break;
case 'closewindow':
this._state.active.client = {
this._active.client = {
class: '',
title: '',
address: '',
@@ -172,7 +168,7 @@ class HyprlandService extends Service {
break;
}
case 'changefloating': {
const client = this._state.clients.get(argv[0]);
const client = this._clients.get(argv[0]);
if (client)
client.floating = argv[1] === '1';
break;
@@ -184,50 +180,6 @@ class HyprlandService extends Service {
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 {
@@ -239,10 +191,10 @@ export default class Hyprland {
return Hyprland._instance;
}
static get active() { return Hyprland.instance._state.active; }
static get monitors() { return Hyprland.instance._state.monitors; }
static get workspaces() { return Hyprland.instance._state.workspaces; }
static get clients() { return Hyprland.instance._state.clients; }
static get active() { return Hyprland.instance._active; }
static get monitors() { return Hyprland.instance._monitors; }
static get workspaces() { return Hyprland.instance._workspaces; }
static get clients() { return Hyprland.instance._clients; }
static HyprctlGet(cmd: string): unknown | object {
const [success, out, err] =
+42 -4
View File
@@ -222,11 +222,8 @@ export function isRunning(dbusName: string) {
}
export function execAsync(cmd: string | string[]) {
if (typeof cmd === 'string')
cmd = cmd.split(' ');
const proc = Gio.Subprocess.new(
cmd,
typeof cmd === 'string' ? cmd.split(' ') : cmd,
Gio.SubprocessFlags.STDOUT_PIPE |
Gio.SubprocessFlags.STDERR_PIPE,
);
@@ -258,3 +255,44 @@ export function exec(cmd: string) {
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);
}
}