Search code examples
xcb

XCB get all monitors ands their x, y coordinates


So far I have got all monitors. A monitor is a screen. So what I did was:

xcb_connection_t *conn;

conn = xcb_connect(NULL, NULL);

if (xcb_connection_has_error(conn)) {
  printf("Error opening display.\n");
  exit(1);
}

const xcb_setup_t* setup;
xcb_screen_t* screen;

setup = xcb_get_setup(conn);
screen = xcb_setup_roots_iterator(setup).data;
printf("Screen dimensions: %d, %d\n", screen->width_in_pixels, screen->height_in_pixels);

This gives me the width and height. However it is critical that I get the x and y. Is doing xcb_get_window_attributes_cookie_t on the screen->root the way to get the x and y?

I was reading here - http://www.linuxhowtos.org/manpages/3/xcb_get_window_attributes_unchecked.htm - but there were no x/y coords given.


Solution

  • I assume that you are interested in the geometries of monitors, i.e., actual physical devices, and not of the X screen.

    In that case, the root window isn't what you are interested in. There are basically two different things to consider here:

    To learn how to query all kinds of details, my recommendation would be to look at programs that do this. A canonical suggestion would be a window manager that supports multi-head setups, such as the i3 window manager which, in fact, supports both Xinerama and RandR, so you can look at its source code for both.

    The information you are looking for can be found in src/randr.c and src/xinerama.c. The necessary RandR API calls are

    • xcb_randr_get_screen_resources_current
    • xcb_randr_get_screen_resources_current_outputs
    • xcb_randr_get_output_info
    • xcb_randr_get_crtc_info

    The latter of those will give you the CRTC information of an output which includes the position and size of the output.

    Another source for the RandR implementation would be xedgewarp:src/randr.c*. I'll include a heavily shortened excerpt from that source code here:

    xcb_randr_get_screen_resources_current_reply_t *reply = xcb_randr_get_screen_resources_current_reply(
            connection, xcb_randr_get_screen_resources_current(connection, root), NULL);
    
    xcb_timestamp_t timestamp = reply->config_timestamp;
    int len = xcb_randr_get_screen_resources_current_outputs_length(reply);
    xcb_randr_output_t *randr_outputs = xcb_randr_get_screen_resources_current_outputs(reply);
    for (int i = 0; i < len; i++) {
        xcb_randr_get_output_info_reply_t *output = xcb_randr_get_output_info_reply(
                connection, xcb_randr_get_output_info(connection, randr_outputs[i], timestamp), NULL);
        if (output == NULL)
            continue;
    
        if (output->crtc == XCB_NONE || output->connection == XCB_RANDR_CONNECTION_DISCONNECTED)
            continue;
    
        xcb_randr_get_crtc_info_reply_t *crtc = xcb_randr_get_crtc_info_reply(connection,
                xcb_randr_get_crtc_info(connection, output->crtc, timestamp), NULL);
        fprintf(stderr, "x = %d | y = %d | w = %d | h = %d\n",
                crtc->x, crtc->y, crtc->width, crtc->height);
        FREE(crtc);
        FREE(output);
    }
    
    FREE(reply);
    

    *) Disclaimer: I am the author of that tool.

    Edit: Note that you also need to listen for screen change events and then query the outputs again if you are interested in keeping your information up to date.