Xrandr 与Xserver 的交互

 

                                Xrandr 与Xserver 的交互

      

在X Windows system 中,Xrandr 做 X client ,Xorg 作为server端。

1.      RandR Externsion 的注册

对于Xorg 1.6.0,如果在xorg.conf文件中,没有显式的disable RandR。Xorg 会将Xrandr extension 加载。

InitExtensions

 

 

RRExtensionInit

 

 

AddExtension (RANDR_NAME, RRNumberEvents, RRNumberErrors,

                       ProcRRDispatch, SProcRRDispatch,

                       NULL, StandardMinorOpcode);

 

          X11/extensions/randr.h:40 :define RANDR_NAME  "RANDR"

此函数的作用是:为全局变量extensions 增加一个新的成员,

                                i = NumExtensions;

                                NumExtensions++;

extensions[i] = ext;

                            ext->index = i;

                            ext->base = i + EXTENSION_BASE(128);

                               strcpy(ext->name,  name); 其中的name 即为RANDR.

             ProcVector[i + EXTENSION_BASE] = MainProc即 ProcRRDispatch;

SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc 即 SProcRRDispatch;

       其中ProcVector是函数指针数组。

    1.1 ProcRRDispatch

       static int

ProcRRDispatch (ClientPtr client)

{

    REQUEST(xReq);

    if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])

       return BadRequest;

    return (*ProcRandrVector[stuff->data]) (client);

}

    其中ProcRandrVector也是函数指针数组。

     int (*ProcRandrVector[RRNumberRequests])(ClientPtr) = {

                 ProcRRQueryVersion,      /* 0 */

/* we skip 1 to make old clients fail pretty immediately */

                   NULL,                     /* 1 ProcRandrOldGetScreenInfo */

/* V1.0 apps share the same set screen config request id */

                 ProcRRSetScreenConfig, /* 2 */

                 NULL,                /* 3 ProcRandrOldScreenChangeSelectInput */

/* 3 used to be ScreenChangeSelectInput; deprecated */

                   ……

                     }    

    可以看出该函数的作用是利用stuff->data 作为index 做为index 来选择不同的函数。

            SProcRRDispatch

SProcRRDispatch 与 ProcRRDispatch的作用完全相同,在这里就不赘述了。但是不太明白两者的区别。

2.      RandR 向X server 发出请求。

     以 RandR函数 XRRGetScreenSizeRange 为例。

    RandR填充数据结构

      typedef struct {

    CARD8   reqType;

    CARD8   randrReqType;

    CARD16  length B16;

    Window  window B32;

} xRRGetScreenSizeRangeReq;

       

req->reqType = info->codes->major_opcode;

    req->randrReqType = X_RRGetScreenSizeRange(值是6);

    req->window = window;

      然后利用if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))将请求发出。

 

Xserver 利用函数ReadRequestFromClient将client送来的request解析出来,并赋值给数据结构:

      typedef struct _xReq {

        CARD8 reqType;

        CARD8 data;            /* meaning depends on request type */

        CARD16 length B16;         /* length in 4 bytes quantities                                  of whole request, including this header */

} xReq;

 

xReq *req = client->requestBuffer; 因此:

xReq-> reqType = req->reqType;

 xReq-> data  =  req->randrReqType (6);

 

2.1        info->codes->major_opcode

info->codes->major_opcode值 其实为第一部分中,RandR Extension 的ext->base = i + EXTENSION_BASE(128)。 但是如何得到ext->base,确实费了一番功夫。

RandR 在赋值 req->reqType = info->codes->major_opcode前,调用函数XRRFindDisplay-> XextAddDisplay,在XextAddDisplay中,会向Xserver也发送一个请求,从而得到ext->base.(具体过程后面介绍)

 

 

3.      Xserver 如何处理Xrandr的请求

 

这段代码没有看懂,以下是debug情况下的总结,我在终端是终端上输入命令xrandr –q。

 

WaitforSometing一直在循环等待,当有请求时。

首先调用EstablishNewConnections -àNextAvailableClient-à InitClient,在InitClient中将client->requestVector = InitialVector。

InitialVector的定义如下:

   int (* InitialVector[3]) (

       ClientPtr /* client */

    ) =

{

    0,

    ProcInitialConnection,

    ProcEstablishConnection

};

 

Dispatch继续向下调用,455行,result = (* client->requestVector[MAJOROP])(client),即调用ProcEstablishConnection。(不明白MAJOROP为什么此时是2.)

 

ProcEstablishConnection调用函数SendConnSetup,SendConnSetup中

client->requestVector = client->swapped ? SwappedProcVector : ProcVector;。进行Vector的选择,本例中选择的是ProcVector。

 

在下一次Dispatch的循环中,455 行调用。

result = (* client->requestVector[MAJOROP])(client); ,其中#define MAJOROP ((xReq *)client->requestBuffer)->reqType ,从2.1可知,reqType为ext->base. 即刚才的语句调用了函数ProcRRDispatch。而在函数ProcRRDispatch又根据xReq-> data最终调用到函数ProcRRGetScreenSizeRange。

 

 

4. 如何得到      RandR Extension 的ext->base = i + EXTENSION_BASE(128)

以Randr中的函数XRRGetScreenInfo为例。

 XRRGetScreenInfo-> XRRFindDisplay->XextAddDisplay (&XRRExtensionInfo, dpy,

         XRRExtensionName,  &rr_extension_hooks,  RRNumberEvents,  0);

è XInitExtension -> XQueryExtension

  XQueryExtension 首先利用GetReq(QueryExtension, req),将

req->reqType = X_##name;\,即req->reqType =X_QueryExternsion,(98)然后调用_XReply (dpy, (xReply *)&rep, 0, xTrue),向Xserver发出请求。

Xserver收到请求后,从ProcVector中找到index 为98的函数ProcQueryExtension,在这个函数中,会根据req中Externsion的名字(RandR),遍历全局变量extensions,找到RandR extension,并返回ext->base。

 

 

 

 

你可能感兴趣的:(linux)