On linux, is it possible to receive notifications when a GUI application is currently changing? I am writing an application that tracks how long a user stays in each graphical application (per process, and not as part of a single process), and he needs some way to access this information. I am doing this in C ++.
Here is what I have found so far:
xprop -id $(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW\)/{print $NF}') | awk '/_NET_WM_PID\(CARDINAL\)/{print $NF}'
This displays the pid of the current application, but requires me to do so often. I would not pull, but I will, if necessary. He also assumes that all graphical interfaces go through x11, which cannot be an unreasonable assumption, but is not fully portable.
Another approach would be to write a shared object that intercepts various gui functions and then modifies the host system's ld.so.preload file to load this shared object with each process. This assumes that all gui applications use dynamically linked graphics libraries. I would also have to write hooks for each graphics library to provide overall coverage. And when researching GTK (I do my testing on a system that works with Gnome), I did not find the functions that are called when switching to windows. However, I did not look very hard.
Is there a way to get notifications via x11 for this kind of thing? Or other graphics libraries for that matter?
Edit:
Ok, this is what I still based on @Andrey code:
#include <X11/Xlib.h> #include <cstring> #include <iostream> using namespace std; pid_t get_window_pid( Display * d, Window& w ); int main() { Display * d; Window w; XEvent e; d = XOpenDisplay( 0 ); if ( !d ) { cerr << "Could not open display" << endl; return 1; } w = DefaultRootWindow( d ); XSelectInput( d, w, PropertyChangeMask ); pid_t window_pid; for ( ;; ) { XNextEvent( d, &e ); if ( e.type == PropertyNotify ) { if ( !strcmp( XGetAtomName( d, e.xproperty.atom ), "_NET_ACTIVE_WINDOW" ) ) { window_pid = get_window_pid( d, w ); cout << window_pid << endl; } } } return 0; } pid_t get_window_pid( Display * d, Window& w ) { Atom atom = XInternAtom( d, "_NET_WM_PID", true ); Atom actual_type; int actual_format; unsigned long nitems; unsigned long bytes_after; unsigned char *prop; int status; status = XGetWindowProperty( d, w, atom, 0, 1024, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop ); if ( status || !prop ) return -1; return prop[1] * 256 + prop[0]; }
But get_window_pid always returns -1, although using xprop -id $(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW\)/{print $NF}') | awk '/_NET_WM_PID\(CARDINAL\)/{print $NF}' xprop -id $(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW\)/{print $NF}') | awk '/_NET_WM_PID\(CARDINAL\)/{print $NF}' correctly returns the pid of the active window. What am I doing wrong?