rroutput.c revision 35c4bbdf
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"
2505b261ecSmrg
2635c4bbdfSmrgRESTYPE RROutputType;
2705b261ecSmrg
2805b261ecSmrg/*
2905b261ecSmrg * Notify the output of some change
3005b261ecSmrg */
3105b261ecSmrgvoid
3235c4bbdfSmrgRROutputChanged(RROutputPtr output, Bool configChanged)
3305b261ecSmrg{
3435c4bbdfSmrg    /* set changed bits on the master screen only */
3535c4bbdfSmrg    ScreenPtr pScreen = output->pScreen;
3635c4bbdfSmrg    rrScrPrivPtr mastersp;
3735c4bbdfSmrg
3805b261ecSmrg    output->changed = TRUE;
3935c4bbdfSmrg    if (!pScreen)
4035c4bbdfSmrg        return;
4135c4bbdfSmrg
4235c4bbdfSmrg    if (pScreen->isGPU) {
4335c4bbdfSmrg        ScreenPtr master = pScreen->current_master;
4435c4bbdfSmrg        if (!master)
4535c4bbdfSmrg            return;
4635c4bbdfSmrg        mastersp = rrGetScrPriv(master);
4705b261ecSmrg    }
4835c4bbdfSmrg    else {
4935c4bbdfSmrg        mastersp = rrGetScrPriv(pScreen);
5035c4bbdfSmrg    }
5135c4bbdfSmrg
5235c4bbdfSmrg    RRSetChanged(pScreen);
5335c4bbdfSmrg    if (configChanged)
5435c4bbdfSmrg        mastersp->configChanged = TRUE;
5505b261ecSmrg}
5605b261ecSmrg
5705b261ecSmrg/*
5805b261ecSmrg * Create an output
5905b261ecSmrg */
6005b261ecSmrg
6105b261ecSmrgRROutputPtr
6235c4bbdfSmrgRROutputCreate(ScreenPtr pScreen,
6335c4bbdfSmrg               const char *name, int nameLength, void *devPrivate)
6405b261ecSmrg{
6535c4bbdfSmrg    RROutputPtr output;
6635c4bbdfSmrg    RROutputPtr *outputs;
6735c4bbdfSmrg    rrScrPrivPtr pScrPriv;
6805b261ecSmrg
6905b261ecSmrg    if (!RRInit())
7035c4bbdfSmrg        return NULL;
7135c4bbdfSmrg
7205b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
7305b261ecSmrg
7405b261ecSmrg    if (pScrPriv->numOutputs)
7535c4bbdfSmrg        outputs = reallocarray(pScrPriv->outputs,
7635c4bbdfSmrg                               pScrPriv->numOutputs + 1, sizeof(RROutputPtr));
7705b261ecSmrg    else
7835c4bbdfSmrg        outputs = malloc(sizeof(RROutputPtr));
7905b261ecSmrg    if (!outputs)
8035c4bbdfSmrg        return FALSE;
8105b261ecSmrg
8205b261ecSmrg    pScrPriv->outputs = outputs;
8335c4bbdfSmrg
8435c4bbdfSmrg    output = malloc(sizeof(RROutputRec) + nameLength + 1);
8505b261ecSmrg    if (!output)
8635c4bbdfSmrg        return NULL;
8735c4bbdfSmrg    output->id = FakeClientID(0);
8805b261ecSmrg    output->pScreen = pScreen;
8905b261ecSmrg    output->name = (char *) (output + 1);
9005b261ecSmrg    output->nameLength = nameLength;
9135c4bbdfSmrg    memcpy(output->name, name, nameLength);
9205b261ecSmrg    output->name[nameLength] = '\0';
9305b261ecSmrg    output->connection = RR_UnknownConnection;
9405b261ecSmrg    output->subpixelOrder = SubPixelUnknown;
9505b261ecSmrg    output->mmWidth = 0;
9605b261ecSmrg    output->mmHeight = 0;
9705b261ecSmrg    output->crtc = NULL;
9805b261ecSmrg    output->numCrtcs = 0;
9905b261ecSmrg    output->crtcs = NULL;
10005b261ecSmrg    output->numClones = 0;
10105b261ecSmrg    output->clones = NULL;
10205b261ecSmrg    output->numModes = 0;
10305b261ecSmrg    output->numPreferred = 0;
10405b261ecSmrg    output->modes = NULL;
10505b261ecSmrg    output->numUserModes = 0;
10605b261ecSmrg    output->userModes = NULL;
10705b261ecSmrg    output->properties = NULL;
1084642e01fSmrg    output->pendingProperties = FALSE;
10905b261ecSmrg    output->changed = FALSE;
11005b261ecSmrg    output->devPrivate = devPrivate;
11135c4bbdfSmrg
11235c4bbdfSmrg    if (!AddResource(output->id, RROutputType, (void *) output))
11335c4bbdfSmrg        return NULL;
11405b261ecSmrg
11505b261ecSmrg    pScrPriv->outputs[pScrPriv->numOutputs++] = output;
11635c4bbdfSmrg
11735c4bbdfSmrg    RRResourcesChanged(pScreen);
11835c4bbdfSmrg
11905b261ecSmrg    return output;
12005b261ecSmrg}
12105b261ecSmrg
12205b261ecSmrg/*
12305b261ecSmrg * Notify extension that output parameters have been changed
12405b261ecSmrg */
12505b261ecSmrgBool
12635c4bbdfSmrgRROutputSetClones(RROutputPtr output, RROutputPtr * clones, int numClones)
12705b261ecSmrg{
12835c4bbdfSmrg    RROutputPtr *newClones;
12935c4bbdfSmrg    int i;
13035c4bbdfSmrg
13135c4bbdfSmrg    if (numClones == output->numClones) {
13235c4bbdfSmrg        for (i = 0; i < numClones; i++)
13335c4bbdfSmrg            if (output->clones[i] != clones[i])
13435c4bbdfSmrg                break;
13535c4bbdfSmrg        if (i == numClones)
13635c4bbdfSmrg            return TRUE;
13705b261ecSmrg    }
13835c4bbdfSmrg    if (numClones) {
13935c4bbdfSmrg        newClones = xallocarray(numClones, sizeof(RROutputPtr));
14035c4bbdfSmrg        if (!newClones)
14135c4bbdfSmrg            return FALSE;
14205b261ecSmrg    }
14305b261ecSmrg    else
14435c4bbdfSmrg        newClones = NULL;
1456747b715Smrg    free(output->clones);
14635c4bbdfSmrg    memcpy(newClones, clones, numClones * sizeof(RROutputPtr));
14705b261ecSmrg    output->clones = newClones;
14805b261ecSmrg    output->numClones = numClones;
14935c4bbdfSmrg    RROutputChanged(output, TRUE);
15005b261ecSmrg    return TRUE;
15105b261ecSmrg}
15205b261ecSmrg
15305b261ecSmrgBool
15435c4bbdfSmrgRROutputSetModes(RROutputPtr output,
15535c4bbdfSmrg                 RRModePtr * modes, int numModes, int numPreferred)
15605b261ecSmrg{
15735c4bbdfSmrg    RRModePtr *newModes;
15835c4bbdfSmrg    int i;
15935c4bbdfSmrg
16035c4bbdfSmrg    if (numModes == output->numModes && numPreferred == output->numPreferred) {
16135c4bbdfSmrg        for (i = 0; i < numModes; i++)
16235c4bbdfSmrg            if (output->modes[i] != modes[i])
16335c4bbdfSmrg                break;
16435c4bbdfSmrg        if (i == numModes) {
16535c4bbdfSmrg            for (i = 0; i < numModes; i++)
16635c4bbdfSmrg                RRModeDestroy(modes[i]);
16735c4bbdfSmrg            return TRUE;
16835c4bbdfSmrg        }
16905b261ecSmrg    }
17005b261ecSmrg
17135c4bbdfSmrg    if (numModes) {
17235c4bbdfSmrg        newModes = xallocarray(numModes, sizeof(RRModePtr));
17335c4bbdfSmrg        if (!newModes)
17435c4bbdfSmrg            return FALSE;
17505b261ecSmrg    }
17605b261ecSmrg    else
17735c4bbdfSmrg        newModes = NULL;
17835c4bbdfSmrg    if (output->modes) {
17935c4bbdfSmrg        for (i = 0; i < output->numModes; i++)
18035c4bbdfSmrg            RRModeDestroy(output->modes[i]);
18135c4bbdfSmrg        free(output->modes);
18205b261ecSmrg    }
18335c4bbdfSmrg    memcpy(newModes, modes, numModes * sizeof(RRModePtr));
18405b261ecSmrg    output->modes = newModes;
18505b261ecSmrg    output->numModes = numModes;
18605b261ecSmrg    output->numPreferred = numPreferred;
18735c4bbdfSmrg    RROutputChanged(output, TRUE);
18805b261ecSmrg    return TRUE;
18905b261ecSmrg}
19005b261ecSmrg
19105b261ecSmrgint
19235c4bbdfSmrgRROutputAddUserMode(RROutputPtr output, RRModePtr mode)
19305b261ecSmrg{
19435c4bbdfSmrg    int m;
19535c4bbdfSmrg    ScreenPtr pScreen = output->pScreen;
19635c4bbdfSmrg
19705b261ecSmrg    rrScrPriv(pScreen);
19835c4bbdfSmrg    RRModePtr *newModes;
19905b261ecSmrg
20005b261ecSmrg    /* Check to see if this mode is already listed for this output */
20135c4bbdfSmrg    for (m = 0; m < output->numModes + output->numUserModes; m++) {
20235c4bbdfSmrg        RRModePtr e = (m < output->numModes ?
20335c4bbdfSmrg                       output->modes[m] :
20435c4bbdfSmrg                       output->userModes[m - output->numModes]);
20535c4bbdfSmrg        if (mode == e)
20635c4bbdfSmrg            return Success;
20705b261ecSmrg    }
20805b261ecSmrg
20905b261ecSmrg    /* Check with the DDX to see if this mode is OK */
21005b261ecSmrg    if (pScrPriv->rrOutputValidateMode)
21135c4bbdfSmrg        if (!pScrPriv->rrOutputValidateMode(pScreen, output, mode))
21235c4bbdfSmrg            return BadMatch;
21305b261ecSmrg
21405b261ecSmrg    if (output->userModes)
21535c4bbdfSmrg        newModes = reallocarray(output->userModes,
21635c4bbdfSmrg                                output->numUserModes + 1, sizeof(RRModePtr));
21705b261ecSmrg    else
21835c4bbdfSmrg        newModes = malloc(sizeof(RRModePtr));
21905b261ecSmrg    if (!newModes)
22035c4bbdfSmrg        return BadAlloc;
22105b261ecSmrg
22205b261ecSmrg    output->userModes = newModes;
22305b261ecSmrg    output->userModes[output->numUserModes++] = mode;
22405b261ecSmrg    ++mode->refcnt;
22535c4bbdfSmrg    RROutputChanged(output, TRUE);
22635c4bbdfSmrg    RRTellChanged(pScreen);
22705b261ecSmrg    return Success;
22805b261ecSmrg}
22905b261ecSmrg
23005b261ecSmrgint
23135c4bbdfSmrgRROutputDeleteUserMode(RROutputPtr output, RRModePtr mode)
23205b261ecSmrg{
23335c4bbdfSmrg    int m;
23435c4bbdfSmrg
23505b261ecSmrg    /* Find this mode in the user mode list */
23635c4bbdfSmrg    for (m = 0; m < output->numUserModes; m++) {
23735c4bbdfSmrg        RRModePtr e = output->userModes[m];
23805b261ecSmrg
23935c4bbdfSmrg        if (mode == e)
24035c4bbdfSmrg            break;
24105b261ecSmrg    }
24205b261ecSmrg    /* Not there, access error */
24305b261ecSmrg    if (m == output->numUserModes)
24435c4bbdfSmrg        return BadAccess;
24505b261ecSmrg
24605b261ecSmrg    /* make sure the mode isn't active for this output */
24705b261ecSmrg    if (output->crtc && output->crtc->mode == mode)
24835c4bbdfSmrg        return BadMatch;
24905b261ecSmrg
25035c4bbdfSmrg    memmove(output->userModes + m, output->userModes + m + 1,
25135c4bbdfSmrg            (output->numUserModes - m - 1) * sizeof(RRModePtr));
25205b261ecSmrg    output->numUserModes--;
25335c4bbdfSmrg    RRModeDestroy(mode);
25405b261ecSmrg    return Success;
25505b261ecSmrg}
25605b261ecSmrg
25705b261ecSmrgBool
25835c4bbdfSmrgRROutputSetCrtcs(RROutputPtr output, RRCrtcPtr * crtcs, int numCrtcs)
25905b261ecSmrg{
26035c4bbdfSmrg    RRCrtcPtr *newCrtcs;
26135c4bbdfSmrg    int i;
26235c4bbdfSmrg
26335c4bbdfSmrg    if (numCrtcs == output->numCrtcs) {
26435c4bbdfSmrg        for (i = 0; i < numCrtcs; i++)
26535c4bbdfSmrg            if (output->crtcs[i] != crtcs[i])
26635c4bbdfSmrg                break;
26735c4bbdfSmrg        if (i == numCrtcs)
26835c4bbdfSmrg            return TRUE;
26905b261ecSmrg    }
27035c4bbdfSmrg    if (numCrtcs) {
27135c4bbdfSmrg        newCrtcs = xallocarray(numCrtcs, sizeof(RRCrtcPtr));
27235c4bbdfSmrg        if (!newCrtcs)
27335c4bbdfSmrg            return FALSE;
27405b261ecSmrg    }
27505b261ecSmrg    else
27635c4bbdfSmrg        newCrtcs = NULL;
2776747b715Smrg    free(output->crtcs);
27835c4bbdfSmrg    memcpy(newCrtcs, crtcs, numCrtcs * sizeof(RRCrtcPtr));
27905b261ecSmrg    output->crtcs = newCrtcs;
28005b261ecSmrg    output->numCrtcs = numCrtcs;
28135c4bbdfSmrg    RROutputChanged(output, TRUE);
28205b261ecSmrg    return TRUE;
28305b261ecSmrg}
28405b261ecSmrg
28505b261ecSmrgBool
28635c4bbdfSmrgRROutputSetConnection(RROutputPtr output, CARD8 connection)
28705b261ecSmrg{
28805b261ecSmrg    if (output->connection == connection)
28935c4bbdfSmrg        return TRUE;
29005b261ecSmrg    output->connection = connection;
29135c4bbdfSmrg    RROutputChanged(output, TRUE);
29205b261ecSmrg    return TRUE;
29305b261ecSmrg}
29405b261ecSmrg
29505b261ecSmrgBool
29635c4bbdfSmrgRROutputSetSubpixelOrder(RROutputPtr output, int subpixelOrder)
29705b261ecSmrg{
29805b261ecSmrg    if (output->subpixelOrder == subpixelOrder)
29935c4bbdfSmrg        return TRUE;
30005b261ecSmrg
30105b261ecSmrg    output->subpixelOrder = subpixelOrder;
30235c4bbdfSmrg    RROutputChanged(output, FALSE);
30305b261ecSmrg    return TRUE;
30405b261ecSmrg}
30505b261ecSmrg
30605b261ecSmrgBool
30735c4bbdfSmrgRROutputSetPhysicalSize(RROutputPtr output, int mmWidth, int mmHeight)
30805b261ecSmrg{
30905b261ecSmrg    if (output->mmWidth == mmWidth && output->mmHeight == mmHeight)
31035c4bbdfSmrg        return TRUE;
31105b261ecSmrg    output->mmWidth = mmWidth;
31205b261ecSmrg    output->mmHeight = mmHeight;
31335c4bbdfSmrg    RROutputChanged(output, FALSE);
31405b261ecSmrg    return TRUE;
31505b261ecSmrg}
31605b261ecSmrg
31705b261ecSmrgvoid
31805b261ecSmrgRRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output)
31905b261ecSmrg{
32005b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
32135c4bbdfSmrg
32235c4bbdfSmrg    rrScrPriv(pScreen);
32335c4bbdfSmrg    RRCrtcPtr crtc = output->crtc;
32435c4bbdfSmrg    RRModePtr mode = crtc ? crtc->mode : NULL;
32535c4bbdfSmrg
32635c4bbdfSmrg    xRROutputChangeNotifyEvent oe = {
32735c4bbdfSmrg        .type = RRNotify + RREventBase,
32835c4bbdfSmrg        .subCode = RRNotify_OutputChange,
32935c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
33035c4bbdfSmrg        .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
33135c4bbdfSmrg        .window = pWin->drawable.id,
33235c4bbdfSmrg        .output = output->id,
33335c4bbdfSmrg        .crtc = crtc ? crtc->id : None,
33435c4bbdfSmrg        .mode = mode ? mode->mode.id : None,
33535c4bbdfSmrg        .rotation = crtc ? crtc->rotation : RR_Rotate_0,
33635c4bbdfSmrg        .connection = output->connection,
33735c4bbdfSmrg        .subpixelOrder = output->subpixelOrder
33835c4bbdfSmrg    };
33935c4bbdfSmrg    WriteEventsToClient(client, 1, (xEvent *) &oe);
34005b261ecSmrg}
34105b261ecSmrg
34205b261ecSmrg/*
34305b261ecSmrg * Destroy a Output at shutdown
34405b261ecSmrg */
34505b261ecSmrgvoid
34635c4bbdfSmrgRROutputDestroy(RROutputPtr output)
34705b261ecSmrg{
34835c4bbdfSmrg    FreeResource(output->id, 0);
34905b261ecSmrg}
35005b261ecSmrg
35105b261ecSmrgstatic int
35235c4bbdfSmrgRROutputDestroyResource(void *value, XID pid)
35305b261ecSmrg{
35435c4bbdfSmrg    RROutputPtr output = (RROutputPtr) value;
35535c4bbdfSmrg    ScreenPtr pScreen = output->pScreen;
35635c4bbdfSmrg    int m;
35735c4bbdfSmrg
35835c4bbdfSmrg    if (pScreen) {
35935c4bbdfSmrg        rrScrPriv(pScreen);
36035c4bbdfSmrg        int i;
36135c4bbdfSmrg
36235c4bbdfSmrg        if (pScrPriv->primaryOutput == output)
36335c4bbdfSmrg            pScrPriv->primaryOutput = NULL;
36435c4bbdfSmrg
36535c4bbdfSmrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
36635c4bbdfSmrg            if (pScrPriv->outputs[i] == output) {
36735c4bbdfSmrg                memmove(pScrPriv->outputs + i, pScrPriv->outputs + i + 1,
36835c4bbdfSmrg                        (pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr));
36935c4bbdfSmrg                --pScrPriv->numOutputs;
37035c4bbdfSmrg                break;
37135c4bbdfSmrg            }
37235c4bbdfSmrg        }
37335c4bbdfSmrg
37435c4bbdfSmrg        RRResourcesChanged(pScreen);
37505b261ecSmrg    }
37635c4bbdfSmrg    if (output->modes) {
37735c4bbdfSmrg        for (m = 0; m < output->numModes; m++)
37835c4bbdfSmrg            RRModeDestroy(output->modes[m]);
37935c4bbdfSmrg        free(output->modes);
38005b261ecSmrg    }
38135c4bbdfSmrg
38205b261ecSmrg    for (m = 0; m < output->numUserModes; m++)
38335c4bbdfSmrg        RRModeDestroy(output->userModes[m]);
3846747b715Smrg    free(output->userModes);
38505b261ecSmrg
3866747b715Smrg    free(output->crtcs);
3876747b715Smrg    free(output->clones);
38835c4bbdfSmrg    RRDeleteAllOutputProperties(output);
3896747b715Smrg    free(output);
39005b261ecSmrg    return 1;
39105b261ecSmrg}
39205b261ecSmrg
39305b261ecSmrg/*
39405b261ecSmrg * Initialize output type
39505b261ecSmrg */
39605b261ecSmrgBool
39735c4bbdfSmrgRROutputInit(void)
39805b261ecSmrg{
39935c4bbdfSmrg    RROutputType = CreateNewResourceType(RROutputDestroyResource, "OUTPUT");
40005b261ecSmrg    if (!RROutputType)
40135c4bbdfSmrg        return FALSE;
4026747b715Smrg
40305b261ecSmrg    return TRUE;
40405b261ecSmrg}
40505b261ecSmrg
4066747b715Smrg/*
4076747b715Smrg * Initialize output type error value
4086747b715Smrg */
4096747b715Smrgvoid
4106747b715SmrgRROutputInitErrorValue(void)
4116747b715Smrg{
4126747b715Smrg    SetResourceTypeErrorValue(RROutputType, RRErrorBase + BadRROutput);
4136747b715Smrg}
4146747b715Smrg
41505b261ecSmrg#define OutputInfoExtra	(SIZEOF(xRRGetOutputInfoReply) - 32)
4164642e01fSmrg
41705b261ecSmrgint
41835c4bbdfSmrgProcRRGetOutputInfo(ClientPtr client)
41905b261ecSmrg{
42005b261ecSmrg    REQUEST(xRRGetOutputInfoReq);
42135c4bbdfSmrg    xRRGetOutputInfoReply rep;
42235c4bbdfSmrg    RROutputPtr output;
42335c4bbdfSmrg    CARD8 *extra;
42435c4bbdfSmrg    unsigned long extraLen;
42535c4bbdfSmrg    ScreenPtr pScreen;
42635c4bbdfSmrg    rrScrPrivPtr pScrPriv;
42735c4bbdfSmrg    RRCrtc *crtcs;
42835c4bbdfSmrg    RRMode *modes;
42935c4bbdfSmrg    RROutput *clones;
43035c4bbdfSmrg    char *name;
43135c4bbdfSmrg    int i;
43235c4bbdfSmrg
43305b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
4346747b715Smrg    VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
43505b261ecSmrg
43605b261ecSmrg    pScreen = output->pScreen;
43705b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
43805b261ecSmrg
43935c4bbdfSmrg    rep = (xRRGetOutputInfoReply) {
44035c4bbdfSmrg        .type = X_Reply,
44135c4bbdfSmrg        .status = RRSetConfigSuccess,
44235c4bbdfSmrg        .sequenceNumber = client->sequence,
44335c4bbdfSmrg        .length = bytes_to_int32(OutputInfoExtra),
44435c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
44535c4bbdfSmrg        .crtc = output->crtc ? output->crtc->id : None,
44635c4bbdfSmrg        .mmWidth = output->mmWidth,
44735c4bbdfSmrg        .mmHeight = output->mmHeight,
44835c4bbdfSmrg        .connection = output->connection,
44935c4bbdfSmrg        .subpixelOrder = output->subpixelOrder,
45035c4bbdfSmrg        .nCrtcs = output->numCrtcs,
45135c4bbdfSmrg        .nModes = output->numModes + output->numUserModes,
45235c4bbdfSmrg        .nPreferred = output->numPreferred,
45335c4bbdfSmrg        .nClones = output->numClones,
45435c4bbdfSmrg        .nameLength = output->nameLength
45535c4bbdfSmrg    };
4566747b715Smrg    extraLen = ((output->numCrtcs +
45735c4bbdfSmrg                 output->numModes + output->numUserModes +
45835c4bbdfSmrg                 output->numClones + bytes_to_int32(rep.nameLength)) << 2);
45935c4bbdfSmrg
46035c4bbdfSmrg    if (extraLen) {
46135c4bbdfSmrg        rep.length += bytes_to_int32(extraLen);
46235c4bbdfSmrg        extra = malloc(extraLen);
46335c4bbdfSmrg        if (!extra)
46435c4bbdfSmrg            return BadAlloc;
46505b261ecSmrg    }
46605b261ecSmrg    else
46735c4bbdfSmrg        extra = NULL;
46805b261ecSmrg
46905b261ecSmrg    crtcs = (RRCrtc *) extra;
47005b261ecSmrg    modes = (RRMode *) (crtcs + output->numCrtcs);
47105b261ecSmrg    clones = (RROutput *) (modes + output->numModes + output->numUserModes);
47205b261ecSmrg    name = (char *) (clones + output->numClones);
47335c4bbdfSmrg
47435c4bbdfSmrg    for (i = 0; i < output->numCrtcs; i++) {
47535c4bbdfSmrg        crtcs[i] = output->crtcs[i]->id;
47635c4bbdfSmrg        if (client->swapped)
47735c4bbdfSmrg            swapl(&crtcs[i]);
47805b261ecSmrg    }
47935c4bbdfSmrg    for (i = 0; i < output->numModes + output->numUserModes; i++) {
48035c4bbdfSmrg        if (i < output->numModes)
48135c4bbdfSmrg            modes[i] = output->modes[i]->mode.id;
48235c4bbdfSmrg        else
48335c4bbdfSmrg            modes[i] = output->userModes[i - output->numModes]->mode.id;
48435c4bbdfSmrg        if (client->swapped)
48535c4bbdfSmrg            swapl(&modes[i]);
48605b261ecSmrg    }
48735c4bbdfSmrg    for (i = 0; i < output->numClones; i++) {
48835c4bbdfSmrg        clones[i] = output->clones[i]->id;
48935c4bbdfSmrg        if (client->swapped)
49035c4bbdfSmrg            swapl(&clones[i]);
49105b261ecSmrg    }
49235c4bbdfSmrg    memcpy(name, output->name, output->nameLength);
49305b261ecSmrg    if (client->swapped) {
49435c4bbdfSmrg        swaps(&rep.sequenceNumber);
49535c4bbdfSmrg        swapl(&rep.length);
49635c4bbdfSmrg        swapl(&rep.timestamp);
49735c4bbdfSmrg        swapl(&rep.crtc);
49835c4bbdfSmrg        swapl(&rep.mmWidth);
49935c4bbdfSmrg        swapl(&rep.mmHeight);
50035c4bbdfSmrg        swaps(&rep.nCrtcs);
50135c4bbdfSmrg        swaps(&rep.nModes);
50235c4bbdfSmrg        swaps(&rep.nPreferred);
50335c4bbdfSmrg        swaps(&rep.nClones);
50435c4bbdfSmrg        swaps(&rep.nameLength);
50505b261ecSmrg    }
50635c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetOutputInfoReply), &rep);
50735c4bbdfSmrg    if (extraLen) {
50835c4bbdfSmrg        WriteToClient(client, extraLen, extra);
50935c4bbdfSmrg        free(extra);
51005b261ecSmrg    }
51135c4bbdfSmrg
5126747b715Smrg    return Success;
51305b261ecSmrg}
5144642e01fSmrg
5156747b715Smrgstatic void
51635c4bbdfSmrgRRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, RROutputPtr output)
5174642e01fSmrg{
5184642e01fSmrg    if (pScrPriv->primaryOutput == output)
51935c4bbdfSmrg        return;
5204642e01fSmrg
5214642e01fSmrg    /* clear the old primary */
5224642e01fSmrg    if (pScrPriv->primaryOutput) {
52335c4bbdfSmrg        RROutputChanged(pScrPriv->primaryOutput, 0);
52435c4bbdfSmrg        pScrPriv->primaryOutput = NULL;
5254642e01fSmrg    }
5264642e01fSmrg
5274642e01fSmrg    /* set the new primary */
5284642e01fSmrg    if (output) {
52935c4bbdfSmrg        pScrPriv->primaryOutput = output;
53035c4bbdfSmrg        RROutputChanged(output, 0);
5314642e01fSmrg    }
5324642e01fSmrg
5334642e01fSmrg    pScrPriv->layoutChanged = TRUE;
5344642e01fSmrg
5354642e01fSmrg    RRTellChanged(pScreen);
5364642e01fSmrg}
5374642e01fSmrg
5384642e01fSmrgint
5394642e01fSmrgProcRRSetOutputPrimary(ClientPtr client)
5404642e01fSmrg{
5414642e01fSmrg    REQUEST(xRRSetOutputPrimaryReq);
5424642e01fSmrg    RROutputPtr output = NULL;
5434642e01fSmrg    WindowPtr pWin;
5444642e01fSmrg    rrScrPrivPtr pScrPriv;
54535c4bbdfSmrg    int ret;
54635c4bbdfSmrg    ScreenPtr slave;
5474642e01fSmrg
5484642e01fSmrg    REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq);
5494642e01fSmrg
55035c4bbdfSmrg    ret = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
55135c4bbdfSmrg    if (ret != Success)
55235c4bbdfSmrg        return ret;
5534642e01fSmrg
5544642e01fSmrg    if (stuff->output) {
55535c4bbdfSmrg        VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
55635c4bbdfSmrg
55735c4bbdfSmrg        if (!output->pScreen->isGPU && output->pScreen != pWin->drawable.pScreen) {
55835c4bbdfSmrg            client->errorValue = stuff->window;
55935c4bbdfSmrg            return BadMatch;
56035c4bbdfSmrg        }
56135c4bbdfSmrg        if (output->pScreen->isGPU && output->pScreen->current_master != pWin->drawable.pScreen) {
56235c4bbdfSmrg            client->errorValue = stuff->window;
56335c4bbdfSmrg            return BadMatch;
56435c4bbdfSmrg        }
5654642e01fSmrg    }
5664642e01fSmrg
5674642e01fSmrg    pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
56835c4bbdfSmrg    if (pScrPriv)
56935c4bbdfSmrg    {
57035c4bbdfSmrg        RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output);
57135c4bbdfSmrg
57235c4bbdfSmrg        xorg_list_for_each_entry(slave,
57335c4bbdfSmrg                                 &pWin->drawable.pScreen->output_slave_list,
57435c4bbdfSmrg                                 output_head) {
57535c4bbdfSmrg            rrScrPrivPtr pSlavePriv;
57635c4bbdfSmrg            pSlavePriv = rrGetScrPriv(slave);
57735c4bbdfSmrg
57835c4bbdfSmrg            RRSetPrimaryOutput(slave, pSlavePriv, output);
57935c4bbdfSmrg        }
58035c4bbdfSmrg    }
5814642e01fSmrg
5826747b715Smrg    return Success;
5834642e01fSmrg}
5844642e01fSmrg
5854642e01fSmrgint
5864642e01fSmrgProcRRGetOutputPrimary(ClientPtr client)
5874642e01fSmrg{
5884642e01fSmrg    REQUEST(xRRGetOutputPrimaryReq);
5894642e01fSmrg    WindowPtr pWin;
5904642e01fSmrg    rrScrPrivPtr pScrPriv;
5914642e01fSmrg    xRRGetOutputPrimaryReply rep;
5924642e01fSmrg    RROutputPtr primary = NULL;
5936747b715Smrg    int rc;
5944642e01fSmrg
5954642e01fSmrg    REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq);
5964642e01fSmrg
5976747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
5986747b715Smrg    if (rc != Success)
59935c4bbdfSmrg        return rc;
6004642e01fSmrg
6014642e01fSmrg    pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
6024642e01fSmrg    if (pScrPriv)
60335c4bbdfSmrg        primary = pScrPriv->primaryOutput;
6044642e01fSmrg
60535c4bbdfSmrg    rep = (xRRGetOutputPrimaryReply) {
60635c4bbdfSmrg        .type = X_Reply,
60735c4bbdfSmrg        .sequenceNumber = client->sequence,
60835c4bbdfSmrg        .output = primary ? primary->id : None
60935c4bbdfSmrg    };
6104642e01fSmrg
6114642e01fSmrg    if (client->swapped) {
61235c4bbdfSmrg        swaps(&rep.sequenceNumber);
61335c4bbdfSmrg        swapl(&rep.output);
6144642e01fSmrg    }
6154642e01fSmrg
6164642e01fSmrg    WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep);
6174642e01fSmrg
6186747b715Smrg    return Success;
6194642e01fSmrg}
620