Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the resolution of RandR outputs through the xcb RandR extension?

Tags:

c

linux

x11

xcb

xrandr

I'm working on a project that is already using xcb and need to get the resolution of individual outputs rather than the resolution of the combined screen. Can I do this with the RandR extension for xcb? If so, how can I use my xcb_connection_t object to do this.

like image 707
Aaron Landis Avatar asked Mar 01 '14 01:03

Aaron Landis


People also ask

How to use XRandR to set the refresh rate and resolution?

Then, use Xrandr to set it. The --output flag is necessary to specify which monitor you’re targeting. Then the --mode flag tells it which resolution to use. The --rate flag allows you to set your monitor’s refresh rate. Take a look at your monitor’s information.

How does XRandR work with no monitor connected?

Looking at the documentation for xrandr, it relies on getting information from the display for supported resolutions. With no monitor connected, xrandr has no information to draw on for setting a display resolution and most likely draws from the resolution set in your Display preferences for the VNC connection.

How to get The Modeline string for XRandR?

# First we need to get the modeline string for xrandr # Luckily, the tool "gtf" will help you calculate it. # All you have to do is to pass the resolution & the- # refresh-rate as the command parameters: gtf 1920 1080 60 # In this case, the horizontal resolution is 1920px the # vertical resolution is 1080px & refresh-rate is 60Hz.

How to setup XRandR with arandr?

try installing arandr to setup your xrandr config with a GUI. then setup you your displays' resolution, orientation and position and finally save the config. Show activity on this post.


1 Answers

I was looking for the answer as well. I don't know if you have succeeded or not, but since you haven't answered this question I guess you have not.

For those who are looking how to do this, you have to understand how XCB generally works. It's especially important for RandR XCB extension. As you probably know to get some information from the X server you need to query it first with a request. In case of XCB after sending a request you are getting a cookie which stores ID of a sent request. Why do you need such cookie? Reason is simple and quite obvious - to get a reply from the X server we need to ask for it with ID of a request we have sent (so the server knows which request you want the answer for).

To make it even clearer here is a simple example from daily life - imagine a bartender with extremely short memory and so it goes like this:

client   : "I'd like to order a beer."
bartender: "OK, I'll get you a beer."
*bartender handles a ticket with an ID of the beer order to the client*
*client waits and waits and then he approaches bartender*
client   : "Dude, give me my beer finally, here's your damn ticket"
*client handles the ticket to bartender, who looks for the order from the 
 ticket in his order book and when he finds it he replies*
bartender: "Here's your beer, enjoy."

OK, so why wouldn't XCB simply send a request and get an answer in one go? Well, that's exactly how Xlib works and it turns out that XCB has been observed to be up to 117 times faster in some conditions. Please read the Basic XCB Notions from XCB tutorial if you want to know more.

Back to the question - how to get the resolution of the outputs (or rather CRTCs)? Here's a minimized version of how I do it:

#include <cstdio>
#include <xcb/xcb.h>
#include <xcb/randr.h>

int main()
{
    //Open connection to X server
    xcb_connection_t* XConnection = xcb_connect(0, 0);

    //Get the first X screen
    xcb_screen_t* XFirstScreen = xcb_setup_roots_iterator(
                               xcb_get_setup(XConnection)).data;
    //Generate ID for the X window
    xcb_window_t XWindowDummy = xcb_generate_id(XConnection);

    //Create dummy X window
    xcb_create_window(XConnection, 0, XWindowDummy, XFirstScreen->root,
                      0, 0, 1, 1, 0, 0, 0, 0, 0);

    //Flush pending requests to the X server
    xcb_flush(XConnection);

    //Send a request for screen resources to the X server
    xcb_randr_get_screen_resources_cookie_t screenResCookie = {};
    screenResCookie = xcb_randr_get_screen_resources(XConnection, 
                                                     XWindowDummy);

    //Receive reply from X server
    xcb_randr_get_screen_resources_reply_t* screenResReply = {};
    screenResReply = xcb_randr_get_screen_resources_reply(XConnection,
                     screenResCookie, 0);

    int crtcs_num = 0;
    xcb_randr_crtc_t* firstCRTC;

    //Get a pointer to the first CRTC and number of CRTCs
    //It is crucial to notice that you are in fact getting
    //an array with firstCRTC being the first element of
    //this array and crtcs_length - length of this array
    if(screenResReply)
    {
        crtcs_num = xcb_randr_get_screen_resources_crtcs_length(screenResReply);

        firstCRTC = xcb_randr_get_screen_resources_crtcs(screenResReply);
    }
    else
        return -1;

    //Array of requests to the X server for CRTC info
    xcb_randr_get_crtc_info_cookie_t* crtcResCookie = new   
               xcb_randr_get_crtc_info_cookie_t[crtcs_num];
    for(int i = 0; i < crtcs_num; i++)
        crtcResCookie[i] = xcb_randr_get_crtc_info(XConnection, 
                                            *(firstCRTC+i), 0);
    //Array of pointers to replies from X server
    xcb_randr_get_crtc_info_reply_t** crtcResReply = new 
               xcb_randr_get_crtc_info_reply_t*[crtcs_num];
    for(int i = 0; i < crtcs_num; i++)
        crtcResReply[i] = xcb_randr_get_crtc_info_reply(XConnection,
                                             crtcResCookie[i], 0);
    //Self-explanatory
    for(int i = 0; i < crtcs_num; i++)
    {
        if(crtcResReply[i])
        {
            printf("CRTC[%i] INFO:\n", i);
            printf("x-off\t: %i\n", crtcResReply[i]->x);
            printf("y-off\t: %i\n", crtcResReply[i]->y);
            printf("width\t: %i\n", crtcResReply[i]->width);
            printf("height\t: %i\n\n", crtcResReply[i]->height);
        }
    }

    xcb_disconnect(XConnection);

    return 0;
}

Example output:

CRTC[0] INFO:
x-off   : 1920
y-off   : 0
width   : 1920
height  : 1200

CRTC[1] INFO:
x-off   : 0
y-off   : 0
width   : 1920
height  : 1200

CRTC[2] INFO:
x-off   : 0
y-off   : 0
width   : 0
height  : 0

CRTC[3] INFO:
x-off   : 0
y-off   : 0
width   : 0
height  : 0

If you want you can improve the readability of the code with vector and whatnot instead of using dynamic allocation with pointers, but I don't think it's that difficult to comprehend.

I'm still new to XCB programming and there PROBABLY is a better way, but this method doesn't seem bad at all. I've spent huge amount of time trying to understand this, so I do hope it will help somebody.

Useful links:

  • XCB Tutorial (recomended to find your way around)
  • XCB API (EXTREMELY useful, in this case especially RandR API)
like image 172
Peter Nimroot Avatar answered Sep 19 '22 17:09

Peter Nimroot