如何通过xcb RandR扩展获得RandR输出的分辨率?

8

我正在从事一个已经使用xcb的项目,需要获取单个输出的分辨率而不是合并屏幕的分辨率。我可以使用RandR扩展来实现这一点吗?如果可以,那么我该如何使用我的xcb_connection_t对象来实现呢。

1个回答

12
我也在寻找答案。我不知道你是否已经成功,但既然你没有回答这个问题,我猜想你还没有成功。
对于那些正在寻找如何做到这一点的人,您必须了解XCB的工作原理。这对于RandR XCB扩展尤为重要。正如您可能知道的那样,要从X服务器获取某些信息,您需要首先使用请求查询它。在XCB的情况下,在发送请求后,您会得到一个cookie,其中存储了已发送请求的ID。为什么需要这样的cookie?原因很简单且很明显——为了从X服务器获取回复,我们需要使用已发送请求的ID来请求它(这样服务器就知道您要回答哪个请求)。
为了使其更清晰,这里有一个日常生活中的简单例子——想象一个记忆力极差的酒保,情况是这样的:
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概念

回到问题——如何获取输出(或者更确切地说是CRTCs)的分辨率?以下是我使用的简化版本:

#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)

多么美妙的答案。 - étale-cohomology
我可以假设大多数现代Linux桌面上都存在xrandr吗?或者如果没有randr,我还需要在xierama中编写类似的东西来获取分辨率吗? - Sai Prasanna
不需要创建虚拟窗口。XFirstScreen->root同样可以胜任。无论如何...感谢您提供这个精彩的答案! - Xatian
我知道你需要释放回复。你也需要释放 xcb_randr_crtc_t 数组吗? - CLearner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接