xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

rrscreen.c (34630B)


      1 /*
      2  * Copyright © 2006 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that copyright
      7  * notice and this permission notice appear in supporting documentation, and
      8  * that the name of the copyright holders not be used in advertising or
      9  * publicity pertaining to distribution of the software without specific,
     10  * written prior permission.  The copyright holders make no representations
     11  * about the suitability of this software for any purpose.  It is provided "as
     12  * is" without express or implied warranty.
     13  *
     14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     20  * OF THIS SOFTWARE.
     21  */
     22 
     23 #include "randrstr.h"
     24 
     25 static CARD16
     26  RR10CurrentSizeID(ScreenPtr pScreen);
     27 
     28 /*
     29  * Edit connection information block so that new clients
     30  * see the current screen size on connect
     31  */
     32 static void
     33 RREditConnectionInfo(ScreenPtr pScreen)
     34 {
     35     xConnSetup *connSetup;
     36     char *vendor;
     37     xPixmapFormat *formats;
     38     xWindowRoot *root;
     39     xDepth *depth;
     40     xVisualType *visual;
     41     int screen = 0;
     42     int d;
     43 
     44     if (ConnectionInfo == NULL)
     45         return;
     46 
     47     connSetup = (xConnSetup *) ConnectionInfo;
     48     vendor = (char *) connSetup + sizeof(xConnSetup);
     49     formats = (xPixmapFormat *) ((char *) vendor +
     50                                  pad_to_int32(connSetup->nbytesVendor));
     51     root = (xWindowRoot *) ((char *) formats +
     52                             sizeof(xPixmapFormat) *
     53                             screenInfo.numPixmapFormats);
     54     while (screen != pScreen->myNum) {
     55         depth = (xDepth *) ((char *) root + sizeof(xWindowRoot));
     56         for (d = 0; d < root->nDepths; d++) {
     57             visual = (xVisualType *) ((char *) depth + sizeof(xDepth));
     58             depth = (xDepth *) ((char *) visual +
     59                                 depth->nVisuals * sizeof(xVisualType));
     60         }
     61         root = (xWindowRoot *) ((char *) depth);
     62         screen++;
     63     }
     64     root->pixWidth = pScreen->width;
     65     root->pixHeight = pScreen->height;
     66     root->mmWidth = pScreen->mmWidth;
     67     root->mmHeight = pScreen->mmHeight;
     68 }
     69 
     70 void
     71 RRSendConfigNotify(ScreenPtr pScreen)
     72 {
     73     WindowPtr pWin = pScreen->root;
     74     xEvent event = {
     75         .u.configureNotify.window = pWin->drawable.id,
     76         .u.configureNotify.aboveSibling = None,
     77         .u.configureNotify.x = 0,
     78         .u.configureNotify.y = 0,
     79 
     80     /* XXX xinerama stuff ? */
     81 
     82         .u.configureNotify.width = pWin->drawable.width,
     83         .u.configureNotify.height = pWin->drawable.height,
     84         .u.configureNotify.borderWidth = wBorderWidth(pWin),
     85         .u.configureNotify.override = pWin->overrideRedirect
     86     };
     87     event.u.u.type = ConfigureNotify;
     88     DeliverEvents(pWin, &event, 1, NullWindow);
     89 }
     90 
     91 void
     92 RRDeliverScreenEvent(ClientPtr client, WindowPtr pWin, ScreenPtr pScreen)
     93 {
     94     rrScrPriv(pScreen);
     95     RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL;
     96     WindowPtr pRoot = pScreen->root;
     97 
     98     xRRScreenChangeNotifyEvent se = {
     99         .type = RRScreenChangeNotify + RREventBase,
    100         .rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0),
    101         .timestamp = pScrPriv->lastSetTime.milliseconds,
    102         .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
    103         .root = pRoot->drawable.id,
    104         .window = pWin->drawable.id,
    105         .subpixelOrder = PictureGetSubpixelOrder(pScreen),
    106 
    107         .sizeID = RR10CurrentSizeID(pScreen)
    108     };
    109 
    110     if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) {
    111         se.widthInPixels = pScreen->height;
    112         se.heightInPixels = pScreen->width;
    113         se.widthInMillimeters = pScreen->mmHeight;
    114         se.heightInMillimeters = pScreen->mmWidth;
    115     }
    116     else {
    117         se.widthInPixels = pScreen->width;
    118         se.heightInPixels = pScreen->height;
    119         se.widthInMillimeters = pScreen->mmWidth;
    120         se.heightInMillimeters = pScreen->mmHeight;
    121     }
    122 
    123     WriteEventsToClient(client, 1, (xEvent *) &se);
    124 }
    125 
    126 /*
    127  * Notify the extension that the screen size has been changed.
    128  * The driver is responsible for calling this whenever it has changed
    129  * the size of the screen
    130  */
    131 void
    132 RRScreenSizeNotify(ScreenPtr pScreen)
    133 {
    134     rrScrPriv(pScreen);
    135     /*
    136      * Deliver ConfigureNotify events when root changes
    137      * pixel size
    138      */
    139     if (pScrPriv->width == pScreen->width &&
    140         pScrPriv->height == pScreen->height &&
    141         pScrPriv->mmWidth == pScreen->mmWidth &&
    142         pScrPriv->mmHeight == pScreen->mmHeight)
    143         return;
    144 
    145     pScrPriv->width = pScreen->width;
    146     pScrPriv->height = pScreen->height;
    147     pScrPriv->mmWidth = pScreen->mmWidth;
    148     pScrPriv->mmHeight = pScreen->mmHeight;
    149     RRSetChanged(pScreen);
    150 /*    pScrPriv->sizeChanged = TRUE; */
    151 
    152     RRTellChanged(pScreen);
    153     RRSendConfigNotify(pScreen);
    154     RREditConnectionInfo(pScreen);
    155 
    156     RRPointerScreenConfigured(pScreen);
    157     /*
    158      * Fix pointer bounds and location
    159      */
    160     ScreenRestructured(pScreen);
    161 }
    162 
    163 /*
    164  * Request that the screen be resized
    165  */
    166 Bool
    167 RRScreenSizeSet(ScreenPtr pScreen,
    168                 CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight)
    169 {
    170     rrScrPriv(pScreen);
    171 
    172 #if RANDR_12_INTERFACE
    173     if (pScrPriv->rrScreenSetSize) {
    174         return (*pScrPriv->rrScreenSetSize) (pScreen,
    175                                              width, height, mmWidth, mmHeight);
    176     }
    177 #endif
    178 #if RANDR_10_INTERFACE
    179     if (pScrPriv->rrSetConfig) {
    180         return TRUE;            /* can't set size separately */
    181     }
    182 #endif
    183     return FALSE;
    184 }
    185 
    186 /*
    187  * Retrieve valid screen size range
    188  */
    189 int
    190 ProcRRGetScreenSizeRange(ClientPtr client)
    191 {
    192     REQUEST(xRRGetScreenSizeRangeReq);
    193     xRRGetScreenSizeRangeReply rep;
    194     WindowPtr pWin;
    195     ScreenPtr pScreen;
    196     rrScrPrivPtr pScrPriv;
    197     int rc;
    198 
    199     REQUEST_SIZE_MATCH(xRRGetScreenSizeRangeReq);
    200     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    201     if (rc != Success)
    202         return rc;
    203 
    204     pScreen = pWin->drawable.pScreen;
    205     pScrPriv = rrGetScrPriv(pScreen);
    206 
    207     rep = (xRRGetScreenSizeRangeReply) {
    208         .type = X_Reply,
    209         .pad = 0,
    210         .sequenceNumber = client->sequence,
    211         .length = 0
    212     };
    213 
    214     if (pScrPriv) {
    215         if (!RRGetInfo(pScreen, FALSE))
    216             return BadAlloc;
    217         rep.minWidth = pScrPriv->minWidth;
    218         rep.minHeight = pScrPriv->minHeight;
    219         rep.maxWidth = pScrPriv->maxWidth;
    220         rep.maxHeight = pScrPriv->maxHeight;
    221     }
    222     else {
    223         rep.maxWidth = rep.minWidth = pScreen->width;
    224         rep.maxHeight = rep.minHeight = pScreen->height;
    225     }
    226     if (client->swapped) {
    227         swaps(&rep.sequenceNumber);
    228         swapl(&rep.length);
    229         swaps(&rep.minWidth);
    230         swaps(&rep.minHeight);
    231         swaps(&rep.maxWidth);
    232         swaps(&rep.maxHeight);
    233     }
    234     WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), &rep);
    235     return Success;
    236 }
    237 
    238 int
    239 ProcRRSetScreenSize(ClientPtr client)
    240 {
    241     REQUEST(xRRSetScreenSizeReq);
    242     WindowPtr pWin;
    243     ScreenPtr pScreen;
    244     rrScrPrivPtr pScrPriv;
    245     int i, rc;
    246 
    247     REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
    248     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    249     if (rc != Success)
    250         return rc;
    251 
    252     pScreen = pWin->drawable.pScreen;
    253     pScrPriv = rrGetScrPriv(pScreen);
    254     if (!pScrPriv)
    255         return BadMatch;
    256 
    257     if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width) {
    258         client->errorValue = stuff->width;
    259         return BadValue;
    260     }
    261     if (stuff->height < pScrPriv->minHeight ||
    262         pScrPriv->maxHeight < stuff->height) {
    263         client->errorValue = stuff->height;
    264         return BadValue;
    265     }
    266     for (i = 0; i < pScrPriv->numCrtcs; i++) {
    267         RRCrtcPtr crtc = pScrPriv->crtcs[i];
    268         RRModePtr mode = crtc->mode;
    269 
    270         if (!RRCrtcIsLeased(crtc) && mode) {
    271             int source_width = mode->mode.width;
    272             int source_height = mode->mode.height;
    273             Rotation rotation = crtc->rotation;
    274 
    275             if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
    276                 source_width = mode->mode.height;
    277                 source_height = mode->mode.width;
    278             }
    279 
    280             if (crtc->x + source_width > stuff->width ||
    281                 crtc->y + source_height > stuff->height)
    282                 return BadMatch;
    283         }
    284     }
    285     if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0) {
    286         client->errorValue = 0;
    287         return BadValue;
    288     }
    289     if (!RRScreenSizeSet(pScreen,
    290                          stuff->width, stuff->height,
    291                          stuff->widthInMillimeters,
    292                          stuff->heightInMillimeters)) {
    293         return BadMatch;
    294     }
    295     return Success;
    296 }
    297 
    298 
    299 #define update_totals(gpuscreen, pScrPriv) do {       \
    300     total_crtcs += pScrPriv->numCrtcs;                \
    301     total_outputs += pScrPriv->numOutputs;            \
    302     modes = RRModesForScreen(gpuscreen, &num_modes);  \
    303     if (!modes)                                       \
    304         return BadAlloc;                              \
    305     for (j = 0; j < num_modes; j++)                   \
    306         total_name_len += modes[j]->mode.nameLength;  \
    307     total_modes += num_modes;                         \
    308     free(modes);                                      \
    309 } while(0)
    310 
    311 static inline void swap_modeinfos(xRRModeInfo *modeinfos, int i)
    312 {
    313     swapl(&modeinfos[i].id);
    314     swaps(&modeinfos[i].width);
    315     swaps(&modeinfos[i].height);
    316     swapl(&modeinfos[i].dotClock);
    317     swaps(&modeinfos[i].hSyncStart);
    318     swaps(&modeinfos[i].hSyncEnd);
    319     swaps(&modeinfos[i].hTotal);
    320     swaps(&modeinfos[i].hSkew);
    321     swaps(&modeinfos[i].vSyncStart);
    322     swaps(&modeinfos[i].vSyncEnd);
    323     swaps(&modeinfos[i].vTotal);
    324     swaps(&modeinfos[i].nameLength);
    325     swapl(&modeinfos[i].modeFlags);
    326 }
    327 
    328 #define update_arrays(gpuscreen, pScrPriv, primary_crtc, has_primary) do {            \
    329     for (j = 0; j < pScrPriv->numCrtcs; j++) {             \
    330         if (has_primary && \
    331             primary_crtc == pScrPriv->crtcs[j]) { \
    332             has_primary = 0;   \
    333             continue; \
    334         }\
    335         crtcs[crtc_count] = pScrPriv->crtcs[j]->id;        \
    336         if (client->swapped)                               \
    337             swapl(&crtcs[crtc_count]);                     \
    338         crtc_count++;                                      \
    339     }                                                      \
    340     for (j = 0; j < pScrPriv->numOutputs; j++) {           \
    341         outputs[output_count] = pScrPriv->outputs[j]->id;  \
    342         if (client->swapped)                               \
    343             swapl(&outputs[output_count]);                 \
    344         output_count++;                                    \
    345     }                                                      \
    346     {                                                      \
    347         RRModePtr mode;                                    \
    348         modes = RRModesForScreen(gpuscreen, &num_modes);   \
    349         for (j = 0; j < num_modes; j++) {                  \
    350             mode = modes[j];                               \
    351             modeinfos[mode_count] = mode->mode;            \
    352             if (client->swapped) {                         \
    353                 swap_modeinfos(modeinfos, mode_count);     \
    354             }                                              \
    355             memcpy(names, mode->name, mode->mode.nameLength); \
    356             names += mode->mode.nameLength;                \
    357             mode_count++;                                  \
    358         }                                                  \
    359         free(modes);                                       \
    360     }                                                      \
    361     } while (0)
    362 
    363 static int
    364 rrGetMultiScreenResources(ClientPtr client, Bool query, ScreenPtr pScreen)
    365 {
    366     int j;
    367     int total_crtcs, total_outputs, total_modes, total_name_len;
    368     int crtc_count, output_count, mode_count;
    369     ScreenPtr iter;
    370     rrScrPrivPtr pScrPriv;
    371     int num_modes;
    372     RRModePtr *modes;
    373     xRRGetScreenResourcesReply rep;
    374     unsigned long extraLen;
    375     CARD8 *extra;
    376     RRCrtc *crtcs;
    377     RRCrtcPtr primary_crtc = NULL;
    378     RROutput *outputs;
    379     xRRModeInfo *modeinfos;
    380     CARD8 *names;
    381     int has_primary = 0;
    382 
    383     /* we need to iterate all the GPU primarys and all their output secondarys */
    384     total_crtcs = 0;
    385     total_outputs = 0;
    386     total_modes = 0;
    387     total_name_len = 0;
    388 
    389     pScrPriv = rrGetScrPriv(pScreen);
    390 
    391     if (query && pScrPriv)
    392         if (!RRGetInfo(pScreen, query))
    393             return BadAlloc;
    394 
    395     update_totals(pScreen, pScrPriv);
    396 
    397     xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
    398         if (!iter->is_output_secondary)
    399             continue;
    400 
    401         pScrPriv = rrGetScrPriv(iter);
    402 
    403         if (query)
    404           if (!RRGetInfo(iter, query))
    405             return BadAlloc;
    406         update_totals(iter, pScrPriv);
    407     }
    408 
    409     pScrPriv = rrGetScrPriv(pScreen);
    410     rep = (xRRGetScreenResourcesReply) {
    411         .type = X_Reply,
    412         .sequenceNumber = client->sequence,
    413         .length = 0,
    414         .timestamp = pScrPriv->lastSetTime.milliseconds,
    415         .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
    416         .nCrtcs = total_crtcs,
    417         .nOutputs = total_outputs,
    418         .nModes = total_modes,
    419         .nbytesNames = total_name_len
    420     };
    421 
    422     rep.length = (total_crtcs + total_outputs +
    423                   total_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
    424                   bytes_to_int32(total_name_len));
    425 
    426     extraLen = rep.length << 2;
    427     if (extraLen) {
    428         extra = malloc(extraLen);
    429         if (!extra) {
    430             return BadAlloc;
    431         }
    432     }
    433     else
    434         extra = NULL;
    435 
    436     crtcs = (RRCrtc *)extra;
    437     outputs = (RROutput *)(crtcs + total_crtcs);
    438     modeinfos = (xRRModeInfo *)(outputs + total_outputs);
    439     names = (CARD8 *)(modeinfos + total_modes);
    440 
    441     crtc_count = 0;
    442     output_count = 0;
    443     mode_count = 0;
    444 
    445     pScrPriv = rrGetScrPriv(pScreen);
    446     if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
    447         has_primary = 1;
    448         primary_crtc = pScrPriv->primaryOutput->crtc;
    449         crtcs[0] = pScrPriv->primaryOutput->crtc->id;
    450         if (client->swapped)
    451             swapl(&crtcs[0]);
    452         crtc_count = 1;
    453     }
    454     update_arrays(pScreen, pScrPriv, primary_crtc, has_primary);
    455 
    456     xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
    457         if (!iter->is_output_secondary)
    458             continue;
    459 
    460         pScrPriv = rrGetScrPriv(iter);
    461 
    462         update_arrays(iter, pScrPriv, primary_crtc, has_primary);
    463     }
    464 
    465     assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
    466     if (client->swapped) {
    467         swaps(&rep.sequenceNumber);
    468         swapl(&rep.length);
    469         swapl(&rep.timestamp);
    470         swapl(&rep.configTimestamp);
    471         swaps(&rep.nCrtcs);
    472         swaps(&rep.nOutputs);
    473         swaps(&rep.nModes);
    474         swaps(&rep.nbytesNames);
    475     }
    476     WriteToClient(client, sizeof(xRRGetScreenResourcesReply), &rep);
    477     if (extraLen) {
    478         WriteToClient(client, extraLen, extra);
    479         free(extra);
    480     }
    481     return Success;
    482 }
    483 
    484 static int
    485 rrGetScreenResources(ClientPtr client, Bool query)
    486 {
    487     REQUEST(xRRGetScreenResourcesReq);
    488     xRRGetScreenResourcesReply rep;
    489     WindowPtr pWin;
    490     ScreenPtr pScreen;
    491     rrScrPrivPtr pScrPriv;
    492     CARD8 *extra;
    493     unsigned long extraLen;
    494     int i, rc, has_primary = 0;
    495     RRCrtc *crtcs;
    496     RROutput *outputs;
    497     xRRModeInfo *modeinfos;
    498     CARD8 *names;
    499 
    500     REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
    501     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    502     if (rc != Success)
    503         return rc;
    504 
    505     pScreen = pWin->drawable.pScreen;
    506     pScrPriv = rrGetScrPriv(pScreen);
    507 
    508     if (query && pScrPriv)
    509         if (!RRGetInfo(pScreen, query))
    510             return BadAlloc;
    511 
    512     if (pScreen->output_secondarys)
    513         return rrGetMultiScreenResources(client, query, pScreen);
    514 
    515     if (!pScrPriv) {
    516         rep = (xRRGetScreenResourcesReply) {
    517             .type = X_Reply,
    518             .sequenceNumber = client->sequence,
    519             .length = 0,
    520             .timestamp = currentTime.milliseconds,
    521             .configTimestamp = currentTime.milliseconds,
    522             .nCrtcs = 0,
    523             .nOutputs = 0,
    524             .nModes = 0,
    525             .nbytesNames = 0
    526         };
    527         extra = NULL;
    528         extraLen = 0;
    529     }
    530     else {
    531         RRModePtr *modes;
    532         int num_modes;
    533 
    534         modes = RRModesForScreen(pScreen, &num_modes);
    535         if (!modes)
    536             return BadAlloc;
    537 
    538         rep = (xRRGetScreenResourcesReply) {
    539             .type = X_Reply,
    540             .sequenceNumber = client->sequence,
    541             .length = 0,
    542             .timestamp = pScrPriv->lastSetTime.milliseconds,
    543             .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
    544             .nCrtcs = pScrPriv->numCrtcs,
    545             .nOutputs = pScrPriv->numOutputs,
    546             .nModes = num_modes,
    547             .nbytesNames = 0
    548         };
    549 
    550 
    551         for (i = 0; i < num_modes; i++)
    552             rep.nbytesNames += modes[i]->mode.nameLength;
    553 
    554         rep.length = (pScrPriv->numCrtcs +
    555                       pScrPriv->numOutputs +
    556                       num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
    557                       bytes_to_int32(rep.nbytesNames));
    558 
    559         extraLen = rep.length << 2;
    560         if (extraLen) {
    561             extra = calloc(1, extraLen);
    562             if (!extra) {
    563                 free(modes);
    564                 return BadAlloc;
    565             }
    566         }
    567         else
    568             extra = NULL;
    569 
    570         crtcs = (RRCrtc *) extra;
    571         outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs);
    572         modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs);
    573         names = (CARD8 *) (modeinfos + num_modes);
    574 
    575         if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
    576             has_primary = 1;
    577             crtcs[0] = pScrPriv->primaryOutput->crtc->id;
    578             if (client->swapped)
    579                 swapl(&crtcs[0]);
    580         }
    581 
    582         for (i = 0; i < pScrPriv->numCrtcs; i++) {
    583             if (has_primary &&
    584                 pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) {
    585                 has_primary = 0;
    586                 continue;
    587             }
    588             crtcs[i + has_primary] = pScrPriv->crtcs[i]->id;
    589             if (client->swapped)
    590                 swapl(&crtcs[i + has_primary]);
    591         }
    592 
    593         for (i = 0; i < pScrPriv->numOutputs; i++) {
    594             outputs[i] = pScrPriv->outputs[i]->id;
    595             if (client->swapped)
    596                 swapl(&outputs[i]);
    597         }
    598 
    599         for (i = 0; i < num_modes; i++) {
    600             RRModePtr mode = modes[i];
    601 
    602             modeinfos[i] = mode->mode;
    603             if (client->swapped) {
    604                 swapl(&modeinfos[i].id);
    605                 swaps(&modeinfos[i].width);
    606                 swaps(&modeinfos[i].height);
    607                 swapl(&modeinfos[i].dotClock);
    608                 swaps(&modeinfos[i].hSyncStart);
    609                 swaps(&modeinfos[i].hSyncEnd);
    610                 swaps(&modeinfos[i].hTotal);
    611                 swaps(&modeinfos[i].hSkew);
    612                 swaps(&modeinfos[i].vSyncStart);
    613                 swaps(&modeinfos[i].vSyncEnd);
    614                 swaps(&modeinfos[i].vTotal);
    615                 swaps(&modeinfos[i].nameLength);
    616                 swapl(&modeinfos[i].modeFlags);
    617             }
    618             memcpy(names, mode->name, mode->mode.nameLength);
    619             names += mode->mode.nameLength;
    620         }
    621         free(modes);
    622         assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
    623     }
    624 
    625     if (client->swapped) {
    626         swaps(&rep.sequenceNumber);
    627         swapl(&rep.length);
    628         swapl(&rep.timestamp);
    629         swapl(&rep.configTimestamp);
    630         swaps(&rep.nCrtcs);
    631         swaps(&rep.nOutputs);
    632         swaps(&rep.nModes);
    633         swaps(&rep.nbytesNames);
    634     }
    635     WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *) &rep);
    636     if (extraLen) {
    637         WriteToClient(client, extraLen, (char *) extra);
    638         free(extra);
    639     }
    640     return Success;
    641 }
    642 
    643 int
    644 ProcRRGetScreenResources(ClientPtr client)
    645 {
    646     return rrGetScreenResources(client, TRUE);
    647 }
    648 
    649 int
    650 ProcRRGetScreenResourcesCurrent(ClientPtr client)
    651 {
    652     return rrGetScreenResources(client, FALSE);
    653 }
    654 
    655 typedef struct _RR10Data {
    656     RRScreenSizePtr sizes;
    657     int nsize;
    658     int nrefresh;
    659     int size;
    660     CARD16 refresh;
    661 } RR10DataRec, *RR10DataPtr;
    662 
    663 /*
    664  * Convert 1.2 monitor data into 1.0 screen data
    665  */
    666 static RR10DataPtr
    667 RR10GetData(ScreenPtr pScreen, RROutputPtr output)
    668 {
    669     RR10DataPtr data;
    670     RRScreenSizePtr size;
    671     int nmode = output->numModes + output->numUserModes;
    672     int o, os, l, r;
    673     RRScreenRatePtr refresh;
    674     CARD16 vRefresh;
    675     RRModePtr mode;
    676     Bool *used;
    677 
    678     /* Make sure there is plenty of space for any combination */
    679     data = malloc(sizeof(RR10DataRec) +
    680                   sizeof(RRScreenSize) * nmode +
    681                   sizeof(RRScreenRate) * nmode + sizeof(Bool) * nmode);
    682     if (!data)
    683         return NULL;
    684     size = (RRScreenSizePtr) (data + 1);
    685     refresh = (RRScreenRatePtr) (size + nmode);
    686     used = (Bool *) (refresh + nmode);
    687     memset(used, '\0', sizeof(Bool) * nmode);
    688     data->sizes = size;
    689     data->nsize = 0;
    690     data->nrefresh = 0;
    691     data->size = 0;
    692     data->refresh = 0;
    693 
    694     /*
    695      * find modes not yet listed
    696      */
    697     for (o = 0; o < output->numModes + output->numUserModes; o++) {
    698         if (used[o])
    699             continue;
    700 
    701         if (o < output->numModes)
    702             mode = output->modes[o];
    703         else
    704             mode = output->userModes[o - output->numModes];
    705 
    706         l = data->nsize;
    707         size[l].id = data->nsize;
    708         size[l].width = mode->mode.width;
    709         size[l].height = mode->mode.height;
    710         if (output->mmWidth && output->mmHeight) {
    711             size[l].mmWidth = output->mmWidth;
    712             size[l].mmHeight = output->mmHeight;
    713         }
    714         else {
    715             size[l].mmWidth = pScreen->mmWidth;
    716             size[l].mmHeight = pScreen->mmHeight;
    717         }
    718         size[l].nRates = 0;
    719         size[l].pRates = &refresh[data->nrefresh];
    720         data->nsize++;
    721 
    722         /*
    723          * Find all modes with matching size
    724          */
    725         for (os = o; os < output->numModes + output->numUserModes; os++) {
    726             if (os < output->numModes)
    727                 mode = output->modes[os];
    728             else
    729                 mode = output->userModes[os - output->numModes];
    730             if (mode->mode.width == size[l].width &&
    731                 mode->mode.height == size[l].height) {
    732                 vRefresh = RRVerticalRefresh(&mode->mode);
    733                 used[os] = TRUE;
    734 
    735                 for (r = 0; r < size[l].nRates; r++)
    736                     if (vRefresh == size[l].pRates[r].rate)
    737                         break;
    738                 if (r == size[l].nRates) {
    739                     size[l].pRates[r].rate = vRefresh;
    740                     size[l].pRates[r].mode = mode;
    741                     size[l].nRates++;
    742                     data->nrefresh++;
    743                 }
    744                 if (mode == output->crtc->mode) {
    745                     data->size = l;
    746                     data->refresh = vRefresh;
    747                 }
    748             }
    749         }
    750     }
    751     return data;
    752 }
    753 
    754 int
    755 ProcRRGetScreenInfo(ClientPtr client)
    756 {
    757     REQUEST(xRRGetScreenInfoReq);
    758     xRRGetScreenInfoReply rep;
    759     WindowPtr pWin;
    760     int rc;
    761     ScreenPtr pScreen;
    762     rrScrPrivPtr pScrPriv;
    763     CARD8 *extra;
    764     unsigned long extraLen;
    765     RROutputPtr output;
    766 
    767     REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
    768     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
    769     if (rc != Success)
    770         return rc;
    771 
    772     pScreen = pWin->drawable.pScreen;
    773     pScrPriv = rrGetScrPriv(pScreen);
    774 
    775     if (pScrPriv)
    776         if (!RRGetInfo(pScreen, TRUE))
    777             return BadAlloc;
    778 
    779     output = RRFirstOutput(pScreen);
    780 
    781     if (!pScrPriv || !output) {
    782         rep = (xRRGetScreenInfoReply) {
    783             .type = X_Reply,
    784             .setOfRotations = RR_Rotate_0,
    785             .sequenceNumber = client->sequence,
    786             .length = 0,
    787             .root = pWin->drawable.pScreen->root->drawable.id,
    788             .timestamp = currentTime.milliseconds,
    789             .configTimestamp = currentTime.milliseconds,
    790             .nSizes = 0,
    791             .sizeID = 0,
    792             .rotation = RR_Rotate_0,
    793             .rate = 0,
    794             .nrateEnts = 0
    795         };
    796         extra = 0;
    797         extraLen = 0;
    798     }
    799     else {
    800         int i, j;
    801         xScreenSizes *size;
    802         CARD16 *rates;
    803         CARD8 *data8;
    804         Bool has_rate = RRClientKnowsRates(client);
    805         RR10DataPtr pData;
    806         RRScreenSizePtr pSize;
    807 
    808         pData = RR10GetData(pScreen, output);
    809         if (!pData)
    810             return BadAlloc;
    811 
    812         rep = (xRRGetScreenInfoReply) {
    813             .type = X_Reply,
    814             .setOfRotations = output->crtc->rotations,
    815             .sequenceNumber = client->sequence,
    816             .length = 0,
    817             .root = pWin->drawable.pScreen->root->drawable.id,
    818             .timestamp = pScrPriv->lastSetTime.milliseconds,
    819             .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
    820             .rotation = output->crtc->rotation,
    821             .nSizes = pData->nsize,
    822             .nrateEnts = pData->nrefresh + pData->nsize,
    823             .sizeID = pData->size,
    824             .rate = pData->refresh
    825         };
    826 
    827         extraLen = rep.nSizes * sizeof(xScreenSizes);
    828         if (has_rate)
    829             extraLen += rep.nrateEnts * sizeof(CARD16);
    830 
    831         if (extraLen) {
    832             extra = (CARD8 *) malloc(extraLen);
    833             if (!extra) {
    834                 free(pData);
    835                 return BadAlloc;
    836             }
    837         }
    838         else
    839             extra = NULL;
    840 
    841         /*
    842          * First comes the size information
    843          */
    844         size = (xScreenSizes *) extra;
    845         rates = (CARD16 *) (size + rep.nSizes);
    846         for (i = 0; i < pData->nsize; i++) {
    847             pSize = &pData->sizes[i];
    848             size->widthInPixels = pSize->width;
    849             size->heightInPixels = pSize->height;
    850             size->widthInMillimeters = pSize->mmWidth;
    851             size->heightInMillimeters = pSize->mmHeight;
    852             if (client->swapped) {
    853                 swaps(&size->widthInPixels);
    854                 swaps(&size->heightInPixels);
    855                 swaps(&size->widthInMillimeters);
    856                 swaps(&size->heightInMillimeters);
    857             }
    858             size++;
    859             if (has_rate) {
    860                 *rates = pSize->nRates;
    861                 if (client->swapped) {
    862                     swaps(rates);
    863                 }
    864                 rates++;
    865                 for (j = 0; j < pSize->nRates; j++) {
    866                     *rates = pSize->pRates[j].rate;
    867                     if (client->swapped) {
    868                         swaps(rates);
    869                     }
    870                     rates++;
    871                 }
    872             }
    873         }
    874         free(pData);
    875 
    876         data8 = (CARD8 *) rates;
    877 
    878         if (data8 - (CARD8 *) extra != extraLen)
    879             FatalError("RRGetScreenInfo bad extra len %ld != %ld\n",
    880                        (unsigned long) (data8 - (CARD8 *) extra), extraLen);
    881         rep.length = bytes_to_int32(extraLen);
    882     }
    883     if (client->swapped) {
    884         swaps(&rep.sequenceNumber);
    885         swapl(&rep.length);
    886         swapl(&rep.timestamp);
    887         swapl(&rep.configTimestamp);
    888         swaps(&rep.rotation);
    889         swaps(&rep.nSizes);
    890         swaps(&rep.sizeID);
    891         swaps(&rep.rate);
    892         swaps(&rep.nrateEnts);
    893     }
    894     WriteToClient(client, sizeof(xRRGetScreenInfoReply), &rep);
    895     if (extraLen) {
    896         WriteToClient(client, extraLen, extra);
    897         free(extra);
    898     }
    899     return Success;
    900 }
    901 
    902 int
    903 ProcRRSetScreenConfig(ClientPtr client)
    904 {
    905     REQUEST(xRRSetScreenConfigReq);
    906     xRRSetScreenConfigReply rep;
    907     DrawablePtr pDraw;
    908     int rc;
    909     ScreenPtr pScreen;
    910     rrScrPrivPtr pScrPriv;
    911     TimeStamp time;
    912     int i;
    913     Rotation rotation;
    914     int rate;
    915     Bool has_rate;
    916     CARD8 status;
    917     RROutputPtr output;
    918     RRCrtcPtr crtc;
    919     RRModePtr mode;
    920     RR10DataPtr pData = NULL;
    921     RRScreenSizePtr pSize;
    922     int width, height;
    923 
    924     UpdateCurrentTime();
    925 
    926     if (RRClientKnowsRates(client)) {
    927         REQUEST_SIZE_MATCH(xRRSetScreenConfigReq);
    928         has_rate = TRUE;
    929     }
    930     else {
    931         REQUEST_SIZE_MATCH(xRR1_0SetScreenConfigReq);
    932         has_rate = FALSE;
    933     }
    934 
    935     rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
    936     if (rc != Success)
    937         return rc;
    938 
    939     pScreen = pDraw->pScreen;
    940 
    941     pScrPriv = rrGetScrPriv(pScreen);
    942 
    943     time = ClientTimeToServerTime(stuff->timestamp);
    944 
    945     if (!pScrPriv) {
    946         time = currentTime;
    947         status = RRSetConfigFailed;
    948         goto sendReply;
    949     }
    950     if (!RRGetInfo(pScreen, FALSE))
    951         return BadAlloc;
    952 
    953     output = RRFirstOutput(pScreen);
    954     if (!output) {
    955         time = currentTime;
    956         status = RRSetConfigFailed;
    957         goto sendReply;
    958     }
    959 
    960     crtc = output->crtc;
    961 
    962     /*
    963      * If the client's config timestamp is not the same as the last config
    964      * timestamp, then the config information isn't up-to-date and
    965      * can't even be validated.
    966      *
    967      * Note that the client only knows about the milliseconds part of the
    968      * timestamp, so using CompareTimeStamps here would cause randr to suddenly
    969      * stop working after several hours have passed (freedesktop bug #6502).
    970      */
    971     if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds) {
    972         status = RRSetConfigInvalidConfigTime;
    973         goto sendReply;
    974     }
    975 
    976     pData = RR10GetData(pScreen, output);
    977     if (!pData)
    978         return BadAlloc;
    979 
    980     if (stuff->sizeID >= pData->nsize) {
    981         /*
    982          * Invalid size ID
    983          */
    984         client->errorValue = stuff->sizeID;
    985         free(pData);
    986         return BadValue;
    987     }
    988     pSize = &pData->sizes[stuff->sizeID];
    989 
    990     /*
    991      * Validate requested rotation
    992      */
    993     rotation = (Rotation) stuff->rotation;
    994 
    995     /* test the rotation bits only! */
    996     switch (rotation & 0xf) {
    997     case RR_Rotate_0:
    998     case RR_Rotate_90:
    999     case RR_Rotate_180:
   1000     case RR_Rotate_270:
   1001         break;
   1002     default:
   1003         /*
   1004          * Invalid rotation
   1005          */
   1006         client->errorValue = stuff->rotation;
   1007         free(pData);
   1008         return BadValue;
   1009     }
   1010 
   1011     if ((~crtc->rotations) & rotation) {
   1012         /*
   1013          * requested rotation or reflection not supported by screen
   1014          */
   1015         client->errorValue = stuff->rotation;
   1016         free(pData);
   1017         return BadMatch;
   1018     }
   1019 
   1020     /*
   1021      * Validate requested refresh
   1022      */
   1023     if (has_rate)
   1024         rate = (int) stuff->rate;
   1025     else
   1026         rate = 0;
   1027 
   1028     if (rate) {
   1029         for (i = 0; i < pSize->nRates; i++) {
   1030             if (pSize->pRates[i].rate == rate)
   1031                 break;
   1032         }
   1033         if (i == pSize->nRates) {
   1034             /*
   1035              * Invalid rate
   1036              */
   1037             client->errorValue = rate;
   1038             free(pData);
   1039             return BadValue;
   1040         }
   1041         mode = pSize->pRates[i].mode;
   1042     }
   1043     else
   1044         mode = pSize->pRates[0].mode;
   1045 
   1046     /*
   1047      * Make sure the requested set-time is not older than
   1048      * the last set-time
   1049      */
   1050     if (CompareTimeStamps(time, pScrPriv->lastSetTime) < 0) {
   1051         status = RRSetConfigInvalidTime;
   1052         goto sendReply;
   1053     }
   1054 
   1055     /*
   1056      * If the screen size is changing, adjust all of the other outputs
   1057      * to fit the new size, mirroring as much as possible
   1058      */
   1059     width = mode->mode.width;
   1060     height = mode->mode.height;
   1061     if (width < pScrPriv->minWidth || pScrPriv->maxWidth < width) {
   1062         client->errorValue = width;
   1063         free(pData);
   1064         return BadValue;
   1065     }
   1066     if (height < pScrPriv->minHeight || pScrPriv->maxHeight < height) {
   1067         client->errorValue = height;
   1068         free(pData);
   1069         return BadValue;
   1070     }
   1071 
   1072     if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
   1073         width = mode->mode.height;
   1074         height = mode->mode.width;
   1075     }
   1076 
   1077     if (width != pScreen->width || height != pScreen->height) {
   1078         int c;
   1079 
   1080         for (c = 0; c < pScrPriv->numCrtcs; c++) {
   1081             if (!RRCrtcSet(pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
   1082                            0, NULL)) {
   1083                 status = RRSetConfigFailed;
   1084                 /* XXX recover from failure */
   1085                 goto sendReply;
   1086             }
   1087         }
   1088         if (!RRScreenSizeSet(pScreen, width, height,
   1089                              pScreen->mmWidth, pScreen->mmHeight)) {
   1090             status = RRSetConfigFailed;
   1091             /* XXX recover from failure */
   1092             goto sendReply;
   1093         }
   1094     }
   1095 
   1096     if (!RRCrtcSet(crtc, mode, 0, 0, stuff->rotation, 1, &output))
   1097         status = RRSetConfigFailed;
   1098     else {
   1099         pScrPriv->lastSetTime = time;
   1100         status = RRSetConfigSuccess;
   1101     }
   1102 
   1103     /*
   1104      * XXX Configure other crtcs to mirror as much as possible
   1105      */
   1106 
   1107  sendReply:
   1108 
   1109     free(pData);
   1110 
   1111     rep = (xRRSetScreenConfigReply) {
   1112         .type = X_Reply,
   1113         .status = status,
   1114         .sequenceNumber = client->sequence,
   1115         .length = 0,
   1116 
   1117         .newTimestamp = pScrPriv->lastSetTime.milliseconds,
   1118         .newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds,
   1119         .root = pDraw->pScreen->root->drawable.id,
   1120         /* .subpixelOrder = ?? */
   1121     };
   1122 
   1123     if (client->swapped) {
   1124         swaps(&rep.sequenceNumber);
   1125         swapl(&rep.length);
   1126         swapl(&rep.newTimestamp);
   1127         swapl(&rep.newConfigTimestamp);
   1128         swapl(&rep.root);
   1129     }
   1130     WriteToClient(client, sizeof(xRRSetScreenConfigReply), &rep);
   1131 
   1132     return Success;
   1133 }
   1134 
   1135 static CARD16
   1136 RR10CurrentSizeID(ScreenPtr pScreen)
   1137 {
   1138     CARD16 sizeID = 0xffff;
   1139     RROutputPtr output = RRFirstOutput(pScreen);
   1140 
   1141     if (output) {
   1142         RR10DataPtr data = RR10GetData(pScreen, output);
   1143 
   1144         if (data) {
   1145             int i;
   1146 
   1147             for (i = 0; i < data->nsize; i++)
   1148                 if (data->sizes[i].width == pScreen->width &&
   1149                     data->sizes[i].height == pScreen->height) {
   1150                     sizeID = (CARD16) i;
   1151                     break;
   1152                 }
   1153             free(data);
   1154         }
   1155     }
   1156     return sizeID;
   1157 }