2 * Copyright © 2000 Compaq Computer Corporation
3 * Copyright © 2002 Hewlett-Packard Company
4 * Copyright © 2006 Intel Corporation
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.
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
24 * Author: Jim Gettys, Hewlett-Packard Company, Inc.
25 * Keith Packard, Intel Corporation
28 #ifdef HAVE_DIX_CONFIG_H
29 #include <dix-config.h>
36 #ifndef SubPixelUnknown
37 #define SubPixelUnknown 0
41 static int RRNScreens;
43 #define wrap(priv,real,mem,func) {\
44 priv->mem = real->mem; \
48 #define unwrap(priv,real,mem) {\
49 real->mem = priv->mem; \
52 static int ProcRRDispatch(ClientPtr pClient);
53 static int SProcRRDispatch(ClientPtr pClient);
57 RESTYPE RRClientType, RREventType; /* resource types for event masks */
58 DevPrivateKeyRec RRClientPrivateKeyRec;
60 DevPrivateKeyRec rrPrivKeyRec;
63 RRClientCallback(CallbackListPtr *list, void *closure, void *data)
65 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
66 ClientPtr pClient = clientinfo->client;
68 rrClientPriv(pClient);
69 RRTimesPtr pTimes = (RRTimesPtr) (pRRClient + 1);
72 pRRClient->major_version = 0;
73 pRRClient->minor_version = 0;
74 for (i = 0; i < screenInfo.numScreens; i++) {
75 ScreenPtr pScreen = screenInfo.screens[i];
80 pTimes[i].setTime = pScrPriv->lastSetTime;
81 pTimes[i].configTime = pScrPriv->lastConfigTime;
87 RRCloseScreen(ScreenPtr pScreen)
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]);
98 if (pScrPriv->provider)
99 RRProviderDestroy(pScrPriv->provider);
101 free(pScrPriv->crtcs);
102 free(pScrPriv->outputs);
104 RRNScreens -= 1; /* ok, one fewer screen with RandR running */
105 return (*pScreen->CloseScreen) (pScreen);
109 SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent * from,
110 xRRScreenChangeNotifyEvent * to)
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);
128 SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent * from,
129 xRRCrtcChangeNotifyEvent * to)
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);
140 cpswaps(from->x, to->x);
141 cpswaps(from->y, to->y);
142 cpswaps(from->width, to->width);
143 cpswaps(from->height, to->height);
147 SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent * from,
148 xRROutputChangeNotifyEvent * to)
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;
165 SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent * from,
166 xRROutputPropertyNotifyEvent * to)
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;
183 SRRProviderChangeNotifyEvent(xRRProviderChangeNotifyEvent * from,
184 xRRProviderChangeNotifyEvent * to)
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);
195 SRRProviderPropertyNotifyEvent(xRRProviderPropertyNotifyEvent * from,
196 xRRProviderPropertyNotifyEvent * to)
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;
213 SRRResourceChangeNotifyEvent(xRRResourceChangeNotifyEvent * from,
214 xRRResourceChangeNotifyEvent * to)
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);
224 SRRNotifyEvent(xEvent *from, xEvent *to)
226 switch (from->u.u.detail) {
227 case RRNotify_CrtcChange:
228 SRRCrtcChangeNotifyEvent((xRRCrtcChangeNotifyEvent *) from,
229 (xRRCrtcChangeNotifyEvent *) to);
231 case RRNotify_OutputChange:
232 SRROutputChangeNotifyEvent((xRROutputChangeNotifyEvent *) from,
233 (xRROutputChangeNotifyEvent *) to);
235 case RRNotify_OutputProperty:
236 SRROutputPropertyNotifyEvent((xRROutputPropertyNotifyEvent *) from,
237 (xRROutputPropertyNotifyEvent *) to);
239 case RRNotify_ProviderChange:
240 SRRProviderChangeNotifyEvent((xRRProviderChangeNotifyEvent *) from,
241 (xRRProviderChangeNotifyEvent *) to);
243 case RRNotify_ProviderProperty:
244 SRRProviderPropertyNotifyEvent((xRRProviderPropertyNotifyEvent *) from,
245 (xRRProviderPropertyNotifyEvent *) to);
247 case RRNotify_ResourceChange:
248 SRRResourceChangeNotifyEvent((xRRResourceChangeNotifyEvent *) from,
249 (xRRResourceChangeNotifyEvent *) to);
255 static int RRGeneration;
260 if (RRGeneration != serverGeneration) {
267 if (!RRProviderInit())
269 RRGeneration = serverGeneration;
271 if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0))
278 RRScreenInit(ScreenPtr pScreen)
280 rrScrPrivPtr pScrPriv;
285 pScrPriv = (rrScrPrivPtr) calloc(1, sizeof(rrScrPrivRec));
289 SetRRScreen(pScreen, pScrPriv);
292 * Calling function best set these function vectors
294 pScrPriv->rrGetInfo = 0;
295 pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width;
296 pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height;
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;
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;
320 * This value doesn't really matter -- any client must call
321 * GetScreenInfo before reading it which will automatically update
324 pScrPriv->lastSetTime = currentTime;
325 pScrPriv->lastConfigTime = currentTime;
327 wrap(pScrPriv, pScreen, CloseScreen, RRCloseScreen);
329 pScreen->ConstrainCursorHarder = RRConstrainCursorHarder;
330 pScreen->ReplaceScanoutPixmap = RRReplaceScanoutPixmap;
331 pScrPriv->numOutputs = 0;
332 pScrPriv->outputs = NULL;
333 pScrPriv->numCrtcs = 0;
334 pScrPriv->crtcs = NULL;
336 RRNScreens += 1; /* keep count of screens that implement randr */
340 /*ARGSUSED*/ static int
341 RRFreeClient(void *data, XID id)
345 RREventPtr *pHead, pCur, pPrev;
347 pRREvent = (RREventPtr) data;
348 pWin = pRREvent->window;
349 dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
350 RREventType, serverClient, DixDestroyAccess);
353 for (pCur = *pHead; pCur && pCur != pRREvent; pCur = pCur->next)
357 pPrev->next = pRREvent->next;
359 *pHead = pRREvent->next;
362 free((void *) pRREvent);
366 /*ARGSUSED*/ static int
367 RRFreeEvents(void *data, XID id)
369 RREventPtr *pHead, pCur, pNext;
371 pHead = (RREventPtr *) data;
372 for (pCur = *pHead; pCur; pCur = pNext) {
374 FreeResource(pCur->clientResource, RRClientType);
377 free((void *) pHead);
382 RRExtensionInit(void)
384 ExtensionEntry *extEntry;
389 if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec, PRIVATE_CLIENT,
390 sizeof(RRClientRec) +
391 screenInfo.numScreens * sizeof(RRTimesRec)))
393 if (!AddCallback(&ClientStateCallback, RRClientCallback, 0))
396 RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient");
399 RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent");
402 extEntry = AddExtension(RANDR_NAME, RRNumberEvents, RRNumberErrors,
403 ProcRRDispatch, SProcRRDispatch,
404 NULL, StandardMinorOpcode);
407 RRErrorBase = extEntry->errorBase;
408 RREventBase = extEntry->eventBase;
409 EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr)
410 SRRScreenChangeNotifyEvent;
411 EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr)
414 RRModeInitErrorValue();
415 RRCrtcInitErrorValue();
416 RROutputInitErrorValue();
417 RRProviderInitErrorValue();
419 RRXineramaExtensionInit();
424 RRResourcesChanged(ScreenPtr pScreen)
427 pScrPriv->resourcesChanged = TRUE;
429 RRSetChanged(pScreen);
433 RRDeliverResourceEvent(ClientPtr client, WindowPtr pWin)
435 ScreenPtr pScreen = pWin->drawable.pScreen;
439 xRRResourceChangeNotifyEvent re = {
440 .type = RRNotify + RREventBase,
441 .subCode = RRNotify_ResourceChange,
442 .timestamp = pScrPriv->lastSetTime.milliseconds,
443 .window = pWin->drawable.id
446 WriteEventsToClient(client, 1, (xEvent *) &re);
450 TellChanged(WindowPtr pWin, void *value)
452 RREventPtr *pHead, pRREvent;
454 ScreenPtr pScreen = pWin->drawable.pScreen;
456 rrScrPrivPtr pSlaveScrPriv;
461 dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
462 RREventType, serverClient, DixReadAccess);
464 return WT_WALKCHILDREN;
466 for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
467 client = pRREvent->client;
468 if (client == serverClient || client->clientGone)
471 if (pRREvent->mask & RRScreenChangeNotifyMask)
472 RRDeliverScreenEvent(client, pWin, pScreen);
474 if (pRREvent->mask & RRCrtcChangeNotifyMask) {
475 for (i = 0; i < pScrPriv->numCrtcs; i++) {
476 RRCrtcPtr crtc = pScrPriv->crtcs[i];
479 RRDeliverCrtcEvent(client, pWin, crtc);
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];
488 RRDeliverCrtcEvent(client, pWin, crtc);
493 if (pRREvent->mask & RROutputChangeNotifyMask) {
494 for (i = 0; i < pScrPriv->numOutputs; i++) {
495 RROutputPtr output = pScrPriv->outputs[i];
498 RRDeliverOutputEvent(client, pWin, output);
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];
507 RRDeliverOutputEvent(client, pWin, output);
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);
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);
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);
530 if (pRREvent->mask & RRResourceChangeNotifyMask) {
531 if (pScrPriv->resourcesChanged) {
532 RRDeliverResourceEvent(client, pWin);
536 return WT_WALKCHILDREN;
540 RRSetChanged(ScreenPtr pScreen)
542 /* set changed bits on the master screen only */
545 rrScrPrivPtr mastersp;
547 if (pScreen->isGPU) {
548 master = pScreen->current_master;
551 mastersp = rrGetScrPriv(master);
558 mastersp->changed = TRUE;
562 * Something changed; send events and adjust pointer position
565 RRTellChanged(ScreenPtr pScreen)
569 rrScrPrivPtr mastersp;
572 rrScrPrivPtr pSlaveScrPriv;
574 if (pScreen->isGPU) {
575 master = pScreen->current_master;
576 mastersp = rrGetScrPriv(master);
583 if (mastersp->changed) {
584 UpdateCurrentTimeIf();
585 if (mastersp->configChanged) {
586 mastersp->lastConfigTime = currentTime;
587 mastersp->configChanged = FALSE;
589 pScrPriv->changed = FALSE;
590 mastersp->changed = FALSE;
592 WalkTree(master, TellChanged, (void *) master);
594 mastersp->resourcesChanged = FALSE;
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;
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;
609 xorg_list_for_each_entry(iter, &master->offload_slave_list, offload_head) {
610 pSlaveScrPriv = rrGetScrPriv(iter);
611 pSlaveScrPriv->provider->changed = FALSE;
613 xorg_list_for_each_entry(iter, &master->unattached_list, unattached_head) {
614 pSlaveScrPriv = rrGetScrPriv(iter);
615 pSlaveScrPriv->provider->changed = FALSE;
618 if (mastersp->layoutChanged) {
619 pScrPriv->layoutChanged = FALSE;
620 RRPointerScreenConfigured(master);
621 RRSendConfigNotify(master);
627 * Return the first output which is connected to an active CRTC
628 * Used in emulating 1.0 behaviour
631 RRFirstOutput(ScreenPtr pScreen)
640 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
641 return pScrPriv->primaryOutput;
643 for (i = 0; i < pScrPriv->numCrtcs; i++) {
644 RRCrtcPtr crtc = pScrPriv->crtcs[i];
646 for (j = 0; j < pScrPriv->numOutputs; j++) {
647 output = pScrPriv->outputs[j];
648 if (output->crtc == crtc)
656 RRVerticalRefresh(xRRModeInfo * mode)
659 CARD32 dots = mode->hTotal * mode->vTotal;
663 refresh = (mode->dotClock + dots / 2) / dots;
664 if (refresh > 0xffff)
666 return (CARD16) refresh;
670 ProcRRDispatch(ClientPtr client)
673 if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
675 return (*ProcRandrVector[stuff->data]) (client);
679 SProcRRDispatch(ClientPtr client)
682 if (stuff->data >= RRNumberRequests || !SProcRandrVector[stuff->data])
684 return (*SProcRandrVector[stuff->data]) (client);