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
, pointer closure
, pointer 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(pointer data
, XID id
)
345 RREventPtr
*pHead
, pCur
, pPrev
;
347 pRREvent
= (RREventPtr
) data
;
348 pWin
= pRREvent
->window
;
349 dixLookupResourceByType((pointer
*) &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((pointer
) pRREvent
);
366 /*ARGSUSED*/ static int
367 RRFreeEvents(pointer data
, XID id
)
369 RREventPtr
*pHead
, pCur
, pNext
;
371 pHead
= (RREventPtr
*) data
;
372 for (pCur
= *pHead
; pCur
; pCur
= pNext
) {
374 FreeResource(pCur
->clientResource
, RRClientType
);
375 free((pointer
) pCur
);
377 free((pointer
) 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
, pointer value
)
452 RREventPtr
*pHead
, pRREvent
;
454 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
456 rrScrPrivPtr pSlaveScrPriv
;
461 dixLookupResourceByType((pointer
*) &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
, (pointer
) 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
|| !ProcRandrVector
[stuff
->data
])
684 return (*SProcRandrVector
[stuff
->data
]) (client
);