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
RRClientCallback(CallbackListPtr * list,void * closure,void * data)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
RRCloseScreen(ScreenPtr pScreen)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
SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent * from,xRRScreenChangeNotifyEvent * to)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
SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent * from,xRRCrtcChangeNotifyEvent * to)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
SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent * from,xRROutputChangeNotifyEvent * to)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
SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent * from,xRROutputPropertyNotifyEvent * to)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
SRRProviderChangeNotifyEvent(xRRProviderChangeNotifyEvent * from,xRRProviderChangeNotifyEvent * to)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
SRRProviderPropertyNotifyEvent(xRRProviderPropertyNotifyEvent * from,xRRProviderPropertyNotifyEvent * to)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
SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from,xRRResourceChangeNotifyEvent * to)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
SRRLeaseNotifyEvent(xRRLeaseNotifyEvent * from,xRRLeaseNotifyEvent * to)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
SRRNotifyEvent(xEvent * from,xEvent * to)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
RRInit(void)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
RRScreenInit(ScreenPtr pScreen)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
RRFreeClient(void * data,XID id)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
RRFreeEvents(void * data,XID id)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
RRExtensionInit(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
RRResourcesChanged(ScreenPtr pScreen)455 RRResourcesChanged(ScreenPtr pScreen)
456 {
457 rrScrPriv(pScreen);
458 pScrPriv->resourcesChanged = TRUE;
459
460 RRSetChanged(pScreen);
461 }
462
463 static void
RRDeliverResourceEvent(ClientPtr client,WindowPtr pWin)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
TellChanged(WindowPtr pWin,void * value)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 pSlaveScrPriv;
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->slave_list, slave_head) {
514 if (!iter->is_output_slave)
515 continue;
516
517 pSlaveScrPriv = rrGetScrPriv(iter);
518 for (i = 0; i < pSlaveScrPriv->numCrtcs; i++) {
519 RRCrtcPtr crtc = pSlaveScrPriv->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->slave_list, slave_head) {
536 if (!iter->is_output_slave)
537 continue;
538
539 pSlaveScrPriv = rrGetScrPriv(iter);
540 for (i = 0; i < pSlaveScrPriv->numOutputs; i++) {
541 RROutputPtr output = pSlaveScrPriv->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->slave_list, slave_head) {
551 pSlaveScrPriv = rrGetScrPriv(iter);
552 if (pSlaveScrPriv->provider->changed)
553 RRDeliverProviderEvent(client, pWin, pSlaveScrPriv->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
RRSetChanged(ScreenPtr pScreen)573 RRSetChanged(ScreenPtr pScreen)
574 {
575 /* set changed bits on the master screen only */
576 ScreenPtr master;
577 rrScrPriv(pScreen);
578 rrScrPrivPtr mastersp;
579
580 if (pScreen->isGPU) {
581 master = pScreen->current_master;
582 if (!master)
583 return;
584 mastersp = rrGetScrPriv(master);
585 }
586 else {
587 master = pScreen;
588 mastersp = pScrPriv;
589 }
590
591 mastersp->changed = TRUE;
592 }
593
594 /*
595 * Something changed; send events and adjust pointer position
596 */
597 void
RRTellChanged(ScreenPtr pScreen)598 RRTellChanged(ScreenPtr pScreen)
599 {
600 ScreenPtr master;
601 rrScrPriv(pScreen);
602 rrScrPrivPtr mastersp;
603 int i;
604 ScreenPtr iter;
605 rrScrPrivPtr pSlaveScrPriv;
606
607 if (pScreen->isGPU) {
608 master = pScreen->current_master;
609 if (!master)
610 return;
611 mastersp = rrGetScrPriv(master);
612 }
613 else {
614 master = pScreen;
615 mastersp = pScrPriv;
616 }
617
618 xorg_list_for_each_entry(iter, &master->slave_list, slave_head) {
619 pSlaveScrPriv = rrGetScrPriv(iter);
620
621 if (!iter->is_output_slave)
622 continue;
623
624 if (CompareTimeStamps(mastersp->lastSetTime,
625 pSlaveScrPriv->lastSetTime) == EARLIER) {
626 mastersp->lastSetTime = pSlaveScrPriv->lastSetTime;
627 }
628 }
629
630 if (mastersp->changed) {
631 UpdateCurrentTimeIf();
632 if (mastersp->configChanged) {
633 mastersp->lastConfigTime = currentTime;
634 mastersp->configChanged = FALSE;
635 }
636 pScrPriv->changed = FALSE;
637 mastersp->changed = FALSE;
638
639 WalkTree(master, TellChanged, (void *) master);
640
641 mastersp->resourcesChanged = FALSE;
642
643 for (i = 0; i < pScrPriv->numOutputs; i++)
644 pScrPriv->outputs[i]->changed = FALSE;
645 for (i = 0; i < pScrPriv->numCrtcs; i++)
646 pScrPriv->crtcs[i]->changed = FALSE;
647
648 xorg_list_for_each_entry(iter, &master->slave_list, slave_head) {
649 pSlaveScrPriv = rrGetScrPriv(iter);
650 pSlaveScrPriv->provider->changed = FALSE;
651 if (iter->is_output_slave) {
652 for (i = 0; i < pSlaveScrPriv->numOutputs; i++)
653 pSlaveScrPriv->outputs[i]->changed = FALSE;
654 for (i = 0; i < pSlaveScrPriv->numCrtcs; i++)
655 pSlaveScrPriv->crtcs[i]->changed = FALSE;
656 }
657 }
658
659 if (mastersp->layoutChanged) {
660 pScrPriv->layoutChanged = FALSE;
661 RRPointerScreenConfigured(master);
662 RRSendConfigNotify(master);
663 }
664 }
665 }
666
667 /*
668 * Return the first output which is connected to an active CRTC
669 * Used in emulating 1.0 behaviour
670 */
671 RROutputPtr
RRFirstOutput(ScreenPtr pScreen)672 RRFirstOutput(ScreenPtr pScreen)
673 {
674 rrScrPriv(pScreen);
675 RROutputPtr output;
676 int i, j;
677
678 if (!pScrPriv)
679 return NULL;
680
681 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
682 return pScrPriv->primaryOutput;
683
684 for (i = 0; i < pScrPriv->numCrtcs; i++) {
685 RRCrtcPtr crtc = pScrPriv->crtcs[i];
686
687 for (j = 0; j < pScrPriv->numOutputs; j++) {
688 output = pScrPriv->outputs[j];
689 if (output->crtc == crtc)
690 return output;
691 }
692 }
693 return NULL;
694 }
695
696 RRCrtcPtr
RRFirstEnabledCrtc(ScreenPtr pScreen)697 RRFirstEnabledCrtc(ScreenPtr pScreen)
698 {
699 rrScrPriv(pScreen);
700 RROutputPtr output;
701 int i, j;
702
703 if (!pScrPriv)
704 return NULL;
705
706 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc &&
707 pScrPriv->primaryOutput->pScreen == pScreen)
708 return pScrPriv->primaryOutput->crtc;
709
710 for (i = 0; i < pScrPriv->numCrtcs; i++) {
711 RRCrtcPtr crtc = pScrPriv->crtcs[i];
712
713 for (j = 0; j < pScrPriv->numOutputs; j++) {
714 output = pScrPriv->outputs[j];
715 if (output->crtc == crtc && crtc->mode)
716 return crtc;
717 }
718 }
719 return NULL;
720 }
721
722
723 CARD16
RRVerticalRefresh(xRRModeInfo * mode)724 RRVerticalRefresh(xRRModeInfo * mode)
725 {
726 CARD32 refresh;
727 CARD32 dots = mode->hTotal * mode->vTotal;
728
729 if (!dots)
730 return 0;
731 refresh = (mode->dotClock + dots / 2) / dots;
732 if (refresh > 0xffff)
733 refresh = 0xffff;
734 return (CARD16) refresh;
735 }
736
737 static int
ProcRRDispatch(ClientPtr client)738 ProcRRDispatch(ClientPtr client)
739 {
740 REQUEST(xReq);
741 if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
742 return BadRequest;
743 UpdateCurrentTimeIf();
744 return (*ProcRandrVector[stuff->data]) (client);
745 }
746
747 static int _X_COLD
SProcRRDispatch(ClientPtr client)748 SProcRRDispatch(ClientPtr client)
749 {
750 REQUEST(xReq);
751 if (stuff->data >= RRNumberRequests || !SProcRandrVector[stuff->data])
752 return BadRequest;
753 UpdateCurrentTimeIf();
754 return (*SProcRandrVector[stuff->data]) (client);
755 }
756