diff --git a/hosts/wim/config/ags/js/misc/closer.js b/hosts/wim/config/ags/js/misc/closer.js index 64938df0..7b1676bc 100644 --- a/hosts/wim/config/ags/js/misc/closer.js +++ b/hosts/wim/config/ags/js/misc/closer.js @@ -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(); + } }]], }), }); diff --git a/hosts/wim/config/ags/services/pointers.js b/hosts/wim/config/ags/services/pointers.js new file mode 100644 index 00000000..7aed4d61 --- /dev/null +++ b/hosts/wim/config/ags/services/pointers.js @@ -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; diff --git a/hosts/wim/config/ags/services_wip/pointers.js b/hosts/wim/config/ags/services_wip/pointers.js deleted file mode 100644 index e0804582..00000000 --- a/hosts/wim/config/ags/services_wip/pointers.js +++ /dev/null @@ -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); - } -}