rrscreen.c revision 6747b715
105b261ecSmrg/*
205b261ecSmrg * Copyright © 2006 Keith Packard
305b261ecSmrg *
405b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
505b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
605b261ecSmrg * the above copyright notice appear in all copies and that both that copyright
705b261ecSmrg * notice and this permission notice appear in supporting documentation, and
805b261ecSmrg * that the name of the copyright holders not be used in advertising or
905b261ecSmrg * publicity pertaining to distribution of the software without specific,
1005b261ecSmrg * written prior permission.  The copyright holders make no representations
1105b261ecSmrg * about the suitability of this software for any purpose.  It is provided "as
1205b261ecSmrg * is" without express or implied warranty.
1305b261ecSmrg *
1405b261ecSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1505b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1605b261ecSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1705b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1805b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1905b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2005b261ecSmrg * OF THIS SOFTWARE.
2105b261ecSmrg */
2205b261ecSmrg
2305b261ecSmrg#include "randrstr.h"
2405b261ecSmrg
254642e01fSmrgstatic const int padlength[4] = {0, 3, 2, 1};
2605b261ecSmrg
2705b261ecSmrgstatic CARD16
2805b261ecSmrgRR10CurrentSizeID (ScreenPtr pScreen);
2905b261ecSmrg
3005b261ecSmrg/*
3105b261ecSmrg * Edit connection information block so that new clients
3205b261ecSmrg * see the current screen size on connect
3305b261ecSmrg */
3405b261ecSmrgstatic void
3505b261ecSmrgRREditConnectionInfo (ScreenPtr pScreen)
3605b261ecSmrg{
3705b261ecSmrg    xConnSetup	    *connSetup;
3805b261ecSmrg    char	    *vendor;
3905b261ecSmrg    xPixmapFormat   *formats;
4005b261ecSmrg    xWindowRoot	    *root;
4105b261ecSmrg    xDepth	    *depth;
4205b261ecSmrg    xVisualType	    *visual;
4305b261ecSmrg    int		    screen = 0;
4405b261ecSmrg    int		    d;
4505b261ecSmrg
4605b261ecSmrg    connSetup = (xConnSetup *) ConnectionInfo;
4705b261ecSmrg    vendor = (char *) connSetup + sizeof (xConnSetup);
4805b261ecSmrg    formats = (xPixmapFormat *) ((char *) vendor +
4905b261ecSmrg				 connSetup->nbytesVendor +
5005b261ecSmrg				 padlength[connSetup->nbytesVendor & 3]);
5105b261ecSmrg    root = (xWindowRoot *) ((char *) formats +
5205b261ecSmrg			    sizeof (xPixmapFormat) * screenInfo.numPixmapFormats);
5305b261ecSmrg    while (screen != pScreen->myNum)
5405b261ecSmrg    {
5505b261ecSmrg	depth = (xDepth *) ((char *) root +
5605b261ecSmrg			    sizeof (xWindowRoot));
5705b261ecSmrg	for (d = 0; d < root->nDepths; d++)
5805b261ecSmrg	{
5905b261ecSmrg	    visual = (xVisualType *) ((char *) depth +
6005b261ecSmrg				      sizeof (xDepth));
6105b261ecSmrg	    depth = (xDepth *) ((char *) visual +
6205b261ecSmrg				depth->nVisuals * sizeof (xVisualType));
6305b261ecSmrg	}
6405b261ecSmrg	root = (xWindowRoot *) ((char *) depth);
6505b261ecSmrg	screen++;
6605b261ecSmrg    }
6705b261ecSmrg    root->pixWidth = pScreen->width;
6805b261ecSmrg    root->pixHeight = pScreen->height;
6905b261ecSmrg    root->mmWidth = pScreen->mmWidth;
7005b261ecSmrg    root->mmHeight = pScreen->mmHeight;
7105b261ecSmrg}
7205b261ecSmrg
7305b261ecSmrgvoid
7405b261ecSmrgRRSendConfigNotify (ScreenPtr pScreen)
7505b261ecSmrg{
766747b715Smrg    WindowPtr	pWin = pScreen->root;
7705b261ecSmrg    xEvent	event;
7805b261ecSmrg
7905b261ecSmrg    event.u.u.type = ConfigureNotify;
8005b261ecSmrg    event.u.configureNotify.window = pWin->drawable.id;
8105b261ecSmrg    event.u.configureNotify.aboveSibling = None;
8205b261ecSmrg    event.u.configureNotify.x = 0;
8305b261ecSmrg    event.u.configureNotify.y = 0;
8405b261ecSmrg
8505b261ecSmrg    /* XXX xinerama stuff ? */
8605b261ecSmrg
8705b261ecSmrg    event.u.configureNotify.width = pWin->drawable.width;
8805b261ecSmrg    event.u.configureNotify.height = pWin->drawable.height;
8905b261ecSmrg    event.u.configureNotify.borderWidth = wBorderWidth (pWin);
9005b261ecSmrg    event.u.configureNotify.override = pWin->overrideRedirect;
9105b261ecSmrg    DeliverEvents(pWin, &event, 1, NullWindow);
9205b261ecSmrg}
9305b261ecSmrg
9405b261ecSmrgvoid
9505b261ecSmrgRRDeliverScreenEvent (ClientPtr client, WindowPtr pWin, ScreenPtr pScreen)
9605b261ecSmrg{
9705b261ecSmrg    rrScrPriv (pScreen);
9805b261ecSmrg    xRRScreenChangeNotifyEvent	se;
9905b261ecSmrg    RRCrtcPtr	crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL;
1006747b715Smrg    WindowPtr	pRoot = pScreen->root;
10105b261ecSmrg
10205b261ecSmrg    se.type = RRScreenChangeNotify + RREventBase;
10305b261ecSmrg    se.rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0);
10405b261ecSmrg    se.timestamp = pScrPriv->lastSetTime.milliseconds;
10505b261ecSmrg    se.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
10605b261ecSmrg    se.root =  pRoot->drawable.id;
10705b261ecSmrg    se.window = pWin->drawable.id;
10805b261ecSmrg    se.subpixelOrder = PictureGetSubpixelOrder (pScreen);
10905b261ecSmrg
11005b261ecSmrg    se.sizeID = RR10CurrentSizeID (pScreen);
11105b261ecSmrg
11205b261ecSmrg    if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) {
11305b261ecSmrg	se.widthInPixels = pScreen->height;
11405b261ecSmrg	se.heightInPixels = pScreen->width;
11505b261ecSmrg	se.widthInMillimeters = pScreen->mmHeight;
11605b261ecSmrg	se.heightInMillimeters = pScreen->mmWidth;
11705b261ecSmrg    } else {
11805b261ecSmrg	se.widthInPixels = pScreen->width;
11905b261ecSmrg	se.heightInPixels = pScreen->height;
12005b261ecSmrg	se.widthInMillimeters = pScreen->mmWidth;
12105b261ecSmrg	se.heightInMillimeters = pScreen->mmHeight;
12205b261ecSmrg    }
12305b261ecSmrg
12405b261ecSmrg    WriteEventsToClient (client, 1, (xEvent *) &se);
12505b261ecSmrg}
12605b261ecSmrg
12705b261ecSmrg/*
12805b261ecSmrg * Notify the extension that the screen size has been changed.
12905b261ecSmrg * The driver is responsible for calling this whenever it has changed
13005b261ecSmrg * the size of the screen
13105b261ecSmrg */
13205b261ecSmrgvoid
13305b261ecSmrgRRScreenSizeNotify (ScreenPtr	pScreen)
13405b261ecSmrg{
13505b261ecSmrg    rrScrPriv(pScreen);
13605b261ecSmrg    /*
13705b261ecSmrg     * Deliver ConfigureNotify events when root changes
13805b261ecSmrg     * pixel size
13905b261ecSmrg     */
14005b261ecSmrg    if (pScrPriv->width == pScreen->width &&
14105b261ecSmrg	pScrPriv->height == pScreen->height &&
14205b261ecSmrg	pScrPriv->mmWidth == pScreen->mmWidth &&
14305b261ecSmrg	pScrPriv->mmHeight == pScreen->mmHeight)
14405b261ecSmrg	return;
14505b261ecSmrg
14605b261ecSmrg    pScrPriv->width = pScreen->width;
14705b261ecSmrg    pScrPriv->height = pScreen->height;
14805b261ecSmrg    pScrPriv->mmWidth = pScreen->mmWidth;
14905b261ecSmrg    pScrPriv->mmHeight = pScreen->mmHeight;
15005b261ecSmrg    pScrPriv->changed = TRUE;
15105b261ecSmrg/*    pScrPriv->sizeChanged = TRUE; */
15205b261ecSmrg
15305b261ecSmrg    RRTellChanged (pScreen);
15405b261ecSmrg    RRSendConfigNotify (pScreen);
15505b261ecSmrg    RREditConnectionInfo (pScreen);
15605b261ecSmrg
15705b261ecSmrg    RRPointerScreenConfigured (pScreen);
15805b261ecSmrg    /*
15905b261ecSmrg     * Fix pointer bounds and location
16005b261ecSmrg     */
16105b261ecSmrg    ScreenRestructured (pScreen);
16205b261ecSmrg}
16305b261ecSmrg
16405b261ecSmrg/*
16505b261ecSmrg * Request that the screen be resized
16605b261ecSmrg */
16705b261ecSmrgBool
16805b261ecSmrgRRScreenSizeSet (ScreenPtr  pScreen,
16905b261ecSmrg		 CARD16	    width,
17005b261ecSmrg		 CARD16	    height,
17105b261ecSmrg		 CARD32	    mmWidth,
17205b261ecSmrg		 CARD32	    mmHeight)
17305b261ecSmrg{
17405b261ecSmrg    rrScrPriv(pScreen);
17505b261ecSmrg
17605b261ecSmrg#if RANDR_12_INTERFACE
17705b261ecSmrg    if (pScrPriv->rrScreenSetSize)
17805b261ecSmrg    {
17905b261ecSmrg	return (*pScrPriv->rrScreenSetSize) (pScreen,
18005b261ecSmrg					     width, height,
18105b261ecSmrg					     mmWidth, mmHeight);
18205b261ecSmrg    }
18305b261ecSmrg#endif
18405b261ecSmrg#if RANDR_10_INTERFACE
18505b261ecSmrg    if (pScrPriv->rrSetConfig)
18605b261ecSmrg    {
18705b261ecSmrg	return TRUE;	/* can't set size separately */
18805b261ecSmrg    }
18905b261ecSmrg#endif
19005b261ecSmrg    return FALSE;
19105b261ecSmrg}
19205b261ecSmrg
19305b261ecSmrg/*
19405b261ecSmrg * Retrieve valid screen size range
19505b261ecSmrg */
1966747b715Smrgint
19705b261ecSmrgProcRRGetScreenSizeRange (ClientPtr client)
19805b261ecSmrg{
19905b261ecSmrg    REQUEST(xRRGetScreenSizeRangeReq);
20005b261ecSmrg    xRRGetScreenSizeRangeReply	rep;
20105b261ecSmrg    WindowPtr			pWin;
20205b261ecSmrg    ScreenPtr			pScreen;
20305b261ecSmrg    rrScrPrivPtr		pScrPriv;
20405b261ecSmrg    int				rc;
20505b261ecSmrg
20605b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
2076747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
20805b261ecSmrg    if (rc != Success)
20905b261ecSmrg	return rc;
21005b261ecSmrg
21105b261ecSmrg    pScreen = pWin->drawable.pScreen;
21205b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
21305b261ecSmrg
21405b261ecSmrg    rep.type = X_Reply;
21505b261ecSmrg    rep.pad = 0;
21605b261ecSmrg    rep.sequenceNumber = client->sequence;
21705b261ecSmrg    rep.length = 0;
21805b261ecSmrg
21905b261ecSmrg    if (pScrPriv)
22005b261ecSmrg    {
2214642e01fSmrg	if (!RRGetInfo (pScreen, FALSE))
22205b261ecSmrg	    return BadAlloc;
22305b261ecSmrg	rep.minWidth  = pScrPriv->minWidth;
22405b261ecSmrg	rep.minHeight = pScrPriv->minHeight;
22505b261ecSmrg	rep.maxWidth  = pScrPriv->maxWidth;
22605b261ecSmrg	rep.maxHeight = pScrPriv->maxHeight;
22705b261ecSmrg    }
22805b261ecSmrg    else
22905b261ecSmrg    {
23005b261ecSmrg	rep.maxWidth  = rep.minWidth  = pScreen->width;
23105b261ecSmrg	rep.maxHeight = rep.minHeight = pScreen->height;
23205b261ecSmrg    }
23305b261ecSmrg    if (client->swapped)
23405b261ecSmrg    {
23505b261ecSmrg	int n;
23605b261ecSmrg
23705b261ecSmrg    	swaps(&rep.sequenceNumber, n);
23805b261ecSmrg    	swapl(&rep.length, n);
23905b261ecSmrg	swaps(&rep.minWidth, n);
24005b261ecSmrg	swaps(&rep.minHeight, n);
24105b261ecSmrg	swaps(&rep.maxWidth, n);
24205b261ecSmrg	swaps(&rep.maxHeight, n);
24305b261ecSmrg    }
24405b261ecSmrg    WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), (char *)&rep);
2456747b715Smrg    return Success;
24605b261ecSmrg}
24705b261ecSmrg
24805b261ecSmrgint
24905b261ecSmrgProcRRSetScreenSize (ClientPtr client)
25005b261ecSmrg{
25105b261ecSmrg    REQUEST(xRRSetScreenSizeReq);
25205b261ecSmrg    WindowPtr		pWin;
25305b261ecSmrg    ScreenPtr		pScreen;
25405b261ecSmrg    rrScrPrivPtr	pScrPriv;
25505b261ecSmrg    int			i, rc;
25605b261ecSmrg
25705b261ecSmrg    REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
2586747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
25905b261ecSmrg    if (rc != Success)
26005b261ecSmrg	return rc;
26105b261ecSmrg
26205b261ecSmrg    pScreen = pWin->drawable.pScreen;
26305b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
26405b261ecSmrg    if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width)
26505b261ecSmrg    {
26605b261ecSmrg	client->errorValue = stuff->width;
26705b261ecSmrg	return BadValue;
26805b261ecSmrg    }
26905b261ecSmrg    if (stuff->height < pScrPriv->minHeight ||
27005b261ecSmrg	pScrPriv->maxHeight < stuff->height)
27105b261ecSmrg    {
27205b261ecSmrg	client->errorValue = stuff->height;
27305b261ecSmrg	return BadValue;
27405b261ecSmrg    }
27505b261ecSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++)
27605b261ecSmrg    {
27705b261ecSmrg	RRCrtcPtr   crtc = pScrPriv->crtcs[i];
27805b261ecSmrg	RRModePtr   mode = crtc->mode;
27905b261ecSmrg	if (mode)
28005b261ecSmrg	{
28105b261ecSmrg	    int		source_width = mode->mode.width;
28205b261ecSmrg	    int		source_height = mode->mode.height;
28305b261ecSmrg	    Rotation	rotation = crtc->rotation;
28405b261ecSmrg
28505b261ecSmrg	    if (rotation == RR_Rotate_90 || rotation == RR_Rotate_270)
28605b261ecSmrg	    {
28705b261ecSmrg		source_width = mode->mode.height;
28805b261ecSmrg		source_height = mode->mode.width;
28905b261ecSmrg	    }
29005b261ecSmrg
29105b261ecSmrg	    if (crtc->x + source_width > stuff->width ||
29205b261ecSmrg		crtc->y + source_height > stuff->height)
29305b261ecSmrg	    return BadMatch;
29405b261ecSmrg	}
29505b261ecSmrg    }
29605b261ecSmrg    if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0)
29705b261ecSmrg    {
29805b261ecSmrg	client->errorValue = 0;
29905b261ecSmrg	return BadValue;
30005b261ecSmrg    }
30105b261ecSmrg    if (!RRScreenSizeSet (pScreen,
30205b261ecSmrg			  stuff->width, stuff->height,
30305b261ecSmrg			  stuff->widthInMillimeters,
30405b261ecSmrg			  stuff->heightInMillimeters))
30505b261ecSmrg    {
30605b261ecSmrg	return BadMatch;
30705b261ecSmrg    }
30805b261ecSmrg    return Success;
30905b261ecSmrg}
31005b261ecSmrg
3114642e01fSmrgstatic int
3124642e01fSmrgrrGetScreenResources(ClientPtr client, Bool query)
31305b261ecSmrg{
31405b261ecSmrg    REQUEST(xRRGetScreenResourcesReq);
31505b261ecSmrg    xRRGetScreenResourcesReply  rep;
31605b261ecSmrg    WindowPtr			pWin;
31705b261ecSmrg    ScreenPtr			pScreen;
31805b261ecSmrg    rrScrPrivPtr		pScrPriv;
31905b261ecSmrg    CARD8			*extra;
32005b261ecSmrg    unsigned long		extraLen;
3214642e01fSmrg    int				i, n, rc, has_primary = 0;
32205b261ecSmrg    RRCrtc			*crtcs;
32305b261ecSmrg    RROutput			*outputs;
32405b261ecSmrg    xRRModeInfo			*modeinfos;
32505b261ecSmrg    CARD8			*names;
32605b261ecSmrg
32705b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
3286747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
32905b261ecSmrg    if (rc != Success)
33005b261ecSmrg	return rc;
33105b261ecSmrg
33205b261ecSmrg    pScreen = pWin->drawable.pScreen;
33305b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
33405b261ecSmrg    rep.pad = 0;
33505b261ecSmrg
3364642e01fSmrg    if (query && pScrPriv)
3374642e01fSmrg	if (!RRGetInfo (pScreen, query))
33805b261ecSmrg	    return BadAlloc;
33905b261ecSmrg
34005b261ecSmrg    if (!pScrPriv)
34105b261ecSmrg    {
34205b261ecSmrg	rep.type = X_Reply;
34305b261ecSmrg	rep.sequenceNumber = client->sequence;
34405b261ecSmrg	rep.length = 0;
34505b261ecSmrg	rep.timestamp = currentTime.milliseconds;
34605b261ecSmrg	rep.configTimestamp = currentTime.milliseconds;
34705b261ecSmrg	rep.nCrtcs = 0;
34805b261ecSmrg	rep.nOutputs = 0;
34905b261ecSmrg	rep.nModes = 0;
35005b261ecSmrg	rep.nbytesNames = 0;
35105b261ecSmrg	extra = NULL;
35205b261ecSmrg	extraLen = 0;
35305b261ecSmrg    }
35405b261ecSmrg    else
35505b261ecSmrg    {
35605b261ecSmrg	RRModePtr   *modes;
35705b261ecSmrg	int	    num_modes;
35805b261ecSmrg
35905b261ecSmrg	modes = RRModesForScreen (pScreen, &num_modes);
36005b261ecSmrg	if (!modes)
36105b261ecSmrg	    return BadAlloc;
36205b261ecSmrg
36305b261ecSmrg	rep.type = X_Reply;
36405b261ecSmrg	rep.sequenceNumber = client->sequence;
36505b261ecSmrg	rep.length = 0;
36605b261ecSmrg	rep.timestamp = pScrPriv->lastSetTime.milliseconds;
36705b261ecSmrg	rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
36805b261ecSmrg	rep.nCrtcs = pScrPriv->numCrtcs;
36905b261ecSmrg	rep.nOutputs = pScrPriv->numOutputs;
37005b261ecSmrg	rep.nModes = num_modes;
37105b261ecSmrg	rep.nbytesNames = 0;
37205b261ecSmrg
37305b261ecSmrg	for (i = 0; i < num_modes; i++)
37405b261ecSmrg	    rep.nbytesNames += modes[i]->mode.nameLength;
37505b261ecSmrg
37605b261ecSmrg	rep.length = (pScrPriv->numCrtcs +
37705b261ecSmrg		      pScrPriv->numOutputs +
3786747b715Smrg		      num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
3796747b715Smrg		      bytes_to_int32(rep.nbytesNames));
38005b261ecSmrg
38105b261ecSmrg	extraLen = rep.length << 2;
38205b261ecSmrg	if (extraLen)
38305b261ecSmrg	{
3846747b715Smrg	    extra = malloc(extraLen);
38505b261ecSmrg	    if (!extra)
38605b261ecSmrg	    {
3876747b715Smrg		free(modes);
38805b261ecSmrg		return BadAlloc;
38905b261ecSmrg	    }
39005b261ecSmrg	}
39105b261ecSmrg	else
39205b261ecSmrg	    extra = NULL;
39305b261ecSmrg
39405b261ecSmrg	crtcs = (RRCrtc *) extra;
39505b261ecSmrg	outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs);
39605b261ecSmrg	modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs);
39705b261ecSmrg	names = (CARD8 *) (modeinfos + num_modes);
3984642e01fSmrg
3994642e01fSmrg	if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc)
4004642e01fSmrg	{
4014642e01fSmrg	    has_primary = 1;
4024642e01fSmrg	    crtcs[0] = pScrPriv->primaryOutput->crtc->id;
4034642e01fSmrg	    if (client->swapped)
4044642e01fSmrg		swapl (&crtcs[0], n);
4054642e01fSmrg	}
40605b261ecSmrg
40705b261ecSmrg	for (i = 0; i < pScrPriv->numCrtcs; i++)
40805b261ecSmrg	{
4094642e01fSmrg	    if (has_primary &&
4104642e01fSmrg		pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i])
4114642e01fSmrg	    {
4124642e01fSmrg		has_primary = 0;
4134642e01fSmrg		continue;
4144642e01fSmrg	    }
4154642e01fSmrg	    crtcs[i + has_primary] = pScrPriv->crtcs[i]->id;
41605b261ecSmrg	    if (client->swapped)
4174642e01fSmrg		swapl (&crtcs[i + has_primary], n);
41805b261ecSmrg	}
41905b261ecSmrg
42005b261ecSmrg	for (i = 0; i < pScrPriv->numOutputs; i++)
42105b261ecSmrg	{
42205b261ecSmrg	    outputs[i] = pScrPriv->outputs[i]->id;
42305b261ecSmrg	    if (client->swapped)
42405b261ecSmrg		swapl (&outputs[i], n);
42505b261ecSmrg	}
42605b261ecSmrg
42705b261ecSmrg	for (i = 0; i < num_modes; i++)
42805b261ecSmrg	{
42905b261ecSmrg	    RRModePtr	mode = modes[i];
43005b261ecSmrg	    modeinfos[i] = mode->mode;
43105b261ecSmrg	    if (client->swapped)
43205b261ecSmrg	    {
43305b261ecSmrg		swapl (&modeinfos[i].id, n);
43405b261ecSmrg		swaps (&modeinfos[i].width, n);
43505b261ecSmrg		swaps (&modeinfos[i].height, n);
43605b261ecSmrg		swapl (&modeinfos[i].dotClock, n);
43705b261ecSmrg		swaps (&modeinfos[i].hSyncStart, n);
43805b261ecSmrg		swaps (&modeinfos[i].hSyncEnd, n);
43905b261ecSmrg		swaps (&modeinfos[i].hTotal, n);
44005b261ecSmrg		swaps (&modeinfos[i].hSkew, n);
44105b261ecSmrg		swaps (&modeinfos[i].vSyncStart, n);
44205b261ecSmrg		swaps (&modeinfos[i].vSyncEnd, n);
44305b261ecSmrg		swaps (&modeinfos[i].vTotal, n);
44405b261ecSmrg		swaps (&modeinfos[i].nameLength, n);
44505b261ecSmrg		swapl (&modeinfos[i].modeFlags, n);
44605b261ecSmrg	    }
44705b261ecSmrg	    memcpy (names, mode->name,
44805b261ecSmrg		    mode->mode.nameLength);
44905b261ecSmrg	    names += mode->mode.nameLength;
45005b261ecSmrg	}
4516747b715Smrg        free(modes);
4526747b715Smrg	assert (bytes_to_int32((char *) names - (char *) extra) == rep.length);
45305b261ecSmrg    }
45405b261ecSmrg
45505b261ecSmrg    if (client->swapped) {
45605b261ecSmrg	swaps(&rep.sequenceNumber, n);
45705b261ecSmrg	swapl(&rep.length, n);
45805b261ecSmrg	swapl(&rep.timestamp, n);
45905b261ecSmrg	swapl(&rep.configTimestamp, n);
46005b261ecSmrg	swaps(&rep.nCrtcs, n);
46105b261ecSmrg	swaps(&rep.nOutputs, n);
46205b261ecSmrg	swaps(&rep.nModes, n);
46305b261ecSmrg	swaps(&rep.nbytesNames, n);
46405b261ecSmrg    }
46505b261ecSmrg    WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *)&rep);
46605b261ecSmrg    if (extraLen)
46705b261ecSmrg    {
46805b261ecSmrg	WriteToClient (client, extraLen, (char *) extra);
4696747b715Smrg	free(extra);
47005b261ecSmrg    }
4716747b715Smrg    return Success;
47205b261ecSmrg}
47305b261ecSmrg
4744642e01fSmrgint
4754642e01fSmrgProcRRGetScreenResources (ClientPtr client)
4764642e01fSmrg{
4774642e01fSmrg    return rrGetScreenResources(client, TRUE);
4784642e01fSmrg}
4794642e01fSmrg
4804642e01fSmrgint
4814642e01fSmrgProcRRGetScreenResourcesCurrent (ClientPtr client)
4824642e01fSmrg{
4834642e01fSmrg    return rrGetScreenResources(client, FALSE);
4844642e01fSmrg}
4854642e01fSmrg
48605b261ecSmrgtypedef struct _RR10Data {
48705b261ecSmrg    RRScreenSizePtr sizes;
48805b261ecSmrg    int		    nsize;
48905b261ecSmrg    int		    nrefresh;
49005b261ecSmrg    int		    size;
49105b261ecSmrg    CARD16	    refresh;
49205b261ecSmrg} RR10DataRec, *RR10DataPtr;
49305b261ecSmrg
49405b261ecSmrg/*
49505b261ecSmrg * Convert 1.2 monitor data into 1.0 screen data
49605b261ecSmrg */
49705b261ecSmrgstatic RR10DataPtr
49805b261ecSmrgRR10GetData (ScreenPtr pScreen, RROutputPtr output)
49905b261ecSmrg{
50005b261ecSmrg    RR10DataPtr	    data;
50105b261ecSmrg    RRScreenSizePtr size;
50205b261ecSmrg    int		    nmode = output->numModes + output->numUserModes;
50305b261ecSmrg    int		    o, os, l, r;
50405b261ecSmrg    RRScreenRatePtr refresh;
50505b261ecSmrg    CARD16	    vRefresh;
50605b261ecSmrg    RRModePtr	    mode;
50705b261ecSmrg    Bool	    *used;
50805b261ecSmrg
50905b261ecSmrg    /* Make sure there is plenty of space for any combination */
51005b261ecSmrg    data = malloc (sizeof (RR10DataRec) +
51105b261ecSmrg		   sizeof (RRScreenSize) * nmode +
51205b261ecSmrg		   sizeof (RRScreenRate) * nmode +
51305b261ecSmrg		   sizeof (Bool) * nmode);
51405b261ecSmrg    if (!data)
51505b261ecSmrg	return NULL;
51605b261ecSmrg    size = (RRScreenSizePtr) (data + 1);
51705b261ecSmrg    refresh = (RRScreenRatePtr) (size + nmode);
51805b261ecSmrg    used = (Bool *) (refresh + nmode);
51905b261ecSmrg    memset (used, '\0', sizeof (Bool) * nmode);
52005b261ecSmrg    data->sizes = size;
52105b261ecSmrg    data->nsize = 0;
52205b261ecSmrg    data->nrefresh = 0;
52305b261ecSmrg    data->size = 0;
52405b261ecSmrg    data->refresh = 0;
52505b261ecSmrg
52605b261ecSmrg    /*
52705b261ecSmrg     * find modes not yet listed
52805b261ecSmrg     */
52905b261ecSmrg    for (o = 0; o < output->numModes + output->numUserModes; o++)
53005b261ecSmrg    {
53105b261ecSmrg	if (used[o]) continue;
53205b261ecSmrg
53305b261ecSmrg	if (o < output->numModes)
53405b261ecSmrg	    mode = output->modes[o];
53505b261ecSmrg	else
53605b261ecSmrg	    mode = output->userModes[o - output->numModes];
53705b261ecSmrg
53805b261ecSmrg	l = data->nsize;
53905b261ecSmrg	size[l].id = data->nsize;
54005b261ecSmrg	size[l].width = mode->mode.width;
54105b261ecSmrg	size[l].height = mode->mode.height;
54205b261ecSmrg	if (output->mmWidth && output->mmHeight) {
54305b261ecSmrg	    size[l].mmWidth = output->mmWidth;
54405b261ecSmrg	    size[l].mmHeight = output->mmHeight;
54505b261ecSmrg	} else {
54605b261ecSmrg	    size[l].mmWidth = pScreen->mmWidth;
54705b261ecSmrg	    size[l].mmHeight = pScreen->mmHeight;
54805b261ecSmrg	}
54905b261ecSmrg	size[l].nRates = 0;
55005b261ecSmrg	size[l].pRates = &refresh[data->nrefresh];
55105b261ecSmrg	data->nsize++;
55205b261ecSmrg
55305b261ecSmrg	/*
55405b261ecSmrg	 * Find all modes with matching size
55505b261ecSmrg	 */
55605b261ecSmrg	for (os = o; os < output->numModes + output->numUserModes; os++)
55705b261ecSmrg	{
55805b261ecSmrg	    if (os < output->numModes)
55905b261ecSmrg		mode = output->modes[os];
56005b261ecSmrg	    else
56105b261ecSmrg		mode = output->userModes[os - output->numModes];
56205b261ecSmrg	    if (mode->mode.width == size[l].width &&
56305b261ecSmrg		mode->mode.height == size[l].height)
56405b261ecSmrg	    {
56505b261ecSmrg		vRefresh = RRVerticalRefresh (&mode->mode);
56605b261ecSmrg		used[os] = TRUE;
56705b261ecSmrg
56805b261ecSmrg		for (r = 0; r < size[l].nRates; r++)
56905b261ecSmrg		    if (vRefresh == size[l].pRates[r].rate)
57005b261ecSmrg			break;
57105b261ecSmrg		if (r == size[l].nRates)
57205b261ecSmrg		{
57305b261ecSmrg		    size[l].pRates[r].rate = vRefresh;
57405b261ecSmrg		    size[l].pRates[r].mode = mode;
57505b261ecSmrg		    size[l].nRates++;
57605b261ecSmrg		    data->nrefresh++;
57705b261ecSmrg		}
57805b261ecSmrg		if (mode == output->crtc->mode)
57905b261ecSmrg		{
58005b261ecSmrg		    data->size = l;
58105b261ecSmrg		    data->refresh = vRefresh;
58205b261ecSmrg		}
58305b261ecSmrg	    }
58405b261ecSmrg	}
58505b261ecSmrg    }
58605b261ecSmrg    return data;
58705b261ecSmrg}
58805b261ecSmrg
58905b261ecSmrgint
59005b261ecSmrgProcRRGetScreenInfo (ClientPtr client)
59105b261ecSmrg{
59205b261ecSmrg    REQUEST(xRRGetScreenInfoReq);
59305b261ecSmrg    xRRGetScreenInfoReply   rep;
59405b261ecSmrg    WindowPtr	    	    pWin;
59505b261ecSmrg    int			    n, rc;
59605b261ecSmrg    ScreenPtr		    pScreen;
59705b261ecSmrg    rrScrPrivPtr	    pScrPriv;
59805b261ecSmrg    CARD8		    *extra;
59905b261ecSmrg    unsigned long	    extraLen;
60005b261ecSmrg    RROutputPtr		    output;
60105b261ecSmrg
60205b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
6036747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
60405b261ecSmrg    if (rc != Success)
60505b261ecSmrg	return rc;
60605b261ecSmrg
60705b261ecSmrg    pScreen = pWin->drawable.pScreen;
60805b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
60905b261ecSmrg    rep.pad = 0;
61005b261ecSmrg
61105b261ecSmrg    if (pScrPriv)
6124642e01fSmrg	if (!RRGetInfo (pScreen, TRUE))
61305b261ecSmrg	    return BadAlloc;
61405b261ecSmrg
61505b261ecSmrg    output = RRFirstOutput (pScreen);
61605b261ecSmrg
61705b261ecSmrg    if (!pScrPriv || !output)
61805b261ecSmrg    {
61905b261ecSmrg	rep.type = X_Reply;
6204642e01fSmrg	rep.setOfRotations = RR_Rotate_0;
62105b261ecSmrg	rep.sequenceNumber = client->sequence;
62205b261ecSmrg	rep.length = 0;
6236747b715Smrg	rep.root = pWin->drawable.pScreen->root->drawable.id;
62405b261ecSmrg	rep.timestamp = currentTime.milliseconds;
62505b261ecSmrg	rep.configTimestamp = currentTime.milliseconds;
62605b261ecSmrg	rep.nSizes = 0;
62705b261ecSmrg	rep.sizeID = 0;
62805b261ecSmrg	rep.rotation = RR_Rotate_0;
62905b261ecSmrg	rep.rate = 0;
63005b261ecSmrg	rep.nrateEnts = 0;
63105b261ecSmrg	extra = 0;
63205b261ecSmrg	extraLen = 0;
63305b261ecSmrg    }
63405b261ecSmrg    else
63505b261ecSmrg    {
63605b261ecSmrg	int			i, j;
63705b261ecSmrg	xScreenSizes		*size;
63805b261ecSmrg	CARD16			*rates;
63905b261ecSmrg	CARD8			*data8;
64005b261ecSmrg	Bool			has_rate = RRClientKnowsRates (client);
64105b261ecSmrg	RR10DataPtr		pData;
64205b261ecSmrg	RRScreenSizePtr		pSize;
64305b261ecSmrg
64405b261ecSmrg	pData = RR10GetData (pScreen, output);
64505b261ecSmrg	if (!pData)
64605b261ecSmrg	    return BadAlloc;
64705b261ecSmrg
64805b261ecSmrg	rep.type = X_Reply;
64905b261ecSmrg	rep.setOfRotations = output->crtc->rotations;
65005b261ecSmrg	rep.sequenceNumber = client->sequence;
65105b261ecSmrg	rep.length = 0;
6526747b715Smrg	rep.root = pWin->drawable.pScreen->root->drawable.id;
65305b261ecSmrg	rep.timestamp = pScrPriv->lastSetTime.milliseconds;
65405b261ecSmrg	rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
65505b261ecSmrg	rep.rotation = output->crtc->rotation;
65605b261ecSmrg	rep.nSizes = pData->nsize;
65705b261ecSmrg        rep.nrateEnts = pData->nrefresh + pData->nsize;
65805b261ecSmrg	rep.sizeID = pData->size;
65905b261ecSmrg	rep.rate = pData->refresh;
66005b261ecSmrg
661b86d567bSmrg	extraLen = rep.nSizes * sizeof (xScreenSizes);
662b86d567bSmrg	if (has_rate)
663b86d567bSmrg		extraLen += rep.nrateEnts * sizeof (CARD16);
66405b261ecSmrg
66505b261ecSmrg	if (extraLen)
66605b261ecSmrg	{
6676747b715Smrg	    extra = (CARD8 *) malloc(extraLen);
66805b261ecSmrg	    if (!extra)
66905b261ecSmrg	    {
6706747b715Smrg		free(pData);
67105b261ecSmrg		return BadAlloc;
67205b261ecSmrg	    }
67305b261ecSmrg	}
67405b261ecSmrg	else
67505b261ecSmrg	    extra = NULL;
67605b261ecSmrg
67705b261ecSmrg	/*
67805b261ecSmrg	 * First comes the size information
67905b261ecSmrg	 */
68005b261ecSmrg	size = (xScreenSizes *) extra;
68105b261ecSmrg	rates = (CARD16 *) (size + rep.nSizes);
68205b261ecSmrg	for (i = 0; i < pData->nsize; i++)
68305b261ecSmrg	{
68405b261ecSmrg	    pSize = &pData->sizes[i];
68505b261ecSmrg	    size->widthInPixels = pSize->width;
68605b261ecSmrg	    size->heightInPixels = pSize->height;
68705b261ecSmrg	    size->widthInMillimeters = pSize->mmWidth;
68805b261ecSmrg	    size->heightInMillimeters = pSize->mmHeight;
68905b261ecSmrg	    if (client->swapped)
69005b261ecSmrg	    {
69105b261ecSmrg	        swaps (&size->widthInPixels, n);
69205b261ecSmrg	        swaps (&size->heightInPixels, n);
69305b261ecSmrg	        swaps (&size->widthInMillimeters, n);
69405b261ecSmrg	        swaps (&size->heightInMillimeters, n);
69505b261ecSmrg	    }
69605b261ecSmrg	    size++;
69705b261ecSmrg	    if (has_rate)
69805b261ecSmrg	    {
69905b261ecSmrg		*rates = pSize->nRates;
70005b261ecSmrg		if (client->swapped)
70105b261ecSmrg		{
70205b261ecSmrg		    swaps (rates, n);
70305b261ecSmrg		}
70405b261ecSmrg		rates++;
70505b261ecSmrg		for (j = 0; j < pSize->nRates; j++)
70605b261ecSmrg		{
70705b261ecSmrg		    *rates = pSize->pRates[j].rate;
70805b261ecSmrg		    if (client->swapped)
70905b261ecSmrg		    {
71005b261ecSmrg			swaps (rates, n);
71105b261ecSmrg		    }
71205b261ecSmrg		    rates++;
71305b261ecSmrg		}
71405b261ecSmrg	    }
71505b261ecSmrg	}
7166747b715Smrg        free(pData);
71705b261ecSmrg
71805b261ecSmrg	data8 = (CARD8 *) rates;
71905b261ecSmrg
72005b261ecSmrg	if (data8 - (CARD8 *) extra != extraLen)
72105b261ecSmrg	    FatalError ("RRGetScreenInfo bad extra len %ld != %ld\n",
72205b261ecSmrg			(unsigned long)(data8 - (CARD8 *) extra), extraLen);
7236747b715Smrg	rep.length =  bytes_to_int32(extraLen);
72405b261ecSmrg    }
72505b261ecSmrg    if (client->swapped) {
72605b261ecSmrg	swaps(&rep.sequenceNumber, n);
72705b261ecSmrg	swapl(&rep.length, n);
72805b261ecSmrg	swapl(&rep.timestamp, n);
72905b261ecSmrg	swaps(&rep.rotation, n);
73005b261ecSmrg	swaps(&rep.nSizes, n);
73105b261ecSmrg	swaps(&rep.sizeID, n);
73205b261ecSmrg	swaps(&rep.rate, n);
73305b261ecSmrg	swaps(&rep.nrateEnts, n);
73405b261ecSmrg    }
73505b261ecSmrg    WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep);
73605b261ecSmrg    if (extraLen)
73705b261ecSmrg    {
73805b261ecSmrg	WriteToClient (client, extraLen, (char *) extra);
7396747b715Smrg	free(extra);
74005b261ecSmrg    }
7416747b715Smrg    return Success;
74205b261ecSmrg}
74305b261ecSmrg
74405b261ecSmrgint
74505b261ecSmrgProcRRSetScreenConfig (ClientPtr client)
74605b261ecSmrg{
74705b261ecSmrg    REQUEST(xRRSetScreenConfigReq);
74805b261ecSmrg    xRRSetScreenConfigReply rep;
74905b261ecSmrg    DrawablePtr		    pDraw;
75005b261ecSmrg    int			    n, rc;
75105b261ecSmrg    ScreenPtr		    pScreen;
75205b261ecSmrg    rrScrPrivPtr	    pScrPriv;
75305b261ecSmrg    TimeStamp		    time;
75405b261ecSmrg    int			    i;
75505b261ecSmrg    Rotation		    rotation;
75605b261ecSmrg    int			    rate;
75705b261ecSmrg    Bool		    has_rate;
75805b261ecSmrg    RROutputPtr		    output;
75905b261ecSmrg    RRCrtcPtr		    crtc;
76005b261ecSmrg    RRModePtr		    mode;
76105b261ecSmrg    RR10DataPtr		    pData = NULL;
76205b261ecSmrg    RRScreenSizePtr    	    pSize;
76305b261ecSmrg    int			    width, height;
76405b261ecSmrg
76505b261ecSmrg    UpdateCurrentTime ();
76605b261ecSmrg
76705b261ecSmrg    if (RRClientKnowsRates (client))
76805b261ecSmrg    {
76905b261ecSmrg	REQUEST_SIZE_MATCH (xRRSetScreenConfigReq);
77005b261ecSmrg	has_rate = TRUE;
77105b261ecSmrg    }
77205b261ecSmrg    else
77305b261ecSmrg    {
77405b261ecSmrg	REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq);
77505b261ecSmrg	has_rate = FALSE;
77605b261ecSmrg    }
77705b261ecSmrg
77805b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
77905b261ecSmrg    if (rc != Success)
78005b261ecSmrg	return rc;
78105b261ecSmrg
78205b261ecSmrg    pScreen = pDraw->pScreen;
78305b261ecSmrg
78405b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
78505b261ecSmrg
78605b261ecSmrg    time = ClientTimeToServerTime(stuff->timestamp);
78705b261ecSmrg
78805b261ecSmrg    if (!pScrPriv)
78905b261ecSmrg    {
79005b261ecSmrg	time = currentTime;
79105b261ecSmrg	rep.status = RRSetConfigFailed;
79205b261ecSmrg	goto sendReply;
79305b261ecSmrg    }
7944642e01fSmrg    if (!RRGetInfo (pScreen, FALSE))
79505b261ecSmrg	return BadAlloc;
79605b261ecSmrg
79705b261ecSmrg    output = RRFirstOutput (pScreen);
79805b261ecSmrg    if (!output)
79905b261ecSmrg    {
80005b261ecSmrg	time = currentTime;
80105b261ecSmrg	rep.status = RRSetConfigFailed;
80205b261ecSmrg	goto sendReply;
80305b261ecSmrg    }
80405b261ecSmrg
80505b261ecSmrg    crtc = output->crtc;
80605b261ecSmrg
80705b261ecSmrg    /*
80805b261ecSmrg     * If the client's config timestamp is not the same as the last config
80905b261ecSmrg     * timestamp, then the config information isn't up-to-date and
81005b261ecSmrg     * can't even be validated.
81105b261ecSmrg     *
81205b261ecSmrg     * Note that the client only knows about the milliseconds part of the
81305b261ecSmrg     * timestamp, so using CompareTimeStamps here would cause randr to suddenly
81405b261ecSmrg     * stop working after several hours have passed (freedesktop bug #6502).
81505b261ecSmrg     */
81605b261ecSmrg    if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds)
81705b261ecSmrg    {
81805b261ecSmrg	rep.status = RRSetConfigInvalidConfigTime;
81905b261ecSmrg	goto sendReply;
82005b261ecSmrg    }
82105b261ecSmrg
82205b261ecSmrg    pData = RR10GetData (pScreen, output);
82305b261ecSmrg    if (!pData)
82405b261ecSmrg	return BadAlloc;
82505b261ecSmrg
82605b261ecSmrg    if (stuff->sizeID >= pData->nsize)
82705b261ecSmrg    {
82805b261ecSmrg	/*
82905b261ecSmrg	 * Invalid size ID
83005b261ecSmrg	 */
83105b261ecSmrg	client->errorValue = stuff->sizeID;
8326747b715Smrg	free(pData);
83305b261ecSmrg	return BadValue;
83405b261ecSmrg    }
83505b261ecSmrg    pSize = &pData->sizes[stuff->sizeID];
83605b261ecSmrg
83705b261ecSmrg    /*
83805b261ecSmrg     * Validate requested rotation
83905b261ecSmrg     */
84005b261ecSmrg    rotation = (Rotation) stuff->rotation;
84105b261ecSmrg
84205b261ecSmrg    /* test the rotation bits only! */
84305b261ecSmrg    switch (rotation & 0xf) {
84405b261ecSmrg    case RR_Rotate_0:
84505b261ecSmrg    case RR_Rotate_90:
84605b261ecSmrg    case RR_Rotate_180:
84705b261ecSmrg    case RR_Rotate_270:
84805b261ecSmrg	break;
84905b261ecSmrg    default:
85005b261ecSmrg	/*
85105b261ecSmrg	 * Invalid rotation
85205b261ecSmrg	 */
85305b261ecSmrg	client->errorValue = stuff->rotation;
8546747b715Smrg	free(pData);
85505b261ecSmrg	return BadValue;
85605b261ecSmrg    }
85705b261ecSmrg
85805b261ecSmrg    if ((~crtc->rotations) & rotation)
85905b261ecSmrg    {
86005b261ecSmrg	/*
86105b261ecSmrg	 * requested rotation or reflection not supported by screen
86205b261ecSmrg	 */
86305b261ecSmrg	client->errorValue = stuff->rotation;
8646747b715Smrg	free(pData);
86505b261ecSmrg	return BadMatch;
86605b261ecSmrg    }
86705b261ecSmrg
86805b261ecSmrg    /*
86905b261ecSmrg     * Validate requested refresh
87005b261ecSmrg     */
87105b261ecSmrg    if (has_rate)
87205b261ecSmrg	rate = (int) stuff->rate;
87305b261ecSmrg    else
87405b261ecSmrg	rate = 0;
87505b261ecSmrg
87605b261ecSmrg    if (rate)
87705b261ecSmrg    {
87805b261ecSmrg	for (i = 0; i < pSize->nRates; i++)
87905b261ecSmrg	{
88005b261ecSmrg	    if (pSize->pRates[i].rate == rate)
88105b261ecSmrg		break;
88205b261ecSmrg	}
88305b261ecSmrg	if (i == pSize->nRates)
88405b261ecSmrg	{
88505b261ecSmrg	    /*
88605b261ecSmrg	     * Invalid rate
88705b261ecSmrg	     */
88805b261ecSmrg	    client->errorValue = rate;
8896747b715Smrg	    free(pData);
89005b261ecSmrg	    return BadValue;
89105b261ecSmrg	}
89205b261ecSmrg	mode = pSize->pRates[i].mode;
89305b261ecSmrg    }
89405b261ecSmrg    else
89505b261ecSmrg	mode = pSize->pRates[0].mode;
89605b261ecSmrg
89705b261ecSmrg    /*
89805b261ecSmrg     * Make sure the requested set-time is not older than
89905b261ecSmrg     * the last set-time
90005b261ecSmrg     */
90105b261ecSmrg    if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
90205b261ecSmrg    {
90305b261ecSmrg	rep.status = RRSetConfigInvalidTime;
90405b261ecSmrg	goto sendReply;
90505b261ecSmrg    }
90605b261ecSmrg
90705b261ecSmrg    /*
90805b261ecSmrg     * If the screen size is changing, adjust all of the other outputs
90905b261ecSmrg     * to fit the new size, mirroring as much as possible
91005b261ecSmrg     */
91105b261ecSmrg    width = mode->mode.width;
91205b261ecSmrg    height = mode->mode.height;
91305b261ecSmrg    if (rotation & (RR_Rotate_90|RR_Rotate_270))
91405b261ecSmrg    {
91505b261ecSmrg	width = mode->mode.height;
91605b261ecSmrg	height = mode->mode.width;
91705b261ecSmrg    }
91805b261ecSmrg    if (width != pScreen->width || height != pScreen->height)
91905b261ecSmrg    {
92005b261ecSmrg	int	c;
92105b261ecSmrg
92205b261ecSmrg	for (c = 0; c < pScrPriv->numCrtcs; c++)
92305b261ecSmrg	{
92405b261ecSmrg	    if (!RRCrtcSet (pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
92505b261ecSmrg			    0, NULL))
92605b261ecSmrg	    {
92705b261ecSmrg		rep.status = RRSetConfigFailed;
92805b261ecSmrg		/* XXX recover from failure */
92905b261ecSmrg		goto sendReply;
93005b261ecSmrg	    }
93105b261ecSmrg	}
93205b261ecSmrg	if (!RRScreenSizeSet (pScreen, width, height,
93305b261ecSmrg			      pScreen->mmWidth, pScreen->mmHeight))
93405b261ecSmrg	{
93505b261ecSmrg	    rep.status = RRSetConfigFailed;
93605b261ecSmrg	    /* XXX recover from failure */
93705b261ecSmrg	    goto sendReply;
93805b261ecSmrg	}
93905b261ecSmrg    }
94005b261ecSmrg
94105b261ecSmrg    if (!RRCrtcSet (crtc, mode, 0, 0, stuff->rotation, 1, &output))
94205b261ecSmrg	rep.status = RRSetConfigFailed;
94352397711Smrg    else {
94452397711Smrg	pScrPriv->lastSetTime = time;
94505b261ecSmrg	rep.status = RRSetConfigSuccess;
94652397711Smrg    }
94705b261ecSmrg
94805b261ecSmrg    /*
94905b261ecSmrg     * XXX Configure other crtcs to mirror as much as possible
95005b261ecSmrg     */
95105b261ecSmrg
95205b261ecSmrgsendReply:
95305b261ecSmrg
9546747b715Smrg    free(pData);
95505b261ecSmrg
95605b261ecSmrg    rep.type = X_Reply;
95705b261ecSmrg    /* rep.status has already been filled in */
95805b261ecSmrg    rep.length = 0;
95905b261ecSmrg    rep.sequenceNumber = client->sequence;
96005b261ecSmrg
96105b261ecSmrg    rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
96205b261ecSmrg    rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds;
9636747b715Smrg    rep.root = pDraw->pScreen->root->drawable.id;
96405b261ecSmrg
96505b261ecSmrg    if (client->swapped)
96605b261ecSmrg    {
96705b261ecSmrg    	swaps(&rep.sequenceNumber, n);
96805b261ecSmrg    	swapl(&rep.length, n);
96905b261ecSmrg	swapl(&rep.newTimestamp, n);
97005b261ecSmrg	swapl(&rep.newConfigTimestamp, n);
97105b261ecSmrg	swapl(&rep.root, n);
97205b261ecSmrg    }
97305b261ecSmrg    WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep);
97405b261ecSmrg
9756747b715Smrg    return Success;
97605b261ecSmrg}
97705b261ecSmrg
97805b261ecSmrgstatic CARD16
97905b261ecSmrgRR10CurrentSizeID (ScreenPtr pScreen)
98005b261ecSmrg{
98105b261ecSmrg    CARD16	sizeID = 0xffff;
98205b261ecSmrg    RROutputPtr output = RRFirstOutput (pScreen);
98305b261ecSmrg
98405b261ecSmrg    if (output)
98505b261ecSmrg    {
98605b261ecSmrg	RR10DataPtr data = RR10GetData (pScreen, output);
98705b261ecSmrg	if (data)
98805b261ecSmrg	{
98905b261ecSmrg	    int i;
99005b261ecSmrg	    for (i = 0; i < data->nsize; i++)
99105b261ecSmrg		if (data->sizes[i].width == pScreen->width &&
99205b261ecSmrg		    data->sizes[i].height == pScreen->height)
99305b261ecSmrg		{
99405b261ecSmrg		    sizeID = (CARD16) i;
99505b261ecSmrg		    break;
99605b261ecSmrg		}
9976747b715Smrg	    free(data);
99805b261ecSmrg	}
99905b261ecSmrg    }
100005b261ecSmrg    return sizeID;
100105b261ecSmrg}
1002