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"
251b5d61b8Smrg#include <X11/Xatom.h>
2605b261ecSmrg
2735c4bbdfSmrgRESTYPE RROutputType;
2805b261ecSmrg
2905b261ecSmrg/*
3005b261ecSmrg * Notify the output of some change
3105b261ecSmrg */
3205b261ecSmrgvoid
3335c4bbdfSmrgRROutputChanged(RROutputPtr output, Bool configChanged)
3405b261ecSmrg{
35ed6184dfSmrg    /* set changed bits on the primary screen only */
3635c4bbdfSmrg    ScreenPtr pScreen = output->pScreen;
37ed6184dfSmrg    rrScrPrivPtr primarysp;
3835c4bbdfSmrg
3905b261ecSmrg    output->changed = TRUE;
4035c4bbdfSmrg    if (!pScreen)
4135c4bbdfSmrg        return;
4235c4bbdfSmrg
4335c4bbdfSmrg    if (pScreen->isGPU) {
44ed6184dfSmrg        ScreenPtr primary = pScreen->current_primary;
45ed6184dfSmrg        if (!primary)
4635c4bbdfSmrg            return;
47ed6184dfSmrg        primarysp = rrGetScrPriv(primary);
4805b261ecSmrg    }
4935c4bbdfSmrg    else {
50ed6184dfSmrg        primarysp = rrGetScrPriv(pScreen);
5135c4bbdfSmrg    }
5235c4bbdfSmrg
5335c4bbdfSmrg    RRSetChanged(pScreen);
5435c4bbdfSmrg    if (configChanged)
55ed6184dfSmrg        primarysp->configChanged = TRUE;
5605b261ecSmrg}
5705b261ecSmrg
5805b261ecSmrg/*
5905b261ecSmrg * Create an output
6005b261ecSmrg */
6105b261ecSmrg
6205b261ecSmrgRROutputPtr
6335c4bbdfSmrgRROutputCreate(ScreenPtr pScreen,
6435c4bbdfSmrg               const char *name, int nameLength, void *devPrivate)
6505b261ecSmrg{
6635c4bbdfSmrg    RROutputPtr output;
6735c4bbdfSmrg    RROutputPtr *outputs;
6835c4bbdfSmrg    rrScrPrivPtr pScrPriv;
691b5d61b8Smrg    Atom nonDesktopAtom;
7005b261ecSmrg
7105b261ecSmrg    if (!RRInit())
7235c4bbdfSmrg        return NULL;
7335c4bbdfSmrg
7405b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
7505b261ecSmrg
761b5d61b8Smrg    outputs = reallocarray(pScrPriv->outputs,
771b5d61b8Smrg                           pScrPriv->numOutputs + 1, sizeof(RROutputPtr));
7805b261ecSmrg    if (!outputs)
791b5d61b8Smrg        return NULL;
8005b261ecSmrg
8105b261ecSmrg    pScrPriv->outputs = outputs;
8235c4bbdfSmrg
8335c4bbdfSmrg    output = malloc(sizeof(RROutputRec) + nameLength + 1);
8405b261ecSmrg    if (!output)
8535c4bbdfSmrg        return NULL;
8635c4bbdfSmrg    output->id = FakeClientID(0);
8705b261ecSmrg    output->pScreen = pScreen;
8805b261ecSmrg    output->name = (char *) (output + 1);
8905b261ecSmrg    output->nameLength = nameLength;
9035c4bbdfSmrg    memcpy(output->name, name, nameLength);
9105b261ecSmrg    output->name[nameLength] = '\0';
9205b261ecSmrg    output->connection = RR_UnknownConnection;
9305b261ecSmrg    output->subpixelOrder = SubPixelUnknown;
9405b261ecSmrg    output->mmWidth = 0;
9505b261ecSmrg    output->mmHeight = 0;
9605b261ecSmrg    output->crtc = NULL;
9705b261ecSmrg    output->numCrtcs = 0;
9805b261ecSmrg    output->crtcs = NULL;
9905b261ecSmrg    output->numClones = 0;
10005b261ecSmrg    output->clones = NULL;
10105b261ecSmrg    output->numModes = 0;
10205b261ecSmrg    output->numPreferred = 0;
10305b261ecSmrg    output->modes = NULL;
10405b261ecSmrg    output->numUserModes = 0;
10505b261ecSmrg    output->userModes = NULL;
10605b261ecSmrg    output->properties = NULL;
1074642e01fSmrg    output->pendingProperties = FALSE;
10805b261ecSmrg    output->changed = FALSE;
1091b5d61b8Smrg    output->nonDesktop = 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
1171b5d61b8Smrg    nonDesktopAtom = MakeAtom(RR_PROPERTY_NON_DESKTOP, strlen(RR_PROPERTY_NON_DESKTOP), TRUE);
1181b5d61b8Smrg    if (nonDesktopAtom != BAD_RESOURCE) {
1191b5d61b8Smrg        static const INT32 values[2] = { 0, 1 };
1201b5d61b8Smrg        (void) RRConfigureOutputProperty(output, nonDesktopAtom, FALSE, FALSE, FALSE,
1211b5d61b8Smrg                                            2, values);
1221b5d61b8Smrg    }
1231b5d61b8Smrg    RROutputSetNonDesktop(output, FALSE);
12435c4bbdfSmrg    RRResourcesChanged(pScreen);
12535c4bbdfSmrg
12605b261ecSmrg    return output;
12705b261ecSmrg}
12805b261ecSmrg
12905b261ecSmrg/*
13005b261ecSmrg * Notify extension that output parameters have been changed
13105b261ecSmrg */
13205b261ecSmrgBool
13335c4bbdfSmrgRROutputSetClones(RROutputPtr output, RROutputPtr * clones, int numClones)
13405b261ecSmrg{
13535c4bbdfSmrg    RROutputPtr *newClones;
13635c4bbdfSmrg    int i;
13735c4bbdfSmrg
13835c4bbdfSmrg    if (numClones == output->numClones) {
13935c4bbdfSmrg        for (i = 0; i < numClones; i++)
14035c4bbdfSmrg            if (output->clones[i] != clones[i])
14135c4bbdfSmrg                break;
14235c4bbdfSmrg        if (i == numClones)
14335c4bbdfSmrg            return TRUE;
14405b261ecSmrg    }
14535c4bbdfSmrg    if (numClones) {
14635c4bbdfSmrg        newClones = xallocarray(numClones, sizeof(RROutputPtr));
14735c4bbdfSmrg        if (!newClones)
14835c4bbdfSmrg            return FALSE;
14905b261ecSmrg    }
15005b261ecSmrg    else
15135c4bbdfSmrg        newClones = NULL;
1526747b715Smrg    free(output->clones);
15335c4bbdfSmrg    memcpy(newClones, clones, numClones * sizeof(RROutputPtr));
15405b261ecSmrg    output->clones = newClones;
15505b261ecSmrg    output->numClones = numClones;
15635c4bbdfSmrg    RROutputChanged(output, TRUE);
15705b261ecSmrg    return TRUE;
15805b261ecSmrg}
15905b261ecSmrg
16005b261ecSmrgBool
16135c4bbdfSmrgRROutputSetModes(RROutputPtr output,
16235c4bbdfSmrg                 RRModePtr * modes, int numModes, int numPreferred)
16305b261ecSmrg{
16435c4bbdfSmrg    RRModePtr *newModes;
16535c4bbdfSmrg    int i;
16635c4bbdfSmrg
16735c4bbdfSmrg    if (numModes == output->numModes && numPreferred == output->numPreferred) {
16835c4bbdfSmrg        for (i = 0; i < numModes; i++)
16935c4bbdfSmrg            if (output->modes[i] != modes[i])
17035c4bbdfSmrg                break;
17135c4bbdfSmrg        if (i == numModes) {
17235c4bbdfSmrg            for (i = 0; i < numModes; i++)
17335c4bbdfSmrg                RRModeDestroy(modes[i]);
17435c4bbdfSmrg            return TRUE;
17535c4bbdfSmrg        }
17605b261ecSmrg    }
17705b261ecSmrg
17835c4bbdfSmrg    if (numModes) {
17935c4bbdfSmrg        newModes = xallocarray(numModes, sizeof(RRModePtr));
18035c4bbdfSmrg        if (!newModes)
18135c4bbdfSmrg            return FALSE;
18205b261ecSmrg    }
18305b261ecSmrg    else
18435c4bbdfSmrg        newModes = NULL;
18535c4bbdfSmrg    if (output->modes) {
18635c4bbdfSmrg        for (i = 0; i < output->numModes; i++)
18735c4bbdfSmrg            RRModeDestroy(output->modes[i]);
18835c4bbdfSmrg        free(output->modes);
18905b261ecSmrg    }
19035c4bbdfSmrg    memcpy(newModes, modes, numModes * sizeof(RRModePtr));
19105b261ecSmrg    output->modes = newModes;
19205b261ecSmrg    output->numModes = numModes;
19305b261ecSmrg    output->numPreferred = numPreferred;
19435c4bbdfSmrg    RROutputChanged(output, TRUE);
19505b261ecSmrg    return TRUE;
19605b261ecSmrg}
19705b261ecSmrg
19805b261ecSmrgint
19935c4bbdfSmrgRROutputAddUserMode(RROutputPtr output, RRModePtr mode)
20005b261ecSmrg{
20135c4bbdfSmrg    int m;
20235c4bbdfSmrg    ScreenPtr pScreen = output->pScreen;
20335c4bbdfSmrg
20405b261ecSmrg    rrScrPriv(pScreen);
20535c4bbdfSmrg    RRModePtr *newModes;
20605b261ecSmrg
20705b261ecSmrg    /* Check to see if this mode is already listed for this output */
20835c4bbdfSmrg    for (m = 0; m < output->numModes + output->numUserModes; m++) {
20935c4bbdfSmrg        RRModePtr e = (m < output->numModes ?
21035c4bbdfSmrg                       output->modes[m] :
21135c4bbdfSmrg                       output->userModes[m - output->numModes]);
21235c4bbdfSmrg        if (mode == e)
21335c4bbdfSmrg            return Success;
21405b261ecSmrg    }
21505b261ecSmrg
21605b261ecSmrg    /* Check with the DDX to see if this mode is OK */
21705b261ecSmrg    if (pScrPriv->rrOutputValidateMode)
21835c4bbdfSmrg        if (!pScrPriv->rrOutputValidateMode(pScreen, output, mode))
21935c4bbdfSmrg            return BadMatch;
22005b261ecSmrg
22105b261ecSmrg    if (output->userModes)
22235c4bbdfSmrg        newModes = reallocarray(output->userModes,
22335c4bbdfSmrg                                output->numUserModes + 1, sizeof(RRModePtr));
22405b261ecSmrg    else
22535c4bbdfSmrg        newModes = malloc(sizeof(RRModePtr));
22605b261ecSmrg    if (!newModes)
22735c4bbdfSmrg        return BadAlloc;
22805b261ecSmrg
22905b261ecSmrg    output->userModes = newModes;
23005b261ecSmrg    output->userModes[output->numUserModes++] = mode;
23105b261ecSmrg    ++mode->refcnt;
23235c4bbdfSmrg    RROutputChanged(output, TRUE);
23335c4bbdfSmrg    RRTellChanged(pScreen);
23405b261ecSmrg    return Success;
23505b261ecSmrg}
23605b261ecSmrg
23705b261ecSmrgint
23835c4bbdfSmrgRROutputDeleteUserMode(RROutputPtr output, RRModePtr mode)
23905b261ecSmrg{
24035c4bbdfSmrg    int m;
24135c4bbdfSmrg
24205b261ecSmrg    /* Find this mode in the user mode list */
24335c4bbdfSmrg    for (m = 0; m < output->numUserModes; m++) {
24435c4bbdfSmrg        RRModePtr e = output->userModes[m];
24505b261ecSmrg
24635c4bbdfSmrg        if (mode == e)
24735c4bbdfSmrg            break;
24805b261ecSmrg    }
24905b261ecSmrg    /* Not there, access error */
25005b261ecSmrg    if (m == output->numUserModes)
25135c4bbdfSmrg        return BadAccess;
25205b261ecSmrg
25305b261ecSmrg    /* make sure the mode isn't active for this output */
25405b261ecSmrg    if (output->crtc && output->crtc->mode == mode)
25535c4bbdfSmrg        return BadMatch;
25605b261ecSmrg
25735c4bbdfSmrg    memmove(output->userModes + m, output->userModes + m + 1,
25835c4bbdfSmrg            (output->numUserModes - m - 1) * sizeof(RRModePtr));
25905b261ecSmrg    output->numUserModes--;
26035c4bbdfSmrg    RRModeDestroy(mode);
26105b261ecSmrg    return Success;
26205b261ecSmrg}
26305b261ecSmrg
26405b261ecSmrgBool
26535c4bbdfSmrgRROutputSetCrtcs(RROutputPtr output, RRCrtcPtr * crtcs, int numCrtcs)
26605b261ecSmrg{
26735c4bbdfSmrg    RRCrtcPtr *newCrtcs;
26835c4bbdfSmrg    int i;
26935c4bbdfSmrg
27035c4bbdfSmrg    if (numCrtcs == output->numCrtcs) {
27135c4bbdfSmrg        for (i = 0; i < numCrtcs; i++)
27235c4bbdfSmrg            if (output->crtcs[i] != crtcs[i])
27335c4bbdfSmrg                break;
27435c4bbdfSmrg        if (i == numCrtcs)
27535c4bbdfSmrg            return TRUE;
27605b261ecSmrg    }
27735c4bbdfSmrg    if (numCrtcs) {
27835c4bbdfSmrg        newCrtcs = xallocarray(numCrtcs, sizeof(RRCrtcPtr));
27935c4bbdfSmrg        if (!newCrtcs)
28035c4bbdfSmrg            return FALSE;
28105b261ecSmrg    }
28205b261ecSmrg    else
28335c4bbdfSmrg        newCrtcs = NULL;
2846747b715Smrg    free(output->crtcs);
28535c4bbdfSmrg    memcpy(newCrtcs, crtcs, numCrtcs * sizeof(RRCrtcPtr));
28605b261ecSmrg    output->crtcs = newCrtcs;
28705b261ecSmrg    output->numCrtcs = numCrtcs;
28835c4bbdfSmrg    RROutputChanged(output, TRUE);
28905b261ecSmrg    return TRUE;
29005b261ecSmrg}
29105b261ecSmrg
29205b261ecSmrgBool
29335c4bbdfSmrgRROutputSetConnection(RROutputPtr output, CARD8 connection)
29405b261ecSmrg{
29505b261ecSmrg    if (output->connection == connection)
29635c4bbdfSmrg        return TRUE;
29705b261ecSmrg    output->connection = connection;
29835c4bbdfSmrg    RROutputChanged(output, TRUE);
29905b261ecSmrg    return TRUE;
30005b261ecSmrg}
30105b261ecSmrg
30205b261ecSmrgBool
30335c4bbdfSmrgRROutputSetSubpixelOrder(RROutputPtr output, int subpixelOrder)
30405b261ecSmrg{
30505b261ecSmrg    if (output->subpixelOrder == subpixelOrder)
30635c4bbdfSmrg        return TRUE;
30705b261ecSmrg
30805b261ecSmrg    output->subpixelOrder = subpixelOrder;
30935c4bbdfSmrg    RROutputChanged(output, FALSE);
31005b261ecSmrg    return TRUE;
31105b261ecSmrg}
31205b261ecSmrg
31305b261ecSmrgBool
31435c4bbdfSmrgRROutputSetPhysicalSize(RROutputPtr output, int mmWidth, int mmHeight)
31505b261ecSmrg{
31605b261ecSmrg    if (output->mmWidth == mmWidth && output->mmHeight == mmHeight)
31735c4bbdfSmrg        return TRUE;
31805b261ecSmrg    output->mmWidth = mmWidth;
31905b261ecSmrg    output->mmHeight = mmHeight;
32035c4bbdfSmrg    RROutputChanged(output, FALSE);
32105b261ecSmrg    return TRUE;
32205b261ecSmrg}
32305b261ecSmrg
3241b5d61b8SmrgBool
3251b5d61b8SmrgRROutputSetNonDesktop(RROutputPtr output, Bool nonDesktop)
3261b5d61b8Smrg{
3271b5d61b8Smrg    const char *nonDesktopStr = RR_PROPERTY_NON_DESKTOP;
3281b5d61b8Smrg    Atom nonDesktopProp = MakeAtom(nonDesktopStr, strlen(nonDesktopStr), TRUE);
3291b5d61b8Smrg    uint32_t value = nonDesktop ? 1 : 0;
3301b5d61b8Smrg
3311b5d61b8Smrg    if (nonDesktopProp == None || nonDesktopProp == BAD_RESOURCE)
3321b5d61b8Smrg        return FALSE;
3331b5d61b8Smrg
3341b5d61b8Smrg    return RRChangeOutputProperty(output, nonDesktopProp, XA_INTEGER, 32,
3351b5d61b8Smrg                                  PropModeReplace, 1, &value, TRUE, FALSE) == Success;
3361b5d61b8Smrg}
3371b5d61b8Smrg
33805b261ecSmrgvoid
33905b261ecSmrgRRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output)
34005b261ecSmrg{
34105b261ecSmrg    ScreenPtr pScreen = pWin->drawable.pScreen;
34235c4bbdfSmrg
34335c4bbdfSmrg    rrScrPriv(pScreen);
34435c4bbdfSmrg    RRCrtcPtr crtc = output->crtc;
34535c4bbdfSmrg    RRModePtr mode = crtc ? crtc->mode : NULL;
34635c4bbdfSmrg
34735c4bbdfSmrg    xRROutputChangeNotifyEvent oe = {
34835c4bbdfSmrg        .type = RRNotify + RREventBase,
34935c4bbdfSmrg        .subCode = RRNotify_OutputChange,
35035c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
35135c4bbdfSmrg        .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
35235c4bbdfSmrg        .window = pWin->drawable.id,
35335c4bbdfSmrg        .output = output->id,
35435c4bbdfSmrg        .crtc = crtc ? crtc->id : None,
35535c4bbdfSmrg        .mode = mode ? mode->mode.id : None,
35635c4bbdfSmrg        .rotation = crtc ? crtc->rotation : RR_Rotate_0,
3571b5d61b8Smrg        .connection = output->nonDesktop ? RR_Disconnected : output->connection,
35835c4bbdfSmrg        .subpixelOrder = output->subpixelOrder
35935c4bbdfSmrg    };
36035c4bbdfSmrg    WriteEventsToClient(client, 1, (xEvent *) &oe);
36105b261ecSmrg}
36205b261ecSmrg
36305b261ecSmrg/*
36405b261ecSmrg * Destroy a Output at shutdown
36505b261ecSmrg */
36605b261ecSmrgvoid
36735c4bbdfSmrgRROutputDestroy(RROutputPtr output)
36805b261ecSmrg{
36935c4bbdfSmrg    FreeResource(output->id, 0);
37005b261ecSmrg}
37105b261ecSmrg
37205b261ecSmrgstatic int
37335c4bbdfSmrgRROutputDestroyResource(void *value, XID pid)
37405b261ecSmrg{
37535c4bbdfSmrg    RROutputPtr output = (RROutputPtr) value;
37635c4bbdfSmrg    ScreenPtr pScreen = output->pScreen;
37735c4bbdfSmrg    int m;
37835c4bbdfSmrg
37935c4bbdfSmrg    if (pScreen) {
38035c4bbdfSmrg        rrScrPriv(pScreen);
38135c4bbdfSmrg        int i;
3821b5d61b8Smrg        RRLeasePtr lease, next;
3831b5d61b8Smrg
3841b5d61b8Smrg        xorg_list_for_each_entry_safe(lease, next, &pScrPriv->leases, list) {
3851b5d61b8Smrg            int o;
3861b5d61b8Smrg            for (o = 0; o < lease->numOutputs; o++) {
3871b5d61b8Smrg                if (lease->outputs[o] == output) {
3881b5d61b8Smrg                    RRTerminateLease(lease);
3891b5d61b8Smrg                    break;
3901b5d61b8Smrg                }
3911b5d61b8Smrg            }
3921b5d61b8Smrg        }
39335c4bbdfSmrg
39435c4bbdfSmrg        if (pScrPriv->primaryOutput == output)
39535c4bbdfSmrg            pScrPriv->primaryOutput = NULL;
39635c4bbdfSmrg
39735c4bbdfSmrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
39835c4bbdfSmrg            if (pScrPriv->outputs[i] == output) {
39935c4bbdfSmrg                memmove(pScrPriv->outputs + i, pScrPriv->outputs + i + 1,
40035c4bbdfSmrg                        (pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr));
40135c4bbdfSmrg                --pScrPriv->numOutputs;
40235c4bbdfSmrg                break;
40335c4bbdfSmrg            }
40435c4bbdfSmrg        }
40535c4bbdfSmrg
40635c4bbdfSmrg        RRResourcesChanged(pScreen);
40705b261ecSmrg    }
40835c4bbdfSmrg    if (output->modes) {
40935c4bbdfSmrg        for (m = 0; m < output->numModes; m++)
41035c4bbdfSmrg            RRModeDestroy(output->modes[m]);
41135c4bbdfSmrg        free(output->modes);
41205b261ecSmrg    }
41335c4bbdfSmrg
41405b261ecSmrg    for (m = 0; m < output->numUserModes; m++)
41535c4bbdfSmrg        RRModeDestroy(output->userModes[m]);
4166747b715Smrg    free(output->userModes);
41705b261ecSmrg
4186747b715Smrg    free(output->crtcs);
4196747b715Smrg    free(output->clones);
42035c4bbdfSmrg    RRDeleteAllOutputProperties(output);
4216747b715Smrg    free(output);
42205b261ecSmrg    return 1;
42305b261ecSmrg}
42405b261ecSmrg
42505b261ecSmrg/*
42605b261ecSmrg * Initialize output type
42705b261ecSmrg */
42805b261ecSmrgBool
42935c4bbdfSmrgRROutputInit(void)
43005b261ecSmrg{
43135c4bbdfSmrg    RROutputType = CreateNewResourceType(RROutputDestroyResource, "OUTPUT");
43205b261ecSmrg    if (!RROutputType)
43335c4bbdfSmrg        return FALSE;
4346747b715Smrg
43505b261ecSmrg    return TRUE;
43605b261ecSmrg}
43705b261ecSmrg
4386747b715Smrg/*
4396747b715Smrg * Initialize output type error value
4406747b715Smrg */
4416747b715Smrgvoid
4426747b715SmrgRROutputInitErrorValue(void)
4436747b715Smrg{
4446747b715Smrg    SetResourceTypeErrorValue(RROutputType, RRErrorBase + BadRROutput);
4456747b715Smrg}
4466747b715Smrg
44705b261ecSmrg#define OutputInfoExtra	(SIZEOF(xRRGetOutputInfoReply) - 32)
4484642e01fSmrg
44905b261ecSmrgint
45035c4bbdfSmrgProcRRGetOutputInfo(ClientPtr client)
45105b261ecSmrg{
45205b261ecSmrg    REQUEST(xRRGetOutputInfoReq);
45335c4bbdfSmrg    xRRGetOutputInfoReply rep;
45435c4bbdfSmrg    RROutputPtr output;
45535c4bbdfSmrg    CARD8 *extra;
45635c4bbdfSmrg    unsigned long extraLen;
45735c4bbdfSmrg    ScreenPtr pScreen;
45835c4bbdfSmrg    rrScrPrivPtr pScrPriv;
45935c4bbdfSmrg    RRCrtc *crtcs;
46035c4bbdfSmrg    RRMode *modes;
46135c4bbdfSmrg    RROutput *clones;
46235c4bbdfSmrg    char *name;
46335c4bbdfSmrg    int i;
4641b5d61b8Smrg    Bool leased;
46535c4bbdfSmrg
46605b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
4676747b715Smrg    VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
46805b261ecSmrg
4691b5d61b8Smrg    leased = RROutputIsLeased(output);
4701b5d61b8Smrg
47105b261ecSmrg    pScreen = output->pScreen;
47205b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
47305b261ecSmrg
4741b5d61b8Smrg    if (leased) {
4751b5d61b8Smrg        rep = (xRRGetOutputInfoReply) {
4761b5d61b8Smrg            .type = X_Reply,
4771b5d61b8Smrg            .status = RRSetConfigSuccess,
4781b5d61b8Smrg            .sequenceNumber = client->sequence,
4791b5d61b8Smrg            .length = bytes_to_int32(OutputInfoExtra),
4801b5d61b8Smrg            .timestamp = pScrPriv->lastSetTime.milliseconds,
4811b5d61b8Smrg            .crtc = None,
4821b5d61b8Smrg            .mmWidth = 0,
4831b5d61b8Smrg            .mmHeight = 0,
4841b5d61b8Smrg            .connection = RR_Disconnected,
4851b5d61b8Smrg            .subpixelOrder = SubPixelUnknown,
4861b5d61b8Smrg            .nCrtcs = 0,
4871b5d61b8Smrg            .nModes = 0,
4881b5d61b8Smrg            .nPreferred = 0,
4891b5d61b8Smrg            .nClones = 0,
4901b5d61b8Smrg            .nameLength = output->nameLength
4911b5d61b8Smrg        };
4921b5d61b8Smrg        extraLen = bytes_to_int32(rep.nameLength) << 2;
4931b5d61b8Smrg        if (extraLen) {
4941b5d61b8Smrg            rep.length += bytes_to_int32(extraLen);
4951b5d61b8Smrg            extra = calloc(1, extraLen);
4961b5d61b8Smrg            if (!extra)
4971b5d61b8Smrg                return BadAlloc;
4981b5d61b8Smrg        }
4991b5d61b8Smrg        else
5001b5d61b8Smrg            extra = NULL;
5011b5d61b8Smrg
5021b5d61b8Smrg        name = (char *) extra;
5031b5d61b8Smrg    } else {
5041b5d61b8Smrg        rep = (xRRGetOutputInfoReply) {
5051b5d61b8Smrg            .type = X_Reply,
5061b5d61b8Smrg            .status = RRSetConfigSuccess,
5071b5d61b8Smrg            .sequenceNumber = client->sequence,
5081b5d61b8Smrg            .length = bytes_to_int32(OutputInfoExtra),
5091b5d61b8Smrg            .timestamp = pScrPriv->lastSetTime.milliseconds,
5101b5d61b8Smrg            .crtc = output->crtc ? output->crtc->id : None,
5111b5d61b8Smrg            .mmWidth = output->mmWidth,
5121b5d61b8Smrg            .mmHeight = output->mmHeight,
5131b5d61b8Smrg            .connection = output->nonDesktop ? RR_Disconnected : output->connection,
5141b5d61b8Smrg            .subpixelOrder = output->subpixelOrder,
5151b5d61b8Smrg            .nCrtcs = output->numCrtcs,
5161b5d61b8Smrg            .nModes = output->numModes + output->numUserModes,
5171b5d61b8Smrg            .nPreferred = output->numPreferred,
5181b5d61b8Smrg            .nClones = output->numClones,
5191b5d61b8Smrg            .nameLength = output->nameLength
5201b5d61b8Smrg        };
5211b5d61b8Smrg        extraLen = ((output->numCrtcs +
5221b5d61b8Smrg                     output->numModes + output->numUserModes +
5231b5d61b8Smrg                     output->numClones + bytes_to_int32(rep.nameLength)) << 2);
5241b5d61b8Smrg
5251b5d61b8Smrg        if (extraLen) {
5261b5d61b8Smrg            rep.length += bytes_to_int32(extraLen);
5271b5d61b8Smrg            extra = calloc(1, extraLen);
5281b5d61b8Smrg            if (!extra)
5291b5d61b8Smrg                return BadAlloc;
5301b5d61b8Smrg        }
5311b5d61b8Smrg        else
5321b5d61b8Smrg            extra = NULL;
53305b261ecSmrg
5341b5d61b8Smrg        crtcs = (RRCrtc *) extra;
5351b5d61b8Smrg        modes = (RRMode *) (crtcs + output->numCrtcs);
5361b5d61b8Smrg        clones = (RROutput *) (modes + output->numModes + output->numUserModes);
5371b5d61b8Smrg        name = (char *) (clones + output->numClones);
53835c4bbdfSmrg
5391b5d61b8Smrg        for (i = 0; i < output->numCrtcs; i++) {
5401b5d61b8Smrg            crtcs[i] = output->crtcs[i]->id;
5411b5d61b8Smrg            if (client->swapped)
5421b5d61b8Smrg                swapl(&crtcs[i]);
5431b5d61b8Smrg        }
5441b5d61b8Smrg        for (i = 0; i < output->numModes + output->numUserModes; i++) {
5451b5d61b8Smrg            if (i < output->numModes)
5461b5d61b8Smrg                modes[i] = output->modes[i]->mode.id;
5471b5d61b8Smrg            else
5481b5d61b8Smrg                modes[i] = output->userModes[i - output->numModes]->mode.id;
5491b5d61b8Smrg            if (client->swapped)
5501b5d61b8Smrg                swapl(&modes[i]);
5511b5d61b8Smrg        }
5521b5d61b8Smrg        for (i = 0; i < output->numClones; i++) {
5531b5d61b8Smrg            clones[i] = output->clones[i]->id;
5541b5d61b8Smrg            if (client->swapped)
5551b5d61b8Smrg                swapl(&clones[i]);
5561b5d61b8Smrg        }
55705b261ecSmrg    }
55835c4bbdfSmrg    memcpy(name, output->name, output->nameLength);
55905b261ecSmrg    if (client->swapped) {
56035c4bbdfSmrg        swaps(&rep.sequenceNumber);
56135c4bbdfSmrg        swapl(&rep.length);
56235c4bbdfSmrg        swapl(&rep.timestamp);
56335c4bbdfSmrg        swapl(&rep.crtc);
56435c4bbdfSmrg        swapl(&rep.mmWidth);
56535c4bbdfSmrg        swapl(&rep.mmHeight);
56635c4bbdfSmrg        swaps(&rep.nCrtcs);
56735c4bbdfSmrg        swaps(&rep.nModes);
56835c4bbdfSmrg        swaps(&rep.nPreferred);
56935c4bbdfSmrg        swaps(&rep.nClones);
57035c4bbdfSmrg        swaps(&rep.nameLength);
57105b261ecSmrg    }
57235c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetOutputInfoReply), &rep);
57335c4bbdfSmrg    if (extraLen) {
57435c4bbdfSmrg        WriteToClient(client, extraLen, extra);
57535c4bbdfSmrg        free(extra);
57605b261ecSmrg    }
57735c4bbdfSmrg
5786747b715Smrg    return Success;
57905b261ecSmrg}
5804642e01fSmrg
5816747b715Smrgstatic void
58235c4bbdfSmrgRRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, RROutputPtr output)
5834642e01fSmrg{
5844642e01fSmrg    if (pScrPriv->primaryOutput == output)
58535c4bbdfSmrg        return;
5864642e01fSmrg
5874642e01fSmrg    /* clear the old primary */
5884642e01fSmrg    if (pScrPriv->primaryOutput) {
58935c4bbdfSmrg        RROutputChanged(pScrPriv->primaryOutput, 0);
59035c4bbdfSmrg        pScrPriv->primaryOutput = NULL;
5914642e01fSmrg    }
5924642e01fSmrg
5934642e01fSmrg    /* set the new primary */
5944642e01fSmrg    if (output) {
59535c4bbdfSmrg        pScrPriv->primaryOutput = output;
59635c4bbdfSmrg        RROutputChanged(output, 0);
5974642e01fSmrg    }
5984642e01fSmrg
5994642e01fSmrg    pScrPriv->layoutChanged = TRUE;
6004642e01fSmrg
6014642e01fSmrg    RRTellChanged(pScreen);
6024642e01fSmrg}
6034642e01fSmrg
6044642e01fSmrgint
6054642e01fSmrgProcRRSetOutputPrimary(ClientPtr client)
6064642e01fSmrg{
6074642e01fSmrg    REQUEST(xRRSetOutputPrimaryReq);
6084642e01fSmrg    RROutputPtr output = NULL;
6094642e01fSmrg    WindowPtr pWin;
6104642e01fSmrg    rrScrPrivPtr pScrPriv;
61135c4bbdfSmrg    int ret;
612ed6184dfSmrg    ScreenPtr secondary;
6134642e01fSmrg
6144642e01fSmrg    REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq);
6154642e01fSmrg
61635c4bbdfSmrg    ret = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
61735c4bbdfSmrg    if (ret != Success)
61835c4bbdfSmrg        return ret;
6194642e01fSmrg
6204642e01fSmrg    if (stuff->output) {
62135c4bbdfSmrg        VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
62235c4bbdfSmrg
6231b5d61b8Smrg        if (RROutputIsLeased(output))
6241b5d61b8Smrg            return BadAccess;
6251b5d61b8Smrg
62635c4bbdfSmrg        if (!output->pScreen->isGPU && output->pScreen != pWin->drawable.pScreen) {
62735c4bbdfSmrg            client->errorValue = stuff->window;
62835c4bbdfSmrg            return BadMatch;
62935c4bbdfSmrg        }
630ed6184dfSmrg        if (output->pScreen->isGPU && output->pScreen->current_primary != pWin->drawable.pScreen) {
63135c4bbdfSmrg            client->errorValue = stuff->window;
63235c4bbdfSmrg            return BadMatch;
63335c4bbdfSmrg        }
6344642e01fSmrg    }
6354642e01fSmrg
6364642e01fSmrg    pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
63735c4bbdfSmrg    if (pScrPriv)
63835c4bbdfSmrg    {
63935c4bbdfSmrg        RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output);
64035c4bbdfSmrg
641ed6184dfSmrg        xorg_list_for_each_entry(secondary,
642ed6184dfSmrg                                 &pWin->drawable.pScreen->secondary_list,
643ed6184dfSmrg                                 secondary_head) {
644ed6184dfSmrg            if (secondary->is_output_secondary)
645ed6184dfSmrg                RRSetPrimaryOutput(secondary, rrGetScrPriv(secondary), output);
64635c4bbdfSmrg        }
64735c4bbdfSmrg    }
6484642e01fSmrg
6496747b715Smrg    return Success;
6504642e01fSmrg}
6514642e01fSmrg
6524642e01fSmrgint
6534642e01fSmrgProcRRGetOutputPrimary(ClientPtr client)
6544642e01fSmrg{
6554642e01fSmrg    REQUEST(xRRGetOutputPrimaryReq);
6564642e01fSmrg    WindowPtr pWin;
6574642e01fSmrg    rrScrPrivPtr pScrPriv;
6584642e01fSmrg    xRRGetOutputPrimaryReply rep;
6594642e01fSmrg    RROutputPtr primary = NULL;
6606747b715Smrg    int rc;
6614642e01fSmrg
6624642e01fSmrg    REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq);
6634642e01fSmrg
6646747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
6656747b715Smrg    if (rc != Success)
66635c4bbdfSmrg        return rc;
6674642e01fSmrg
6684642e01fSmrg    pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
6694642e01fSmrg    if (pScrPriv)
67035c4bbdfSmrg        primary = pScrPriv->primaryOutput;
6714642e01fSmrg
67235c4bbdfSmrg    rep = (xRRGetOutputPrimaryReply) {
67335c4bbdfSmrg        .type = X_Reply,
67435c4bbdfSmrg        .sequenceNumber = client->sequence,
67535c4bbdfSmrg        .output = primary ? primary->id : None
67635c4bbdfSmrg    };
6774642e01fSmrg
6784642e01fSmrg    if (client->swapped) {
67935c4bbdfSmrg        swaps(&rep.sequenceNumber);
68035c4bbdfSmrg        swapl(&rep.output);
6814642e01fSmrg    }
6824642e01fSmrg
6834642e01fSmrg    WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep);
6844642e01fSmrg
6856747b715Smrg    return Success;
6864642e01fSmrg}
687