Get Window Properties using X.getProperty - unable to decipher the output
Closed this issue ยท 9 comments
First of all thanks for writing such an amazing utility. I am hoping you could help me with a slight problem I am facing.
My end objective is to track the application usage i.e how much time a user spends on a particular application for eg : chrome browser, notepad ++ editor or any other application for that matter.
For this we need to detect the active window change ( essentially active process changes ). Gladly I came across the code snippet posted by you on SO ( link ) and was able to detect the active window changes.
However, we need to extract the process ID ( PID ) from the information we have in hand. I tried using X.getProperty
method as mentioned by you in the post and outputs an array of length 4. How can i retrieve process id from this output. There isn't much documentation in regard on the github page or elsewhere.
Here the code I am using :
var x11 = require('x11');
x11.createClient(function(err, display) {
var X = display.client;
var win = display.screen[0].root;
X.ChangeWindowAttributes(win, { eventMask: x11.eventMask.PropertyChange });
X.on('event', function(ev) {
if(ev.name == 'PropertyNotify') {
X.GetAtomName(ev.atom, function(err, name) {
if (name == '_NET_ACTIVE_WINDOW') {
console.log('Active window changed',X,window,ev.atom);
X.GetProperty(0,win,ev.atom,X.atoms.WINDOW,0,4, function(err, prop) {
if (!err) {
console.log(prop.data);
// outputs : [130, 0, 128, 4]
// what's this information in this array ?
// Can we use this array somehow to get the process id of the active window?
}
});
}
});
}
}); // ending on event listener
});
I'll be much grateful if you could provide any help in this regard. Thanks in advance. :)
pid should be stored in _NET_WM_PID
property - see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm140200472565744
also have a look at https://github.com/santigimeno/node-ewmh/blob/10d9e4cfebec8230c0a150a3b84a5e5f620d011c/lib/ewmh.js#L71 ( it's a setter, but format is similar )
and to answer your question - "outputs an array of length 4" - these are 4 bytes of CARDINAL/32
type ( unsigned 32 bit int ). In node you can do something like Buffer([1, 2, 3, 4]).readUInt32LE(0)
. There is also browser-y way: new Float32Array((new Uint8Array([i1,i2,i3,i4])).buffer)[0];
- see
http://www.html5rocks.com/en/tutorials/webgl/typed_arrays/
and http://stackoverflow.com/questions/26152024/pack-4-8-bit-unsigned-integer-to-a-32-bit-float
This may also help you to get the _NET_WM_PID
property: https://github.com/santigimeno/node-x11-prop. The example is for WM_CLASS
but you get the idea.
yes, even better
I think https://github.com/santigimeno/node-x11-prop/blob/master/examples/get_set_prop.js#L19
replaced with get_property(X, wid, '_NET_WM_PID', 'CARDINAL, function(err, data) { //...
should work
Thanks a ton for your suggestion. I tried the suggestions mentioned above except ewmh ( extended window manager hints ), I am sorry but I am still not getting the PID.
Here's what i tried so far:
1.
Code:
var X = display.client;
var win = display.screen[0].root;
var wid = X.AllocID();
X.ChangeWindowAttributes(win, { eventMask: x11.eventMask.PropertyChange });
X.on('event', function(ev) {
if(ev.name == 'PropertyNotify') {
X.GetAtomName(ev.atom, function(err, name) {
if (name == '_NET_ACTIVE_WINDOW') {
get_property(X, wid, '_NET_WM_PID', 'CARDINAL', function(err, data) {
console.log('===> ',data);
});
}
});
}
}); // ending on event listener
Output:
2.
In the above example I thought wid shouldn't be X.AllocID();
but should be ev.wid i.e wid which we get from the event obj. So, i tried this:
Code :
X.on('event', function(ev) {
if(ev.name == 'PropertyNotify') {
X.GetAtomName(ev.atom, function(err, name) {
if (name == '_NET_ACTIVE_WINDOW') {
get_property(X, ev.wid, '_NET_WM_PID', 'CARDINAL', function(err, data) {
console.log('Inside get_property function, Data captured is: ',data);
});
}
});
}
}); // ending on event listener
Output :
3.
So, when the second method didn't I explored a little more I found out that get_property
internally uses X.GetProperty
. From the source of X.GetProperty here https://github.com/sidorares/node-x11/blob/master/autogen/proto/xproto.xml#L2083, i tried to understand what argument this function accepts. So, from there i came to know the X.GetProperty actually accepts type atom and not the property name to which atom corresponds. So, then i tried this:
Code:
X.on('event', function(ev) {
if(ev.name == 'PropertyNotify') {
X.GetAtomName(ev.atom, function(err, name) {
if (name == '_NET_ACTIVE_WINDOW') {
X.InternAtom(false,'_NET_WM_PID',function(err,atom){
get_property(X,ev.wid,atom , 'CARDINAL', function(err, data) {
console.log('Inside get_property function, Data captured is: ',data);
});
});
}
});
}
}); // ending on event listener
Output :
I will keep exploring more stuff as i really need to get this working but, it will be much easier for me if you guys help me out a little bit more on this one. Can you please tell me where I am going wrong or can you please try and confirm the suggestions you gave me.
Environment I am working on:
OS : Ubuntu 14.04 LTS
Platform : Node-webkit ( 14.3 )
In case this is of any help.
Thanks Again.
This works for me:
x11.createClient(function(err, display) {
var X = display.client;
X.InternAtom(false, '_NET_WM_PID', function(err, pidAtom ) {
X.ChangeWindowAttributes(display.screen[0].root, { eventMask: x11.eventMask.PropertyChange });
X.on('event', function(ev) {
if(ev.name == 'PropertyNotify') {
X.GetAtomName(ev.atom, function(err, name) {
if (name == '_NET_ACTIVE_WINDOW') {
X.GetProperty(0, display.screen[0].root, ev.atom, X.atoms.WINDOW, 0, 4, function(err, prop) {
var active = prop.data.readUInt32LE(0);
X.GetProperty(0, active, pidAtom, X.atoms.CARDINAL, 0, 4, function(err, prop) {
console.log('PID:', prop.data.readUInt32LE(0));
});
});
}
});
}
});
});
});
This works perfectly.
Can't thank you enough. Much Appreciated.
Just for completion. The same code using x11-prop
:
var x11 = require('x11');
var x11prop = require('x11-prop');
var get_property = x11prop.get_property;
x11.createClient(function(err, display) {
if (err) {
throw err;
}
var X = display.client;
var root = display.screen[0].root;
X.ChangeWindowAttributes(root, { eventMask: x11.eventMask.PropertyChange });
X.on('event', function(ev) {
if(ev.name === 'PropertyNotify') {
X.GetAtomName(ev.atom, function(err, name) {
if (name === '_NET_ACTIVE_WINDOW') {
get_property(X, ev.wid, ev.atom, function(err, data) {
console.log('_NET_ACTIVE_WINDOW: ' + data);
get_property(X, data[0], '_NET_WM_PID', function(err, data) {
console.log('_NET_WM_PID: ' + data);
});
});
}
});
}
});
});
Notice you don't need to pass the atom with the type of the property CARDINAL
or whatever. The module just calculates it for you.
For anyone coming across this in 2021, the following worked for me:
var x11 = require('x11');
x11.createClient(function(err, display) {
var X = display.client;
X.ChangeWindowAttributes(display.screen[0].root, { eventMask: x11.eventMask.PropertyChange });
X.on('event', function(ev) {
console.log(ev)
if(ev.name == 'PropertyNotify') {
X.GetAtomName(ev.atom, function(err, name) {
if (name == '_NET_ACTIVE_WINDOW') {
X.GetProperty(0, ev.wid, ev.atom, X.atoms.WINDOW, 0, 4, function(err, prop) {
console.log('New active window:' + prop.data.readUInt32LE(0));
});
}
});
}
});
});
The code using get_property
threw errors sending me towards this rabbit hole, but the X.GetProperty
was throwing Bad Window
error.
Changing ev.window
to ev.wid
seems to work because there is actually a ev.wid
value in the returned data.