rrcrtc.c revision 05b261ec
1/*
2 * Copyright © 2006 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include "randrstr.h"
24#include "swaprep.h"
25
26RESTYPE	RRCrtcType;
27
28/*
29 * Notify the CRTC of some change
30 */
31void
32RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
33{
34    ScreenPtr	pScreen = crtc->pScreen;
35
36    crtc->changed = TRUE;
37    if (pScreen)
38    {
39	rrScrPriv(pScreen);
40
41	pScrPriv->changed = TRUE;
42	/*
43	 * Send ConfigureNotify on any layout change
44	 */
45	if (layoutChanged)
46	    pScrPriv->layoutChanged = TRUE;
47    }
48}
49
50/*
51 * Create a CRTC
52 */
53RRCrtcPtr
54RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
55{
56    RRCrtcPtr	    crtc;
57    RRCrtcPtr	    *crtcs;
58    rrScrPrivPtr    pScrPriv;
59
60    if (!RRInit())
61	return NULL;
62
63    pScrPriv = rrGetScrPriv(pScreen);
64
65    /* make space for the crtc pointer */
66    if (pScrPriv->numCrtcs)
67	crtcs = xrealloc (pScrPriv->crtcs,
68			  (pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
69    else
70	crtcs = xalloc (sizeof (RRCrtcPtr));
71    if (!crtcs)
72	return FALSE;
73    pScrPriv->crtcs = crtcs;
74
75    crtc = xalloc (sizeof (RRCrtcRec));
76    if (!crtc)
77	return NULL;
78    crtc->id = FakeClientID (0);
79    crtc->pScreen = pScreen;
80    crtc->mode = NULL;
81    crtc->x = 0;
82    crtc->y = 0;
83    crtc->rotation = RR_Rotate_0;
84    crtc->rotations = RR_Rotate_0;
85    crtc->outputs = NULL;
86    crtc->numOutputs = 0;
87    crtc->gammaSize = 0;
88    crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
89    crtc->changed = FALSE;
90    crtc->devPrivate = devPrivate;
91
92    if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
93	return NULL;
94
95    /* attach the screen and crtc together */
96    crtc->pScreen = pScreen;
97    pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
98
99    return crtc;
100}
101
102/*
103 * Set the allowed rotations on a CRTC
104 */
105void
106RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations)
107{
108    crtc->rotations = rotations;
109}
110
111/*
112 * Notify the extension that the Crtc has been reconfigured,
113 * the driver calls this whenever it has updated the mode
114 */
115Bool
116RRCrtcNotify (RRCrtcPtr	    crtc,
117	      RRModePtr	    mode,
118	      int	    x,
119	      int	    y,
120	      Rotation	    rotation,
121	      int	    numOutputs,
122	      RROutputPtr   *outputs)
123{
124    int	    i, j;
125
126    /*
127     * Check to see if any of the new outputs were
128     * not in the old list and mark them as changed
129     */
130    for (i = 0; i < numOutputs; i++)
131    {
132	for (j = 0; j < crtc->numOutputs; j++)
133	    if (outputs[i] == crtc->outputs[j])
134		break;
135	if (j == crtc->numOutputs)
136	{
137	    outputs[i]->crtc = crtc;
138	    RROutputChanged (outputs[i], FALSE);
139	    RRCrtcChanged (crtc, FALSE);
140	}
141    }
142    /*
143     * Check to see if any of the old outputs are
144     * not in the new list and mark them as changed
145     */
146    for (j = 0; j < crtc->numOutputs; j++)
147    {
148	for (i = 0; i < numOutputs; i++)
149	    if (outputs[i] == crtc->outputs[j])
150		break;
151	if (i == numOutputs)
152	{
153	    crtc->outputs[j]->crtc = NULL;
154	    RROutputChanged (crtc->outputs[j], FALSE);
155	    RRCrtcChanged (crtc, FALSE);
156	}
157    }
158    /*
159     * Reallocate the crtc output array if necessary
160     */
161    if (numOutputs != crtc->numOutputs)
162    {
163	RROutputPtr *newoutputs;
164
165	if (numOutputs)
166	{
167	    if (crtc->numOutputs)
168		newoutputs = xrealloc (crtc->outputs,
169				    numOutputs * sizeof (RROutputPtr));
170	    else
171		newoutputs = xalloc (numOutputs * sizeof (RROutputPtr));
172	    if (!newoutputs)
173		return FALSE;
174	}
175	else
176	{
177	    if (crtc->outputs)
178		xfree (crtc->outputs);
179	    newoutputs = NULL;
180	}
181	crtc->outputs = newoutputs;
182	crtc->numOutputs = numOutputs;
183    }
184    /*
185     * Copy the new list of outputs into the crtc
186     */
187    memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr));
188    /*
189     * Update remaining crtc fields
190     */
191    if (mode != crtc->mode)
192    {
193	if (crtc->mode)
194	    RRModeDestroy (crtc->mode);
195	crtc->mode = mode;
196	if (mode != NULL)
197	    mode->refcnt++;
198	RRCrtcChanged (crtc, TRUE);
199    }
200    if (x != crtc->x)
201    {
202	crtc->x = x;
203	RRCrtcChanged (crtc, TRUE);
204    }
205    if (y != crtc->y)
206    {
207	crtc->y = y;
208	RRCrtcChanged (crtc, TRUE);
209    }
210    if (rotation != crtc->rotation)
211    {
212	crtc->rotation = rotation;
213	RRCrtcChanged (crtc, TRUE);
214    }
215    return TRUE;
216}
217
218void
219RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
220{
221    ScreenPtr pScreen = pWin->drawable.pScreen;
222    rrScrPriv (pScreen);
223    xRRCrtcChangeNotifyEvent	ce;
224    RRModePtr	mode = crtc->mode;
225
226    ce.type = RRNotify + RREventBase;
227    ce.subCode = RRNotify_CrtcChange;
228    ce.sequenceNumber = client->sequence;
229    ce.timestamp = pScrPriv->lastSetTime.milliseconds;
230    ce.window = pWin->drawable.id;
231    ce.crtc = crtc->id;
232    ce.rotation = crtc->rotation;
233    if (mode)
234    {
235	ce.mode = mode->mode.id;
236	ce.x = crtc->x;
237	ce.y = crtc->y;
238	ce.width = mode->mode.width;
239	ce.height = mode->mode.height;
240    }
241    else
242    {
243	ce.mode = None;
244	ce.x = 0;
245	ce.y = 0;
246	ce.width = 0;
247	ce.height = 0;
248    }
249    WriteEventsToClient (client, 1, (xEvent *) &ce);
250}
251
252static Bool
253RRCrtcPendingProperties (RRCrtcPtr crtc)
254{
255    ScreenPtr	pScreen = crtc->pScreen;
256    rrScrPriv(pScreen);
257    int		o;
258
259    for (o = 0; o < pScrPriv->numOutputs; o++)
260    {
261	RROutputPtr output = pScrPriv->outputs[o];
262	if (output->crtc == crtc && output->pendingProperties)
263	    return TRUE;
264    }
265    return FALSE;
266}
267
268/*
269 * Request that the Crtc be reconfigured
270 */
271Bool
272RRCrtcSet (RRCrtcPtr    crtc,
273	   RRModePtr	mode,
274	   int		x,
275	   int		y,
276	   Rotation	rotation,
277	   int		numOutputs,
278	   RROutputPtr  *outputs)
279{
280    ScreenPtr	pScreen = crtc->pScreen;
281    Bool	ret = FALSE;
282    rrScrPriv(pScreen);
283
284    /* See if nothing changed */
285    if (crtc->mode == mode &&
286	crtc->x == x &&
287	crtc->y == y &&
288	crtc->rotation == rotation &&
289	crtc->numOutputs == numOutputs &&
290	!memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
291	!RRCrtcPendingProperties (crtc))
292    {
293	ret = TRUE;
294    }
295    else
296    {
297#if RANDR_12_INTERFACE
298	if (pScrPriv->rrCrtcSet)
299	{
300	    ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
301					  rotation, numOutputs, outputs);
302	}
303	else
304#endif
305	{
306#if RANDR_10_INTERFACE
307	    if (pScrPriv->rrSetConfig)
308	    {
309		RRScreenSize	    size;
310		RRScreenRate	    rate;
311
312		if (!mode)
313		{
314		    RRCrtcNotify (crtc, NULL, x, y, rotation, 0, NULL);
315		    ret = TRUE;
316		}
317		else
318		{
319		    size.width = mode->mode.width;
320		    size.height = mode->mode.height;
321		    if (outputs[0]->mmWidth && outputs[0]->mmHeight)
322		    {
323			size.mmWidth = outputs[0]->mmWidth;
324			size.mmHeight = outputs[0]->mmHeight;
325		    }
326		    else
327		    {
328			size.mmWidth = pScreen->mmWidth;
329			size.mmHeight = pScreen->mmHeight;
330		    }
331		    size.nRates = 1;
332		    rate.rate = RRVerticalRefresh (&mode->mode);
333		    size.pRates = &rate;
334		    ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size);
335		    /*
336		     * Old 1.0 interface tied screen size to mode size
337		     */
338		    if (ret)
339		    {
340			RRCrtcNotify (crtc, mode, x, y, rotation, 1, outputs);
341			RRScreenSizeNotify (pScreen);
342		    }
343		}
344	    }
345#endif
346	}
347	if (ret)
348	{
349	    int	o;
350	    RRTellChanged (pScreen);
351
352	    for (o = 0; o < numOutputs; o++)
353		RRPostPendingProperties (outputs[o]);
354	}
355    }
356    return ret;
357}
358
359/*
360 * Destroy a Crtc at shutdown
361 */
362void
363RRCrtcDestroy (RRCrtcPtr crtc)
364{
365    FreeResource (crtc->id, 0);
366}
367
368static int
369RRCrtcDestroyResource (pointer value, XID pid)
370{
371    RRCrtcPtr	crtc = (RRCrtcPtr) value;
372    ScreenPtr	pScreen = crtc->pScreen;
373
374    if (pScreen)
375    {
376	rrScrPriv(pScreen);
377	int		i;
378
379	for (i = 0; i < pScrPriv->numCrtcs; i++)
380	{
381	    if (pScrPriv->crtcs[i] == crtc)
382	    {
383		memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
384			 (pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr));
385		--pScrPriv->numCrtcs;
386		break;
387	    }
388	}
389    }
390    if (crtc->gammaRed)
391	xfree (crtc->gammaRed);
392    if (crtc->mode)
393	RRModeDestroy (crtc->mode);
394    xfree (crtc);
395    return 1;
396}
397
398/*
399 * Request that the Crtc gamma be changed
400 */
401
402Bool
403RRCrtcGammaSet (RRCrtcPtr   crtc,
404		CARD16	    *red,
405		CARD16	    *green,
406		CARD16	    *blue)
407{
408    Bool	ret = TRUE;
409#if RANDR_12_INTERFACE
410    ScreenPtr	pScreen = crtc->pScreen;
411#endif
412
413    memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
414    memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
415    memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
416#if RANDR_12_INTERFACE
417    if (pScreen)
418    {
419	rrScrPriv(pScreen);
420	if (pScrPriv->rrCrtcSetGamma)
421	    ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
422    }
423#endif
424    return ret;
425}
426
427/*
428 * Notify the extension that the Crtc gamma has been changed
429 * The driver calls this whenever it has changed the gamma values
430 * in the RRCrtcRec
431 */
432
433Bool
434RRCrtcGammaNotify (RRCrtcPtr	crtc)
435{
436    return TRUE;    /* not much going on here */
437}
438
439/**
440 * Returns the width/height that the crtc scans out from the framebuffer
441 */
442void
443RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
444{
445    if (crtc->mode == NULL) {
446	*width = 0;
447	*height = 0;
448	return;
449    }
450
451    switch (crtc->rotation & 0xf) {
452    case RR_Rotate_0:
453    case RR_Rotate_180:
454	*width = crtc->mode->mode.width;
455	*height = crtc->mode->mode.height;
456	break;
457    case RR_Rotate_90:
458    case RR_Rotate_270:
459	*width = crtc->mode->mode.height;
460	*height = crtc->mode->mode.width;
461	break;
462    }
463}
464
465/*
466 * Set the size of the gamma table at server startup time
467 */
468
469Bool
470RRCrtcGammaSetSize (RRCrtcPtr	crtc,
471		    int		size)
472{
473    CARD16  *gamma;
474
475    if (size == crtc->gammaSize)
476	return TRUE;
477    if (size)
478    {
479	gamma = xalloc (size * 3 * sizeof (CARD16));
480	if (!gamma)
481	    return FALSE;
482    }
483    else
484	gamma = NULL;
485    if (crtc->gammaRed)
486	xfree (crtc->gammaRed);
487    crtc->gammaRed = gamma;
488    crtc->gammaGreen = gamma + size;
489    crtc->gammaBlue = gamma + size*2;
490    crtc->gammaSize = size;
491    return TRUE;
492}
493
494/*
495 * Initialize crtc type
496 */
497Bool
498RRCrtcInit (void)
499{
500    RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource);
501    if (!RRCrtcType)
502	return FALSE;
503#ifdef XResExtension
504	RegisterResourceName (RRCrtcType, "CRTC");
505#endif
506    return TRUE;
507}
508
509int
510ProcRRGetCrtcInfo (ClientPtr client)
511{
512    REQUEST(xRRGetCrtcInfoReq);
513    xRRGetCrtcInfoReply	rep;
514    RRCrtcPtr			crtc;
515    CARD8			*extra;
516    unsigned long		extraLen;
517    ScreenPtr			pScreen;
518    rrScrPrivPtr		pScrPriv;
519    RRModePtr			mode;
520    RROutput			*outputs;
521    RROutput			*possible;
522    int				i, j, k, n;
523    int				width, height;
524
525    REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
526    crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
527
528    if (!crtc)
529	return RRErrorBase + BadRRCrtc;
530
531    /* All crtcs must be associated with screens before client
532     * requests are processed
533     */
534    pScreen = crtc->pScreen;
535    pScrPriv = rrGetScrPriv(pScreen);
536
537    mode = crtc->mode;
538
539    rep.type = X_Reply;
540    rep.status = RRSetConfigSuccess;
541    rep.sequenceNumber = client->sequence;
542    rep.length = 0;
543    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
544    rep.x = crtc->x;
545    rep.y = crtc->y;
546    RRCrtcGetScanoutSize (crtc, &width, &height);
547    rep.width = width;
548    rep.height = height;
549    rep.mode = mode ? mode->mode.id : 0;
550    rep.rotation = crtc->rotation;
551    rep.rotations = crtc->rotations;
552    rep.nOutput = crtc->numOutputs;
553    k = 0;
554    for (i = 0; i < pScrPriv->numOutputs; i++)
555	for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
556	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
557		k++;
558    rep.nPossibleOutput = k;
559
560    rep.length = rep.nOutput + rep.nPossibleOutput;
561
562    extraLen = rep.length << 2;
563    if (extraLen)
564    {
565	extra = xalloc (extraLen);
566	if (!extra)
567	    return BadAlloc;
568    }
569    else
570	extra = NULL;
571
572    outputs = (RROutput *) extra;
573    possible = (RROutput *) (outputs + rep.nOutput);
574
575    for (i = 0; i < crtc->numOutputs; i++)
576    {
577	outputs[i] = crtc->outputs[i]->id;
578	if (client->swapped)
579	    swapl (&outputs[i], n);
580    }
581    k = 0;
582    for (i = 0; i < pScrPriv->numOutputs; i++)
583	for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
584	    if (pScrPriv->outputs[i]->crtcs[j] == crtc)
585	    {
586		possible[k] = pScrPriv->outputs[i]->id;
587		if (client->swapped)
588		    swapl (&possible[k], n);
589		k++;
590	    }
591
592    if (client->swapped) {
593	swaps(&rep.sequenceNumber, n);
594	swapl(&rep.length, n);
595	swapl(&rep.timestamp, n);
596	swaps(&rep.x, n);
597	swaps(&rep.y, n);
598	swaps(&rep.width, n);
599	swaps(&rep.height, n);
600	swapl(&rep.mode, n);
601	swaps(&rep.rotation, n);
602	swaps(&rep.rotations, n);
603	swaps(&rep.nOutput, n);
604	swaps(&rep.nPossibleOutput, n);
605    }
606    WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep);
607    if (extraLen)
608    {
609	WriteToClient (client, extraLen, (char *) extra);
610	xfree (extra);
611    }
612
613    return client->noClientException;
614}
615
616int
617ProcRRSetCrtcConfig (ClientPtr client)
618{
619    REQUEST(xRRSetCrtcConfigReq);
620    xRRSetCrtcConfigReply   rep;
621    ScreenPtr		    pScreen;
622    rrScrPrivPtr	    pScrPriv;
623    RRCrtcPtr		    crtc;
624    RRModePtr		    mode;
625    int			    numOutputs;
626    RROutputPtr		    *outputs = NULL;
627    RROutput		    *outputIds;
628    TimeStamp		    configTime;
629    TimeStamp		    time;
630    Rotation		    rotation;
631    int			    i, j;
632
633    REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
634    numOutputs = (stuff->length - (SIZEOF (xRRSetCrtcConfigReq) >> 2));
635
636    crtc = LookupIDByType (stuff->crtc, RRCrtcType);
637    if (!crtc)
638    {
639	client->errorValue = stuff->crtc;
640	return RRErrorBase + BadRRCrtc;
641    }
642    if (stuff->mode == None)
643    {
644	mode = NULL;
645	if (numOutputs > 0)
646	    return BadMatch;
647    }
648    else
649    {
650	mode = LookupIDByType (stuff->mode, RRModeType);
651	if (!mode)
652	{
653	    client->errorValue = stuff->mode;
654	    return RRErrorBase + BadRRMode;
655	}
656	if (numOutputs == 0)
657	    return BadMatch;
658    }
659    if (numOutputs)
660    {
661	outputs = xalloc (numOutputs * sizeof (RROutputPtr));
662	if (!outputs)
663	    return BadAlloc;
664    }
665    else
666	outputs = NULL;
667
668    outputIds = (RROutput *) (stuff + 1);
669    for (i = 0; i < numOutputs; i++)
670    {
671	outputs[i] = (RROutputPtr) LookupIDByType (outputIds[i], RROutputType);
672	if (!outputs[i])
673	{
674	    client->errorValue = outputIds[i];
675	    if (outputs)
676		xfree (outputs);
677	    return RRErrorBase + BadRROutput;
678	}
679	/* validate crtc for this output */
680	for (j = 0; j < outputs[i]->numCrtcs; j++)
681	    if (outputs[i]->crtcs[j] == crtc)
682		break;
683	if (j == outputs[i]->numCrtcs)
684	{
685	    if (outputs)
686		xfree (outputs);
687	    return BadMatch;
688	}
689	/* validate mode for this output */
690	for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
691	{
692	    RRModePtr	m = (j < outputs[i]->numModes ?
693			     outputs[i]->modes[j] :
694			     outputs[i]->userModes[j - outputs[i]->numModes]);
695	    if (m == mode)
696		break;
697	}
698	if (j == outputs[i]->numModes + outputs[i]->numUserModes)
699	{
700	    if (outputs)
701		xfree (outputs);
702	    return BadMatch;
703	}
704    }
705    /* validate clones */
706    for (i = 0; i < numOutputs; i++)
707    {
708	for (j = 0; j < numOutputs; j++)
709	{
710	    int k;
711	    if (i == j)
712		continue;
713	    for (k = 0; k < outputs[i]->numClones; k++)
714	    {
715		if (outputs[i]->clones[k] == outputs[j])
716		    break;
717	    }
718	    if (k == outputs[i]->numClones)
719	    {
720		if (outputs)
721		    xfree (outputs);
722		return BadMatch;
723	    }
724	}
725    }
726
727    pScreen = crtc->pScreen;
728    pScrPriv = rrGetScrPriv(pScreen);
729
730    time = ClientTimeToServerTime(stuff->timestamp);
731    configTime = ClientTimeToServerTime(stuff->configTimestamp);
732
733    if (!pScrPriv)
734    {
735	time = currentTime;
736	rep.status = RRSetConfigFailed;
737	goto sendReply;
738    }
739
740#if 0
741    /*
742     * if the client's config timestamp is not the same as the last config
743     * timestamp, then the config information isn't up-to-date and
744     * can't even be validated
745     */
746    if (CompareTimeStamps (configTime, pScrPriv->lastConfigTime) != 0)
747    {
748	rep.status = RRSetConfigInvalidConfigTime;
749	goto sendReply;
750    }
751#endif
752
753    /*
754     * Validate requested rotation
755     */
756    rotation = (Rotation) stuff->rotation;
757
758    /* test the rotation bits only! */
759    switch (rotation & 0xf) {
760    case RR_Rotate_0:
761    case RR_Rotate_90:
762    case RR_Rotate_180:
763    case RR_Rotate_270:
764	break;
765    default:
766	/*
767	 * Invalid rotation
768	 */
769	client->errorValue = stuff->rotation;
770	if (outputs)
771	    xfree (outputs);
772	return BadValue;
773    }
774
775    if (mode)
776    {
777	if ((~crtc->rotations) & rotation)
778	{
779	    /*
780	     * requested rotation or reflection not supported by screen
781	     */
782	    client->errorValue = stuff->rotation;
783	    if (outputs)
784		xfree (outputs);
785	    return BadMatch;
786	}
787
788#ifdef RANDR_12_INTERFACE
789	/*
790	 * Check screen size bounds if the DDX provides a 1.2 interface
791	 * for setting screen size. Else, assume the CrtcSet sets
792	 * the size along with the mode
793	 */
794	if (pScrPriv->rrScreenSetSize)
795	{
796	    int source_width = mode->mode.width;
797	    int	source_height = mode->mode.height;
798
799	    if ((rotation & 0xf) == RR_Rotate_90 || (rotation & 0xf) == RR_Rotate_270)
800	    {
801		source_width = mode->mode.height;
802		source_height = mode->mode.width;
803	    }
804	    if (stuff->x + source_width > pScreen->width)
805	    {
806		client->errorValue = stuff->x;
807		if (outputs)
808		    xfree (outputs);
809		return BadValue;
810	    }
811
812	    if (stuff->y + source_height > pScreen->height)
813	    {
814		client->errorValue = stuff->y;
815		if (outputs)
816		    xfree (outputs);
817		return BadValue;
818	    }
819	}
820#endif
821    }
822
823    /*
824     * Make sure the requested set-time is not older than
825     * the last set-time
826     */
827    if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
828    {
829	rep.status = RRSetConfigInvalidTime;
830	goto sendReply;
831    }
832
833    if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
834		   rotation, numOutputs, outputs))
835    {
836	rep.status = RRSetConfigFailed;
837	goto sendReply;
838    }
839    rep.status = RRSetConfigSuccess;
840
841sendReply:
842    if (outputs)
843	xfree (outputs);
844
845    rep.type = X_Reply;
846    /* rep.status has already been filled in */
847    rep.length = 0;
848    rep.sequenceNumber = client->sequence;
849    rep.newTimestamp = pScrPriv->lastConfigTime.milliseconds;
850
851    if (client->swapped)
852    {
853	int n;
854    	swaps(&rep.sequenceNumber, n);
855    	swapl(&rep.length, n);
856	swapl(&rep.newTimestamp, n);
857    }
858    WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
859
860    return client->noClientException;
861}
862
863int
864ProcRRGetCrtcGammaSize (ClientPtr client)
865{
866    REQUEST(xRRGetCrtcGammaSizeReq);
867    xRRGetCrtcGammaSizeReply	reply;
868    RRCrtcPtr			crtc;
869    int				n;
870
871    REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
872    crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
873    if (!crtc)
874	return RRErrorBase + BadRRCrtc;
875
876    reply.type = X_Reply;
877    reply.sequenceNumber = client->sequence;
878    reply.length = 0;
879    reply.size = crtc->gammaSize;
880    if (client->swapped) {
881	swaps (&reply.sequenceNumber, n);
882	swapl (&reply.length, n);
883	swaps (&reply.size, n);
884    }
885    WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
886    return client->noClientException;
887}
888
889int
890ProcRRGetCrtcGamma (ClientPtr client)
891{
892    REQUEST(xRRGetCrtcGammaReq);
893    xRRGetCrtcGammaReply	reply;
894    RRCrtcPtr			crtc;
895    int				n;
896    unsigned long		len;
897
898    REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
899    crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
900    if (!crtc)
901	return RRErrorBase + BadRRCrtc;
902
903    len = crtc->gammaSize * 3 * 2;
904
905    reply.type = X_Reply;
906    reply.sequenceNumber = client->sequence;
907    reply.length = (len + 3) >> 2;
908    reply.size = crtc->gammaSize;
909    if (client->swapped) {
910	swaps (&reply.sequenceNumber, n);
911	swapl (&reply.length, n);
912	swaps (&reply.size, n);
913    }
914    WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
915    if (crtc->gammaSize)
916    {
917	client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
918	WriteSwappedDataToClient (client, len, (char *) crtc->gammaRed);
919    }
920    return client->noClientException;
921}
922
923int
924ProcRRSetCrtcGamma (ClientPtr client)
925{
926    REQUEST(xRRSetCrtcGammaReq);
927    RRCrtcPtr			crtc;
928    unsigned long		len;
929    CARD16			*red, *green, *blue;
930
931    REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
932    crtc = LookupCrtc (client, stuff->crtc, DixWriteAccess);
933    if (!crtc)
934	return RRErrorBase + BadRRCrtc;
935
936    len = client->req_len - (sizeof (xRRSetCrtcGammaReq) >> 2);
937    if (len < (stuff->size * 3 + 1) >> 1)
938	return BadLength;
939
940    if (stuff->size != crtc->gammaSize)
941	return BadMatch;
942
943    red = (CARD16 *) (stuff + 1);
944    green = red + crtc->gammaSize;
945    blue = green + crtc->gammaSize;
946
947    RRCrtcGammaSet (crtc, red, green, blue);
948
949    return Success;
950}
951
952