Как получить разрешение выходных данных RandR через расширение xcb RandR?

Я работаю над проектом, который уже использует xcb, и мне нужно получить разрешение отдельных выходов, а не разрешение комбинированного экрана. Могу ли я сделать это с расширением RandR для xcb? Если да, то как я могу использовать свой объект xcb_connection_t для этого.


person Aaron Landis    schedule 01.03.2014    source источник


Ответы (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, и, ВОЗМОЖНО, это лучший способ, но этот метод совсем не кажется плохим. Я потратил огромное количество времени, пытаясь понять это, поэтому я надеюсь, что это кому-то поможет.

Полезные ссылки:

person Peter Nimroot    schedule 26.11.2014
comment
Какой красивый ответ - person étale-cohomology; 26.04.2017
comment
Могу ли я предположить, что xrandr существует на большинстве современных настольных компьютеров Linux? Или я должен также написать что-то подобное в xierama, чтобы получить разрешения, если randr отсутствует? - person Sai Prasanna; 12.06.2017
comment
Нет необходимости создавать фиктивное окно. XFirstScreen-›root также должен выполнять эту работу. В любом случае ... спасибо за этот замечательный ответ! - person Xatian; 17.12.2020