feat(ags): make a service to monitor clicks instead of closer window
This commit is contained in:
parent
9b7fd772f0
commit
0733e83964
3 changed files with 138 additions and 113 deletions
|
@ -1,5 +1,7 @@
|
|||
import { App, Widget } from '../../imports.js';
|
||||
const { Window, EventBox } = Widget;
|
||||
import { App, Utils, Widget } from '../../imports.js';
|
||||
const { Window, Revealer } = Widget;
|
||||
|
||||
import Pointers from '../../services/pointers.js';
|
||||
|
||||
const ALWAYS_OPEN = [
|
||||
'closer',
|
||||
|
@ -12,7 +14,6 @@ const ALWAYS_OPEN = [
|
|||
];
|
||||
|
||||
|
||||
// TODO: close on scroll event too?
|
||||
export const closeAll = () => {
|
||||
App.windows.forEach(w => {
|
||||
if (!ALWAYS_OPEN.some(window => window === w.name))
|
||||
|
@ -21,19 +22,61 @@ export const closeAll = () => {
|
|||
App.closeWindow('closer');
|
||||
};
|
||||
|
||||
Pointers.connect('new-line', (_, out) => {
|
||||
if (out) {
|
||||
Utils.execAsync('hyprctl layers -j').then(layers => {
|
||||
layers = JSON.parse(layers);
|
||||
|
||||
Utils.execAsync('hyprctl cursorpos -j').then(pos => {
|
||||
pos = JSON.parse(pos);
|
||||
|
||||
Object.values(layers).forEach(key => {
|
||||
let bar = key['levels']['3']
|
||||
.find(n => n.namespace === "bar");
|
||||
|
||||
let widgets = key['levels']['3']
|
||||
.filter(n => !ALWAYS_OPEN.includes(n.namespace));
|
||||
|
||||
if (pos.x > bar.x && pos.x < bar.x + bar.w &&
|
||||
pos.y > bar.y && pos.y < bar.y + bar.h) {
|
||||
|
||||
// don't handle clicks when on bar
|
||||
}
|
||||
else {
|
||||
widgets.forEach(l => {
|
||||
if (!(pos.x > l.x && pos.x < l.x + l.w &&
|
||||
pos.y > l.y && pos.y < l.y + l.h)) {
|
||||
closeAll();
|
||||
return
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}).catch(print);
|
||||
}).catch(print);
|
||||
}
|
||||
})
|
||||
|
||||
export const Closer = Window({
|
||||
name: 'closer',
|
||||
popup: true,
|
||||
layer: 'top',
|
||||
anchor: [ 'top', 'bottom', 'left', 'right' ],
|
||||
|
||||
child: EventBox({
|
||||
onPrimaryClickRelease: () => closeAll(),
|
||||
connections: [[App, (_b, _w, _v) => {
|
||||
child: Revealer({
|
||||
connections: [[App, (_, windowName, visible) => {
|
||||
if (!Array.from(App.windows).some(w => w[1].visible &&
|
||||
!ALWAYS_OPEN.some(window => window === w[0]))) {
|
||||
App.closeWindow('closer');
|
||||
}
|
||||
|
||||
if (windowName === 'closer') {
|
||||
if (visible)
|
||||
Pointers.startProc();
|
||||
else
|
||||
Pointers.killProc();
|
||||
}
|
||||
}]],
|
||||
}),
|
||||
});
|
||||
|
|
88
hosts/wim/config/ags/services/pointers.js
Normal file
88
hosts/wim/config/ags/services/pointers.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
// TODO: read /dev to recalculate devices and remake subprocess
|
||||
|
||||
import { Service, Utils } from '../imports.js';
|
||||
|
||||
|
||||
class Pointers extends Service {
|
||||
static {
|
||||
Service.register(this, {
|
||||
'proc-started': ['boolean'],
|
||||
'proc-destroyed': ['boolean'],
|
||||
'device-fetched': ['boolean'],
|
||||
'new-line': ['string'],
|
||||
});
|
||||
}
|
||||
|
||||
proc;
|
||||
output = "";
|
||||
devices = new Map();
|
||||
|
||||
get proc() { return this.proc; }
|
||||
get output() { return this.output; }
|
||||
get devices() { return this.devices; }
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.parseDevices();
|
||||
}
|
||||
|
||||
parseDevices() {
|
||||
Utils.execAsync(['libinput', 'list-devices']).then(out => {
|
||||
let lines = out.split('\n');
|
||||
let device = null;
|
||||
let devices = new Map();
|
||||
|
||||
lines.forEach(line => {
|
||||
let parts = line.split(':');
|
||||
|
||||
if (parts[0] === 'Device') {
|
||||
device = {};
|
||||
devices.set(parts[1].trim(), device);
|
||||
}
|
||||
else if (device && parts[1]) {
|
||||
let key = parts[0].trim();
|
||||
let value = parts[1].trim();
|
||||
device[key] = value;
|
||||
}
|
||||
});
|
||||
this.devices = Array.from(devices).filter(dev => dev.Capabilities &&
|
||||
dev.Capabilities.includes('pointer'));
|
||||
this.emit('device-fetched', true);
|
||||
}).catch(print);
|
||||
}
|
||||
|
||||
startProc() {
|
||||
let args = [];
|
||||
this.devices.forEach(dev => {
|
||||
if (dev.Kernel) {
|
||||
args.push('--device');
|
||||
args.push(dev.Kernel);
|
||||
}
|
||||
});
|
||||
|
||||
this.proc = Utils.subprocess(
|
||||
['libinput', 'debug-events', ...args],
|
||||
(output) => {
|
||||
if (output.includes('BTN') && output.includes('released') ||
|
||||
output.includes('TOUCH_UP') ||
|
||||
output.includes('HOLD_END') && !output.includes('cancelled')) {
|
||||
|
||||
this.output = output;
|
||||
this.emit('new-line', output);
|
||||
}
|
||||
},
|
||||
(err) => logError(err)
|
||||
);
|
||||
this.emit('proc-started', true);
|
||||
}
|
||||
|
||||
killProc() {
|
||||
if (this.proc) {
|
||||
this.proc.force_exit();
|
||||
this.emit('proc-destroyed', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const pointersService = new Pointers();
|
||||
export default pointersService;
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
import Libinput from './libinput.js';
|
||||
Libinput.instance.connect('device-init', () => {
|
||||
let pointers = [];
|
||||
Libinput.devices.forEach(dev => {
|
||||
if (dev.Capabilities.includes('pointer')) {
|
||||
pointers.push(dev);
|
||||
}
|
||||
})
|
||||
Libinput.addDebugInstance('pointers', pointers)
|
||||
.connect('new-line', e => print(e.lastLine))
|
||||
});
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
// WIP
|
||||
Utils.execAsync('hyprctl layers -j').then(layers => {
|
||||
layers = JSON.parse(layers);
|
||||
Utils.execAsync('hyprctl cursorpos -j').then(pos => {
|
||||
pos = JSON.parse(pos);
|
||||
|
||||
Object.values(layers).forEach(key => {
|
||||
key['levels']['3'].forEach(l => {
|
||||
print(l.namespace);
|
||||
if (pos.x > l.x && pos.x < l.x + l.w &&
|
||||
pos.y > l.y && pos.y < l.y + l.h)
|
||||
{
|
||||
print('inside window');
|
||||
}
|
||||
else {
|
||||
print('outside window');
|
||||
}
|
||||
});
|
||||
});
|
||||
}).catch(print);
|
||||
}).catch(print);
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// TODO: use hyprctl layers to determine if clicks were on a widget
|
||||
// read /dev to recalculate devices and remake subprocess
|
||||
|
||||
const { Service, Utils } = '../imports.js';
|
||||
|
||||
|
||||
class PointersService extends Service {
|
||||
static {
|
||||
Service.register(this, {
|
||||
'log-started': ['boolean'],
|
||||
'device-fetched': ['boolean'],
|
||||
});
|
||||
}
|
||||
|
||||
log;
|
||||
output = "";
|
||||
devices = new Map();
|
||||
|
||||
get log() {return this.log;}
|
||||
get output() {return this.output;}
|
||||
get devices() {return this.devices;}
|
||||
|
||||
parseDevices() {
|
||||
Utils.execAsync(['libinput', 'list-devices']).then(out => {
|
||||
let lines = out.split('\n');
|
||||
let device = null;
|
||||
let devices = new Map();
|
||||
|
||||
lines.forEach(line => {
|
||||
let parts = line.split(':');
|
||||
|
||||
if (parts[0] === 'Device') {
|
||||
device = {};
|
||||
devices.set(parts[1].trim(), device);
|
||||
}
|
||||
else if (device && parts[1]) {
|
||||
let key = parts[0].trim();
|
||||
let value = parts[1].trim();
|
||||
device[key] = value;
|
||||
}
|
||||
});
|
||||
this.devices = devices.filter(dev => dev.Capabilities && dev.Capabilities.includes('pointer'));
|
||||
this.emit('device-fetched', true);
|
||||
});
|
||||
}
|
||||
|
||||
startLog() {
|
||||
let args = [];
|
||||
this.devices.forEach(dev => {
|
||||
if (dev.Kernel) {
|
||||
args.push('--device');
|
||||
args.push(dev.Kernel);
|
||||
}
|
||||
});
|
||||
|
||||
this.log = Utils.subprocess(
|
||||
['libinput', 'debug-events', ...args],
|
||||
(output) => {
|
||||
this.output = output;
|
||||
},
|
||||
(err) => logError(err)
|
||||
);
|
||||
this.emit('log-started', true);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue