Can I act on the event that a window opens without polling?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP








up vote
4
down vote

favorite
1












I am trying to find a way to detect the event of a window (any window) being opened in Ubuntu 16.04



I would like to be able to detect the "window open" event and check if the opened window was my sought window and thereafter run a bash script or a C/C++ function.



So far I've found that I can use wmctrl -l to find which windows are already opened. I could use this command and perhaps grep to find if my sought window is opened and then act on this information.



I'd prefer not to poll, as I'd not want the application to stand idle when the window opens. The action should be as "instantaneous" as possible.



Is there an event or signal I could listen for to achieve this? From the kernel, window manager (Compiz) or maybe some log file that changes?



EDIT:
To clarify, I have an application (not under my control) which might show a window at any time, this window does not have a title but it does have the WM_CLASS set (the WM_CLASS is the same for all windows of the application). I want to act upon the event that this window is shown (or created, whichever is best/easier).



It doesn't seem like the window is opened "within" the main applications window. Using xwininfo -children -id <window-id> shows that the main application and the sought window are on different branches, connected to "the root window".



The branches looks like this, where R is "the root node"; A is a root node of the main application's branch and Y is the root of the branch with sought window W:



 R
/
A Y
/
B C X

Q W


So I'm hoping that I can find the unique structure of Y-X-W



I'm not sure I have to listen to all windows, but it is my assumption that I'll have to check what happens within "the root window" and try to find the sought window.










share|improve this question























  • Just found that xprop has a -spy option: Examine window properties forever, looking for property change events. I have no idea whether that is helpful, but it's the only thing I found that doesn't involve polling.
    – dessert
    Mar 1 at 9:52










  • I have looked at xprop -spy before, I discarded it since I was thinking that I needed to listen to the window I was searching for. But you might be on to something. Tested it out by xprop -spy -root and it doesn't show any info at window creation, but it does make a note when there is a focus change and, as it happens, the window I'm searching for will be pushed to the front. So maybe I can use it, I'll give it a shot and see if I can solve it :)
    – Christian Eriksson
    Mar 1 at 10:13











  • Are there any news, did you manage to solve the issue?
    – dessert
    Mar 16 at 18:46






  • 1




    Yes, I manged to create a solution using the spy option. I also had some luck with the xlib library. I'll write something up for an answer.
    – Christian Eriksson
    Mar 17 at 19:46














up vote
4
down vote

favorite
1












I am trying to find a way to detect the event of a window (any window) being opened in Ubuntu 16.04



I would like to be able to detect the "window open" event and check if the opened window was my sought window and thereafter run a bash script or a C/C++ function.



So far I've found that I can use wmctrl -l to find which windows are already opened. I could use this command and perhaps grep to find if my sought window is opened and then act on this information.



I'd prefer not to poll, as I'd not want the application to stand idle when the window opens. The action should be as "instantaneous" as possible.



Is there an event or signal I could listen for to achieve this? From the kernel, window manager (Compiz) or maybe some log file that changes?



EDIT:
To clarify, I have an application (not under my control) which might show a window at any time, this window does not have a title but it does have the WM_CLASS set (the WM_CLASS is the same for all windows of the application). I want to act upon the event that this window is shown (or created, whichever is best/easier).



It doesn't seem like the window is opened "within" the main applications window. Using xwininfo -children -id <window-id> shows that the main application and the sought window are on different branches, connected to "the root window".



The branches looks like this, where R is "the root node"; A is a root node of the main application's branch and Y is the root of the branch with sought window W:



 R
/
A Y
/
B C X

Q W


So I'm hoping that I can find the unique structure of Y-X-W



I'm not sure I have to listen to all windows, but it is my assumption that I'll have to check what happens within "the root window" and try to find the sought window.










share|improve this question























  • Just found that xprop has a -spy option: Examine window properties forever, looking for property change events. I have no idea whether that is helpful, but it's the only thing I found that doesn't involve polling.
    – dessert
    Mar 1 at 9:52










  • I have looked at xprop -spy before, I discarded it since I was thinking that I needed to listen to the window I was searching for. But you might be on to something. Tested it out by xprop -spy -root and it doesn't show any info at window creation, but it does make a note when there is a focus change and, as it happens, the window I'm searching for will be pushed to the front. So maybe I can use it, I'll give it a shot and see if I can solve it :)
    – Christian Eriksson
    Mar 1 at 10:13











  • Are there any news, did you manage to solve the issue?
    – dessert
    Mar 16 at 18:46






  • 1




    Yes, I manged to create a solution using the spy option. I also had some luck with the xlib library. I'll write something up for an answer.
    – Christian Eriksson
    Mar 17 at 19:46












up vote
4
down vote

favorite
1









up vote
4
down vote

favorite
1






1





I am trying to find a way to detect the event of a window (any window) being opened in Ubuntu 16.04



I would like to be able to detect the "window open" event and check if the opened window was my sought window and thereafter run a bash script or a C/C++ function.



So far I've found that I can use wmctrl -l to find which windows are already opened. I could use this command and perhaps grep to find if my sought window is opened and then act on this information.



I'd prefer not to poll, as I'd not want the application to stand idle when the window opens. The action should be as "instantaneous" as possible.



Is there an event or signal I could listen for to achieve this? From the kernel, window manager (Compiz) or maybe some log file that changes?



EDIT:
To clarify, I have an application (not under my control) which might show a window at any time, this window does not have a title but it does have the WM_CLASS set (the WM_CLASS is the same for all windows of the application). I want to act upon the event that this window is shown (or created, whichever is best/easier).



It doesn't seem like the window is opened "within" the main applications window. Using xwininfo -children -id <window-id> shows that the main application and the sought window are on different branches, connected to "the root window".



The branches looks like this, where R is "the root node"; A is a root node of the main application's branch and Y is the root of the branch with sought window W:



 R
/
A Y
/
B C X

Q W


So I'm hoping that I can find the unique structure of Y-X-W



I'm not sure I have to listen to all windows, but it is my assumption that I'll have to check what happens within "the root window" and try to find the sought window.










share|improve this question















I am trying to find a way to detect the event of a window (any window) being opened in Ubuntu 16.04



I would like to be able to detect the "window open" event and check if the opened window was my sought window and thereafter run a bash script or a C/C++ function.



So far I've found that I can use wmctrl -l to find which windows are already opened. I could use this command and perhaps grep to find if my sought window is opened and then act on this information.



I'd prefer not to poll, as I'd not want the application to stand idle when the window opens. The action should be as "instantaneous" as possible.



Is there an event or signal I could listen for to achieve this? From the kernel, window manager (Compiz) or maybe some log file that changes?



EDIT:
To clarify, I have an application (not under my control) which might show a window at any time, this window does not have a title but it does have the WM_CLASS set (the WM_CLASS is the same for all windows of the application). I want to act upon the event that this window is shown (or created, whichever is best/easier).



It doesn't seem like the window is opened "within" the main applications window. Using xwininfo -children -id <window-id> shows that the main application and the sought window are on different branches, connected to "the root window".



The branches looks like this, where R is "the root node"; A is a root node of the main application's branch and Y is the root of the branch with sought window W:



 R
/
A Y
/
B C X

Q W


So I'm hoping that I can find the unique structure of Y-X-W



I'm not sure I have to listen to all windows, but it is my assumption that I'll have to check what happens within "the root window" and try to find the sought window.







bash window c++ c events






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 20 at 11:25

























asked Feb 27 at 12:55









Christian Eriksson

1617




1617











  • Just found that xprop has a -spy option: Examine window properties forever, looking for property change events. I have no idea whether that is helpful, but it's the only thing I found that doesn't involve polling.
    – dessert
    Mar 1 at 9:52










  • I have looked at xprop -spy before, I discarded it since I was thinking that I needed to listen to the window I was searching for. But you might be on to something. Tested it out by xprop -spy -root and it doesn't show any info at window creation, but it does make a note when there is a focus change and, as it happens, the window I'm searching for will be pushed to the front. So maybe I can use it, I'll give it a shot and see if I can solve it :)
    – Christian Eriksson
    Mar 1 at 10:13











  • Are there any news, did you manage to solve the issue?
    – dessert
    Mar 16 at 18:46






  • 1




    Yes, I manged to create a solution using the spy option. I also had some luck with the xlib library. I'll write something up for an answer.
    – Christian Eriksson
    Mar 17 at 19:46
















  • Just found that xprop has a -spy option: Examine window properties forever, looking for property change events. I have no idea whether that is helpful, but it's the only thing I found that doesn't involve polling.
    – dessert
    Mar 1 at 9:52










  • I have looked at xprop -spy before, I discarded it since I was thinking that I needed to listen to the window I was searching for. But you might be on to something. Tested it out by xprop -spy -root and it doesn't show any info at window creation, but it does make a note when there is a focus change and, as it happens, the window I'm searching for will be pushed to the front. So maybe I can use it, I'll give it a shot and see if I can solve it :)
    – Christian Eriksson
    Mar 1 at 10:13











  • Are there any news, did you manage to solve the issue?
    – dessert
    Mar 16 at 18:46






  • 1




    Yes, I manged to create a solution using the spy option. I also had some luck with the xlib library. I'll write something up for an answer.
    – Christian Eriksson
    Mar 17 at 19:46















Just found that xprop has a -spy option: Examine window properties forever, looking for property change events. I have no idea whether that is helpful, but it's the only thing I found that doesn't involve polling.
– dessert
Mar 1 at 9:52




Just found that xprop has a -spy option: Examine window properties forever, looking for property change events. I have no idea whether that is helpful, but it's the only thing I found that doesn't involve polling.
– dessert
Mar 1 at 9:52












I have looked at xprop -spy before, I discarded it since I was thinking that I needed to listen to the window I was searching for. But you might be on to something. Tested it out by xprop -spy -root and it doesn't show any info at window creation, but it does make a note when there is a focus change and, as it happens, the window I'm searching for will be pushed to the front. So maybe I can use it, I'll give it a shot and see if I can solve it :)
– Christian Eriksson
Mar 1 at 10:13





I have looked at xprop -spy before, I discarded it since I was thinking that I needed to listen to the window I was searching for. But you might be on to something. Tested it out by xprop -spy -root and it doesn't show any info at window creation, but it does make a note when there is a focus change and, as it happens, the window I'm searching for will be pushed to the front. So maybe I can use it, I'll give it a shot and see if I can solve it :)
– Christian Eriksson
Mar 1 at 10:13













Are there any news, did you manage to solve the issue?
– dessert
Mar 16 at 18:46




Are there any news, did you manage to solve the issue?
– dessert
Mar 16 at 18:46




1




1




Yes, I manged to create a solution using the spy option. I also had some luck with the xlib library. I'll write something up for an answer.
– Christian Eriksson
Mar 17 at 19:46




Yes, I manged to create a solution using the spy option. I also had some luck with the xlib library. I'll write something up for an answer.
– Christian Eriksson
Mar 17 at 19:46










1 Answer
1






active

oldest

votes

















up vote
4
down vote



accepted










I found two ways of solving this problem.



  1. Use the xprop -spy -root _NET_ACTIVE_WINDOW command in combination with grep in a bash script.

  2. 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:




  • A Xlib Manual and short tutorial by Christophe Tronche

  • Alan's tutorial on Xlib.

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.






share|improve this answer






















    Your Answer







    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "89"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1010276%2fcan-i-act-on-the-event-that-a-window-opens-without-polling%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    4
    down vote



    accepted










    I found two ways of solving this problem.



    1. Use the xprop -spy -root _NET_ACTIVE_WINDOW command in combination with grep in a bash script.

    2. 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:




    • A Xlib Manual and short tutorial by Christophe Tronche

    • Alan's tutorial on Xlib.

    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.






    share|improve this answer


























      up vote
      4
      down vote



      accepted










      I found two ways of solving this problem.



      1. Use the xprop -spy -root _NET_ACTIVE_WINDOW command in combination with grep in a bash script.

      2. 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:




      • A Xlib Manual and short tutorial by Christophe Tronche

      • Alan's tutorial on Xlib.

      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.






      share|improve this answer
























        up vote
        4
        down vote



        accepted







        up vote
        4
        down vote



        accepted






        I found two ways of solving this problem.



        1. Use the xprop -spy -root _NET_ACTIVE_WINDOW command in combination with grep in a bash script.

        2. 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:




        • A Xlib Manual and short tutorial by Christophe Tronche

        • Alan's tutorial on Xlib.

        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.






        share|improve this answer














        I found two ways of solving this problem.



        1. Use the xprop -spy -root _NET_ACTIVE_WINDOW command in combination with grep in a bash script.

        2. 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:




        • A Xlib Manual and short tutorial by Christophe Tronche

        • Alan's tutorial on Xlib.

        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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Mar 20 at 11:26

























        answered Mar 20 at 9:47









        Christian Eriksson

        1617




        1617



























             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1010276%2fcan-i-act-on-the-event-that-a-window-opens-without-polling%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            pylint3 and pip3 broken

            Missing snmpget and snmpwalk

            How to enroll fingerprints to Ubuntu 17.10 with VFS491