xserver

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

randr.c (22208B)


      1 /*
      2  * Copyright © 2000 Compaq Computer Corporation
      3  * Copyright © 2002 Hewlett-Packard Company
      4  * Copyright © 2006 Intel Corporation
      5  * Copyright © 2017 Keith Packard
      6  *
      7  * Permission to use, copy, modify, distribute, and sell this software and its
      8  * documentation for any purpose is hereby granted without fee, provided that
      9  * the above copyright notice appear in all copies and that both that copyright
     10  * notice and this permission notice appear in supporting documentation, and
     11  * that the name of the copyright holders not be used in advertising or
     12  * publicity pertaining to distribution of the software without specific,
     13  * written prior permission.  The copyright holders make no representations
     14  * about the suitability of this software for any purpose.  It is provided "as
     15  * is" without express or implied warranty.
     16  *
     17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     19  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     23  * OF THIS SOFTWARE.
     24  *
     25  * Author:  Jim Gettys, Hewlett-Packard Company, Inc.
     26  *	    Keith Packard, Intel Corporation
     27  */
     28 
     29 #ifdef HAVE_DIX_CONFIG_H
     30 #include <dix-config.h>
     31 #endif
     32 
     33 #include "randrstr.h"
     34 #include "extinit.h"
     35 
     36 /* From render.h */
     37 #ifndef SubPixelUnknown
     38 #define SubPixelUnknown 0
     39 #endif
     40 
     41 #define RR_VALIDATE
     42 static int RRNScreens;
     43 
     44 #define wrap(priv,real,mem,func) {\
     45     priv->mem = real->mem; \
     46     real->mem = func; \
     47 }
     48 
     49 #define unwrap(priv,real,mem) {\
     50     real->mem = priv->mem; \
     51 }
     52 
     53 static int ProcRRDispatch(ClientPtr pClient);
     54 static int SProcRRDispatch(ClientPtr pClient);
     55 
     56 int RREventBase;
     57 int RRErrorBase;
     58 RESTYPE RRClientType, RREventType;      /* resource types for event masks */
     59 DevPrivateKeyRec RRClientPrivateKeyRec;
     60 
     61 DevPrivateKeyRec rrPrivKeyRec;
     62 
     63 static void
     64 RRClientCallback(CallbackListPtr *list, void *closure, void *data)
     65 {
     66     NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
     67     ClientPtr pClient = clientinfo->client;
     68 
     69     rrClientPriv(pClient);
     70     RRTimesPtr pTimes = (RRTimesPtr) (pRRClient + 1);
     71     int i;
     72 
     73     pRRClient->major_version = 0;
     74     pRRClient->minor_version = 0;
     75     for (i = 0; i < screenInfo.numScreens; i++) {
     76         ScreenPtr pScreen = screenInfo.screens[i];
     77 
     78         rrScrPriv(pScreen);
     79 
     80         if (pScrPriv) {
     81             pTimes[i].setTime = pScrPriv->lastSetTime;
     82             pTimes[i].configTime = pScrPriv->lastConfigTime;
     83         }
     84     }
     85 }
     86 
     87 static Bool
     88 RRCloseScreen(ScreenPtr pScreen)
     89 {
     90     rrScrPriv(pScreen);
     91     int j;
     92     RRLeasePtr lease, next;
     93 
     94     unwrap(pScrPriv, pScreen, CloseScreen);
     95 
     96     xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list)
     97         RRTerminateLease(lease);
     98     for (j = pScrPriv->numCrtcs - 1; j >= 0; j--)
     99         RRCrtcDestroy(pScrPriv->crtcs[j]);
    100     for (j = pScrPriv->numOutputs - 1; j >= 0; j--)
    101         RROutputDestroy(pScrPriv->outputs[j]);
    102 
    103     if (pScrPriv->provider)
    104         RRProviderDestroy(pScrPriv->provider);
    105 
    106     RRMonitorClose(pScreen);
    107 
    108     free(pScrPriv->crtcs);
    109     free(pScrPriv->outputs);
    110     free(pScrPriv);
    111     RRNScreens -= 1;            /* ok, one fewer screen with RandR running */
    112     return (*pScreen->CloseScreen) (pScreen);
    113 }
    114 
    115 static void
    116 SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent * from,
    117                            xRRScreenChangeNotifyEvent * to)
    118 {
    119     to->type = from->type;
    120     to->rotation = from->rotation;
    121     cpswaps(from->sequenceNumber, to->sequenceNumber);
    122     cpswapl(from->timestamp, to->timestamp);
    123     cpswapl(from->configTimestamp, to->configTimestamp);
    124     cpswapl(from->root, to->root);
    125     cpswapl(from->window, to->window);
    126     cpswaps(from->sizeID, to->sizeID);
    127     cpswaps(from->subpixelOrder, to->subpixelOrder);
    128     cpswaps(from->widthInPixels, to->widthInPixels);
    129     cpswaps(from->heightInPixels, to->heightInPixels);
    130     cpswaps(from->widthInMillimeters, to->widthInMillimeters);
    131     cpswaps(from->heightInMillimeters, to->heightInMillimeters);
    132 }
    133 
    134 static void
    135 SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent * from,
    136                          xRRCrtcChangeNotifyEvent * to)
    137 {
    138     to->type = from->type;
    139     to->subCode = from->subCode;
    140     cpswaps(from->sequenceNumber, to->sequenceNumber);
    141     cpswapl(from->timestamp, to->timestamp);
    142     cpswapl(from->window, to->window);
    143     cpswapl(from->crtc, to->crtc);
    144     cpswapl(from->mode, to->mode);
    145     cpswaps(from->rotation, to->rotation);
    146     /* pad1 */
    147     cpswaps(from->x, to->x);
    148     cpswaps(from->y, to->y);
    149     cpswaps(from->width, to->width);
    150     cpswaps(from->height, to->height);
    151 }
    152 
    153 static void
    154 SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent * from,
    155                            xRROutputChangeNotifyEvent * to)
    156 {
    157     to->type = from->type;
    158     to->subCode = from->subCode;
    159     cpswaps(from->sequenceNumber, to->sequenceNumber);
    160     cpswapl(from->timestamp, to->timestamp);
    161     cpswapl(from->configTimestamp, to->configTimestamp);
    162     cpswapl(from->window, to->window);
    163     cpswapl(from->output, to->output);
    164     cpswapl(from->crtc, to->crtc);
    165     cpswapl(from->mode, to->mode);
    166     cpswaps(from->rotation, to->rotation);
    167     to->connection = from->connection;
    168     to->subpixelOrder = from->subpixelOrder;
    169 }
    170 
    171 static void
    172 SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent * from,
    173                              xRROutputPropertyNotifyEvent * to)
    174 {
    175     to->type = from->type;
    176     to->subCode = from->subCode;
    177     cpswaps(from->sequenceNumber, to->sequenceNumber);
    178     cpswapl(from->window, to->window);
    179     cpswapl(from->output, to->output);
    180     cpswapl(from->atom, to->atom);
    181     cpswapl(from->timestamp, to->timestamp);
    182     to->state = from->state;
    183     /* pad1 */
    184     /* pad2 */
    185     /* pad3 */
    186     /* pad4 */
    187 }
    188 
    189 static void
    190 SRRProviderChangeNotifyEvent(xRRProviderChangeNotifyEvent * from,
    191                          xRRProviderChangeNotifyEvent * to)
    192 {
    193     to->type = from->type;
    194     to->subCode = from->subCode;
    195     cpswaps(from->sequenceNumber, to->sequenceNumber);
    196     cpswapl(from->timestamp, to->timestamp);
    197     cpswapl(from->window, to->window);
    198     cpswapl(from->provider, to->provider);
    199 }
    200 
    201 static void
    202 SRRProviderPropertyNotifyEvent(xRRProviderPropertyNotifyEvent * from,
    203                                xRRProviderPropertyNotifyEvent * to)
    204 {
    205     to->type = from->type;
    206     to->subCode = from->subCode;
    207     cpswaps(from->sequenceNumber, to->sequenceNumber);
    208     cpswapl(from->window, to->window);
    209     cpswapl(from->provider, to->provider);
    210     cpswapl(from->atom, to->atom);
    211     cpswapl(from->timestamp, to->timestamp);
    212     to->state = from->state;
    213     /* pad1 */
    214     /* pad2 */
    215     /* pad3 */
    216     /* pad4 */
    217 }
    218 
    219 static void _X_COLD
    220 SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from,
    221                              xRRResourceChangeNotifyEvent * to)
    222 {
    223     to->type = from->type;
    224     to->subCode = from->subCode;
    225     cpswaps(from->sequenceNumber, to->sequenceNumber);
    226     cpswapl(from->timestamp, to->timestamp);
    227     cpswapl(from->window, to->window);
    228 }
    229 
    230 static void _X_COLD
    231 SRRLeaseNotifyEvent(xRRLeaseNotifyEvent * from,
    232                     xRRLeaseNotifyEvent * to)
    233 {
    234     to->type = from->type;
    235     to->subCode = from->subCode;
    236     cpswaps(from->sequenceNumber, to->sequenceNumber);
    237     cpswapl(from->timestamp, to->timestamp);
    238     cpswapl(from->window, to->window);
    239     cpswapl(from->lease, to->lease);
    240     to->created = from->created;
    241 }
    242 
    243 static void _X_COLD
    244 SRRNotifyEvent(xEvent *from, xEvent *to)
    245 {
    246     switch (from->u.u.detail) {
    247     case RRNotify_CrtcChange:
    248         SRRCrtcChangeNotifyEvent((xRRCrtcChangeNotifyEvent *) from,
    249                                  (xRRCrtcChangeNotifyEvent *) to);
    250         break;
    251     case RRNotify_OutputChange:
    252         SRROutputChangeNotifyEvent((xRROutputChangeNotifyEvent *) from,
    253                                    (xRROutputChangeNotifyEvent *) to);
    254         break;
    255     case RRNotify_OutputProperty:
    256         SRROutputPropertyNotifyEvent((xRROutputPropertyNotifyEvent *) from,
    257                                      (xRROutputPropertyNotifyEvent *) to);
    258         break;
    259     case RRNotify_ProviderChange:
    260         SRRProviderChangeNotifyEvent((xRRProviderChangeNotifyEvent *) from,
    261                                    (xRRProviderChangeNotifyEvent *) to);
    262         break;
    263     case RRNotify_ProviderProperty:
    264         SRRProviderPropertyNotifyEvent((xRRProviderPropertyNotifyEvent *) from,
    265                                        (xRRProviderPropertyNotifyEvent *) to);
    266         break;
    267     case RRNotify_ResourceChange:
    268         SRRResourceChangeNotifyEvent((xRRResourceChangeNotifyEvent *) from,
    269                                    (xRRResourceChangeNotifyEvent *) to);
    270         break;
    271     case RRNotify_Lease:
    272         SRRLeaseNotifyEvent((xRRLeaseNotifyEvent *) from,
    273                             (xRRLeaseNotifyEvent *) to);
    274         break;
    275     default:
    276         break;
    277     }
    278 }
    279 
    280 static int RRGeneration;
    281 
    282 Bool
    283 RRInit(void)
    284 {
    285     if (RRGeneration != serverGeneration) {
    286         if (!RRModeInit())
    287             return FALSE;
    288         if (!RRCrtcInit())
    289             return FALSE;
    290         if (!RROutputInit())
    291             return FALSE;
    292         if (!RRProviderInit())
    293             return FALSE;
    294         if (!RRLeaseInit())
    295             return FALSE;
    296         RRGeneration = serverGeneration;
    297     }
    298     if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0))
    299         return FALSE;
    300 
    301     return TRUE;
    302 }
    303 
    304 Bool
    305 RRScreenInit(ScreenPtr pScreen)
    306 {
    307     rrScrPrivPtr pScrPriv;
    308 
    309     if (!RRInit())
    310         return FALSE;
    311 
    312     pScrPriv = (rrScrPrivPtr) calloc(1, sizeof(rrScrPrivRec));
    313     if (!pScrPriv)
    314         return FALSE;
    315 
    316     SetRRScreen(pScreen, pScrPriv);
    317 
    318     /*
    319      * Calling function best set these function vectors
    320      */
    321     pScrPriv->rrGetInfo = 0;
    322     pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width;
    323     pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height;
    324 
    325     pScrPriv->width = pScreen->width;
    326     pScrPriv->height = pScreen->height;
    327     pScrPriv->mmWidth = pScreen->mmWidth;
    328     pScrPriv->mmHeight = pScreen->mmHeight;
    329 #if RANDR_12_INTERFACE
    330     pScrPriv->rrScreenSetSize = NULL;
    331     pScrPriv->rrCrtcSet = NULL;
    332     pScrPriv->rrCrtcSetGamma = NULL;
    333 #endif
    334 #if RANDR_10_INTERFACE
    335     pScrPriv->rrSetConfig = 0;
    336     pScrPriv->rotations = RR_Rotate_0;
    337     pScrPriv->reqWidth = pScreen->width;
    338     pScrPriv->reqHeight = pScreen->height;
    339     pScrPriv->nSizes = 0;
    340     pScrPriv->pSizes = NULL;
    341     pScrPriv->rotation = RR_Rotate_0;
    342     pScrPriv->rate = 0;
    343     pScrPriv->size = 0;
    344 #endif
    345 
    346     /*
    347      * This value doesn't really matter -- any client must call
    348      * GetScreenInfo before reading it which will automatically update
    349      * the time
    350      */
    351     pScrPriv->lastSetTime = currentTime;
    352     pScrPriv->lastConfigTime = currentTime;
    353 
    354     wrap(pScrPriv, pScreen, CloseScreen, RRCloseScreen);
    355 
    356     pScreen->ConstrainCursorHarder = RRConstrainCursorHarder;
    357     pScreen->ReplaceScanoutPixmap = RRReplaceScanoutPixmap;
    358     pScrPriv->numOutputs = 0;
    359     pScrPriv->outputs = NULL;
    360     pScrPriv->numCrtcs = 0;
    361     pScrPriv->crtcs = NULL;
    362 
    363     xorg_list_init(&pScrPriv->leases);
    364 
    365     RRMonitorInit(pScreen);
    366 
    367     RRNScreens += 1;            /* keep count of screens that implement randr */
    368     return TRUE;
    369 }
    370 
    371  /*ARGSUSED*/ static int
    372 RRFreeClient(void *data, XID id)
    373 {
    374     RREventPtr pRREvent;
    375     WindowPtr pWin;
    376     RREventPtr *pHead, pCur, pPrev;
    377 
    378     pRREvent = (RREventPtr) data;
    379     pWin = pRREvent->window;
    380     dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
    381                             RREventType, serverClient, DixDestroyAccess);
    382     if (pHead) {
    383         pPrev = 0;
    384         for (pCur = *pHead; pCur && pCur != pRREvent; pCur = pCur->next)
    385             pPrev = pCur;
    386         if (pCur) {
    387             if (pPrev)
    388                 pPrev->next = pRREvent->next;
    389             else
    390                 *pHead = pRREvent->next;
    391         }
    392     }
    393     free((void *) pRREvent);
    394     return 1;
    395 }
    396 
    397  /*ARGSUSED*/ static int
    398 RRFreeEvents(void *data, XID id)
    399 {
    400     RREventPtr *pHead, pCur, pNext;
    401 
    402     pHead = (RREventPtr *) data;
    403     for (pCur = *pHead; pCur; pCur = pNext) {
    404         pNext = pCur->next;
    405         FreeResource(pCur->clientResource, RRClientType);
    406         free((void *) pCur);
    407     }
    408     free((void *) pHead);
    409     return 1;
    410 }
    411 
    412 void
    413 RRExtensionInit(void)
    414 {
    415     ExtensionEntry *extEntry;
    416 
    417     if (RRNScreens == 0)
    418         return;
    419 
    420     if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec, PRIVATE_CLIENT,
    421                                sizeof(RRClientRec) +
    422                                screenInfo.numScreens * sizeof(RRTimesRec)))
    423         return;
    424     if (!AddCallback(&ClientStateCallback, RRClientCallback, 0))
    425         return;
    426 
    427     RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient");
    428     if (!RRClientType)
    429         return;
    430     RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent");
    431     if (!RREventType)
    432         return;
    433     extEntry = AddExtension(RANDR_NAME, RRNumberEvents, RRNumberErrors,
    434                             ProcRRDispatch, SProcRRDispatch,
    435                             NULL, StandardMinorOpcode);
    436     if (!extEntry)
    437         return;
    438     RRErrorBase = extEntry->errorBase;
    439     RREventBase = extEntry->eventBase;
    440     EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr)
    441         SRRScreenChangeNotifyEvent;
    442     EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr)
    443         SRRNotifyEvent;
    444 
    445     RRModeInitErrorValue();
    446     RRCrtcInitErrorValue();
    447     RROutputInitErrorValue();
    448     RRProviderInitErrorValue();
    449 #ifdef PANORAMIX
    450     RRXineramaExtensionInit();
    451 #endif
    452 }
    453 
    454 void
    455 RRResourcesChanged(ScreenPtr pScreen)
    456 {
    457     rrScrPriv(pScreen);
    458     pScrPriv->resourcesChanged = TRUE;
    459 
    460     RRSetChanged(pScreen);
    461 }
    462 
    463 static void
    464 RRDeliverResourceEvent(ClientPtr client, WindowPtr pWin)
    465 {
    466     ScreenPtr pScreen = pWin->drawable.pScreen;
    467 
    468     rrScrPriv(pScreen);
    469 
    470     xRRResourceChangeNotifyEvent re = {
    471         .type = RRNotify + RREventBase,
    472         .subCode = RRNotify_ResourceChange,
    473         .timestamp = pScrPriv->lastSetTime.milliseconds,
    474         .window = pWin->drawable.id
    475     };
    476 
    477     WriteEventsToClient(client, 1, (xEvent *) &re);
    478 }
    479 
    480 static int
    481 TellChanged(WindowPtr pWin, void *value)
    482 {
    483     RREventPtr *pHead, pRREvent;
    484     ClientPtr client;
    485     ScreenPtr pScreen = pWin->drawable.pScreen;
    486     ScreenPtr iter;
    487     rrScrPrivPtr pSecondaryScrPriv;
    488 
    489     rrScrPriv(pScreen);
    490     int i;
    491 
    492     dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
    493                             RREventType, serverClient, DixReadAccess);
    494     if (!pHead)
    495         return WT_WALKCHILDREN;
    496 
    497     for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
    498         client = pRREvent->client;
    499         if (client == serverClient || client->clientGone)
    500             continue;
    501 
    502         if (pRREvent->mask & RRScreenChangeNotifyMask)
    503             RRDeliverScreenEvent(client, pWin, pScreen);
    504 
    505         if (pRREvent->mask & RRCrtcChangeNotifyMask) {
    506             for (i = 0; i < pScrPriv->numCrtcs; i++) {
    507                 RRCrtcPtr crtc = pScrPriv->crtcs[i];
    508 
    509                 if (crtc->changed)
    510                     RRDeliverCrtcEvent(client, pWin, crtc);
    511             }
    512 
    513             xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
    514                 if (!iter->is_output_secondary)
    515                     continue;
    516 
    517                 pSecondaryScrPriv = rrGetScrPriv(iter);
    518                 for (i = 0; i < pSecondaryScrPriv->numCrtcs; i++) {
    519                     RRCrtcPtr crtc = pSecondaryScrPriv->crtcs[i];
    520 
    521                     if (crtc->changed)
    522                         RRDeliverCrtcEvent(client, pWin, crtc);
    523                 }
    524             }
    525         }
    526 
    527         if (pRREvent->mask & RROutputChangeNotifyMask) {
    528             for (i = 0; i < pScrPriv->numOutputs; i++) {
    529                 RROutputPtr output = pScrPriv->outputs[i];
    530 
    531                 if (output->changed)
    532                     RRDeliverOutputEvent(client, pWin, output);
    533             }
    534 
    535             xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
    536                 if (!iter->is_output_secondary)
    537                     continue;
    538 
    539                 pSecondaryScrPriv = rrGetScrPriv(iter);
    540                 for (i = 0; i < pSecondaryScrPriv->numOutputs; i++) {
    541                     RROutputPtr output = pSecondaryScrPriv->outputs[i];
    542 
    543                     if (output->changed)
    544                         RRDeliverOutputEvent(client, pWin, output);
    545                 }
    546             }
    547         }
    548 
    549         if (pRREvent->mask & RRProviderChangeNotifyMask) {
    550             xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
    551                 pSecondaryScrPriv = rrGetScrPriv(iter);
    552                 if (pSecondaryScrPriv->provider->changed)
    553                     RRDeliverProviderEvent(client, pWin, pSecondaryScrPriv->provider);
    554             }
    555         }
    556 
    557         if (pRREvent->mask & RRResourceChangeNotifyMask) {
    558             if (pScrPriv->resourcesChanged) {
    559                 RRDeliverResourceEvent(client, pWin);
    560             }
    561         }
    562 
    563         if (pRREvent->mask & RRLeaseNotifyMask) {
    564             if (pScrPriv->leasesChanged) {
    565                 RRDeliverLeaseEvent(client, pWin);
    566             }
    567         }
    568     }
    569     return WT_WALKCHILDREN;
    570 }
    571 
    572 void
    573 RRSetChanged(ScreenPtr pScreen)
    574 {
    575     /* set changed bits on the primary screen only */
    576     ScreenPtr primary;
    577     rrScrPriv(pScreen);
    578     rrScrPrivPtr primarysp;
    579 
    580     if (pScreen->isGPU) {
    581         primary = pScreen->current_primary;
    582         if (!primary)
    583             return;
    584         primarysp = rrGetScrPriv(primary);
    585     }
    586     else {
    587         primary = pScreen;
    588         primarysp = pScrPriv;
    589     }
    590 
    591     primarysp->changed = TRUE;
    592 }
    593 
    594 /*
    595  * Something changed; send events and adjust pointer position
    596  */
    597 void
    598 RRTellChanged(ScreenPtr pScreen)
    599 {
    600     ScreenPtr primary;
    601     rrScrPriv(pScreen);
    602     rrScrPrivPtr primarysp;
    603     int i;
    604     ScreenPtr iter;
    605     rrScrPrivPtr pSecondaryScrPriv;
    606 
    607     if (pScreen->isGPU) {
    608         primary = pScreen->current_primary;
    609         if (!primary)
    610             return;
    611         primarysp = rrGetScrPriv(primary);
    612     }
    613     else {
    614         primary = pScreen;
    615         primarysp = pScrPriv;
    616     }
    617 
    618     /* If there's no root window yet, can't send events */
    619     if (!primary->root)
    620         return;
    621 
    622     xorg_list_for_each_entry(iter, &primary->secondary_list, secondary_head) {
    623         pSecondaryScrPriv = rrGetScrPriv(iter);
    624 
    625         if (!iter->is_output_secondary)
    626             continue;
    627 
    628         if (CompareTimeStamps(primarysp->lastSetTime,
    629                               pSecondaryScrPriv->lastSetTime) == EARLIER) {
    630             primarysp->lastSetTime = pSecondaryScrPriv->lastSetTime;
    631         }
    632     }
    633 
    634     if (primarysp->changed) {
    635         UpdateCurrentTimeIf();
    636         if (primarysp->configChanged) {
    637             primarysp->lastConfigTime = currentTime;
    638             primarysp->configChanged = FALSE;
    639         }
    640         pScrPriv->changed = FALSE;
    641         primarysp->changed = FALSE;
    642 
    643         WalkTree(primary, TellChanged, (void *) primary);
    644 
    645         primarysp->resourcesChanged = FALSE;
    646 
    647         for (i = 0; i < pScrPriv->numOutputs; i++)
    648             pScrPriv->outputs[i]->changed = FALSE;
    649         for (i = 0; i < pScrPriv->numCrtcs; i++)
    650             pScrPriv->crtcs[i]->changed = FALSE;
    651 
    652         xorg_list_for_each_entry(iter, &primary->secondary_list, secondary_head) {
    653             pSecondaryScrPriv = rrGetScrPriv(iter);
    654             pSecondaryScrPriv->provider->changed = FALSE;
    655             if (iter->is_output_secondary) {
    656                 for (i = 0; i < pSecondaryScrPriv->numOutputs; i++)
    657                     pSecondaryScrPriv->outputs[i]->changed = FALSE;
    658                 for (i = 0; i < pSecondaryScrPriv->numCrtcs; i++)
    659                     pSecondaryScrPriv->crtcs[i]->changed = FALSE;
    660             }
    661         }
    662 
    663         if (primarysp->layoutChanged) {
    664             pScrPriv->layoutChanged = FALSE;
    665             RRPointerScreenConfigured(primary);
    666             RRSendConfigNotify(primary);
    667         }
    668     }
    669 }
    670 
    671 /*
    672  * Return the first output which is connected to an active CRTC
    673  * Used in emulating 1.0 behaviour
    674  */
    675 RROutputPtr
    676 RRFirstOutput(ScreenPtr pScreen)
    677 {
    678     rrScrPriv(pScreen);
    679     RROutputPtr output;
    680     int i, j;
    681 
    682     if (!pScrPriv)
    683         return NULL;
    684 
    685     if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
    686         return pScrPriv->primaryOutput;
    687 
    688     for (i = 0; i < pScrPriv->numCrtcs; i++) {
    689         RRCrtcPtr crtc = pScrPriv->crtcs[i];
    690 
    691         for (j = 0; j < pScrPriv->numOutputs; j++) {
    692             output = pScrPriv->outputs[j];
    693             if (output->crtc == crtc)
    694                 return output;
    695         }
    696     }
    697     return NULL;
    698 }
    699 
    700 RRCrtcPtr
    701 RRFirstEnabledCrtc(ScreenPtr pScreen)
    702 {
    703     rrScrPriv(pScreen);
    704     RROutputPtr output;
    705     int i, j;
    706 
    707     if (!pScrPriv)
    708         return NULL;
    709 
    710     if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc &&
    711         pScrPriv->primaryOutput->pScreen == pScreen)
    712         return pScrPriv->primaryOutput->crtc;
    713 
    714     for (i = 0; i < pScrPriv->numCrtcs; i++) {
    715         RRCrtcPtr crtc = pScrPriv->crtcs[i];
    716 
    717         for (j = 0; j < pScrPriv->numOutputs; j++) {
    718             output = pScrPriv->outputs[j];
    719             if (output->crtc == crtc && crtc->mode)
    720                 return crtc;
    721         }
    722     }
    723     return NULL;
    724 }
    725 
    726 
    727 CARD16
    728 RRVerticalRefresh(xRRModeInfo * mode)
    729 {
    730     CARD32 refresh;
    731     CARD32 dots = mode->hTotal * mode->vTotal;
    732 
    733     if (!dots)
    734         return 0;
    735     refresh = (mode->dotClock + dots / 2) / dots;
    736     if (refresh > 0xffff)
    737         refresh = 0xffff;
    738     return (CARD16) refresh;
    739 }
    740 
    741 static int
    742 ProcRRDispatch(ClientPtr client)
    743 {
    744     REQUEST(xReq);
    745     if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
    746         return BadRequest;
    747     UpdateCurrentTimeIf();
    748     return (*ProcRandrVector[stuff->data]) (client);
    749 }
    750 
    751 static int _X_COLD
    752 SProcRRDispatch(ClientPtr client)
    753 {
    754     REQUEST(xReq);
    755     if (stuff->data >= RRNumberRequests || !SProcRandrVector[stuff->data])
    756         return BadRequest;
    757     UpdateCurrentTimeIf();
    758     return (*SProcRandrVector[stuff->data]) (client);
    759 }