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