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>
35 #ifndef SubPixelUnknown
36 #define SubPixelUnknown 0
40 static int RRNScreens
;
42 #define wrap(priv,real,mem,func) {\
43 priv->mem = real->mem; \
47 #define unwrap(priv,real,mem) {\
48 real->mem = priv->mem; \
51 static int ProcRRDispatch(ClientPtr pClient
);
52 static int SProcRRDispatch(ClientPtr pClient
);
56 RESTYPE RRClientType
, RREventType
; /* resource types for event masks */
57 DevPrivateKeyRec RRClientPrivateKeyRec
;
59 DevPrivateKeyRec rrPrivKeyRec
;
62 RRClientCallback(CallbackListPtr
*list
, pointer closure
, pointer data
)
64 NewClientInfoRec
*clientinfo
= (NewClientInfoRec
*) data
;
65 ClientPtr pClient
= clientinfo
->client
;
67 rrClientPriv(pClient
);
68 RRTimesPtr pTimes
= (RRTimesPtr
) (pRRClient
+ 1);
71 pRRClient
->major_version
= 0;
72 pRRClient
->minor_version
= 0;
73 for (i
= 0; i
< screenInfo
.numScreens
; i
++) {
74 ScreenPtr pScreen
= screenInfo
.screens
[i
];
79 pTimes
[i
].setTime
= pScrPriv
->lastSetTime
;
80 pTimes
[i
].configTime
= pScrPriv
->lastConfigTime
;
86 RRCloseScreen(int i
, ScreenPtr pScreen
)
91 unwrap(pScrPriv
, pScreen
, CloseScreen
);
92 for (j
= pScrPriv
->numCrtcs
- 1; j
>= 0; j
--)
93 RRCrtcDestroy(pScrPriv
->crtcs
[j
]);
94 for (j
= pScrPriv
->numOutputs
- 1; j
>= 0; j
--)
95 RROutputDestroy(pScrPriv
->outputs
[j
]);
97 free(pScrPriv
->crtcs
);
98 free(pScrPriv
->outputs
);
100 RRNScreens
-= 1; /* ok, one fewer screen with RandR running */
101 return (*pScreen
->CloseScreen
) (i
, pScreen
);
105 SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent
* from
,
106 xRRScreenChangeNotifyEvent
* to
)
108 to
->type
= from
->type
;
109 to
->rotation
= from
->rotation
;
110 cpswaps(from
->sequenceNumber
, to
->sequenceNumber
);
111 cpswapl(from
->timestamp
, to
->timestamp
);
112 cpswapl(from
->configTimestamp
, to
->configTimestamp
);
113 cpswapl(from
->root
, to
->root
);
114 cpswapl(from
->window
, to
->window
);
115 cpswaps(from
->sizeID
, to
->sizeID
);
116 cpswaps(from
->subpixelOrder
, to
->subpixelOrder
);
117 cpswaps(from
->widthInPixels
, to
->widthInPixels
);
118 cpswaps(from
->heightInPixels
, to
->heightInPixels
);
119 cpswaps(from
->widthInMillimeters
, to
->widthInMillimeters
);
120 cpswaps(from
->heightInMillimeters
, to
->heightInMillimeters
);
124 SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent
* from
,
125 xRRCrtcChangeNotifyEvent
* to
)
127 to
->type
= from
->type
;
128 to
->subCode
= from
->subCode
;
129 cpswaps(from
->sequenceNumber
, to
->sequenceNumber
);
130 cpswapl(from
->timestamp
, to
->timestamp
);
131 cpswapl(from
->window
, to
->window
);
132 cpswapl(from
->crtc
, to
->crtc
);
133 cpswapl(from
->mode
, to
->mode
);
134 cpswaps(from
->rotation
, to
->rotation
);
136 cpswaps(from
->x
, to
->x
);
137 cpswaps(from
->y
, to
->y
);
138 cpswaps(from
->width
, to
->width
);
139 cpswaps(from
->height
, to
->height
);
143 SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent
* from
,
144 xRROutputChangeNotifyEvent
* to
)
146 to
->type
= from
->type
;
147 to
->subCode
= from
->subCode
;
148 cpswaps(from
->sequenceNumber
, to
->sequenceNumber
);
149 cpswapl(from
->timestamp
, to
->timestamp
);
150 cpswapl(from
->configTimestamp
, to
->configTimestamp
);
151 cpswapl(from
->window
, to
->window
);
152 cpswapl(from
->output
, to
->output
);
153 cpswapl(from
->crtc
, to
->crtc
);
154 cpswapl(from
->mode
, to
->mode
);
155 cpswaps(from
->rotation
, to
->rotation
);
156 to
->connection
= from
->connection
;
157 to
->subpixelOrder
= from
->subpixelOrder
;
161 SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent
* from
,
162 xRROutputPropertyNotifyEvent
* to
)
164 to
->type
= from
->type
;
165 to
->subCode
= from
->subCode
;
166 cpswaps(from
->sequenceNumber
, to
->sequenceNumber
);
167 cpswapl(from
->window
, to
->window
);
168 cpswapl(from
->output
, to
->output
);
169 cpswapl(from
->atom
, to
->atom
);
170 cpswapl(from
->timestamp
, to
->timestamp
);
171 to
->state
= from
->state
;
179 SRRNotifyEvent(xEvent
*from
, xEvent
*to
)
181 switch (from
->u
.u
.detail
) {
182 case RRNotify_CrtcChange
:
183 SRRCrtcChangeNotifyEvent((xRRCrtcChangeNotifyEvent
*) from
,
184 (xRRCrtcChangeNotifyEvent
*) to
);
186 case RRNotify_OutputChange
:
187 SRROutputChangeNotifyEvent((xRROutputChangeNotifyEvent
*) from
,
188 (xRROutputChangeNotifyEvent
*) to
);
190 case RRNotify_OutputProperty
:
191 SRROutputPropertyNotifyEvent((xRROutputPropertyNotifyEvent
*) from
,
192 (xRROutputPropertyNotifyEvent
*) to
);
199 static int RRGeneration
;
204 if (RRGeneration
!= serverGeneration
) {
211 RRGeneration
= serverGeneration
;
213 if (!dixRegisterPrivateKey(&rrPrivKeyRec
, PRIVATE_SCREEN
, 0))
220 RRScreenInit(ScreenPtr pScreen
)
222 rrScrPrivPtr pScrPriv
;
227 pScrPriv
= (rrScrPrivPtr
) calloc(1, sizeof(rrScrPrivRec
));
231 SetRRScreen(pScreen
, pScrPriv
);
234 * Calling function best set these function vectors
236 pScrPriv
->rrGetInfo
= 0;
237 pScrPriv
->maxWidth
= pScrPriv
->minWidth
= pScreen
->width
;
238 pScrPriv
->maxHeight
= pScrPriv
->minHeight
= pScreen
->height
;
240 pScrPriv
->width
= pScreen
->width
;
241 pScrPriv
->height
= pScreen
->height
;
242 pScrPriv
->mmWidth
= pScreen
->mmWidth
;
243 pScrPriv
->mmHeight
= pScreen
->mmHeight
;
244 #if RANDR_12_INTERFACE
245 pScrPriv
->rrScreenSetSize
= NULL
;
246 pScrPriv
->rrCrtcSet
= NULL
;
247 pScrPriv
->rrCrtcSetGamma
= NULL
;
249 #if RANDR_10_INTERFACE
250 pScrPriv
->rrSetConfig
= 0;
251 pScrPriv
->rotations
= RR_Rotate_0
;
252 pScrPriv
->reqWidth
= pScreen
->width
;
253 pScrPriv
->reqHeight
= pScreen
->height
;
254 pScrPriv
->nSizes
= 0;
255 pScrPriv
->pSizes
= NULL
;
256 pScrPriv
->rotation
= RR_Rotate_0
;
262 * This value doesn't really matter -- any client must call
263 * GetScreenInfo before reading it which will automatically update
266 pScrPriv
->lastSetTime
= currentTime
;
267 pScrPriv
->lastConfigTime
= currentTime
;
269 wrap(pScrPriv
, pScreen
, CloseScreen
, RRCloseScreen
);
271 pScreen
->ConstrainCursorHarder
= RRConstrainCursorHarder
;
273 pScrPriv
->numOutputs
= 0;
274 pScrPriv
->outputs
= NULL
;
275 pScrPriv
->numCrtcs
= 0;
276 pScrPriv
->crtcs
= NULL
;
278 RRNScreens
+= 1; /* keep count of screens that implement randr */
282 /*ARGSUSED*/ static int
283 RRFreeClient(pointer data
, XID id
)
287 RREventPtr
*pHead
, pCur
, pPrev
;
289 pRREvent
= (RREventPtr
) data
;
290 pWin
= pRREvent
->window
;
291 dixLookupResourceByType((pointer
*) &pHead
, pWin
->drawable
.id
,
292 RREventType
, serverClient
, DixDestroyAccess
);
295 for (pCur
= *pHead
; pCur
&& pCur
!= pRREvent
; pCur
= pCur
->next
)
299 pPrev
->next
= pRREvent
->next
;
301 *pHead
= pRREvent
->next
;
304 free((pointer
) pRREvent
);
308 /*ARGSUSED*/ static int
309 RRFreeEvents(pointer data
, XID id
)
311 RREventPtr
*pHead
, pCur
, pNext
;
313 pHead
= (RREventPtr
*) data
;
314 for (pCur
= *pHead
; pCur
; pCur
= pNext
) {
316 FreeResource(pCur
->clientResource
, RRClientType
);
317 free((pointer
) pCur
);
319 free((pointer
) pHead
);
324 RRExtensionInit(void)
326 ExtensionEntry
*extEntry
;
331 if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec
, PRIVATE_CLIENT
,
332 sizeof(RRClientRec
) +
333 screenInfo
.numScreens
* sizeof(RRTimesRec
)))
335 if (!AddCallback(&ClientStateCallback
, RRClientCallback
, 0))
338 RRClientType
= CreateNewResourceType(RRFreeClient
, "RandRClient");
341 RREventType
= CreateNewResourceType(RRFreeEvents
, "RandREvent");
344 extEntry
= AddExtension(RANDR_NAME
, RRNumberEvents
, RRNumberErrors
,
345 ProcRRDispatch
, SProcRRDispatch
,
346 NULL
, StandardMinorOpcode
);
349 RRErrorBase
= extEntry
->errorBase
;
350 RREventBase
= extEntry
->eventBase
;
351 EventSwapVector
[RREventBase
+ RRScreenChangeNotify
] = (EventSwapPtr
)
352 SRRScreenChangeNotifyEvent
;
353 EventSwapVector
[RREventBase
+ RRNotify
] = (EventSwapPtr
)
356 RRModeInitErrorValue();
357 RRCrtcInitErrorValue();
358 RROutputInitErrorValue();
361 RRXineramaExtensionInit();
366 TellChanged(WindowPtr pWin
, pointer value
)
368 RREventPtr
*pHead
, pRREvent
;
370 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
375 dixLookupResourceByType((pointer
*) &pHead
, pWin
->drawable
.id
,
376 RREventType
, serverClient
, DixReadAccess
);
378 return WT_WALKCHILDREN
;
380 for (pRREvent
= *pHead
; pRREvent
; pRREvent
= pRREvent
->next
) {
381 client
= pRREvent
->client
;
382 if (client
== serverClient
|| client
->clientGone
)
385 if (pRREvent
->mask
& RRScreenChangeNotifyMask
)
386 RRDeliverScreenEvent(client
, pWin
, pScreen
);
388 if (pRREvent
->mask
& RRCrtcChangeNotifyMask
) {
389 for (i
= 0; i
< pScrPriv
->numCrtcs
; i
++) {
390 RRCrtcPtr crtc
= pScrPriv
->crtcs
[i
];
393 RRDeliverCrtcEvent(client
, pWin
, crtc
);
397 if (pRREvent
->mask
& RROutputChangeNotifyMask
) {
398 for (i
= 0; i
< pScrPriv
->numOutputs
; i
++) {
399 RROutputPtr output
= pScrPriv
->outputs
[i
];
402 RRDeliverOutputEvent(client
, pWin
, output
);
406 return WT_WALKCHILDREN
;
410 * Something changed; send events and adjust pointer position
413 RRTellChanged(ScreenPtr pScreen
)
418 if (pScrPriv
->changed
) {
420 if (pScrPriv
->configChanged
) {
421 pScrPriv
->lastConfigTime
= currentTime
;
422 pScrPriv
->configChanged
= FALSE
;
424 pScrPriv
->changed
= FALSE
;
425 WalkTree(pScreen
, TellChanged
, (pointer
) pScreen
);
426 for (i
= 0; i
< pScrPriv
->numOutputs
; i
++)
427 pScrPriv
->outputs
[i
]->changed
= FALSE
;
428 for (i
= 0; i
< pScrPriv
->numCrtcs
; i
++)
429 pScrPriv
->crtcs
[i
]->changed
= FALSE
;
430 if (pScrPriv
->layoutChanged
) {
431 pScrPriv
->layoutChanged
= FALSE
;
432 RRPointerScreenConfigured(pScreen
);
433 RRSendConfigNotify(pScreen
);
439 * Return the first output which is connected to an active CRTC
440 * Used in emulating 1.0 behaviour
443 RRFirstOutput(ScreenPtr pScreen
)
449 if (pScrPriv
->primaryOutput
&& pScrPriv
->primaryOutput
->crtc
)
450 return pScrPriv
->primaryOutput
;
452 for (i
= 0; i
< pScrPriv
->numCrtcs
; i
++) {
453 RRCrtcPtr crtc
= pScrPriv
->crtcs
[i
];
455 for (j
= 0; j
< pScrPriv
->numOutputs
; j
++) {
456 output
= pScrPriv
->outputs
[j
];
457 if (output
->crtc
== crtc
)
465 RRVerticalRefresh(xRRModeInfo
* mode
)
468 CARD32 dots
= mode
->hTotal
* mode
->vTotal
;
472 refresh
= (mode
->dotClock
+ dots
/ 2) / dots
;
473 if (refresh
> 0xffff)
475 return (CARD16
) refresh
;
479 ProcRRDispatch(ClientPtr client
)
482 if (stuff
->data
>= RRNumberRequests
|| !ProcRandrVector
[stuff
->data
])
484 return (*ProcRandrVector
[stuff
->data
]) (client
);
488 SProcRRDispatch(ClientPtr client
)
491 if (stuff
->data
>= RRNumberRequests
|| !ProcRandrVector
[stuff
->data
])
493 return (*SProcRandrVector
[stuff
->data
]) (client
);