Search code examples
window-managersxcb

How does XCB map/draw other processes' GUIs to the screen?


I've been reading a lot about XCB's API and compiling a lot of examples from various sites. However, none of them directly address the issue of actually creating real windows for GUI applications; they all sorta linger on how to draw primitive 2d graphics with XCB. E.g. create a window, draw a few squares, close the window.

How do you actually make processes spawn their windows within your XCB window manager?

I can only assume that when a process is made, X server is notified and forwards the request to your application and then you map a window for the process to the screen and whatever underlying graphics subsystems do the drawing on behalf of X server (and your window manager).

I've also read about how people fork() third party processes from their window manager. This seems like a silly idea. Is it? Shouldn't applications run independently of the window manager?

I've read through a lot of window manager source code and, call me a novice, but I've seen nothing that's directly linked to how applications draw their own windows.

I'd appreciate it greatly if someone could shed light on how you're supposed to handle application's window creation via XCB. Thanks.


Solution

  • However, none of them directly address the issue of actually creating real windows for GUI applications;

    That's not something you want to do with bare protocol level APIs anyway. If you want a rich GUI, use a toolkit that does all the heavy lifting for you. Xlib / XCB will give you only rudimentary tools which works well for rather simple windows; even there I wouldn't start a project without at least using something like cairo.

    How do you actually make processes spawn their windows within your XCB window manager?

    By calling xcb_create_window and then xcb_map_window. That's it. That's all. You create a window and then you make it visible.

    Of course there's a lot of other stuff you should do with your windows, but in terms of creating and displaying it, that's it.

    I can only assume that when a process is made, X server is notified

    The X server doesn't care about processes.

    forwards the request to your application

    What request?

    Shouldn't applications run independently of the window manager?

    Well, yes… but realistically, the lifetime of the window manager equals the lifetime of the X server (people don't usually switch window managers in between). And without the X server all X clients die anyway.

    So theoretically it's completely independent, but the reality is that there's no real reason to make such a distinction. That said, all window managers I know of which offer some way to launch applications fork it such that the forked process survives even if the window manager exits.

    I've read through a lot of window manager source code and, call me a novice, but I've seen nothing that's directly linked to how applications draw their own windows.

    That's because the window manager isn't involved in rendering windows – at all. The window manager only knows that windows exist and manages their abstract properties, but for all the window manager knows, a window is a rectangle with a few properties.

    Actually rendering to the window is something the X client will do itself directly with the X server.

    The one type of rendering a window manager is usually involved in is decoration rendering (window borders and titles and the like). But the window manager is also just an X client, so in this regard it's just another application rendering something (and usually a window manager renders such decorations into frame windows it created itself – so-called reparenting window managers).


    Update after your first comment: The X client (which wants to create a window) sends those requests (create / map window) to the X server. X offers multiple implementations of how this happens, the most common case on Linux systems nowadays being UNIX sockets.

    In X there's different events clients can select. One of these event types are substructure redirects, which means a client can ask the X server to be notified whenever some window, e.g., creates child windows.

    The root window is also just a window, but it has some unique properties like the fact that it always exists and cannot be closed. Only one X client can select substructure redirect on the root window – doing this is what makes the window manager a window manager.

    So now we have an X client with substructure redirect on the root window (our WM). Now any time a client requests to map a window, the X server will instead redirect this request to the window manager client (via a MapRequestEvent) and stop there. The only exception to this is map requests coming from the window manager itself: these the X server will process (in order to not just play ping pong with the window manager for all eternity).

    This basically set up an intervention loop: client requests X server to map the window, X server forwards request to the window manager, window manager may choose to send the map request for the window back to the server, server processes the map request because it came from the window manager.

    And that's it; that's how mapping the window worked.

    How is my window manager meant to tell when to make and map a window?

    The window manager doesn't tell the client what to do. How would it know what a client even wants to do? It's the opposite: the client does stuff and the window manager intervenes and reacts as it sees fit (in some regards – the window manager by no means has full control over the X server).

    Is there some kind of event loop I need to create a case for (where there would be a request to create a window from X server)?

    As stated above, deciding when to create windows is up to the client. But yes, a core concept of X clients is that they need to set up an event loop.

    For example in the case of mapping the window: the client sends the map request and MUST NOT assume the window to be mapped (because the window manager can choose to reject the request!). The client knows that their window was mapped because when it happens, the X server will create a MapEvent and send it to the client.

    Note that the window manager can not only reject map requests from the client, it can even map windows it has never even received a map request from the client for. So a client must always wait for these events and react accordingly if one of its windows has been mapped.

    There's a whole other bunch of events that are important for clients, in particular Expose events which tell the client that it needs to redraw (parts of) its window.