How to get started writing a compositing WM?
There are two parts in your question: 1) How to write WM 2) how to write composite manager
Some links to help understand part two (in addition to xcompmgr source):
- http://www.talisman.org/~erlkonig/misc/x11-composite-tutorial/ (Uses Qt, but very generic and low level)
- https://github.com/gustavosbarreto/compmgr
- http://projects.mini-dweeb.org/projects/unagi
Window manager, "part one":
- I have simple ~100 loc wm in JavaScript: https://github.com/sidorares/node-x11/blob/master/examples/windowmanager/wm.js
- another minimalist wm (in C), good to start as a reference: https://code.google.com/p/winmalist/
- most important keyword:
SubstructureRedirect
event mask. A bit of documentation here
Request image from X11 compositing WM in C or C++
I now have a working example that I will post here:
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <xcb/composite.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "usage: %s windowId\n", argv[0]);
return EXIT_FAILURE;
}
xcb_window_t req_win_id = strtoul(argv[1], NULL, 0);
xcb_connection_t *connection = xcb_connect(NULL, NULL);
xcb_generic_error_t *err = NULL, *err2 = NULL;
xcb_composite_query_version_cookie_t comp_ver_cookie = xcb_composite_query_version(connection, 0, 2);
xcb_composite_query_version_reply_t *comp_ver_reply = xcb_composite_query_version_reply(connection, comp_ver_cookie, &err);
if (comp_ver_reply)
{
if (comp_ver_reply->minor_version < 2) {
fprintf(stderr, "query composite failure: server returned v%d.%d\n", comp_ver_reply->major_version, comp_ver_reply->minor_version);
free(comp_ver_reply);
return EXIT_FAILURE;
}
free(comp_ver_reply);
}
else if (err)
{
fprintf(stderr, "xcb error: %d\n", err->error_code);
free(err);
return EXIT_FAILURE;
}
const xcb_setup_t *setup = xcb_get_setup(connection);
xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(setup);
xcb_screen_t *screen = screen_iter.data;
// request redirection of window
xcb_composite_redirect_window(connection, req_win_id, XCB_COMPOSITE_REDIRECT_AUTOMATIC);
int win_h, win_w, win_d;
xcb_get_geometry_cookie_t gg_cookie = xcb_get_geometry(connection, req_win_id);
xcb_get_geometry_reply_t *gg_reply = xcb_get_geometry_reply(connection, gg_cookie, &err);
if (gg_reply) {
win_w = gg_reply->width;
win_h = gg_reply->height;
win_d = gg_reply->depth;
free(gg_reply);
} else {
if (err) {
fprintf(stderr, "get geometry: XCB error %d\n", err->error_code);
free(err);
}
return EXIT_FAILURE;
}
// create a pixmap
xcb_pixmap_t win_pixmap = xcb_generate_id(connection);
xcb_composite_name_window_pixmap(connection, req_win_id, win_pixmap);
// get the image
xcb_get_image_cookie_t gi_cookie = xcb_get_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, win_pixmap, 0, 0, win_w, win_h, (uint32_t)(~0UL));
xcb_get_image_reply_t *gi_reply = xcb_get_image_reply(connection, gi_cookie, &err);
if (gi_reply) {
int data_len = xcb_get_image_data_length(gi_reply);
fprintf(stderr, "data_len = %d\n", data_len);
fprintf(stderr, "visual = %u\n", gi_reply->visual);
fprintf(stderr, "depth = %u\n", gi_reply->depth);
fprintf(stderr, "size = %dx%d\n", win_w, win_h);
uint8_t *data = xcb_get_image_data(gi_reply);
fwrite(data, data_len, 1, stdout);
free(gi_reply);
}
return EXIT_SUCCESS;
}
It was a case of overdoing it. I got the idea that I should use Xrender from somewhere and started pulling tons of data from that extension that I didn't really need. But the real problem I had was that the pixmap given to xcb_composite_name_window_pixmap should not be created first, but rather I just needed the new id for it. It turns out that it is really as simple as I expected it to be. All you need is the Window ID and the size, do some checks to make sure composite is there and a good version (>=0.2 in this case), and call xcb_composite_redirect_window, xcb_composite_name_window_pixmap (with a generated pixmap id), and xcb_get_image (+reply,data_len,data) in that order, and you have the image.
How does compositor work on X?
The simpler you code it, the best it will work.
- Get a list of the visible windows
- Sort them by inverse z-order (from the bottom-most to the top-most)
- Draw the shadow and then the window itself for each window
You need no black magic.
If you are wondering how it works, it's straightforward: you have to use the 'composite' X extension. It enables the overlay window, which is the only visible window on the screen once it is enabled, then you have to draw all the windows on it as you will be provided with a Pixmap
for each window.
EDIT:
If you are seeking for documentation, you can use the linux manual (the man command), and the header files, they're the main (also best and perhaps the only real) source of documentation, as all the other sources/websites rely on them afaik.
How to make an overlay of all tags
My collision module or the bling module has something close enough. Getting the exact layout you ask for is non-trivial because AwesomeWM is not a compositing window manager. This means it cannot really take screenshots (let alone live-views) of invisible clients/windows. Usually, the only "safe" thing is to display the outline and client icon
.
If you really, really want this, you need:
- A compositing manager such as picom
- Either these patches or use
gears.surface(client.content)
to take a screenshot - Lot of code to properly render a wibox with the right screenshots. You can read the bling or collision code to know how to get the size and position.
Related Topics
Not Authorized for Query on Admin.System.Namespaces on Mongodb
How to Sleep for 1 Second Between Each Xargs Command
Amazon Ec2 - Apache Server Restart Issue
Understanding Bash Short-Circuiting
Crontab Day of the Week Syntax
Git Enter Long Passphrase for Every Push
How to Simulate a Failed Disk During Testing
How to Specify Filenames Within a Zip When Creating It on the Command Line from a Pipe
What Is a Good Way to Dump a Linux Core File from Inside a Process
Why Does C99 Complain About Storage Sizes
Search for a Cronjob with Crontab -L
Does Gcc, Icc, or Microsoft's C/C++ Compiler Support or Know Anything About Numa
How to Get Started Developing on *Nix
How Can the Linux Kernel Be Forced to Enumerate the Pci-E Bus