rroutput.c revision 4642e01f
105b261ecSmrg/*
205b261ecSmrg * Copyright © 2006 Keith Packard
34642e01fSmrg * Copyright © 2008 Red Hat, Inc.
405b261ecSmrg *
505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
705b261ecSmrg * the above copyright notice appear in all copies and that both that copyright
805b261ecSmrg * notice and this permission notice appear in supporting documentation, and
905b261ecSmrg * that the name of the copyright holders not be used in advertising or
1005b261ecSmrg * publicity pertaining to distribution of the software without specific,
1105b261ecSmrg * written prior permission.  The copyright holders make no representations
1205b261ecSmrg * about the suitability of this software for any purpose.  It is provided "as
1305b261ecSmrg * is" without express or implied warranty.
1405b261ecSmrg *
1505b261ecSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1705b261ecSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2105b261ecSmrg * OF THIS SOFTWARE.
2205b261ecSmrg */
2305b261ecSmrg
2405b261ecSmrg#include "randrstr.h"
254642e01fSmrg#include "registry.h"
2605b261ecSmrg
2705b261ecSmrgRESTYPE	RROutputType;
2805b261ecSmrg
2905b261ecSmrg/*
3005b261ecSmrg * Notify the output of some change
3105b261ecSmrg */
3205b261ecSmrgvoid
3305b261ecSmrgRROutputChanged (RROutputPtr output, Bool configChanged)
3405b261ecSmrg{
3505b261ecSmrg    ScreenPtr	pScreen = output->pScreen;
3605b261ecSmrg
3705b261ecSmrg    output->changed = TRUE;
3805b261ecSmrg    if (pScreen)
3905b261ecSmrg    {
4005b261ecSmrg	rrScrPriv (pScreen);
4105b261ecSmrg	pScrPriv->changed = TRUE;
4205b261ecSmrg	if (configChanged)
4305b261ecSmrg	    pScrPriv->configChanged = TRUE;
4405b261ecSmrg    }
4505b261ecSmrg}
4605b261ecSmrg
4705b261ecSmrg/*
4805b261ecSmrg * Create an output
4905b261ecSmrg */
5005b261ecSmrg
5105b261ecSmrgRROutputPtr
5205b261ecSmrgRROutputCreate (ScreenPtr   pScreen,
5305b261ecSmrg		const char  *name,
5405b261ecSmrg		int	    nameLength,
5505b261ecSmrg		void	    *devPrivate)
5605b261ecSmrg{
5705b261ecSmrg    RROutputPtr	    output;
5805b261ecSmrg    RROutputPtr	    *outputs;
5905b261ecSmrg    rrScrPrivPtr    pScrPriv;
6005b261ecSmrg
6105b261ecSmrg    if (!RRInit())
6205b261ecSmrg	return NULL;
6305b261ecSmrg
6405b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
6505b261ecSmrg
6605b261ecSmrg    if (pScrPriv->numOutputs)
6705b261ecSmrg	outputs = xrealloc (pScrPriv->outputs,
6805b261ecSmrg			    (pScrPriv->numOutputs + 1) * sizeof (RROutputPtr));
6905b261ecSmrg    else
7005b261ecSmrg	outputs = xalloc (sizeof (RROutputPtr));
7105b261ecSmrg    if (!outputs)
7205b261ecSmrg	return FALSE;
7305b261ecSmrg
7405b261ecSmrg    pScrPriv->outputs = outputs;
7505b261ecSmrg
7605b261ecSmrg    output = xalloc (sizeof (RROutputRec) + nameLength + 1);
7705b261ecSmrg    if (!output)
7805b261ecSmrg	return NULL;
7905b261ecSmrg    output->id = FakeClientID (0);
8005b261ecSmrg    output->pScreen = pScreen;
8105b261ecSmrg    output->name = (char *) (output + 1);
8205b261ecSmrg    output->nameLength = nameLength;
8305b261ecSmrg    memcpy (output->name, name, nameLength);
8405b261ecSmrg    output->name[nameLength] = '\0';
8505b261ecSmrg    output->connection = RR_UnknownConnection;
8605b261ecSmrg    output->subpixelOrder = SubPixelUnknown;
8705b261ecSmrg    output->mmWidth = 0;
8805b261ecSmrg    output->mmHeight = 0;
8905b261ecSmrg    output->crtc = NULL;
9005b261ecSmrg    output->numCrtcs = 0;
9105b261ecSmrg    output->crtcs = NULL;
9205b261ecSmrg    output->numClones = 0;
9305b261ecSmrg    output->clones = NULL;
9405b261ecSmrg    output->numModes = 0;
9505b261ecSmrg    output->numPreferred = 0;
9605b261ecSmrg    output->modes = NULL;
9705b261ecSmrg    output->numUserModes = 0;
9805b261ecSmrg    output->userModes = NULL;
9905b261ecSmrg    output->properties = NULL;
1004642e01fSmrg    output->pendingProperties = FALSE;
10105b261ecSmrg    output->changed = FALSE;
10205b261ecSmrg    output->devPrivate = devPrivate;
10305b261ecSmrg
10405b261ecSmrg    if (!AddResource (output->id, RROutputType, (pointer) output))
10505b261ecSmrg	return NULL;
10605b261ecSmrg
10705b261ecSmrg    pScrPriv->outputs[pScrPriv->numOutputs++] = output;
10805b261ecSmrg    return output;
10905b261ecSmrg}
11005b261ecSmrg
11105b261ecSmrg/*
11205b261ecSmrg * Notify extension that output parameters have been changed
11305b261ecSmrg */
11405b261ecSmrgBool
11505b261ecSmrgRROutputSetClones (RROutputPtr  output,
11605b261ecSmrg		   RROutputPtr  *clones,
11705b261ecSmrg		   int		numClones)
11805b261ecSmrg{
11905b261ecSmrg    RROutputPtr	*newClones;
12005b261ecSmrg    int		i;
12105b261ecSmrg
12205b261ecSmrg    if (numClones == output->numClones)
12305b261ecSmrg    {
12405b261ecSmrg	for (i = 0; i < numClones; i++)
12505b261ecSmrg	    if (output->clones[i] != clones[i])
12605b261ecSmrg		break;
12705b261ecSmrg	if (i == numClones)
12805b261ecSmrg	    return TRUE;
12905b261ecSmrg    }
13005b261ecSmrg    if (numClones)
13105b261ecSmrg    {
13205b261ecSmrg	newClones = xalloc (numClones * sizeof (RROutputPtr));
13305b261ecSmrg	if (!newClones)
13405b261ecSmrg	    return FALSE;
13505b261ecSmrg    }
13605b261ecSmrg    else
13705b261ecSmrg	newClones = NULL;
13805b261ecSmrg    if (output->clones)
13905b261ecSmrg	xfree (output->clones);
14005b261ecSmrg    memcpy (newClones, clones, numClones * sizeof (RROutputPtr));
14105b261ecSmrg    output->clones = newClones;
14205b261ecSmrg    output->numClones = numClones;
14305b261ecSmrg    RROutputChanged (output, TRUE);
14405b261ecSmrg    return TRUE;
14505b261ecSmrg}
14605b261ecSmrg
14705b261ecSmrgBool
14805b261ecSmrgRROutputSetModes (RROutputPtr	output,
14905b261ecSmrg		  RRModePtr	*modes,
15005b261ecSmrg		  int		numModes,
15105b261ecSmrg		  int		numPreferred)
15205b261ecSmrg{
15305b261ecSmrg    RRModePtr	*newModes;
15405b261ecSmrg    int		i;
15505b261ecSmrg
15605b261ecSmrg    if (numModes == output->numModes && numPreferred == output->numPreferred)
15705b261ecSmrg    {
15805b261ecSmrg	for (i = 0; i < numModes; i++)
15905b261ecSmrg	    if (output->modes[i] != modes[i])
16005b261ecSmrg		break;
16105b261ecSmrg	if (i == numModes)
16205b261ecSmrg	{
16305b261ecSmrg	    for (i = 0; i < numModes; i++)
16405b261ecSmrg		RRModeDestroy (modes[i]);
16505b261ecSmrg	    return TRUE;
16605b261ecSmrg	}
16705b261ecSmrg    }
16805b261ecSmrg
16905b261ecSmrg    if (numModes)
17005b261ecSmrg    {
17105b261ecSmrg	newModes = xalloc (numModes * sizeof (RRModePtr));
17205b261ecSmrg	if (!newModes)
17305b261ecSmrg	    return FALSE;
17405b261ecSmrg    }
17505b261ecSmrg    else
17605b261ecSmrg	newModes = NULL;
17705b261ecSmrg    if (output->modes)
17805b261ecSmrg    {
17905b261ecSmrg	for (i = 0; i < output->numModes; i++)
18005b261ecSmrg	    RRModeDestroy (output->modes[i]);
18105b261ecSmrg	xfree (output->modes);
18205b261ecSmrg    }
18305b261ecSmrg    memcpy (newModes, modes, numModes * sizeof (RRModePtr));
18405b261ecSmrg    output->modes = newModes;
18505b261ecSmrg    output->numModes = numModes;
18605b261ecSmrg    output->numPreferred = numPreferred;
18705b261ecSmrg    RROutputChanged (output, TRUE);
18805b261ecSmrg    return TRUE;
18905b261ecSmrg}
19005b261ecSmrg
19105b261ecSmrgint
19205b261ecSmrgRROutputAddUserMode (RROutputPtr    output,
19305b261ecSmrg		     RRModePtr	    mode)
19405b261ecSmrg{
19505b261ecSmrg    int		m;
19605b261ecSmrg    ScreenPtr	pScreen = output->pScreen;
19705b261ecSmrg    rrScrPriv(pScreen);
19805b261ecSmrg    RRModePtr	*newModes;
19905b261ecSmrg
20005b261ecSmrg    /* Check to see if this mode is already listed for this output */
20105b261ecSmrg    for (m = 0; m < output->numModes + output->numUserModes; m++)
20205b261ecSmrg    {
20305b261ecSmrg	RRModePtr   e = (m < output->numModes ?
20405b261ecSmrg			 output->modes[m] :
20505b261ecSmrg			 output->userModes[m - output->numModes]);
20605b261ecSmrg	if (mode == e)
20705b261ecSmrg	    return Success;
20805b261ecSmrg    }
20905b261ecSmrg
21005b261ecSmrg    /* Check with the DDX to see if this mode is OK */
21105b261ecSmrg    if (pScrPriv->rrOutputValidateMode)
21205b261ecSmrg	if (!pScrPriv->rrOutputValidateMode (pScreen, output, mode))
21305b261ecSmrg	    return BadMatch;
21405b261ecSmrg
21505b261ecSmrg    if (output->userModes)
21605b261ecSmrg	newModes = xrealloc (output->userModes,
21705b261ecSmrg			     (output->numUserModes + 1) * sizeof (RRModePtr));
21805b261ecSmrg    else
21905b261ecSmrg	newModes = xalloc (sizeof (RRModePtr));
22005b261ecSmrg    if (!newModes)
22105b261ecSmrg	return BadAlloc;
22205b261ecSmrg
22305b261ecSmrg    output->userModes = newModes;
22405b261ecSmrg    output->userModes[output->numUserModes++] = mode;
22505b261ecSmrg    ++mode->refcnt;
22605b261ecSmrg    RROutputChanged (output, TRUE);
22705b261ecSmrg    RRTellChanged (pScreen);
22805b261ecSmrg    return Success;
22905b261ecSmrg}
23005b261ecSmrg
23105b261ecSmrgint
23205b261ecSmrgRROutputDeleteUserMode (RROutputPtr output,
23305b261ecSmrg			RRModePtr   mode)
23405b261ecSmrg{
23505b261ecSmrg    int		m;
23605b261ecSmrg
23705b261ecSmrg    /* Find this mode in the user mode list */
23805b261ecSmrg    for (m = 0; m < output->numUserModes; m++)
23905b261ecSmrg    {
24005b261ecSmrg	RRModePtr   e = output->userModes[m];
24105b261ecSmrg
24205b261ecSmrg	if (mode == e)
24305b261ecSmrg	    break;
24405b261ecSmrg    }
24505b261ecSmrg    /* Not there, access error */
24605b261ecSmrg    if (m == output->numUserModes)
24705b261ecSmrg	return BadAccess;
24805b261ecSmrg
24905b261ecSmrg    /* make sure the mode isn't active for this output */
25005b261ecSmrg    if (output->crtc && output->crtc->mode == mode)
25105b261ecSmrg	return BadMatch;
25205b261ecSmrg
25305b261ecSmrg    memmove (output->userModes + m, output->userModes + m + 1,
25405b261ecSmrg	     (output->numUserModes - m - 1) * sizeof (RRModePtr));
25505b261ecSmrg    output->numUserModes--;
25605b261ecSmrg    RRModeDestroy (mode);
25705b261ecSmrg    return Success;
25805b261ecSmrg}
25905b261ecSmrg
26005b261ecSmrgBool
26105b261ecSmrgRROutputSetCrtcs (RROutputPtr	output,
26205b261ecSmrg		  RRCrtcPtr	*crtcs,
26305b261ecSmrg		  int		numCrtcs)
26405b261ecSmrg{
26505b261ecSmrg    RRCrtcPtr	*newCrtcs;
26605b261ecSmrg    int		i;
26705b261ecSmrg
26805b261ecSmrg    if (numCrtcs == output->numCrtcs)
26905b261ecSmrg    {
27005b261ecSmrg	for (i = 0; i < numCrtcs; i++)
27105b261ecSmrg	    if (output->crtcs[i] != crtcs[i])
27205b261ecSmrg		break;
27305b261ecSmrg	if (i == numCrtcs)
27405b261ecSmrg	    return TRUE;
27505b261ecSmrg    }
27605b261ecSmrg    if (numCrtcs)
27705b261ecSmrg    {
27805b261ecSmrg	newCrtcs = xalloc (numCrtcs * sizeof (RRCrtcPtr));
27905b261ecSmrg	if (!newCrtcs)
28005b261ecSmrg	    return FALSE;
28105b261ecSmrg    }
28205b261ecSmrg    else
28305b261ecSmrg	newCrtcs = NULL;
28405b261ecSmrg    if (output->crtcs)
28505b261ecSmrg	xfree (output->crtcs);
28605b261ecSmrg    memcpy (newCrtcs, crtcs, numCrtcs * sizeof (RRCrtcPtr));
28705b261ecSmrg    output->crtcs = newCrtcs;
28805b261ecSmrg    output->numCrtcs = numCrtcs;
28905b261ecSmrg    RROutputChanged (output, TRUE);
29005b261ecSmrg    return TRUE;
29105b261ecSmrg}
29205b261ecSmrg
29305b261ecSmrgBool
29405b261ecSmrgRROutputSetConnection (RROutputPtr  output,
29505b261ecSmrg		       CARD8	    connection)
29605b261ecSmrg{
29705b261ecSmrg    if (output->connection == connection)
29805b261ecSmrg	return TRUE;
29905b261ecSmrg    output->connection = connection;
30005b261ecSmrg    RROutputChanged (output, TRUE);
30105b261ecSmrg    return TRUE;
30205b261ecSmrg}
30305b261ecSmrg
30405b261ecSmrgBool
30505b261ecSmrgRROutputSetSubpixelOrder (RROutputPtr output,
30605b261ecSmrg			  int	      subpixelOrder)
30705b261ecSmrg{
30805b261ecSmrg    if (output->subpixelOrder == subpixelOrder)
30905b261ecSmrg	return TRUE;
31005b261ecSmrg
31105b261ecSmrg    output->subpixelOrder = subpixelOrder;
31205b261ecSmrg    RROutputChanged (output, FALSE);
31305b261ecSmrg    return TRUE;
31405b261ecSmrg}
31505b261ecSmrg
31605b261ecSmrgBool
31705b261ecSmrgRROutputSetPhysicalSize (RROutputPtr	output,
31805b261ecSmrg			 int		mmWidth,
31905b261ecSmrg			 int		mmHeight)
32005b261ecSmrg{
32105b261ecSmrg    if (output->mmWidth == mmWidth && output->mmHeight == mmHeight)
32205b261ecSmrg	return TRUE;
32305b261ecSmrg    output->mmWidth = mmWidth;
32405b261ecSmrg    output->mmHeight = mmHeight;
32505b261ecSmrg    RROutputChanged (output, FALSE);
32605b261ecSmrg    return TRUE;
32705b261ecSmrg}
32805b261ecSmrg
32905b261ecSmrg
33005b261ecSmrgvoid
33105b261ecSmrgRRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output)
33205b261ecSmrg{
33305b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
33405b261ecSmrg    rrScrPriv (pScreen);
33505b261ecSmrg    xRROutputChangeNotifyEvent	oe;
33605b261ecSmrg    RRCrtcPtr	crtc = output->crtc;
33705b261ecSmrg    RRModePtr	mode = crtc ? crtc->mode : 0;
33805b261ecSmrg
33905b261ecSmrg    oe.type = RRNotify + RREventBase;
34005b261ecSmrg    oe.subCode = RRNotify_OutputChange;
34105b261ecSmrg    oe.sequenceNumber = client->sequence;
34205b261ecSmrg    oe.timestamp = pScrPriv->lastSetTime.milliseconds;
34305b261ecSmrg    oe.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
34405b261ecSmrg    oe.window = pWin->drawable.id;
34505b261ecSmrg    oe.output = output->id;
34605b261ecSmrg    if (crtc)
34705b261ecSmrg    {
34805b261ecSmrg	oe.crtc = crtc->id;
34905b261ecSmrg	oe.mode = mode ? mode->mode.id : None;
35005b261ecSmrg	oe.rotation = crtc->rotation;
35105b261ecSmrg    }
35205b261ecSmrg    else
35305b261ecSmrg    {
35405b261ecSmrg	oe.crtc = None;
35505b261ecSmrg	oe.mode = None;
35605b261ecSmrg	oe.rotation = RR_Rotate_0;
35705b261ecSmrg    }
35805b261ecSmrg    oe.connection = output->connection;
35905b261ecSmrg    oe.subpixelOrder = output->subpixelOrder;
36005b261ecSmrg    WriteEventsToClient (client, 1, (xEvent *) &oe);
36105b261ecSmrg}
36205b261ecSmrg
36305b261ecSmrg/*
36405b261ecSmrg * Destroy a Output at shutdown
36505b261ecSmrg */
36605b261ecSmrgvoid
36705b261ecSmrgRROutputDestroy (RROutputPtr output)
36805b261ecSmrg{
36905b261ecSmrg    FreeResource (output->id, 0);
37005b261ecSmrg}
37105b261ecSmrg
37205b261ecSmrgstatic int
37305b261ecSmrgRROutputDestroyResource (pointer value, XID pid)
37405b261ecSmrg{
37505b261ecSmrg    RROutputPtr	output = (RROutputPtr) value;
37605b261ecSmrg    ScreenPtr	pScreen = output->pScreen;
37705b261ecSmrg    int		m;
37805b261ecSmrg
37905b261ecSmrg    if (pScreen)
38005b261ecSmrg    {
38105b261ecSmrg	rrScrPriv(pScreen);
38205b261ecSmrg	int		i;
3834642e01fSmrg
3844642e01fSmrg	if (pScrPriv->primaryOutput == output)
3854642e01fSmrg	    pScrPriv->primaryOutput = NULL;
38605b261ecSmrg
38705b261ecSmrg	for (i = 0; i < pScrPriv->numOutputs; i++)
38805b261ecSmrg	{
38905b261ecSmrg	    if (pScrPriv->outputs[i] == output)
39005b261ecSmrg	    {
39105b261ecSmrg		memmove (pScrPriv->outputs + i, pScrPriv->outputs + i + 1,
39205b261ecSmrg			 (pScrPriv->numOutputs - (i + 1)) * sizeof (RROutputPtr));
39305b261ecSmrg		--pScrPriv->numOutputs;
39405b261ecSmrg		break;
39505b261ecSmrg	    }
39605b261ecSmrg	}
39705b261ecSmrg    }
39805b261ecSmrg    if (output->modes)
39905b261ecSmrg    {
40005b261ecSmrg	for (m = 0; m < output->numModes; m++)
40105b261ecSmrg	    RRModeDestroy (output->modes[m]);
40205b261ecSmrg	xfree (output->modes);
40305b261ecSmrg    }
40405b261ecSmrg
40505b261ecSmrg    for (m = 0; m < output->numUserModes; m++)
40605b261ecSmrg	RRModeDestroy (output->userModes[m]);
40705b261ecSmrg    if (output->userModes)
40805b261ecSmrg	xfree (output->userModes);
40905b261ecSmrg
41005b261ecSmrg    if (output->crtcs)
41105b261ecSmrg	xfree (output->crtcs);
41205b261ecSmrg    if (output->clones)
41305b261ecSmrg	xfree (output->clones);
41405b261ecSmrg    RRDeleteAllOutputProperties (output);
41505b261ecSmrg    xfree (output);
41605b261ecSmrg    return 1;
41705b261ecSmrg}
41805b261ecSmrg
41905b261ecSmrg/*
42005b261ecSmrg * Initialize output type
42105b261ecSmrg */
42205b261ecSmrgBool
42305b261ecSmrgRROutputInit (void)
42405b261ecSmrg{
42505b261ecSmrg    RROutputType = CreateNewResourceType (RROutputDestroyResource);
42605b261ecSmrg    if (!RROutputType)
42705b261ecSmrg	return FALSE;
4284642e01fSmrg    RegisterResourceName (RROutputType, "OUTPUT");
42905b261ecSmrg    return TRUE;
43005b261ecSmrg}
43105b261ecSmrg
43205b261ecSmrg#define OutputInfoExtra	(SIZEOF(xRRGetOutputInfoReply) - 32)
4334642e01fSmrg
43405b261ecSmrgint
43505b261ecSmrgProcRRGetOutputInfo (ClientPtr client)
43605b261ecSmrg{
43705b261ecSmrg    REQUEST(xRRGetOutputInfoReq);
43805b261ecSmrg    xRRGetOutputInfoReply	rep;
43905b261ecSmrg    RROutputPtr			output;
44005b261ecSmrg    CARD8			*extra;
44105b261ecSmrg    unsigned long		extraLen;
44205b261ecSmrg    ScreenPtr			pScreen;
44305b261ecSmrg    rrScrPrivPtr		pScrPriv;
44405b261ecSmrg    RRCrtc			*crtcs;
44505b261ecSmrg    RRMode			*modes;
44605b261ecSmrg    RROutput			*clones;
44705b261ecSmrg    char			*name;
44805b261ecSmrg    int				i, n;
44905b261ecSmrg
45005b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
45105b261ecSmrg    output = LookupOutput(client, stuff->output, DixReadAccess);
45205b261ecSmrg
45305b261ecSmrg    if (!output)
45405b261ecSmrg    {
45505b261ecSmrg	client->errorValue = stuff->output;
45605b261ecSmrg	return RRErrorBase + BadRROutput;
45705b261ecSmrg    }
45805b261ecSmrg
45905b261ecSmrg    pScreen = output->pScreen;
46005b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
46105b261ecSmrg
46205b261ecSmrg    rep.type = X_Reply;
46305b261ecSmrg    rep.sequenceNumber = client->sequence;
46405b261ecSmrg    rep.length = OutputInfoExtra >> 2;
46505b261ecSmrg    rep.timestamp = pScrPriv->lastSetTime.milliseconds;
46605b261ecSmrg    rep.crtc = output->crtc ? output->crtc->id : None;
46705b261ecSmrg    rep.mmWidth = output->mmWidth;
46805b261ecSmrg    rep.mmHeight = output->mmHeight;
46905b261ecSmrg    rep.connection = output->connection;
47005b261ecSmrg    rep.subpixelOrder = output->subpixelOrder;
47105b261ecSmrg    rep.nCrtcs = output->numCrtcs;
47205b261ecSmrg    rep.nModes = output->numModes + output->numUserModes;
47305b261ecSmrg    rep.nPreferred = output->numPreferred;
47405b261ecSmrg    rep.nClones = output->numClones;
47505b261ecSmrg    rep.nameLength = output->nameLength;
47605b261ecSmrg
47705b261ecSmrg    extraLen = ((output->numCrtcs +
47805b261ecSmrg		 output->numModes + output->numUserModes +
47905b261ecSmrg		 output->numClones +
48005b261ecSmrg		 ((rep.nameLength + 3) >> 2)) << 2);
48105b261ecSmrg
48205b261ecSmrg    if (extraLen)
48305b261ecSmrg    {
48405b261ecSmrg	rep.length += extraLen >> 2;
48505b261ecSmrg	extra = xalloc (extraLen);
48605b261ecSmrg	if (!extra)
48705b261ecSmrg	    return BadAlloc;
48805b261ecSmrg    }
48905b261ecSmrg    else
49005b261ecSmrg	extra = NULL;
49105b261ecSmrg
49205b261ecSmrg    crtcs = (RRCrtc *) extra;
49305b261ecSmrg    modes = (RRMode *) (crtcs + output->numCrtcs);
49405b261ecSmrg    clones = (RROutput *) (modes + output->numModes + output->numUserModes);
49505b261ecSmrg    name = (char *) (clones + output->numClones);
49605b261ecSmrg
49705b261ecSmrg    for (i = 0; i < output->numCrtcs; i++)
49805b261ecSmrg    {
49905b261ecSmrg	crtcs[i] = output->crtcs[i]->id;
50005b261ecSmrg	if (client->swapped)
50105b261ecSmrg	    swapl (&crtcs[i], n);
50205b261ecSmrg    }
50305b261ecSmrg    for (i = 0; i < output->numModes + output->numUserModes; i++)
50405b261ecSmrg    {
50505b261ecSmrg	if (i < output->numModes)
50605b261ecSmrg	    modes[i] = output->modes[i]->mode.id;
50705b261ecSmrg	else
50805b261ecSmrg	    modes[i] = output->userModes[i - output->numModes]->mode.id;
50905b261ecSmrg	if (client->swapped)
51005b261ecSmrg	    swapl (&modes[i], n);
51105b261ecSmrg    }
51205b261ecSmrg    for (i = 0; i < output->numClones; i++)
51305b261ecSmrg    {
51405b261ecSmrg	clones[i] = output->clones[i]->id;
51505b261ecSmrg	if (client->swapped)
51605b261ecSmrg	    swapl (&clones[i], n);
51705b261ecSmrg    }
51805b261ecSmrg    memcpy (name, output->name, output->nameLength);
51905b261ecSmrg    if (client->swapped) {
52005b261ecSmrg	swaps(&rep.sequenceNumber, n);
52105b261ecSmrg	swapl(&rep.length, n);
52205b261ecSmrg	swapl(&rep.timestamp, n);
52305b261ecSmrg	swapl(&rep.crtc, n);
52405b261ecSmrg	swapl(&rep.mmWidth, n);
52505b261ecSmrg	swapl(&rep.mmHeight, n);
52605b261ecSmrg	swaps(&rep.nCrtcs, n);
52705b261ecSmrg	swaps(&rep.nModes, n);
52805b261ecSmrg	swaps(&rep.nClones, n);
52905b261ecSmrg	swaps(&rep.nameLength, n);
53005b261ecSmrg    }
53105b261ecSmrg    WriteToClient(client, sizeof(xRRGetOutputInfoReply), (char *)&rep);
53205b261ecSmrg    if (extraLen)
53305b261ecSmrg    {
53405b261ecSmrg	WriteToClient (client, extraLen, (char *) extra);
53505b261ecSmrg	xfree (extra);
53605b261ecSmrg    }
53705b261ecSmrg
53805b261ecSmrg    return client->noClientException;
53905b261ecSmrg}
5404642e01fSmrg
5414642e01fSmrgvoid
5424642e01fSmrgRRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv,
5434642e01fSmrg		   RROutputPtr output)
5444642e01fSmrg{
5454642e01fSmrg    if (pScrPriv->primaryOutput == output)
5464642e01fSmrg	return;
5474642e01fSmrg
5484642e01fSmrg    /* clear the old primary */
5494642e01fSmrg    if (pScrPriv->primaryOutput) {
5504642e01fSmrg	RROutputChanged(pScrPriv->primaryOutput, 0);
5514642e01fSmrg	pScrPriv->primaryOutput = NULL;
5524642e01fSmrg    }
5534642e01fSmrg
5544642e01fSmrg    /* set the new primary */
5554642e01fSmrg    if (output) {
5564642e01fSmrg	pScrPriv->primaryOutput = output;
5574642e01fSmrg	RROutputChanged(output, 0);
5584642e01fSmrg    }
5594642e01fSmrg
5604642e01fSmrg    pScrPriv->layoutChanged = TRUE;
5614642e01fSmrg
5624642e01fSmrg    RRTellChanged(pScreen);
5634642e01fSmrg}
5644642e01fSmrg
5654642e01fSmrgint
5664642e01fSmrgProcRRSetOutputPrimary(ClientPtr client)
5674642e01fSmrg{
5684642e01fSmrg    REQUEST(xRRSetOutputPrimaryReq);
5694642e01fSmrg    RROutputPtr output = NULL;
5704642e01fSmrg    WindowPtr pWin;
5714642e01fSmrg    rrScrPrivPtr pScrPriv;
5724642e01fSmrg
5734642e01fSmrg    REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq);
5744642e01fSmrg
5754642e01fSmrg    pWin = SecurityLookupIDByType(client, stuff->window, RT_WINDOW,
5764642e01fSmrg				  DixReadAccess);
5774642e01fSmrg
5784642e01fSmrg    if (!pWin) {
5794642e01fSmrg	client->errorValue = stuff->window;
5804642e01fSmrg	return BadWindow;
5814642e01fSmrg    }
5824642e01fSmrg
5834642e01fSmrg    if (stuff->output) {
5844642e01fSmrg	output = LookupOutput(client, stuff->output, DixReadAccess);
5854642e01fSmrg
5864642e01fSmrg	if (!output) {
5874642e01fSmrg	    client->errorValue = stuff->output;
5884642e01fSmrg	    return RRErrorBase + BadRROutput;
5894642e01fSmrg	}
5904642e01fSmrg
5914642e01fSmrg	if (output->pScreen != pWin->drawable.pScreen) {
5924642e01fSmrg	    client->errorValue = stuff->window;
5934642e01fSmrg	    return BadMatch;
5944642e01fSmrg	}
5954642e01fSmrg    }
5964642e01fSmrg
5974642e01fSmrg    pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
5984642e01fSmrg    RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output);
5994642e01fSmrg
6004642e01fSmrg    return client->noClientException;
6014642e01fSmrg}
6024642e01fSmrg
6034642e01fSmrgint
6044642e01fSmrgProcRRGetOutputPrimary(ClientPtr client)
6054642e01fSmrg{
6064642e01fSmrg    REQUEST(xRRGetOutputPrimaryReq);
6074642e01fSmrg    WindowPtr pWin;
6084642e01fSmrg    rrScrPrivPtr pScrPriv;
6094642e01fSmrg    xRRGetOutputPrimaryReply rep;
6104642e01fSmrg    RROutputPtr primary = NULL;
6114642e01fSmrg
6124642e01fSmrg    REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq);
6134642e01fSmrg
6144642e01fSmrg    pWin = SecurityLookupIDByType(client, stuff->window, RT_WINDOW,
6154642e01fSmrg				  DixReadAccess);
6164642e01fSmrg
6174642e01fSmrg    if (!pWin) {
6184642e01fSmrg	client->errorValue = stuff->window;
6194642e01fSmrg	return BadWindow;
6204642e01fSmrg    }
6214642e01fSmrg
6224642e01fSmrg    pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
6234642e01fSmrg    if (pScrPriv)
6244642e01fSmrg	primary = pScrPriv->primaryOutput;
6254642e01fSmrg
6264642e01fSmrg    memset(&rep, 0, sizeof(rep));
6274642e01fSmrg    rep.type = X_Reply;
6284642e01fSmrg    rep.sequenceNumber = client->sequence;
6294642e01fSmrg    rep.output = primary ? primary->id : None;
6304642e01fSmrg
6314642e01fSmrg    if (client->swapped) {
6324642e01fSmrg	int n;
6334642e01fSmrg	swaps(&rep.sequenceNumber, n);
6344642e01fSmrg	swapl(&rep.output, n);
6354642e01fSmrg    }
6364642e01fSmrg
6374642e01fSmrg    WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep);
6384642e01fSmrg
6394642e01fSmrg    return client->noClientException;
6404642e01fSmrg}
641