1706f2543Smrg/*
2706f2543Smrg * Copyright © 2006 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
7706f2543Smrg * notice and this permission notice appear in supporting documentation, and
8706f2543Smrg * that the name of the copyright holders not be used in advertising or
9706f2543Smrg * publicity pertaining to distribution of the software without specific,
10706f2543Smrg * written prior permission.  The copyright holders make no representations
11706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
12706f2543Smrg * is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20706f2543Smrg * OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#include "randrstr.h"
24706f2543Smrg
25706f2543Smrgstatic const int padlength[4] = {0, 3, 2, 1};
26706f2543Smrg
27706f2543Smrgstatic CARD16
28706f2543SmrgRR10CurrentSizeID (ScreenPtr pScreen);
29706f2543Smrg
30706f2543Smrg/*
31706f2543Smrg * Edit connection information block so that new clients
32706f2543Smrg * see the current screen size on connect
33706f2543Smrg */
34706f2543Smrgstatic void
35706f2543SmrgRREditConnectionInfo (ScreenPtr pScreen)
36706f2543Smrg{
37706f2543Smrg    xConnSetup	    *connSetup;
38706f2543Smrg    char	    *vendor;
39706f2543Smrg    xPixmapFormat   *formats;
40706f2543Smrg    xWindowRoot	    *root;
41706f2543Smrg    xDepth	    *depth;
42706f2543Smrg    xVisualType	    *visual;
43706f2543Smrg    int		    screen = 0;
44706f2543Smrg    int		    d;
45706f2543Smrg
46706f2543Smrg    connSetup = (xConnSetup *) ConnectionInfo;
47706f2543Smrg    vendor = (char *) connSetup + sizeof (xConnSetup);
48706f2543Smrg    formats = (xPixmapFormat *) ((char *) vendor +
49706f2543Smrg				 connSetup->nbytesVendor +
50706f2543Smrg				 padlength[connSetup->nbytesVendor & 3]);
51706f2543Smrg    root = (xWindowRoot *) ((char *) formats +
52706f2543Smrg			    sizeof (xPixmapFormat) * screenInfo.numPixmapFormats);
53706f2543Smrg    while (screen != pScreen->myNum)
54706f2543Smrg    {
55706f2543Smrg	depth = (xDepth *) ((char *) root +
56706f2543Smrg			    sizeof (xWindowRoot));
57706f2543Smrg	for (d = 0; d < root->nDepths; d++)
58706f2543Smrg	{
59706f2543Smrg	    visual = (xVisualType *) ((char *) depth +
60706f2543Smrg				      sizeof (xDepth));
61706f2543Smrg	    depth = (xDepth *) ((char *) visual +
62706f2543Smrg				depth->nVisuals * sizeof (xVisualType));
63706f2543Smrg	}
64706f2543Smrg	root = (xWindowRoot *) ((char *) depth);
65706f2543Smrg	screen++;
66706f2543Smrg    }
67706f2543Smrg    root->pixWidth = pScreen->width;
68706f2543Smrg    root->pixHeight = pScreen->height;
69706f2543Smrg    root->mmWidth = pScreen->mmWidth;
70706f2543Smrg    root->mmHeight = pScreen->mmHeight;
71706f2543Smrg}
72706f2543Smrg
73706f2543Smrgvoid
74706f2543SmrgRRSendConfigNotify (ScreenPtr pScreen)
75706f2543Smrg{
76706f2543Smrg    WindowPtr	pWin = pScreen->root;
77706f2543Smrg    xEvent	event;
78706f2543Smrg
79706f2543Smrg    event.u.u.type = ConfigureNotify;
80706f2543Smrg    event.u.configureNotify.window = pWin->drawable.id;
81706f2543Smrg    event.u.configureNotify.aboveSibling = None;
82706f2543Smrg    event.u.configureNotify.x = 0;
83706f2543Smrg    event.u.configureNotify.y = 0;
84706f2543Smrg
85706f2543Smrg    /* XXX xinerama stuff ? */
86706f2543Smrg
87706f2543Smrg    event.u.configureNotify.width = pWin->drawable.width;
88706f2543Smrg    event.u.configureNotify.height = pWin->drawable.height;
89706f2543Smrg    event.u.configureNotify.borderWidth = wBorderWidth (pWin);
90706f2543Smrg    event.u.configureNotify.override = pWin->overrideRedirect;
91706f2543Smrg    DeliverEvents(pWin, &event, 1, NullWindow);
92706f2543Smrg}
93706f2543Smrg
94706f2543Smrgvoid
95706f2543SmrgRRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen)
96706f2543Smrg{
97706f2543Smrg    rrScrPriv (pScreen);
98706f2543Smrg    xRRScreenChangeNotifyEvent	se;
99706f2543Smrg    RRCrtcPtr	crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL;
100706f2543Smrg    WindowPtr	pRoot = pScreen->root;
101706f2543Smrg
102706f2543Smrg    se.type = RRScreenChangeNotify + RREventBase;
103706f2543Smrg    se.rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0);
104706f2543Smrg    se.timestamp = pScrPriv->lastSetTime.milliseconds;
105706f2543Smrg    se.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
106706f2543Smrg    se.root =  pRoot->drawable.id;
107706f2543Smrg    se.window = pWin->drawable.id;
108706f2543Smrg    se.subpixelOrder = PictureGetSubpixelOrder (pScreen);
109706f2543Smrg
110706f2543Smrg    se.sizeID = RR10CurrentSizeID (pScreen);
111706f2543Smrg
112706f2543Smrg    if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) {
113706f2543Smrg	se.widthInPixels = pScreen->height;
114706f2543Smrg	se.heightInPixels = pScreen->width;
115706f2543Smrg	se.widthInMillimeters = pScreen->mmHeight;
116706f2543Smrg	se.heightInMillimeters = pScreen->mmWidth;
117706f2543Smrg    } else {
118706f2543Smrg	se.widthInPixels = pScreen->width;
119706f2543Smrg	se.heightInPixels = pScreen->height;
120706f2543Smrg	se.widthInMillimeters = pScreen->mmWidth;
121706f2543Smrg	se.heightInMillimeters = pScreen->mmHeight;
122706f2543Smrg    }
123706f2543Smrg
124706f2543Smrg    WriteEventsToClient (client, 1, (xEvent *) &se);
125706f2543Smrg}
126706f2543Smrg
127706f2543Smrg/*
128706f2543Smrg * Notify the extension that the screen size has been changed.
129706f2543Smrg * The driver is responsible for calling this whenever it has changed
130706f2543Smrg * the size of the screen
131706f2543Smrg */
132706f2543Smrgvoid
133706f2543SmrgRRScreenSizeNotify (ScreenPtr	pScreen)
134706f2543Smrg{
135706f2543Smrg    rrScrPriv(pScreen);
136706f2543Smrg    /*
137706f2543Smrg     * Deliver ConfigureNotify events when root changes
138706f2543Smrg     * pixel size
139706f2543Smrg     */
140706f2543Smrg    if (pScrPriv->width == pScreen->width &&
141706f2543Smrg	pScrPriv->height == pScreen->height &&
142706f2543Smrg	pScrPriv->mmWidth == pScreen->mmWidth &&
143706f2543Smrg	pScrPriv->mmHeight == pScreen->mmHeight)
144706f2543Smrg	return;
145706f2543Smrg
146706f2543Smrg    pScrPriv->width = pScreen->width;
147706f2543Smrg    pScrPriv->height = pScreen->height;
148706f2543Smrg    pScrPriv->mmWidth = pScreen->mmWidth;
149706f2543Smrg    pScrPriv->mmHeight = pScreen->mmHeight;
150706f2543Smrg    pScrPriv->changed = TRUE;
151706f2543Smrg/*    pScrPriv->sizeChanged = TRUE; */
152706f2543Smrg
153706f2543Smrg    RRTellChanged (pScreen);
154706f2543Smrg    RRSendConfigNotify (pScreen);
155706f2543Smrg    RREditConnectionInfo (pScreen);
156706f2543Smrg
157706f2543Smrg    RRPointerScreenConfigured (pScreen);
158706f2543Smrg    /*
159706f2543Smrg     * Fix pointer bounds and location
160706f2543Smrg     */
161706f2543Smrg    ScreenRestructured (pScreen);
162706f2543Smrg}
163706f2543Smrg
164706f2543Smrg/*
165706f2543Smrg * Request that the screen be resized
166706f2543Smrg */
167706f2543SmrgBool
168706f2543SmrgRRScreenSizeSet (ScreenPtr  pScreen,
169706f2543Smrg		 CARD16	    width,
170706f2543Smrg		 CARD16	    height,
171706f2543Smrg		 CARD32	    mmWidth,
172706f2543Smrg		 CARD32	    mmHeight)
173706f2543Smrg{
174706f2543Smrg    rrScrPriv(pScreen);
175706f2543Smrg
176706f2543Smrg#if RANDR_12_INTERFACE
177706f2543Smrg    if (pScrPriv->rrScreenSetSize)
178706f2543Smrg    {
179706f2543Smrg	return (*pScrPriv->rrScreenSetSize) (pScreen,
180706f2543Smrg					     width, height,
181706f2543Smrg					     mmWidth, mmHeight);
182706f2543Smrg    }
183706f2543Smrg#endif
184706f2543Smrg#if RANDR_10_INTERFACE
185706f2543Smrg    if (pScrPriv->rrSetConfig)
186706f2543Smrg    {
187706f2543Smrg	return TRUE;	/* can't set size separately */
188706f2543Smrg    }
189706f2543Smrg#endif
190706f2543Smrg    return FALSE;
191706f2543Smrg}
192706f2543Smrg
193706f2543Smrg/*
194706f2543Smrg * Retrieve valid screen size range
195706f2543Smrg */
196706f2543Smrgint
197706f2543SmrgProcRRGetScreenSizeRange (ClientPtr client)
198706f2543Smrg{
199706f2543Smrg    REQUEST(xRRGetScreenSizeRangeReq);
200706f2543Smrg    xRRGetScreenSizeRangeReply	rep;
201706f2543Smrg    WindowPtr			pWin;
202706f2543Smrg    ScreenPtr			pScreen;
203706f2543Smrg    rrScrPrivPtr		pScrPriv;
204706f2543Smrg    int				rc;
205706f2543Smrg
206706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
207706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
208706f2543Smrg    if (rc != Success)
209706f2543Smrg	return rc;
210706f2543Smrg
211706f2543Smrg    pScreen = pWin->drawable.pScreen;
212706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
213706f2543Smrg
214706f2543Smrg    rep.type = X_Reply;
215706f2543Smrg    rep.pad = 0;
216706f2543Smrg    rep.sequenceNumber = client->sequence;
217706f2543Smrg    rep.length = 0;
218706f2543Smrg
219706f2543Smrg    if (pScrPriv)
220706f2543Smrg    {
221706f2543Smrg	if (!RRGetInfo (pScreen, FALSE))
222706f2543Smrg	    return BadAlloc;
223706f2543Smrg	rep.minWidth  = pScrPriv->minWidth;
224706f2543Smrg	rep.minHeight = pScrPriv->minHeight;
225706f2543Smrg	rep.maxWidth  = pScrPriv->maxWidth;
226706f2543Smrg	rep.maxHeight = pScrPriv->maxHeight;
227706f2543Smrg    }
228706f2543Smrg    else
229706f2543Smrg    {
230706f2543Smrg	rep.maxWidth  = rep.minWidth  = pScreen->width;
231706f2543Smrg	rep.maxHeight = rep.minHeight = pScreen->height;
232706f2543Smrg    }
233706f2543Smrg    if (client->swapped)
234706f2543Smrg    {
235706f2543Smrg	int n;
236706f2543Smrg
237706f2543Smrg    	swaps(&rep.sequenceNumber, n);
238706f2543Smrg    	swapl(&rep.length, n);
239706f2543Smrg	swaps(&rep.minWidth, n);
240706f2543Smrg	swaps(&rep.minHeight, n);
241706f2543Smrg	swaps(&rep.maxWidth, n);
242706f2543Smrg	swaps(&rep.maxHeight, n);
243706f2543Smrg    }
244706f2543Smrg    WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), (char *)&rep);
245706f2543Smrg    return Success;
246706f2543Smrg}
247706f2543Smrg
248706f2543Smrgint
249706f2543SmrgProcRRSetScreenSize (ClientPtr client)
250706f2543Smrg{
251706f2543Smrg    REQUEST(xRRSetScreenSizeReq);
252706f2543Smrg    WindowPtr		pWin;
253706f2543Smrg    ScreenPtr		pScreen;
254706f2543Smrg    rrScrPrivPtr	pScrPriv;
255706f2543Smrg    int			i, rc;
256706f2543Smrg
257706f2543Smrg    REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
258706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
259706f2543Smrg    if (rc != Success)
260706f2543Smrg	return rc;
261706f2543Smrg
262706f2543Smrg    pScreen = pWin->drawable.pScreen;
263706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
264706f2543Smrg    if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width)
265706f2543Smrg    {
266706f2543Smrg	client->errorValue = stuff->width;
267706f2543Smrg	return BadValue;
268706f2543Smrg    }
269706f2543Smrg    if (stuff->height < pScrPriv->minHeight ||
270706f2543Smrg	pScrPriv->maxHeight < stuff->height)
271706f2543Smrg    {
272706f2543Smrg	client->errorValue = stuff->height;
273706f2543Smrg	return BadValue;
274706f2543Smrg    }
275706f2543Smrg    for (i = 0; i < pScrPriv->numCrtcs; i++)
276706f2543Smrg    {
277706f2543Smrg	RRCrtcPtr   crtc = pScrPriv->crtcs[i];
278706f2543Smrg	RRModePtr   mode = crtc->mode;
279706f2543Smrg	if (mode)
280706f2543Smrg	{
281706f2543Smrg	    int		source_width = mode->mode.width;
282706f2543Smrg	    int		source_height = mode->mode.height;
283706f2543Smrg	    Rotation	rotation = crtc->rotation;
284706f2543Smrg
285706f2543Smrg	    if (rotation == RR_Rotate_90 || rotation == RR_Rotate_270)
286706f2543Smrg	    {
287706f2543Smrg		source_width = mode->mode.height;
288706f2543Smrg		source_height = mode->mode.width;
289706f2543Smrg	    }
290706f2543Smrg
291706f2543Smrg	    if (crtc->x + source_width > stuff->width ||
292706f2543Smrg		crtc->y + source_height > stuff->height)
293706f2543Smrg	    return BadMatch;
294706f2543Smrg	}
295706f2543Smrg    }
296706f2543Smrg    if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0)
297706f2543Smrg    {
298706f2543Smrg	client->errorValue = 0;
299706f2543Smrg	return BadValue;
300706f2543Smrg    }
301706f2543Smrg    if (!RRScreenSizeSet (pScreen,
302706f2543Smrg			  stuff->width, stuff->height,
303706f2543Smrg			  stuff->widthInMillimeters,
304706f2543Smrg			  stuff->heightInMillimeters))
305706f2543Smrg    {
306706f2543Smrg	return BadMatch;
307706f2543Smrg    }
308706f2543Smrg    return Success;
309706f2543Smrg}
310706f2543Smrg
311706f2543Smrgstatic int
312706f2543SmrgrrGetScreenResources(ClientPtr client, Bool query)
313706f2543Smrg{
314706f2543Smrg    REQUEST(xRRGetScreenResourcesReq);
315706f2543Smrg    xRRGetScreenResourcesReply  rep;
316706f2543Smrg    WindowPtr			pWin;
317706f2543Smrg    ScreenPtr			pScreen;
318706f2543Smrg    rrScrPrivPtr		pScrPriv;
319706f2543Smrg    CARD8			*extra;
320706f2543Smrg    unsigned long		extraLen;
321706f2543Smrg    int				i, n, rc, has_primary = 0;
322706f2543Smrg    RRCrtc			*crtcs;
323706f2543Smrg    RROutput			*outputs;
324706f2543Smrg    xRRModeInfo			*modeinfos;
325706f2543Smrg    CARD8			*names;
326706f2543Smrg
327706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
328706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
329706f2543Smrg    if (rc != Success)
330706f2543Smrg	return rc;
331706f2543Smrg
332706f2543Smrg    pScreen = pWin->drawable.pScreen;
333706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
334706f2543Smrg    rep.pad = 0;
335706f2543Smrg
336706f2543Smrg    if (query && pScrPriv)
337706f2543Smrg	if (!RRGetInfo (pScreen, query))
338706f2543Smrg	    return BadAlloc;
339706f2543Smrg
340706f2543Smrg    if (!pScrPriv)
341706f2543Smrg    {
342706f2543Smrg	rep.type = X_Reply;
343706f2543Smrg	rep.sequenceNumber = client->sequence;
344706f2543Smrg	rep.length = 0;
345706f2543Smrg	rep.timestamp = currentTime.milliseconds;
346706f2543Smrg	rep.configTimestamp = currentTime.milliseconds;
347706f2543Smrg	rep.nCrtcs = 0;
348706f2543Smrg	rep.nOutputs = 0;
349706f2543Smrg	rep.nModes = 0;
350706f2543Smrg	rep.nbytesNames = 0;
351706f2543Smrg	extra = NULL;
352706f2543Smrg	extraLen = 0;
353706f2543Smrg    }
354706f2543Smrg    else
355706f2543Smrg    {
356706f2543Smrg	RRModePtr   *modes;
357706f2543Smrg	int	    num_modes;
358706f2543Smrg
359706f2543Smrg	modes = RRModesForScreen (pScreen, &num_modes);
360706f2543Smrg	if (!modes)
361706f2543Smrg	    return BadAlloc;
362706f2543Smrg
363706f2543Smrg	rep.type = X_Reply;
364706f2543Smrg	rep.sequenceNumber = client->sequence;
365706f2543Smrg	rep.length = 0;
366706f2543Smrg	rep.timestamp = pScrPriv->lastSetTime.milliseconds;
367706f2543Smrg	rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
368706f2543Smrg	rep.nCrtcs = pScrPriv->numCrtcs;
369706f2543Smrg	rep.nOutputs = pScrPriv->numOutputs;
370706f2543Smrg	rep.nModes = num_modes;
371706f2543Smrg	rep.nbytesNames = 0;
372706f2543Smrg
373706f2543Smrg	for (i = 0; i < num_modes; i++)
374706f2543Smrg	    rep.nbytesNames += modes[i]->mode.nameLength;
375706f2543Smrg
376706f2543Smrg	rep.length = (pScrPriv->numCrtcs +
377706f2543Smrg		      pScrPriv->numOutputs +
378706f2543Smrg		      num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
379706f2543Smrg		      bytes_to_int32(rep.nbytesNames));
380706f2543Smrg
381706f2543Smrg	extraLen = rep.length << 2;
382706f2543Smrg	if (extraLen)
383706f2543Smrg	{
384706f2543Smrg	    extra = malloc(extraLen);
385706f2543Smrg	    if (!extra)
386706f2543Smrg	    {
387706f2543Smrg		free(modes);
388706f2543Smrg		return BadAlloc;
389706f2543Smrg	    }
390706f2543Smrg	}
391706f2543Smrg	else
392706f2543Smrg	    extra = NULL;
393706f2543Smrg
394706f2543Smrg	crtcs = (RRCrtc *) extra;
395706f2543Smrg	outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs);
396706f2543Smrg	modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs);
397706f2543Smrg	names = (CARD8 *) (modeinfos + num_modes);
398706f2543Smrg
399706f2543Smrg	if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
400706f2543Smrg	{
401706f2543Smrg	    has_primary = 1;
402706f2543Smrg	    crtcs[0] = pScrPriv->primaryOutput->crtc->id;
403706f2543Smrg	    if (client->swapped)
404706f2543Smrg		swapl (&crtcs[0], n);
405706f2543Smrg	}
406706f2543Smrg
407706f2543Smrg	for (i = 0; i < pScrPriv->numCrtcs; i++)
408706f2543Smrg	{
409706f2543Smrg	    if (has_primary &&
410706f2543Smrg		pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i])
411706f2543Smrg	    {
412706f2543Smrg		has_primary = 0;
413706f2543Smrg		continue;
414706f2543Smrg	    }
415706f2543Smrg	    crtcs[i + has_primary] = pScrPriv->crtcs[i]->id;
416706f2543Smrg	    if (client->swapped)
417706f2543Smrg		swapl (&crtcs[i + has_primary], n);
418706f2543Smrg	}
419706f2543Smrg
420706f2543Smrg	for (i = 0; i < pScrPriv->numOutputs; i++)
421706f2543Smrg	{
422706f2543Smrg	    outputs[i] = pScrPriv->outputs[i]->id;
423706f2543Smrg	    if (client->swapped)
424706f2543Smrg		swapl (&outputs[i], n);
425706f2543Smrg	}
426706f2543Smrg
427706f2543Smrg	for (i = 0; i < num_modes; i++)
428706f2543Smrg	{
429706f2543Smrg	    RRModePtr	mode = modes[i];
430706f2543Smrg	    modeinfos[i] = mode->mode;
431706f2543Smrg	    if (client->swapped)
432706f2543Smrg	    {
433706f2543Smrg		swapl (&modeinfos[i].id, n);
434706f2543Smrg		swaps (&modeinfos[i].width, n);
435706f2543Smrg		swaps (&modeinfos[i].height, n);
436706f2543Smrg		swapl (&modeinfos[i].dotClock, n);
437706f2543Smrg		swaps (&modeinfos[i].hSyncStart, n);
438706f2543Smrg		swaps (&modeinfos[i].hSyncEnd, n);
439706f2543Smrg		swaps (&modeinfos[i].hTotal, n);
440706f2543Smrg		swaps (&modeinfos[i].hSkew, n);
441706f2543Smrg		swaps (&modeinfos[i].vSyncStart, n);
442706f2543Smrg		swaps (&modeinfos[i].vSyncEnd, n);
443706f2543Smrg		swaps (&modeinfos[i].vTotal, n);
444706f2543Smrg		swaps (&modeinfos[i].nameLength, n);
445706f2543Smrg		swapl (&modeinfos[i].modeFlags, n);
446706f2543Smrg	    }
447706f2543Smrg	    memcpy (names, mode->name,
448706f2543Smrg		    mode->mode.nameLength);
449706f2543Smrg	    names += mode->mode.nameLength;
450706f2543Smrg	}
451706f2543Smrg        free(modes);
452706f2543Smrg	assert (bytes_to_int32((char *) names - (char *) extra) == rep.length);
453706f2543Smrg    }
454706f2543Smrg
455706f2543Smrg    if (client->swapped) {
456706f2543Smrg	swaps(&rep.sequenceNumber, n);
457706f2543Smrg	swapl(&rep.length, n);
458706f2543Smrg	swapl(&rep.timestamp, n);
459706f2543Smrg	swapl(&rep.configTimestamp, n);
460706f2543Smrg	swaps(&rep.nCrtcs, n);
461706f2543Smrg	swaps(&rep.nOutputs, n);
462706f2543Smrg	swaps(&rep.nModes, n);
463706f2543Smrg	swaps(&rep.nbytesNames, n);
464706f2543Smrg    }
465706f2543Smrg    WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *)&rep);
466706f2543Smrg    if (extraLen)
467706f2543Smrg    {
468706f2543Smrg	WriteToClient (client, extraLen, (char *) extra);
469706f2543Smrg	free(extra);
470706f2543Smrg    }
471706f2543Smrg    return Success;
472706f2543Smrg}
473706f2543Smrg
474706f2543Smrgint
475706f2543SmrgProcRRGetScreenResources (ClientPtr client)
476706f2543Smrg{
477706f2543Smrg    return rrGetScreenResources(client, TRUE);
478706f2543Smrg}
479706f2543Smrg
480706f2543Smrgint
481706f2543SmrgProcRRGetScreenResourcesCurrent (ClientPtr client)
482706f2543Smrg{
483706f2543Smrg    return rrGetScreenResources(client, FALSE);
484706f2543Smrg}
485706f2543Smrg
486706f2543Smrgtypedef struct _RR10Data {
487706f2543Smrg    RRScreenSizePtr sizes;
488706f2543Smrg    int		    nsize;
489706f2543Smrg    int		    nrefresh;
490706f2543Smrg    int		    size;
491706f2543Smrg    CARD16	    refresh;
492706f2543Smrg} RR10DataRec, *RR10DataPtr;
493706f2543Smrg
494706f2543Smrg/*
495706f2543Smrg * Convert 1.2 monitor data into 1.0 screen data
496706f2543Smrg */
497706f2543Smrgstatic RR10DataPtr
498706f2543SmrgRR10GetData (ScreenPtr pScreen, RROutputPtr output)
499706f2543Smrg{
500706f2543Smrg    RR10DataPtr	    data;
501706f2543Smrg    RRScreenSizePtr size;
502706f2543Smrg    int		    nmode = output->numModes + output->numUserModes;
503706f2543Smrg    int		    o, os, l, r;
504706f2543Smrg    RRScreenRatePtr refresh;
505706f2543Smrg    CARD16	    vRefresh;
506706f2543Smrg    RRModePtr	    mode;
507706f2543Smrg    Bool	    *used;
508706f2543Smrg
509706f2543Smrg    /* Make sure there is plenty of space for any combination */
510706f2543Smrg    data = malloc (sizeof (RR10DataRec) +
511706f2543Smrg		   sizeof (RRScreenSize) * nmode +
512706f2543Smrg		   sizeof (RRScreenRate) * nmode +
513706f2543Smrg		   sizeof (Bool) * nmode);
514706f2543Smrg    if (!data)
515706f2543Smrg	return NULL;
516706f2543Smrg    size = (RRScreenSizePtr) (data + 1);
517706f2543Smrg    refresh = (RRScreenRatePtr) (size + nmode);
518706f2543Smrg    used = (Bool *) (refresh + nmode);
519706f2543Smrg    memset (used, '\0', sizeof (Bool) * nmode);
520706f2543Smrg    data->sizes = size;
521706f2543Smrg    data->nsize = 0;
522706f2543Smrg    data->nrefresh = 0;
523706f2543Smrg    data->size = 0;
524706f2543Smrg    data->refresh = 0;
525706f2543Smrg
526706f2543Smrg    /*
527706f2543Smrg     * find modes not yet listed
528706f2543Smrg     */
529706f2543Smrg    for (o = 0; o < output->numModes + output->numUserModes; o++)
530706f2543Smrg    {
531706f2543Smrg	if (used[o]) continue;
532706f2543Smrg
533706f2543Smrg	if (o < output->numModes)
534706f2543Smrg	    mode = output->modes[o];
535706f2543Smrg	else
536706f2543Smrg	    mode = output->userModes[o - output->numModes];
537706f2543Smrg
538706f2543Smrg	l = data->nsize;
539706f2543Smrg	size[l].id = data->nsize;
540706f2543Smrg	size[l].width = mode->mode.width;
541706f2543Smrg	size[l].height = mode->mode.height;
542706f2543Smrg	if (output->mmWidth && output->mmHeight) {
543706f2543Smrg	    size[l].mmWidth = output->mmWidth;
544706f2543Smrg	    size[l].mmHeight = output->mmHeight;
545706f2543Smrg	} else {
546706f2543Smrg	    size[l].mmWidth = pScreen->mmWidth;
547706f2543Smrg	    size[l].mmHeight = pScreen->mmHeight;
548706f2543Smrg	}
549706f2543Smrg	size[l].nRates = 0;
550706f2543Smrg	size[l].pRates = &refresh[data->nrefresh];
551706f2543Smrg	data->nsize++;
552706f2543Smrg
553706f2543Smrg	/*
554706f2543Smrg	 * Find all modes with matching size
555706f2543Smrg	 */
556706f2543Smrg	for (os = o; os < output->numModes + output->numUserModes; os++)
557706f2543Smrg	{
558706f2543Smrg	    if (os < output->numModes)
559706f2543Smrg		mode = output->modes[os];
560706f2543Smrg	    else
561706f2543Smrg		mode = output->userModes[os - output->numModes];
562706f2543Smrg	    if (mode->mode.width == size[l].width &&
563706f2543Smrg		mode->mode.height == size[l].height)
564706f2543Smrg	    {
565706f2543Smrg		vRefresh = RRVerticalRefresh (&mode->mode);
566706f2543Smrg		used[os] = TRUE;
567706f2543Smrg
568706f2543Smrg		for (r = 0; r < size[l].nRates; r++)
569706f2543Smrg		    if (vRefresh == size[l].pRates[r].rate)
570706f2543Smrg			break;
571706f2543Smrg		if (r == size[l].nRates)
572706f2543Smrg		{
573706f2543Smrg		    size[l].pRates[r].rate = vRefresh;
574706f2543Smrg		    size[l].pRates[r].mode = mode;
575706f2543Smrg		    size[l].nRates++;
576706f2543Smrg		    data->nrefresh++;
577706f2543Smrg		}
578706f2543Smrg		if (mode == output->crtc->mode)
579706f2543Smrg		{
580706f2543Smrg		    data->size = l;
581706f2543Smrg		    data->refresh = vRefresh;
582706f2543Smrg		}
583706f2543Smrg	    }
584706f2543Smrg	}
585706f2543Smrg    }
586706f2543Smrg    return data;
587706f2543Smrg}
588706f2543Smrg
589706f2543Smrgint
590706f2543SmrgProcRRGetScreenInfo (ClientPtr client)
591706f2543Smrg{
592706f2543Smrg    REQUEST(xRRGetScreenInfoReq);
593706f2543Smrg    xRRGetScreenInfoReply   rep;
594706f2543Smrg    WindowPtr	    	    pWin;
595706f2543Smrg    int			    n, rc;
596706f2543Smrg    ScreenPtr		    pScreen;
597706f2543Smrg    rrScrPrivPtr	    pScrPriv;
598706f2543Smrg    CARD8		    *extra;
599706f2543Smrg    unsigned long	    extraLen;
600706f2543Smrg    RROutputPtr		    output;
601706f2543Smrg
602706f2543Smrg    REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
603706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
604706f2543Smrg    if (rc != Success)
605706f2543Smrg	return rc;
606706f2543Smrg
607706f2543Smrg    pScreen = pWin->drawable.pScreen;
608706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
609706f2543Smrg    rep.pad = 0;
610706f2543Smrg
611706f2543Smrg    if (pScrPriv)
612706f2543Smrg	if (!RRGetInfo (pScreen, TRUE))
613706f2543Smrg	    return BadAlloc;
614706f2543Smrg
615706f2543Smrg    output = RRFirstOutput (pScreen);
616706f2543Smrg
617706f2543Smrg    if (!pScrPriv || !output)
618706f2543Smrg    {
619706f2543Smrg	rep.type = X_Reply;
620706f2543Smrg	rep.setOfRotations = RR_Rotate_0;
621706f2543Smrg	rep.sequenceNumber = client->sequence;
622706f2543Smrg	rep.length = 0;
623706f2543Smrg	rep.root = pWin->drawable.pScreen->root->drawable.id;
624706f2543Smrg	rep.timestamp = currentTime.milliseconds;
625706f2543Smrg	rep.configTimestamp = currentTime.milliseconds;
626706f2543Smrg	rep.nSizes = 0;
627706f2543Smrg	rep.sizeID = 0;
628706f2543Smrg	rep.rotation = RR_Rotate_0;
629706f2543Smrg	rep.rate = 0;
630706f2543Smrg	rep.nrateEnts = 0;
631706f2543Smrg	extra = 0;
632706f2543Smrg	extraLen = 0;
633706f2543Smrg    }
634706f2543Smrg    else
635706f2543Smrg    {
636706f2543Smrg	int			i, j;
637706f2543Smrg	xScreenSizes		*size;
638706f2543Smrg	CARD16			*rates;
639706f2543Smrg	CARD8			*data8;
640706f2543Smrg	Bool			has_rate = RRClientKnowsRates (client);
641706f2543Smrg	RR10DataPtr		pData;
642706f2543Smrg	RRScreenSizePtr		pSize;
643706f2543Smrg
644706f2543Smrg	pData = RR10GetData (pScreen, output);
645706f2543Smrg	if (!pData)
646706f2543Smrg	    return BadAlloc;
647706f2543Smrg
648706f2543Smrg	rep.type = X_Reply;
649706f2543Smrg	rep.setOfRotations = output->crtc->rotations;
650706f2543Smrg	rep.sequenceNumber = client->sequence;
651706f2543Smrg	rep.length = 0;
652706f2543Smrg	rep.root = pWin->drawable.pScreen->root->drawable.id;
653706f2543Smrg	rep.timestamp = pScrPriv->lastSetTime.milliseconds;
654706f2543Smrg	rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
655706f2543Smrg	rep.rotation = output->crtc->rotation;
656706f2543Smrg	rep.nSizes = pData->nsize;
657706f2543Smrg        rep.nrateEnts = pData->nrefresh + pData->nsize;
658706f2543Smrg	rep.sizeID = pData->size;
659706f2543Smrg	rep.rate = pData->refresh;
660706f2543Smrg
661706f2543Smrg	extraLen = rep.nSizes * sizeof (xScreenSizes);
662706f2543Smrg	if (has_rate)
663706f2543Smrg		extraLen += rep.nrateEnts * sizeof (CARD16);
664706f2543Smrg
665706f2543Smrg	if (extraLen)
666706f2543Smrg	{
667706f2543Smrg	    extra = (CARD8 *) malloc(extraLen);
668706f2543Smrg	    if (!extra)
669706f2543Smrg	    {
670706f2543Smrg		free(pData);
671706f2543Smrg		return BadAlloc;
672706f2543Smrg	    }
673706f2543Smrg	}
674706f2543Smrg	else
675706f2543Smrg	    extra = NULL;
676706f2543Smrg
677706f2543Smrg	/*
678706f2543Smrg	 * First comes the size information
679706f2543Smrg	 */
680706f2543Smrg	size = (xScreenSizes *) extra;
681706f2543Smrg	rates = (CARD16 *) (size + rep.nSizes);
682706f2543Smrg	for (i = 0; i < pData->nsize; i++)
683706f2543Smrg	{
684706f2543Smrg	    pSize = &pData->sizes[i];
685706f2543Smrg	    size->widthInPixels = pSize->width;
686706f2543Smrg	    size->heightInPixels = pSize->height;
687706f2543Smrg	    size->widthInMillimeters = pSize->mmWidth;
688706f2543Smrg	    size->heightInMillimeters = pSize->mmHeight;
689706f2543Smrg	    if (client->swapped)
690706f2543Smrg	    {
691706f2543Smrg	        swaps (&size->widthInPixels, n);
692706f2543Smrg	        swaps (&size->heightInPixels, n);
693706f2543Smrg	        swaps (&size->widthInMillimeters, n);
694706f2543Smrg	        swaps (&size->heightInMillimeters, n);
695706f2543Smrg	    }
696706f2543Smrg	    size++;
697706f2543Smrg	    if (has_rate)
698706f2543Smrg	    {
699706f2543Smrg		*rates = pSize->nRates;
700706f2543Smrg		if (client->swapped)
701706f2543Smrg		{
702706f2543Smrg		    swaps (rates, n);
703706f2543Smrg		}
704706f2543Smrg		rates++;
705706f2543Smrg		for (j = 0; j < pSize->nRates; j++)
706706f2543Smrg		{
707706f2543Smrg		    *rates = pSize->pRates[j].rate;
708706f2543Smrg		    if (client->swapped)
709706f2543Smrg		    {
710706f2543Smrg			swaps (rates, n);
711706f2543Smrg		    }
712706f2543Smrg		    rates++;
713706f2543Smrg		}
714706f2543Smrg	    }
715706f2543Smrg	}
716706f2543Smrg        free(pData);
717706f2543Smrg
718706f2543Smrg	data8 = (CARD8 *) rates;
719706f2543Smrg
720706f2543Smrg	if (data8 - (CARD8 *) extra != extraLen)
721706f2543Smrg	    FatalError ("RRGetScreenInfo bad extra len %ld != %ld\n",
722706f2543Smrg			(unsigned long)(data8 - (CARD8 *) extra), extraLen);
723706f2543Smrg	rep.length =  bytes_to_int32(extraLen);
724706f2543Smrg    }
725706f2543Smrg    if (client->swapped) {
726706f2543Smrg	swaps(&rep.sequenceNumber, n);
727706f2543Smrg	swapl(&rep.length, n);
728706f2543Smrg	swapl(&rep.timestamp, n);
729706f2543Smrg	swaps(&rep.rotation, n);
730706f2543Smrg	swaps(&rep.nSizes, n);
731706f2543Smrg	swaps(&rep.sizeID, n);
732706f2543Smrg	swaps(&rep.rate, n);
733706f2543Smrg	swaps(&rep.nrateEnts, n);
734706f2543Smrg    }
735706f2543Smrg    WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep);
736706f2543Smrg    if (extraLen)
737706f2543Smrg    {
738706f2543Smrg	WriteToClient (client, extraLen, (char *) extra);
739706f2543Smrg	free(extra);
740706f2543Smrg    }
741706f2543Smrg    return Success;
742706f2543Smrg}
743706f2543Smrg
744706f2543Smrgint
745706f2543SmrgProcRRSetScreenConfig (ClientPtr client)
746706f2543Smrg{
747706f2543Smrg    REQUEST(xRRSetScreenConfigReq);
748706f2543Smrg    xRRSetScreenConfigReply rep;
749706f2543Smrg    DrawablePtr		    pDraw;
750706f2543Smrg    int			    n, rc;
751706f2543Smrg    ScreenPtr		    pScreen;
752706f2543Smrg    rrScrPrivPtr	    pScrPriv;
753706f2543Smrg    TimeStamp		    time;
754706f2543Smrg    int			    i;
755706f2543Smrg    Rotation		    rotation;
756706f2543Smrg    int			    rate;
757706f2543Smrg    Bool		    has_rate;
758706f2543Smrg    RROutputPtr		    output;
759706f2543Smrg    RRCrtcPtr		    crtc;
760706f2543Smrg    RRModePtr		    mode;
761706f2543Smrg    RR10DataPtr		    pData = NULL;
762706f2543Smrg    RRScreenSizePtr    	    pSize;
763706f2543Smrg    int			    width, height;
764706f2543Smrg
765706f2543Smrg    UpdateCurrentTime ();
766706f2543Smrg
767706f2543Smrg    if (RRClientKnowsRates (client))
768706f2543Smrg    {
769706f2543Smrg	REQUEST_SIZE_MATCH (xRRSetScreenConfigReq);
770706f2543Smrg	has_rate = TRUE;
771706f2543Smrg    }
772706f2543Smrg    else
773706f2543Smrg    {
774706f2543Smrg	REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq);
775706f2543Smrg	has_rate = FALSE;
776706f2543Smrg    }
777706f2543Smrg
778706f2543Smrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
779706f2543Smrg    if (rc != Success)
780706f2543Smrg	return rc;
781706f2543Smrg
782706f2543Smrg    pScreen = pDraw->pScreen;
783706f2543Smrg
784706f2543Smrg    pScrPriv = rrGetScrPriv(pScreen);
785706f2543Smrg
786706f2543Smrg    time = ClientTimeToServerTime(stuff->timestamp);
787706f2543Smrg
788706f2543Smrg    if (!pScrPriv)
789706f2543Smrg    {
790706f2543Smrg	time = currentTime;
791706f2543Smrg	rep.status = RRSetConfigFailed;
792706f2543Smrg	goto sendReply;
793706f2543Smrg    }
794706f2543Smrg    if (!RRGetInfo (pScreen, FALSE))
795706f2543Smrg	return BadAlloc;
796706f2543Smrg
797706f2543Smrg    output = RRFirstOutput (pScreen);
798706f2543Smrg    if (!output)
799706f2543Smrg    {
800706f2543Smrg	time = currentTime;
801706f2543Smrg	rep.status = RRSetConfigFailed;
802706f2543Smrg	goto sendReply;
803706f2543Smrg    }
804706f2543Smrg
805706f2543Smrg    crtc = output->crtc;
806706f2543Smrg
807706f2543Smrg    /*
808706f2543Smrg     * If the client's config timestamp is not the same as the last config
809706f2543Smrg     * timestamp, then the config information isn't up-to-date and
810706f2543Smrg     * can't even be validated.
811706f2543Smrg     *
812706f2543Smrg     * Note that the client only knows about the milliseconds part of the
813706f2543Smrg     * timestamp, so using CompareTimeStamps here would cause randr to suddenly
814706f2543Smrg     * stop working after several hours have passed (freedesktop bug #6502).
815706f2543Smrg     */
816706f2543Smrg    if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds)
817706f2543Smrg    {
818706f2543Smrg	rep.status = RRSetConfigInvalidConfigTime;
819706f2543Smrg	goto sendReply;
820706f2543Smrg    }
821706f2543Smrg
822706f2543Smrg    pData = RR10GetData (pScreen, output);
823706f2543Smrg    if (!pData)
824706f2543Smrg	return BadAlloc;
825706f2543Smrg
826706f2543Smrg    if (stuff->sizeID >= pData->nsize)
827706f2543Smrg    {
828706f2543Smrg	/*
829706f2543Smrg	 * Invalid size ID
830706f2543Smrg	 */
831706f2543Smrg	client->errorValue = stuff->sizeID;
832706f2543Smrg	free(pData);
833706f2543Smrg	return BadValue;
834706f2543Smrg    }
835706f2543Smrg    pSize = &pData->sizes[stuff->sizeID];
836706f2543Smrg
837706f2543Smrg    /*
838706f2543Smrg     * Validate requested rotation
839706f2543Smrg     */
840706f2543Smrg    rotation = (Rotation) stuff->rotation;
841706f2543Smrg
842706f2543Smrg    /* test the rotation bits only! */
843706f2543Smrg    switch (rotation & 0xf) {
844706f2543Smrg    case RR_Rotate_0:
845706f2543Smrg    case RR_Rotate_90:
846706f2543Smrg    case RR_Rotate_180:
847706f2543Smrg    case RR_Rotate_270:
848706f2543Smrg	break;
849706f2543Smrg    default:
850706f2543Smrg	/*
851706f2543Smrg	 * Invalid rotation
852706f2543Smrg	 */
853706f2543Smrg	client->errorValue = stuff->rotation;
854706f2543Smrg	free(pData);
855706f2543Smrg	return BadValue;
856706f2543Smrg    }
857706f2543Smrg
858706f2543Smrg    if ((~crtc->rotations) & rotation)
859706f2543Smrg    {
860706f2543Smrg	/*
861706f2543Smrg	 * requested rotation or reflection not supported by screen
862706f2543Smrg	 */
863706f2543Smrg	client->errorValue = stuff->rotation;
864706f2543Smrg	free(pData);
865706f2543Smrg	return BadMatch;
866706f2543Smrg    }
867706f2543Smrg
868706f2543Smrg    /*
869706f2543Smrg     * Validate requested refresh
870706f2543Smrg     */
871706f2543Smrg    if (has_rate)
872706f2543Smrg	rate = (int) stuff->rate;
873706f2543Smrg    else
874706f2543Smrg	rate = 0;
875706f2543Smrg
876706f2543Smrg    if (rate)
877706f2543Smrg    {
878706f2543Smrg	for (i = 0; i < pSize->nRates; i++)
879706f2543Smrg	{
880706f2543Smrg	    if (pSize->pRates[i].rate == rate)
881706f2543Smrg		break;
882706f2543Smrg	}
883706f2543Smrg	if (i == pSize->nRates)
884706f2543Smrg	{
885706f2543Smrg	    /*
886706f2543Smrg	     * Invalid rate
887706f2543Smrg	     */
888706f2543Smrg	    client->errorValue = rate;
889706f2543Smrg	    free(pData);
890706f2543Smrg	    return BadValue;
891706f2543Smrg	}
892706f2543Smrg	mode = pSize->pRates[i].mode;
893706f2543Smrg    }
894706f2543Smrg    else
895706f2543Smrg	mode = pSize->pRates[0].mode;
896706f2543Smrg
897706f2543Smrg    /*
898706f2543Smrg     * Make sure the requested set-time is not older than
899706f2543Smrg     * the last set-time
900706f2543Smrg     */
901706f2543Smrg    if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
902706f2543Smrg    {
903706f2543Smrg	rep.status = RRSetConfigInvalidTime;
904706f2543Smrg	goto sendReply;
905706f2543Smrg    }
906706f2543Smrg
907706f2543Smrg    /*
908706f2543Smrg     * If the screen size is changing, adjust all of the other outputs
909706f2543Smrg     * to fit the new size, mirroring as much as possible
910706f2543Smrg     */
911706f2543Smrg    width = mode->mode.width;
912706f2543Smrg    height = mode->mode.height;
913706f2543Smrg    if (width < pScrPriv->minWidth || pScrPriv->maxWidth < width) {
914706f2543Smrg	client->errorValue = width;
915706f2543Smrg	free(pData);
916706f2543Smrg	return BadValue;
917706f2543Smrg    }
918706f2543Smrg    if (height < pScrPriv->minHeight || pScrPriv->maxHeight < height) {
919706f2543Smrg	client->errorValue = height;
920706f2543Smrg	free(pData);
921706f2543Smrg	return BadValue;
922706f2543Smrg    }
923706f2543Smrg
924706f2543Smrg    if (rotation & (RR_Rotate_90|RR_Rotate_270))
925706f2543Smrg    {
926706f2543Smrg	width = mode->mode.height;
927706f2543Smrg	height = mode->mode.width;
928706f2543Smrg    }
929706f2543Smrg
930706f2543Smrg    if (width != pScreen->width || height != pScreen->height)
931706f2543Smrg    {
932706f2543Smrg	int	c;
933706f2543Smrg
934706f2543Smrg	for (c = 0; c < pScrPriv->numCrtcs; c++)
935706f2543Smrg	{
936706f2543Smrg	    if (!RRCrtcSet (pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
937706f2543Smrg			    0, NULL))
938706f2543Smrg	    {
939706f2543Smrg		rep.status = RRSetConfigFailed;
940706f2543Smrg		/* XXX recover from failure */
941706f2543Smrg		goto sendReply;
942706f2543Smrg	    }
943706f2543Smrg	}
944706f2543Smrg	if (!RRScreenSizeSet (pScreen, width, height,
945706f2543Smrg			      pScreen->mmWidth, pScreen->mmHeight))
946706f2543Smrg	{
947706f2543Smrg	    rep.status = RRSetConfigFailed;
948706f2543Smrg	    /* XXX recover from failure */
949706f2543Smrg	    goto sendReply;
950706f2543Smrg	}
951706f2543Smrg    }
952706f2543Smrg
953706f2543Smrg    if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output))
954706f2543Smrg	rep.status = RRSetConfigFailed;
955706f2543Smrg    else {
956706f2543Smrg	pScrPriv->lastSetTime = time;
957706f2543Smrg	rep.status = RRSetConfigSuccess;
958706f2543Smrg    }
959706f2543Smrg
960706f2543Smrg    /*
961706f2543Smrg     * XXX Configure other crtcs to mirror as much as possible
962706f2543Smrg     */
963706f2543Smrg
964706f2543SmrgsendReply:
965706f2543Smrg
966706f2543Smrg    free(pData);
967706f2543Smrg
968706f2543Smrg    rep.type = X_Reply;
969706f2543Smrg    /* rep.status has already been filled in */
970706f2543Smrg    rep.length = 0;
971706f2543Smrg    rep.sequenceNumber = client->sequence;
972706f2543Smrg
973706f2543Smrg    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
974706f2543Smrg    rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds;
975706f2543Smrg    rep.root = pDraw->pScreen->root->drawable.id;
976706f2543Smrg
977706f2543Smrg    if (client->swapped)
978706f2543Smrg    {
979706f2543Smrg    	swaps(&rep.sequenceNumber, n);
980706f2543Smrg    	swapl(&rep.length, n);
981706f2543Smrg	swapl(&rep.newTimestamp, n);
982706f2543Smrg	swapl(&rep.newConfigTimestamp, n);
983706f2543Smrg	swapl(&rep.root, n);
984706f2543Smrg    }
985706f2543Smrg    WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep);
986706f2543Smrg
987706f2543Smrg    return Success;
988706f2543Smrg}
989706f2543Smrg
990706f2543Smrgstatic CARD16
991706f2543SmrgRR10CurrentSizeID (ScreenPtr pScreen)
992706f2543Smrg{
993706f2543Smrg    CARD16	sizeID = 0xffff;
994706f2543Smrg    RROutputPtr output = RRFirstOutput (pScreen);
995706f2543Smrg
996706f2543Smrg    if (output)
997706f2543Smrg    {
998706f2543Smrg	RR10DataPtr data = RR10GetData (pScreen, output);
999706f2543Smrg	if (data)
1000706f2543Smrg	{
1001706f2543Smrg	    int i;
1002706f2543Smrg	    for (i = 0; i < data->nsize; i++)
1003706f2543Smrg		if (data->sizes[i].width == pScreen->width &&
1004706f2543Smrg		    data->sizes[i].height == pScreen->height)
1005706f2543Smrg		{
1006706f2543Smrg		    sizeID = (CARD16) i;
1007706f2543Smrg		    break;
1008706f2543Smrg		}
1009706f2543Smrg	    free(data);
1010706f2543Smrg	}
1011706f2543Smrg    }
1012706f2543Smrg    return sizeID;
1013706f2543Smrg}
1014