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
34/* From render.h */
35#ifndef SubPixelUnknown
36#define SubPixelUnknown 0
37#endif
38
39#define RR_VALIDATE
40static int	RRNScreens;
41
42#define wrap(priv,real,mem,func) {\
43    priv->mem = real->mem; \
44    real->mem = func; \
45}
46
47#define unwrap(priv,real,mem) {\
48    real->mem = priv->mem; \
49}
50
51static int ProcRRDispatch (ClientPtr pClient);
52static int SProcRRDispatch (ClientPtr pClient);
53
54int	RREventBase;
55int	RRErrorBase;
56RESTYPE RRClientType, RREventType; /* resource types for event masks */
57DevPrivateKeyRec RRClientPrivateKeyRec;
58
59DevPrivateKeyRec rrPrivKeyRec;
60
61static void
62RRClientCallback (CallbackListPtr	*list,
63		  pointer		closure,
64		  pointer		data)
65{
66    NewClientInfoRec	*clientinfo = (NewClientInfoRec *) data;
67    ClientPtr		pClient = clientinfo->client;
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    {
76	ScreenPtr   pScreen = screenInfo.screens[i];
77	rrScrPriv(pScreen);
78
79	if (pScrPriv)
80	{
81	    pTimes[i].setTime = pScrPriv->lastSetTime;
82	    pTimes[i].configTime = pScrPriv->lastConfigTime;
83	}
84    }
85}
86
87static Bool
88RRCloseScreen (int i, ScreenPtr pScreen)
89{
90    rrScrPriv(pScreen);
91    int		    j;
92
93    unwrap (pScrPriv, pScreen, CloseScreen);
94    for (j = pScrPriv->numCrtcs - 1; j >= 0; j--)
95	RRCrtcDestroy (pScrPriv->crtcs[j]);
96    for (j = pScrPriv->numOutputs - 1; j >= 0; j--)
97	RROutputDestroy (pScrPriv->outputs[j]);
98
99    free(pScrPriv->crtcs);
100    free(pScrPriv->outputs);
101    free(pScrPriv);
102    RRNScreens -= 1;	/* ok, one fewer screen with RandR running */
103    return (*pScreen->CloseScreen) (i, pScreen);
104}
105
106static void
107SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent *from,
108			   xRRScreenChangeNotifyEvent *to)
109{
110    to->type = from->type;
111    to->rotation = from->rotation;
112    cpswaps(from->sequenceNumber, to->sequenceNumber);
113    cpswapl(from->timestamp, to->timestamp);
114    cpswapl(from->configTimestamp, to->configTimestamp);
115    cpswapl(from->root, to->root);
116    cpswapl(from->window, to->window);
117    cpswaps(from->sizeID, to->sizeID);
118    cpswaps(from->subpixelOrder, to->subpixelOrder);
119    cpswaps(from->widthInPixels, to->widthInPixels);
120    cpswaps(from->heightInPixels, to->heightInPixels);
121    cpswaps(from->widthInMillimeters, to->widthInMillimeters);
122    cpswaps(from->heightInMillimeters, to->heightInMillimeters);
123}
124
125static void
126SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent *from,
127			 xRRCrtcChangeNotifyEvent *to)
128{
129    to->type = from->type;
130    to->subCode = from->subCode;
131    cpswaps(from->sequenceNumber, to->sequenceNumber);
132    cpswapl(from->timestamp, to->timestamp);
133    cpswapl(from->window, to->window);
134    cpswapl(from->crtc, to->crtc);
135    cpswapl(from->mode, to->mode);
136    cpswaps(from->rotation, to->rotation);
137    /* pad1 */
138    cpswaps(from->x, to->x);
139    cpswaps(from->y, to->y);
140    cpswaps(from->width, to->width);
141    cpswaps(from->height, to->height);
142}
143
144static void
145SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent *from,
146			   xRROutputChangeNotifyEvent *to)
147{
148    to->type = from->type;
149    to->subCode = from->subCode;
150    cpswaps(from->sequenceNumber, to->sequenceNumber);
151    cpswapl(from->timestamp, to->timestamp);
152    cpswapl(from->configTimestamp, to->configTimestamp);
153    cpswapl(from->window, to->window);
154    cpswapl(from->output, to->output);
155    cpswapl(from->crtc, to->crtc);
156    cpswapl(from->mode, to->mode);
157    cpswaps(from->rotation, to->rotation);
158    to->connection = from->connection;
159    to->subpixelOrder = from->subpixelOrder;
160}
161
162static void
163SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent *from,
164			     xRROutputPropertyNotifyEvent *to)
165{
166    to->type = from->type;
167    to->subCode = from->subCode;
168    cpswaps(from->sequenceNumber, to->sequenceNumber);
169    cpswapl(from->window, to->window);
170    cpswapl(from->output, to->output);
171    cpswapl(from->atom, to->atom);
172    cpswapl(from->timestamp, to->timestamp);
173    to->state = from->state;
174    /* pad1 */
175    /* pad2 */
176    /* pad3 */
177    /* pad4 */
178}
179
180static void
181SRRNotifyEvent (xEvent *from,
182		xEvent *to)
183{
184    switch (from->u.u.detail) {
185    case RRNotify_CrtcChange:
186	SRRCrtcChangeNotifyEvent ((xRRCrtcChangeNotifyEvent *) from,
187				  (xRRCrtcChangeNotifyEvent *) to);
188	break;
189    case RRNotify_OutputChange:
190	SRROutputChangeNotifyEvent ((xRROutputChangeNotifyEvent *) from,
191				    (xRROutputChangeNotifyEvent *) to);
192	break;
193    case RRNotify_OutputProperty:
194	SRROutputPropertyNotifyEvent ((xRROutputPropertyNotifyEvent *) from,
195				      (xRROutputPropertyNotifyEvent *) to);
196	break;
197    default:
198	break;
199    }
200}
201
202static int RRGeneration;
203
204Bool RRInit (void)
205{
206    if (RRGeneration != serverGeneration)
207    {
208	if (!RRModeInit ())
209	    return FALSE;
210	if (!RRCrtcInit ())
211	    return FALSE;
212	if (!RROutputInit ())
213	    return FALSE;
214	RRGeneration = serverGeneration;
215    }
216    if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0))
217	return FALSE;
218
219    return TRUE;
220}
221
222Bool RRScreenInit(ScreenPtr pScreen)
223{
224    rrScrPrivPtr   pScrPriv;
225
226    if (!RRInit ())
227	return FALSE;
228
229    pScrPriv = (rrScrPrivPtr) calloc(1, sizeof (rrScrPrivRec));
230    if (!pScrPriv)
231	return FALSE;
232
233    SetRRScreen(pScreen, pScrPriv);
234
235    /*
236     * Calling function best set these function vectors
237     */
238    pScrPriv->rrGetInfo = 0;
239    pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width;
240    pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height;
241
242    pScrPriv->width = pScreen->width;
243    pScrPriv->height = pScreen->height;
244    pScrPriv->mmWidth = pScreen->mmWidth;
245    pScrPriv->mmHeight = pScreen->mmHeight;
246#if RANDR_12_INTERFACE
247    pScrPriv->rrScreenSetSize = NULL;
248    pScrPriv->rrCrtcSet = NULL;
249    pScrPriv->rrCrtcSetGamma = NULL;
250#endif
251#if RANDR_10_INTERFACE
252    pScrPriv->rrSetConfig = 0;
253    pScrPriv->rotations = RR_Rotate_0;
254    pScrPriv->reqWidth = pScreen->width;
255    pScrPriv->reqHeight = pScreen->height;
256    pScrPriv->nSizes = 0;
257    pScrPriv->pSizes = NULL;
258    pScrPriv->rotation = RR_Rotate_0;
259    pScrPriv->rate = 0;
260    pScrPriv->size = 0;
261#endif
262
263    /*
264     * This value doesn't really matter -- any client must call
265     * GetScreenInfo before reading it which will automatically update
266     * the time
267     */
268    pScrPriv->lastSetTime = currentTime;
269    pScrPriv->lastConfigTime = currentTime;
270
271    wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen);
272
273    pScrPriv->numOutputs = 0;
274    pScrPriv->outputs = NULL;
275    pScrPriv->numCrtcs = 0;
276    pScrPriv->crtcs = NULL;
277
278    RRNScreens += 1;	/* keep count of screens that implement randr */
279    return TRUE;
280}
281
282/*ARGSUSED*/
283static int
284RRFreeClient (pointer data, XID id)
285{
286    RREventPtr   pRREvent;
287    WindowPtr	    pWin;
288    RREventPtr   *pHead, pCur, pPrev;
289
290    pRREvent = (RREventPtr) data;
291    pWin = pRREvent->window;
292    dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
293			    RREventType, serverClient, DixDestroyAccess);
294    if (pHead) {
295	pPrev = 0;
296	for (pCur = *pHead; pCur && pCur != pRREvent; pCur=pCur->next)
297	    pPrev = pCur;
298	if (pCur)
299	{
300	    if (pPrev)
301	    	pPrev->next = pRREvent->next;
302	    else
303	    	*pHead = pRREvent->next;
304	}
305    }
306    free((pointer) pRREvent);
307    return 1;
308}
309
310/*ARGSUSED*/
311static int
312RRFreeEvents (pointer data, XID id)
313{
314    RREventPtr   *pHead, pCur, pNext;
315
316    pHead = (RREventPtr *) data;
317    for (pCur = *pHead; pCur; pCur = pNext) {
318	pNext = pCur->next;
319	FreeResource (pCur->clientResource, RRClientType);
320	free((pointer) pCur);
321    }
322    free((pointer) pHead);
323    return 1;
324}
325
326void
327RRExtensionInit (void)
328{
329    ExtensionEntry *extEntry;
330
331    if (RRNScreens == 0) return;
332
333    if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec, PRIVATE_CLIENT,
334			       sizeof (RRClientRec) +
335			       screenInfo.numScreens * sizeof (RRTimesRec)))
336	return;
337    if (!AddCallback (&ClientStateCallback, RRClientCallback, 0))
338	return;
339
340    RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient");
341    if (!RRClientType)
342	return;
343    RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent");
344    if (!RREventType)
345	return;
346    extEntry = AddExtension (RANDR_NAME, RRNumberEvents, RRNumberErrors,
347			     ProcRRDispatch, SProcRRDispatch,
348			     NULL, StandardMinorOpcode);
349    if (!extEntry)
350	return;
351    RRErrorBase = extEntry->errorBase;
352    RREventBase = extEntry->eventBase;
353    EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr)
354	SRRScreenChangeNotifyEvent;
355    EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr)
356	SRRNotifyEvent;
357
358    RRModeInitErrorValue();
359    RRCrtcInitErrorValue();
360    RROutputInitErrorValue();
361
362#ifdef PANORAMIX
363    RRXineramaExtensionInit();
364#endif
365}
366
367static int
368TellChanged (WindowPtr pWin, pointer value)
369{
370    RREventPtr			*pHead, pRREvent;
371    ClientPtr			client;
372    ScreenPtr			pScreen = pWin->drawable.pScreen;
373    rrScrPriv(pScreen);
374    int				i;
375
376    dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
377			    RREventType, serverClient, DixReadAccess);
378    if (!pHead)
379	return WT_WALKCHILDREN;
380
381    for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
382    {
383	client = pRREvent->client;
384	if (client == serverClient || client->clientGone)
385	    continue;
386
387	if (pRREvent->mask & RRScreenChangeNotifyMask)
388	    RRDeliverScreenEvent (client, pWin, pScreen);
389
390	if (pRREvent->mask & RRCrtcChangeNotifyMask)
391	{
392	    for (i = 0; i < pScrPriv->numCrtcs; i++)
393	    {
394		RRCrtcPtr   crtc = pScrPriv->crtcs[i];
395		if (crtc->changed)
396		    RRDeliverCrtcEvent (client, pWin, crtc);
397	    }
398	}
399
400	if (pRREvent->mask & RROutputChangeNotifyMask)
401	{
402	    for (i = 0; i < pScrPriv->numOutputs; i++)
403	    {
404		RROutputPtr   output = pScrPriv->outputs[i];
405		if (output->changed)
406		    RRDeliverOutputEvent (client, pWin, output);
407	    }
408	}
409    }
410    return WT_WALKCHILDREN;
411}
412
413/*
414 * Something changed; send events and adjust pointer position
415 */
416void
417RRTellChanged (ScreenPtr pScreen)
418{
419    rrScrPriv (pScreen);
420    int i;
421
422    if (pScrPriv->changed)
423    {
424	UpdateCurrentTime ();
425	if (pScrPriv->configChanged)
426	{
427	    pScrPriv->lastConfigTime = currentTime;
428	    pScrPriv->configChanged = FALSE;
429	}
430	pScrPriv->changed = FALSE;
431	WalkTree (pScreen, TellChanged, (pointer) pScreen);
432	for (i = 0; i < pScrPriv->numOutputs; i++)
433	    pScrPriv->outputs[i]->changed = FALSE;
434	for (i = 0; i < pScrPriv->numCrtcs; i++)
435	    pScrPriv->crtcs[i]->changed = FALSE;
436	if (pScrPriv->layoutChanged)
437	{
438	    pScrPriv->layoutChanged = FALSE;
439	    RRPointerScreenConfigured (pScreen);
440	    RRSendConfigNotify (pScreen);
441	}
442    }
443}
444
445void
446RRSetChanged(ScreenPtr pScreen)
447{
448	rrScrPriv(pScreen);
449
450	pScrPriv->changed = TRUE;
451}
452
453/*
454 * Return the first output which is connected to an active CRTC
455 * Used in emulating 1.0 behaviour
456 */
457RROutputPtr
458RRFirstOutput (ScreenPtr pScreen)
459{
460    rrScrPriv(pScreen);
461    RROutputPtr		    output;
462    int	i, j;
463
464    if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
465	return pScrPriv->primaryOutput;
466
467    for (i = 0; i < pScrPriv->numCrtcs; i++)
468    {
469	RRCrtcPtr   crtc = pScrPriv->crtcs[i];
470	for (j = 0; j < pScrPriv->numOutputs; j++)
471	{
472	    output = pScrPriv->outputs[j];
473	    if (output->crtc == crtc)
474		return output;
475	}
476    }
477    return NULL;
478}
479
480CARD16
481RRVerticalRefresh (xRRModeInfo *mode)
482{
483    CARD32  refresh;
484    CARD32  dots = mode->hTotal * mode->vTotal;
485    if (!dots)
486	return 0;
487    refresh = (mode->dotClock + dots/2) / dots;
488    if (refresh > 0xffff)
489	refresh = 0xffff;
490    return (CARD16) refresh;
491}
492
493static int
494ProcRRDispatch (ClientPtr client)
495{
496    REQUEST(xReq);
497    if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
498	return BadRequest;
499    return (*ProcRandrVector[stuff->data]) (client);
500}
501
502static int
503SProcRRDispatch (ClientPtr client)
504{
505    REQUEST(xReq);
506    if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data])
507	return BadRequest;
508    return (*SProcRandrVector[stuff->data]) (client);
509}
510
511