sidorares/node-x11

Can it be used to get the current window manager's name?

NyaomiDEV opened this issue · 15 comments

As the title says, I am interested in this module since it seems to have the power to grab the current running window manager. Does anyone know how to do it?

I am planning to replace this xprop call with actual code

xprop -id (xprop -root -notype | awk '$1=="_NET_SUPPORTING_WM_CHECK:"{print $5}') -notype -f _NET_WM_NAME 8t | grep "_NET_WM_NAME = " | cut --delimiter=' ' --fields=3 | cut --delimiter='"' --fields=2

As a side note, I would need to replace those two calls too

xprop -f _KDE_NET_WM_BLUR_BEHIND_REGION 32c -set _KDE_NET_WM_BLUR_BEHIND_REGION 0 -id <windowID>

xprop -f _KDE_NET_WM_BLUR_BEHIND_REGION 32c -remove _KDE_NET_WM_BLUR_BEHIND_REGION -id <windowID>

Yes, I am trying to request the blur to KWin for an Electron application btw

yes, follow documentation here: https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html#idm44927025469168

_NET_SUPPORTING_WM_CHECK

_NET_SUPPORTING_WM_CHECK, WINDOW/32
The Window Manager MUST set this property on the root window to be the ID of a child window created by himself, to indicate that a compliant window manager is active. The child window MUST also have the _NET_SUPPORTING_WM_CHECK property set to the ID of the child window. The child window MUST also have the _NET_WM_NAME property set to the name of the Window Manager.

I see you already found it :)

GetProperty example:

X.GetProperty(0, id, p, 0, 0, 10000000, function(err, propValue) {

@sidorares I had those xprop calls here, so that part was the easy one 👌

Okay I did something but I am not there really...
My current problem is that I want to 'get rid' of the X Client so that I can work with the returned data in the global scope (and also, this test script hangs).

"use strict";
var x11 = require("x11");

function getPropertyData(id, _propertyName){
	return x11.createClient(function(err, display) {
		let X = display.client;
		if(typeof id === "undefined")
			id = display.screen[0].root;
		
		X.ListProperties(id, function(err, props) {
			props.forEach(function(prop) {
				X.GetAtomName(prop, function(err, propName) {
					if(propName === _propertyName){
						X.GetProperty(0, id, prop, 0, 0, 10000000, function(err, propValue) {
							// How do I return this value?
							return propValue.data;
						});
					}
				});
			});
		});
	});
}

var WMID = getPropertyData(undefined, "_NET_SUPPORTING_WM_CHECK");

Also, I wasn't able to figure out a way to avoid the forEach iteration (maybe there isn't one, idk)

answer to "How do I return this value?" - pass a callback and call it with results
Also no need to list all properties since you know property name. Just get atom id for '_NET_SUPPORTING_WM_CHECK' and then GetProperty for that id

function getPropertyData(id, _propertyName, callback){
	return x11.createClient(function(err, display) {
		let X = display.client;
		if(typeof id === "undefined")
			id = display.screen[0].root;

		X.InternAtom(false, _propertyName, function(err, propId) {
			X.GetProperty(0, id, propId, 0, 0, 10000000, callback)
		});
	});
}

getPropertyData(undefined, "_NET_SUPPORTING_WM_CHECK",  (err, data) => {
   console.log('WMID', data)
});

That works, but the node app won't exit after calling the callback to retrieve the data.
Also, any way to replace the other two commands? I hope I am not bothering too much

That works, but the node app won't exit

you'll need to close client tcp connection:

function getPropertyData(id, _propertyName, callback){
	return x11.createClient(function(err, display) {
		let X = display.client;
		if(typeof id === "undefined")
			id = display.screen[0].root;

		X.InternAtom(false, _propertyName, function(err, propId) {
			X.GetProperty(0, id, propId, 0, 0, 10000000, function(err, data) {
                            X.close();
                            callback(data);
                         })
		});
	});
}

Also, any way to replace the other two commands? I hope I am not bothering too much

Have a look at set_property / change_property helpers here -

https://github.com/santigimeno/node-ewmh/blob/master/lib/ewmh.js#L91
https://github.com/santigimeno/node-x11-prop/blob/master/lib/set_prop.js

I added the type name to the returned data, and I tried to wrap some stuff around but to no avail.
My current code:

"use strict";
var x11 = require("x11");

function _internal_getPropertyData(id, _propertyName, callback){
	return x11.createClient(function(err, display) {
		let X = display.client;
		if(typeof id === "undefined")
			id = display.screen[0].root;

		X.InternAtom(false, _propertyName, function(err, propId) {
			X.GetProperty(0, id, propId, 0, 0, 10000000, function(err, propData){
				X.GetAtomName(propData.type, function(err, typeName){
					propData.typeName = typeName;
					callback(propData);
					X.close();
				});
			});
		});
	});
}

function getPropertyData(id, propName){
	var __data = {};
	_internal_getPropertyData(id, propName, (data) => {
		__data = data;
		console.log('inside callback', data);
	});
	return __data;
}

console.log('outside callback', getPropertyData(undefined, "_NET_SUPPORTING_WM_CHECK"));

produces the following output

outside callback {}
inside callback {
  type: 33,
  bytesAfter: 0,
  data: <Buffer 07 00 60 03>,
  typeName: 'WINDOW'
}

it seems my function returns before the callback can put the actual value on the variable to be returned...

this is not how callback-style control works, wrapping helper function won't help. Why do you need this wrapper? Just call like this

getPropertyData(id, propName, function(err, data) {
   // code that needs data and code that continues after that goes here
})

Also if you use async/await in your main code you can wrap this callback-style api to return Promise

Please take a look at those lines, I intend to replace them without major rewrites.

Promises are good enough btw, how should I wrap this out then? Nevermind, I did it

Okay I managed to set/remove/query for the properties I needed. Thanks!! :)