2

I dont have a lot of experience with C so sorry if this is a dumb question. I'm writing an application that will monitor and manipulate application windows and i need to figure out how to do the following:

  • Get a list of all application windows
  • Be notified when a window is resized
  • Be notified when the a user maximises/minimises a window
  • Set the size and position of an application window.

I spent quite a while searching google but did not find anything useful. The language is not to important as i could make this project work with C or C++ maybe even C# Any help would be appreciated.

leiyc
  • 903
  • 11
  • 23

2 Answers2

1

on linux windows are handled by X11 ( X Window System https://en.wikipedia.org/wiki/X_Window_System, https://en.wikipedia.org/wiki/X.Org_Server ) and X Window Managers like Enlightenment ( https://en.wikipedia.org/wiki/Comparison_of_X_window_managers ), and tools and libraries like xdotool or Xlib ( https://www.lemoda.net/c/xlib-resize/ ...).

X11 is low(est)-level application window handling on linux

on this X11 basis you normally write programs that contain windows using Qt or GTK+ framework, in both frameworks are implemented methods to do all your mentioned tasks ( What should I choose: GTK+ or Qt? )

important is the installed X windows manager ( https://en.wikipedia.org/wiki/Comparison_of_X_window_managers ). In the overlying Qt and GTK+ frameworks only functions can be used that are implemented by the underlying X window manager

resize window event capturing in Qt and GTK :

A list of all open X windows can be queried with XQueryTree function from the Xlib library

( How to get the list of open windows from xserver )

xwininfo ( https://linux.die.net/man/1/xwininfo ) can be used to collect information about open windows

ralf htp
  • 9,149
  • 4
  • 22
  • 34
  • Been looking into your suggestions (thank you btw) I have figured out how to move/resize windows using xdotool but i'm having a little trouble with actually detecting window changes. i have the example gtk code you linked working but that only applies to the applications own window. I cannot find a way to detect events from all active application windows. – brandon3055 Aug 19 '18 at 08:50
  • not at home writing from phone so short. In GTK any events like resize is handled by **signals and events** and callback functions they trigger. An example for multiple windows is in gamedev.net/forums/topic/427117-gtk-and-multiple-windows for signals see the link in https://stackoverflow.com/questions/1060039/gtk-detecting-window-resize-from-the-user – ralf htp Aug 19 '18 at 11:26
  • In http://zetcode.com/gui/gtk2/gtkevents/ is information with code on GTK signals and events – ralf htp Aug 19 '18 at 15:00
  • 1
    Sorry i dont think were on the same page here. The page you linked shows how to handle multiple windows opened by your application. But i want to listen to other windows not created by my application. For example say the user moves/resizes a chrome window. i would like to listen for that event. – brandon3055 Aug 19 '18 at 17:19
  • this is only possible when capturing low-level X11 events with tools like xdotool or similar so directly from the X Server. GTK is higher level and limited to its own applications – ralf htp Aug 19 '18 at 17:59
  • this is the background information https://seasonofcode.com/posts/how-x-window-managers-work-and-how-to-write-one-part-i.html – ralf htp Aug 19 '18 at 19:04
  • Thanks that explains why i wasn't making any progress. I have been poking at X11 for a couple hours now but so far i have not been able to get it to send me any events. Not even for a specific window. This is the code i have so far, put together from a bunch of different articles on the web. I have a feeling i am making an obvious mistake. https://gist.github.com/brandon3055/4a41e444960a90f394da35c301b1729f – brandon3055 Aug 19 '18 at 20:23
  • I should probably also mention i am working with gnome on Ubuntu 18.04 I have a feeling this may be an issue with my desktop environment as explained in this thread http://www.linuxforums.org/forum/programming-scripting/59649-how-capture-x11-events-globally-post321955.html?s=d8adac014d6def343de6c9a415ed30ce#post321955 I could not even get that example code working. – brandon3055 Aug 19 '18 at 21:25
  • maybe try o get a list of all open windows like described in https://stackoverflow.com/questions/252906/how-to-get-the-list-of-open-windows-from-xserver, then you have the window ids and can possibly capture the events. am on ubuntu 16.04 and `xwininfo -tree -root` is working for me ( https://linux.die.net/man/1/xwininfo ) – ralf htp Aug 20 '18 at 09:18
1

EDIT: I was just thinking of something else when I answered the question the first time. In fact what you are asking for is pretty simple.

Here is a potential solution.

  1. Register for Create/Destroy/Resize window events (XCB_EVENT_MASK_STRUCTURE_NOTIFY) so you can keep up with newly added/destroyed/resized windows. Depending on your setup you may want to add the XCB_EVENT_MASK_PROPERTY_CHANGE so you can tell if the "minimized" or "maximized" property is set.

  2. Query _NET_CLIENT_LIST (ie via xcb_ewmh_get_client_list) or use XQueryTree to get all (application) windows. The former will give you a filtered list that will probably be a superset of "application windows". The latter will give you every single window which will probably be more than what you want.

  3. Send configure request to resize the window. Like others have said, xdotool can be used to send these requests. Note that, in general, these requests are likely to be blocked/modified by the WM. If you don't own the window, there is no good way around this unless your WM allows it. If you do own the window, you could set the override redirect field on the window.

Below is a code sample on how you might listen for events (complied with -lxcb). Note that this is just a sample and you would probably want to filter events in the switch statement (ie you don't want all properties)

void main(){
//create connection using default display
xcb_connection_t* dis = xcb_connect(NULL, NULL);
if(xcb_connection_has_error(dis))
    exit(1);

xcb_screen_t*screen=xcb_setup_roots_iterator(xcb_get_setup(dis)).data;
int root = screen->root;
int mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY|XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY|XCB_EVENT_MASK_PROPERTY_CHANGE;
if(xcb_request_check(dis,xcb_change_window_attributes_checked(dis, root,XCB_CW_EVENT_MASK, &mask)))
    exit(1);//an error occured

while(1){
    xcb_generic_event_t *event;
    event = xcb_wait_for_event(dis);
    switch(event->response_type){
        case XCB_CREATE_NOTIFY:
            printf("New window\n");
            break;
        case XCB_DESTROY_NOTIFY:
            printf("Window deleted\n");
            break;
        case XCB_PROPERTY_NOTIFY:
            printf("Window property change\n");
            break;
        case XCB_CONFIGURE_NOTIFY:
            printf("Window size has changed\n");
            break;
    }
}

}

If you are new to X11, I personally recommend xcb instead of Xlib because its easier to debug, but its just a personal preference. You could use either or both. Also keep in mind that X11 api has been ported to many languages like python so you are not stuck with C.

Looking through your comments, yes DE/WM can impact your code. Not sure of your use case or how deep you want to go but you can

  • switch WM (there are a lot to choose from)
  • Run in a sandbox where no WM is running
  • See if your WM can white list certain windows so you can modify them directly or see if you WM is scriptable/allows you to add hooks when certain events are run
  • Write your own WM. You can get notified of every event you care about but you'd have to do everything else you'd ever want so it would be a lot of work

I will admit that X programming can have a bit of a learning curve but it gets better.

TAAPSogeking
  • 350
  • 4
  • 14
  • 1
    XCB is not the easy way into X programming though. It exposes a lot of details that are hidden by the Xlib API. It is therefore easier to see where something goes wrong. Unfortunately it's not easier to see why :). – rubenvb Aug 20 '18 at 12:31
  • @rubenvb I can see your point of xcb not being better than Xlib when it comes down to why a given line was wrong. Probably gonna have to look up the error code or get the error string and then look up the error either way. – TAAPSogeking Aug 21 '18 at 06:21
  • One more thing to mention, `Xlib` has actually already been re-written to use `xcb`, so very few apps are going to become better/faster/more reliable because of being written to access `xcb` directly. Also, having spent a fair amount of time writing with each, on the `xcb` side the error messages from the API and the documentation are extremely limited. Far better to write to xlib in my experience. Sadly X may not be around much longer as RedHat and Ubuntu ship Wayland by default, and wlroots is a very long way away from providing a complete desktop independent API the way xlib does... – erwin Dec 07 '21 at 05:26