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.
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)
© 2022 - 2024 — McMap. All rights reserved.