I found two ways of solving this problem.
- Use the
xprop -spy -root _NET_ACTIVE_WINDOW
command in combination with grep
in a bash script.
- Create a C++ (could have been C or python as well my project was in C++ to begin with) application using the Xlib library to listen for events from the X-server.
I ended up using alternative 1 but I'll provide some info on both below.
Using xprop:
The application which creates the sought window always puts the new window on top and in focus. The xprop -spy <window-id>
command allows one to listen to changes in the properties of <window-id>
and -root
is the id of the "root window" (R in the tree in the question above). To listen for changes of specific properties we can provide the property's name in this case _NET_ACTIVE_WINDOW
which holds the id of the window currently in focus, see spec. We then get a stream of output like this:
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x3c00010
and can use grep
to extract the ID. To check if the active window is the sought window we need to know what makes it unique, this might be different for everyone but most likely the first filter would be the WM_CLASS
property, see description. Here is a small example of this:
#!/bin/bash
class_name=$1
# regex for extracting hex id's
grep_id='0[xX][a-zA-Z0-9]\{7\}'
xprop -spy -root _NET_ACTIVE_WINDOW | grep --line-buffered -o $grep_id |
while read -r id; do
class="`xprop -id $id WM_CLASS | grep $class_name`"
if [ -n "$class" ]; then
# Found a window with the correct WM_CLASS now what makes your
# window unique?
fi
done
Bash gist:
Here is a gist for the case in the question, where the tree was the identifying factor.
Limitations of xprop -spy
: this doesn't specifically listen to a window opening, rather when a window is focused. This means that if the window stays open, goes out of focus and then comes into focus again, this script will still report this event.
Xlib programming:
This is more complicated but also more powerful. Some great resources for getting started are:
For this one has to open a connection and register as a listener to the X-server:
// Open connection to X server
Display *dsp = XOpenDisplay(NIL);
assert(dsp);
// Start listening to root window
XSelectInput(dsp, DefaultRootWindow(dsp), SubstructureNotifyMask);
Depending on which events one is looking for a EventMask should be chosen.
For a continuous application (which want to handle subsequent events) one probably want to set an error handler function which should return 0 (maybe with a warning) so execution continues smoothly, like so:
XSetErrorHandler(bad_window_handler);
In a loop one can then handle events from the X-server
XEvent e;
XNextEvent(dsp, &e); // blocks until next event from X-server
To handle the event in e
we can check the type of e
e.type == CreateNotify // A window was created
e.type == ReparentNotify // A window got a new parent
e.type == MapNotify // A window was drawn
e.type == DestroyNotify // A window was destroyed
The XEvent
struct contains information in different types of struct depending on the event type.
The following libraries are needed:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
And applications should be compiled with the -lX11
flag to include the Xlib libraries.
Xlib gists + Gotchas:
I've created two gists that listens to events from X-server. Note that I was interested in the structure of a window's tree for identification. Others might have other properties to uniquely identify windows.
The first listens to the CreateNotify
event to determine if a window with the correct WM_CLASS was created, call it W. At this point the window will likely not be in the correct tree structure. For example it might be created as a child to the root rather than windows controlled by the application. We therefore listen to the ReparentNotify
event to see if W has a new parent.
Unfortunately we are not guaranteed the correct tree structure here either, as other windows might later be added to W's tree. But if W's tree structure is unique and it's shape is not a sub-tree of another window with the same class we can at least find these window's by checking ReparentNotify
(we might not even need to check the CreateNotify
as we can check WM_CLASS at any point we have a window-id).
The Second listens to the MapNotify
event and checks the structure of the window's tree. It then looks for the correct WM_CLASS in the tree. After this one could go on to determine if the structure is correct.
Again, at the MapNotify
we are not guaranteed a "finished" tree structure. However it seems that the structure generally "settles" a short time after this event. To be reasonably sure that the structure won't change I added a short pause before collecting the tree. How long this pause should be in order to not risk other changes to the tree I don't know, 500ms seemed to work well for me.
Misc:
X11 windows can be created in many different languages, so I imagine listening to them would be possible in many different languages as well.
Some tools to investigate windows with:
xprop
xwininfo
specifically with options -tree
or -children
One can also check the source code of the commands above, xprop and xwininfo, for some guidance and inspiration.
Best Answer
Run
and add
acpi=off
inGRUB_CMDLINE_LINUX_DEFAULT
, afterquiet splash
inside of the quotes.This fixed the issue in 10.10 desktop on a MSI Wind U100.