Я работаю над проектом, который уже использует xcb, и мне нужно получить разрешение отдельных выходов, а не разрешение комбинированного экрана. Могу ли я сделать это с расширением RandR для xcb? Если да, то как я могу использовать свой объект xcb_connection_t
для этого.
Как получить разрешение выходных данных RandR через расширение xcb RandR?
Ответы (1)
Я тоже искал ответ. Я не знаю, удалось вам это или нет, но, поскольку вы не ответили на этот вопрос, я думаю, что нет.
Для тех, кто ищет, как это сделать, вы должны понимать, как вообще работает XCB. Это особенно важно для расширения RandR XCB. Как вы, наверное, знаете, чтобы получить некоторую информацию с X-сервера, вам нужно сначала запросить его с помощью запроса. В случае XCB после отправки запроса вы получаете cookie, в котором хранится ID отправленного запроса. Зачем вам такое печенье? Причина проста и вполне очевидна - чтобы получить ответ от X-сервера, нам нужно запросить его с идентификатором отправленного нами запроса (чтобы сервер знал, на какой запрос вы хотите получить ответ).
Чтобы было еще понятнее, вот простой пример из повседневной жизни — представьте себе бармена с очень короткой памятью, и он выглядит так:
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."
Хорошо, так почему бы XCB просто не отправить запрос и не получить ответ за один раз? Что ж, именно так работает Xlib, и оказывается, что XCB в некоторых условиях работает до 117 раз быстрее. Если вы хотите узнать больше, прочтите Основные понятия XCB из руководства по XCB.
Вернемся к вопросу - как получить разрешение выходов (точнее CRTC)? Вот минимизированная версия того, как я это делаю:
#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;
}
Пример вывода:
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
Если вы хотите, вы можете улучшить читаемость кода с помощью векторов и прочего вместо использования динамического распределения с указателями, но я не думаю, что это сложно понять.
Я все еще новичок в программировании XCB, и, ВОЗМОЖНО, это лучший способ, но этот метод совсем не кажется плохим. Я потратил огромное количество времени, пытаясь понять это, поэтому я надеюсь, что это кому-то поможет.
Полезные ссылки:
- Учебное пособие по XCB (рекомендуется для ознакомления)
- XCB API (ОЧЕНЬ полезный, в данном случае особенно RandR API)