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
2505b261ecSmrgstatic CARD16
2635c4bbdfSmrg RR10CurrentSizeID(ScreenPtr pScreen);
2705b261ecSmrg
2805b261ecSmrg/*
2905b261ecSmrg * Edit connection information block so that new clients
3005b261ecSmrg * see the current screen size on connect
3105b261ecSmrg */
3205b261ecSmrgstatic void
3335c4bbdfSmrgRREditConnectionInfo(ScreenPtr pScreen)
3405b261ecSmrg{
3535c4bbdfSmrg    xConnSetup *connSetup;
3635c4bbdfSmrg    char *vendor;
3735c4bbdfSmrg    xPixmapFormat *formats;
3835c4bbdfSmrg    xWindowRoot *root;
3935c4bbdfSmrg    xDepth *depth;
4035c4bbdfSmrg    xVisualType *visual;
4135c4bbdfSmrg    int screen = 0;
4235c4bbdfSmrg    int d;
4305b261ecSmrg
441b5d61b8Smrg    if (ConnectionInfo == NULL)
451b5d61b8Smrg        return;
461b5d61b8Smrg
4705b261ecSmrg    connSetup = (xConnSetup *) ConnectionInfo;
4835c4bbdfSmrg    vendor = (char *) connSetup + sizeof(xConnSetup);
4905b261ecSmrg    formats = (xPixmapFormat *) ((char *) vendor +
5035c4bbdfSmrg                                 pad_to_int32(connSetup->nbytesVendor));
5105b261ecSmrg    root = (xWindowRoot *) ((char *) formats +
5235c4bbdfSmrg                            sizeof(xPixmapFormat) *
5335c4bbdfSmrg                            screenInfo.numPixmapFormats);
5435c4bbdfSmrg    while (screen != pScreen->myNum) {
5535c4bbdfSmrg        depth = (xDepth *) ((char *) root + sizeof(xWindowRoot));
5635c4bbdfSmrg        for (d = 0; d < root->nDepths; d++) {
5735c4bbdfSmrg            visual = (xVisualType *) ((char *) depth + sizeof(xDepth));
5835c4bbdfSmrg            depth = (xDepth *) ((char *) visual +
5935c4bbdfSmrg                                depth->nVisuals * sizeof(xVisualType));
6035c4bbdfSmrg        }
6135c4bbdfSmrg        root = (xWindowRoot *) ((char *) depth);
6235c4bbdfSmrg        screen++;
6305b261ecSmrg    }
6405b261ecSmrg    root->pixWidth = pScreen->width;
6505b261ecSmrg    root->pixHeight = pScreen->height;
6605b261ecSmrg    root->mmWidth = pScreen->mmWidth;
6705b261ecSmrg    root->mmHeight = pScreen->mmHeight;
6805b261ecSmrg}
6905b261ecSmrg
7005b261ecSmrgvoid
7135c4bbdfSmrgRRSendConfigNotify(ScreenPtr pScreen)
7205b261ecSmrg{
7335c4bbdfSmrg    WindowPtr pWin = pScreen->root;
7435c4bbdfSmrg    xEvent event = {
7535c4bbdfSmrg        .u.configureNotify.window = pWin->drawable.id,
7635c4bbdfSmrg        .u.configureNotify.aboveSibling = None,
7735c4bbdfSmrg        .u.configureNotify.x = 0,
7835c4bbdfSmrg        .u.configureNotify.y = 0,
7905b261ecSmrg
8005b261ecSmrg    /* XXX xinerama stuff ? */
8135c4bbdfSmrg
8235c4bbdfSmrg        .u.configureNotify.width = pWin->drawable.width,
8335c4bbdfSmrg        .u.configureNotify.height = pWin->drawable.height,
8435c4bbdfSmrg        .u.configureNotify.borderWidth = wBorderWidth(pWin),
8535c4bbdfSmrg        .u.configureNotify.override = pWin->overrideRedirect
8635c4bbdfSmrg    };
8735c4bbdfSmrg    event.u.u.type = ConfigureNotify;
8805b261ecSmrg    DeliverEvents(pWin, &event, 1, NullWindow);
8905b261ecSmrg}
9005b261ecSmrg
9105b261ecSmrgvoid
9235c4bbdfSmrgRRDeliverScreenEvent(ClientPtr client, WindowPtr pWin, ScreenPtr pScreen)
9305b261ecSmrg{
9435c4bbdfSmrg    rrScrPriv(pScreen);
9535c4bbdfSmrg    RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL;
9635c4bbdfSmrg    WindowPtr pRoot = pScreen->root;
9735c4bbdfSmrg
9835c4bbdfSmrg    xRRScreenChangeNotifyEvent se = {
9935c4bbdfSmrg        .type = RRScreenChangeNotify + RREventBase,
10035c4bbdfSmrg        .rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0),
10135c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
10235c4bbdfSmrg        .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
10335c4bbdfSmrg        .root = pRoot->drawable.id,
10435c4bbdfSmrg        .window = pWin->drawable.id,
10535c4bbdfSmrg        .subpixelOrder = PictureGetSubpixelOrder(pScreen),
10635c4bbdfSmrg
10735c4bbdfSmrg        .sizeID = RR10CurrentSizeID(pScreen)
10835c4bbdfSmrg    };
10905b261ecSmrg
11005b261ecSmrg    if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) {
11135c4bbdfSmrg        se.widthInPixels = pScreen->height;
11235c4bbdfSmrg        se.heightInPixels = pScreen->width;
11335c4bbdfSmrg        se.widthInMillimeters = pScreen->mmHeight;
11435c4bbdfSmrg        se.heightInMillimeters = pScreen->mmWidth;
11535c4bbdfSmrg    }
11635c4bbdfSmrg    else {
11735c4bbdfSmrg        se.widthInPixels = pScreen->width;
11835c4bbdfSmrg        se.heightInPixels = pScreen->height;
11935c4bbdfSmrg        se.widthInMillimeters = pScreen->mmWidth;
12035c4bbdfSmrg        se.heightInMillimeters = pScreen->mmHeight;
12135c4bbdfSmrg    }
12235c4bbdfSmrg
12335c4bbdfSmrg    WriteEventsToClient(client, 1, (xEvent *) &se);
12405b261ecSmrg}
12505b261ecSmrg
12605b261ecSmrg/*
12705b261ecSmrg * Notify the extension that the screen size has been changed.
12805b261ecSmrg * The driver is responsible for calling this whenever it has changed
12905b261ecSmrg * the size of the screen
13005b261ecSmrg */
13105b261ecSmrgvoid
13235c4bbdfSmrgRRScreenSizeNotify(ScreenPtr pScreen)
13305b261ecSmrg{
13405b261ecSmrg    rrScrPriv(pScreen);
13505b261ecSmrg    /*
13605b261ecSmrg     * Deliver ConfigureNotify events when root changes
13705b261ecSmrg     * pixel size
13805b261ecSmrg     */
13905b261ecSmrg    if (pScrPriv->width == pScreen->width &&
14035c4bbdfSmrg        pScrPriv->height == pScreen->height &&
14135c4bbdfSmrg        pScrPriv->mmWidth == pScreen->mmWidth &&
14235c4bbdfSmrg        pScrPriv->mmHeight == pScreen->mmHeight)
14335c4bbdfSmrg        return;
14435c4bbdfSmrg
14505b261ecSmrg    pScrPriv->width = pScreen->width;
14605b261ecSmrg    pScrPriv->height = pScreen->height;
14705b261ecSmrg    pScrPriv->mmWidth = pScreen->mmWidth;
14805b261ecSmrg    pScrPriv->mmHeight = pScreen->mmHeight;
14935c4bbdfSmrg    RRSetChanged(pScreen);
15005b261ecSmrg/*    pScrPriv->sizeChanged = TRUE; */
15105b261ecSmrg
15235c4bbdfSmrg    RRTellChanged(pScreen);
15335c4bbdfSmrg    RRSendConfigNotify(pScreen);
15435c4bbdfSmrg    RREditConnectionInfo(pScreen);
15535c4bbdfSmrg
15635c4bbdfSmrg    RRPointerScreenConfigured(pScreen);
15705b261ecSmrg    /*
15805b261ecSmrg     * Fix pointer bounds and location
15905b261ecSmrg     */
16035c4bbdfSmrg    ScreenRestructured(pScreen);
16105b261ecSmrg}
16205b261ecSmrg
16305b261ecSmrg/*
16405b261ecSmrg * Request that the screen be resized
16505b261ecSmrg */
16605b261ecSmrgBool
16735c4bbdfSmrgRRScreenSizeSet(ScreenPtr pScreen,
16835c4bbdfSmrg                CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight)
16905b261ecSmrg{
17005b261ecSmrg    rrScrPriv(pScreen);
17105b261ecSmrg
17205b261ecSmrg#if RANDR_12_INTERFACE
17335c4bbdfSmrg    if (pScrPriv->rrScreenSetSize) {
17435c4bbdfSmrg        return (*pScrPriv->rrScreenSetSize) (pScreen,
17535c4bbdfSmrg                                             width, height, mmWidth, mmHeight);
17605b261ecSmrg    }
17705b261ecSmrg#endif
17805b261ecSmrg#if RANDR_10_INTERFACE
17935c4bbdfSmrg    if (pScrPriv->rrSetConfig) {
18035c4bbdfSmrg        return TRUE;            /* can't set size separately */
18105b261ecSmrg    }
18205b261ecSmrg#endif
18305b261ecSmrg    return FALSE;
18405b261ecSmrg}
18505b261ecSmrg
18605b261ecSmrg/*
18705b261ecSmrg * Retrieve valid screen size range
18805b261ecSmrg */
1896747b715Smrgint
19035c4bbdfSmrgProcRRGetScreenSizeRange(ClientPtr client)
19105b261ecSmrg{
19205b261ecSmrg    REQUEST(xRRGetScreenSizeRangeReq);
19335c4bbdfSmrg    xRRGetScreenSizeRangeReply rep;
19435c4bbdfSmrg    WindowPtr pWin;
19535c4bbdfSmrg    ScreenPtr pScreen;
19635c4bbdfSmrg    rrScrPrivPtr pScrPriv;
19735c4bbdfSmrg    int rc;
19835c4bbdfSmrg
19935c4bbdfSmrg    REQUEST_SIZE_MATCH(xRRGetScreenSizeRangeReq);
2006747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
20105b261ecSmrg    if (rc != Success)
20235c4bbdfSmrg        return rc;
20305b261ecSmrg
20405b261ecSmrg    pScreen = pWin->drawable.pScreen;
20505b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
20635c4bbdfSmrg
20735c4bbdfSmrg    rep = (xRRGetScreenSizeRangeReply) {
20835c4bbdfSmrg        .type = X_Reply,
20935c4bbdfSmrg        .pad = 0,
21035c4bbdfSmrg        .sequenceNumber = client->sequence,
21135c4bbdfSmrg        .length = 0
21235c4bbdfSmrg    };
21335c4bbdfSmrg
21435c4bbdfSmrg    if (pScrPriv) {
21535c4bbdfSmrg        if (!RRGetInfo(pScreen, FALSE))
21635c4bbdfSmrg            return BadAlloc;
21735c4bbdfSmrg        rep.minWidth = pScrPriv->minWidth;
21835c4bbdfSmrg        rep.minHeight = pScrPriv->minHeight;
21935c4bbdfSmrg        rep.maxWidth = pScrPriv->maxWidth;
22035c4bbdfSmrg        rep.maxHeight = pScrPriv->maxHeight;
22105b261ecSmrg    }
22235c4bbdfSmrg    else {
22335c4bbdfSmrg        rep.maxWidth = rep.minWidth = pScreen->width;
22435c4bbdfSmrg        rep.maxHeight = rep.minHeight = pScreen->height;
22535c4bbdfSmrg    }
22635c4bbdfSmrg    if (client->swapped) {
22735c4bbdfSmrg        swaps(&rep.sequenceNumber);
22835c4bbdfSmrg        swapl(&rep.length);
22935c4bbdfSmrg        swaps(&rep.minWidth);
23035c4bbdfSmrg        swaps(&rep.minHeight);
23135c4bbdfSmrg        swaps(&rep.maxWidth);
23235c4bbdfSmrg        swaps(&rep.maxHeight);
23335c4bbdfSmrg    }
23435c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), &rep);
2356747b715Smrg    return Success;
23605b261ecSmrg}
23705b261ecSmrg
23805b261ecSmrgint
23935c4bbdfSmrgProcRRSetScreenSize(ClientPtr client)
24005b261ecSmrg{
24105b261ecSmrg    REQUEST(xRRSetScreenSizeReq);
24235c4bbdfSmrg    WindowPtr pWin;
24335c4bbdfSmrg    ScreenPtr pScreen;
24435c4bbdfSmrg    rrScrPrivPtr pScrPriv;
24535c4bbdfSmrg    int i, rc;
24635c4bbdfSmrg
24705b261ecSmrg    REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
2486747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
24905b261ecSmrg    if (rc != Success)
25035c4bbdfSmrg        return rc;
25105b261ecSmrg
25205b261ecSmrg    pScreen = pWin->drawable.pScreen;
25305b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
25435c4bbdfSmrg    if (!pScrPriv)
25535c4bbdfSmrg        return BadMatch;
25635c4bbdfSmrg
25735c4bbdfSmrg    if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width) {
25835c4bbdfSmrg        client->errorValue = stuff->width;
25935c4bbdfSmrg        return BadValue;
26035c4bbdfSmrg    }
26135c4bbdfSmrg    if (stuff->height < pScrPriv->minHeight ||
26235c4bbdfSmrg        pScrPriv->maxHeight < stuff->height) {
26335c4bbdfSmrg        client->errorValue = stuff->height;
26435c4bbdfSmrg        return BadValue;
26535c4bbdfSmrg    }
26635c4bbdfSmrg    for (i = 0; i < pScrPriv->numCrtcs; i++) {
26735c4bbdfSmrg        RRCrtcPtr crtc = pScrPriv->crtcs[i];
26835c4bbdfSmrg        RRModePtr mode = crtc->mode;
26935c4bbdfSmrg
2701b5d61b8Smrg        if (!RRCrtcIsLeased(crtc) && mode) {
27135c4bbdfSmrg            int source_width = mode->mode.width;
27235c4bbdfSmrg            int source_height = mode->mode.height;
27335c4bbdfSmrg            Rotation rotation = crtc->rotation;
27435c4bbdfSmrg
2751b5d61b8Smrg            if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
27635c4bbdfSmrg                source_width = mode->mode.height;
27735c4bbdfSmrg                source_height = mode->mode.width;
27835c4bbdfSmrg            }
27935c4bbdfSmrg
28035c4bbdfSmrg            if (crtc->x + source_width > stuff->width ||
28135c4bbdfSmrg                crtc->y + source_height > stuff->height)
28235c4bbdfSmrg                return BadMatch;
28335c4bbdfSmrg        }
28435c4bbdfSmrg    }
28535c4bbdfSmrg    if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0) {
28635c4bbdfSmrg        client->errorValue = 0;
28735c4bbdfSmrg        return BadValue;
28835c4bbdfSmrg    }
28935c4bbdfSmrg    if (!RRScreenSizeSet(pScreen,
29035c4bbdfSmrg                         stuff->width, stuff->height,
29135c4bbdfSmrg                         stuff->widthInMillimeters,
29235c4bbdfSmrg                         stuff->heightInMillimeters)) {
29335c4bbdfSmrg        return BadMatch;
29435c4bbdfSmrg    }
29535c4bbdfSmrg    return Success;
29635c4bbdfSmrg}
29735c4bbdfSmrg
29835c4bbdfSmrg
29935c4bbdfSmrg#define update_totals(gpuscreen, pScrPriv) do {       \
30035c4bbdfSmrg    total_crtcs += pScrPriv->numCrtcs;                \
30135c4bbdfSmrg    total_outputs += pScrPriv->numOutputs;            \
30235c4bbdfSmrg    modes = RRModesForScreen(gpuscreen, &num_modes);  \
30335c4bbdfSmrg    if (!modes)                                       \
30435c4bbdfSmrg        return BadAlloc;                              \
30535c4bbdfSmrg    for (j = 0; j < num_modes; j++)                   \
30635c4bbdfSmrg        total_name_len += modes[j]->mode.nameLength;  \
30735c4bbdfSmrg    total_modes += num_modes;                         \
30835c4bbdfSmrg    free(modes);                                      \
30935c4bbdfSmrg} while(0)
31035c4bbdfSmrg
31135c4bbdfSmrgstatic inline void swap_modeinfos(xRRModeInfo *modeinfos, int i)
31235c4bbdfSmrg{
31335c4bbdfSmrg    swapl(&modeinfos[i].id);
31435c4bbdfSmrg    swaps(&modeinfos[i].width);
31535c4bbdfSmrg    swaps(&modeinfos[i].height);
31635c4bbdfSmrg    swapl(&modeinfos[i].dotClock);
31735c4bbdfSmrg    swaps(&modeinfos[i].hSyncStart);
31835c4bbdfSmrg    swaps(&modeinfos[i].hSyncEnd);
31935c4bbdfSmrg    swaps(&modeinfos[i].hTotal);
32035c4bbdfSmrg    swaps(&modeinfos[i].hSkew);
32135c4bbdfSmrg    swaps(&modeinfos[i].vSyncStart);
32235c4bbdfSmrg    swaps(&modeinfos[i].vSyncEnd);
32335c4bbdfSmrg    swaps(&modeinfos[i].vTotal);
32435c4bbdfSmrg    swaps(&modeinfos[i].nameLength);
32535c4bbdfSmrg    swapl(&modeinfos[i].modeFlags);
32635c4bbdfSmrg}
32735c4bbdfSmrg
32835c4bbdfSmrg#define update_arrays(gpuscreen, pScrPriv, primary_crtc, has_primary) do {            \
32935c4bbdfSmrg    for (j = 0; j < pScrPriv->numCrtcs; j++) {             \
33035c4bbdfSmrg        if (has_primary && \
33135c4bbdfSmrg            primary_crtc == pScrPriv->crtcs[j]) { \
33235c4bbdfSmrg            has_primary = 0;   \
33335c4bbdfSmrg            continue; \
33435c4bbdfSmrg        }\
33535c4bbdfSmrg        crtcs[crtc_count] = pScrPriv->crtcs[j]->id;        \
33635c4bbdfSmrg        if (client->swapped)                               \
33735c4bbdfSmrg            swapl(&crtcs[crtc_count]);                     \
33835c4bbdfSmrg        crtc_count++;                                      \
33935c4bbdfSmrg    }                                                      \
34035c4bbdfSmrg    for (j = 0; j < pScrPriv->numOutputs; j++) {           \
34135c4bbdfSmrg        outputs[output_count] = pScrPriv->outputs[j]->id;  \
34235c4bbdfSmrg        if (client->swapped)                               \
34335c4bbdfSmrg            swapl(&outputs[output_count]);                 \
34435c4bbdfSmrg        output_count++;                                    \
34535c4bbdfSmrg    }                                                      \
34635c4bbdfSmrg    {                                                      \
34735c4bbdfSmrg        RRModePtr mode;                                    \
34835c4bbdfSmrg        modes = RRModesForScreen(gpuscreen, &num_modes);   \
34935c4bbdfSmrg        for (j = 0; j < num_modes; j++) {                  \
35035c4bbdfSmrg            mode = modes[j];                               \
35135c4bbdfSmrg            modeinfos[mode_count] = mode->mode;            \
35235c4bbdfSmrg            if (client->swapped) {                         \
35335c4bbdfSmrg                swap_modeinfos(modeinfos, mode_count);     \
35435c4bbdfSmrg            }                                              \
35535c4bbdfSmrg            memcpy(names, mode->name, mode->mode.nameLength); \
35635c4bbdfSmrg            names += mode->mode.nameLength;                \
35735c4bbdfSmrg            mode_count++;                                  \
35835c4bbdfSmrg        }                                                  \
35935c4bbdfSmrg        free(modes);                                       \
36035c4bbdfSmrg    }                                                      \
36135c4bbdfSmrg    } while (0)
36235c4bbdfSmrg
36335c4bbdfSmrgstatic int
36435c4bbdfSmrgrrGetMultiScreenResources(ClientPtr client, Bool query, ScreenPtr pScreen)
36535c4bbdfSmrg{
36635c4bbdfSmrg    int j;
36735c4bbdfSmrg    int total_crtcs, total_outputs, total_modes, total_name_len;
36835c4bbdfSmrg    int crtc_count, output_count, mode_count;
36935c4bbdfSmrg    ScreenPtr iter;
37035c4bbdfSmrg    rrScrPrivPtr pScrPriv;
37135c4bbdfSmrg    int num_modes;
37235c4bbdfSmrg    RRModePtr *modes;
37335c4bbdfSmrg    xRRGetScreenResourcesReply rep;
37435c4bbdfSmrg    unsigned long extraLen;
37535c4bbdfSmrg    CARD8 *extra;
37635c4bbdfSmrg    RRCrtc *crtcs;
37735c4bbdfSmrg    RRCrtcPtr primary_crtc = NULL;
37835c4bbdfSmrg    RROutput *outputs;
37935c4bbdfSmrg    xRRModeInfo *modeinfos;
38035c4bbdfSmrg    CARD8 *names;
38135c4bbdfSmrg    int has_primary = 0;
38235c4bbdfSmrg
383ed6184dfSmrg    /* we need to iterate all the GPU primarys and all their output secondarys */
38435c4bbdfSmrg    total_crtcs = 0;
38535c4bbdfSmrg    total_outputs = 0;
38635c4bbdfSmrg    total_modes = 0;
38735c4bbdfSmrg    total_name_len = 0;
38835c4bbdfSmrg
38935c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
39035c4bbdfSmrg
39135c4bbdfSmrg    if (query && pScrPriv)
39235c4bbdfSmrg        if (!RRGetInfo(pScreen, query))
39335c4bbdfSmrg            return BadAlloc;
39435c4bbdfSmrg
39535c4bbdfSmrg    update_totals(pScreen, pScrPriv);
39635c4bbdfSmrg
397ed6184dfSmrg    xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
398ed6184dfSmrg        if (!iter->is_output_secondary)
3991b5d61b8Smrg            continue;
4001b5d61b8Smrg
40135c4bbdfSmrg        pScrPriv = rrGetScrPriv(iter);
40235c4bbdfSmrg
40335c4bbdfSmrg        if (query)
40435c4bbdfSmrg          if (!RRGetInfo(iter, query))
40535c4bbdfSmrg            return BadAlloc;
40635c4bbdfSmrg        update_totals(iter, pScrPriv);
40735c4bbdfSmrg    }
40835c4bbdfSmrg
40935c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
41035c4bbdfSmrg    rep = (xRRGetScreenResourcesReply) {
41135c4bbdfSmrg        .type = X_Reply,
41235c4bbdfSmrg        .sequenceNumber = client->sequence,
41335c4bbdfSmrg        .length = 0,
41435c4bbdfSmrg        .timestamp = pScrPriv->lastSetTime.milliseconds,
41535c4bbdfSmrg        .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
41635c4bbdfSmrg        .nCrtcs = total_crtcs,
41735c4bbdfSmrg        .nOutputs = total_outputs,
41835c4bbdfSmrg        .nModes = total_modes,
41935c4bbdfSmrg        .nbytesNames = total_name_len
42035c4bbdfSmrg    };
42135c4bbdfSmrg
42235c4bbdfSmrg    rep.length = (total_crtcs + total_outputs +
42335c4bbdfSmrg                  total_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
42435c4bbdfSmrg                  bytes_to_int32(total_name_len));
42535c4bbdfSmrg
42635c4bbdfSmrg    extraLen = rep.length << 2;
42735c4bbdfSmrg    if (extraLen) {
42835c4bbdfSmrg        extra = malloc(extraLen);
42935c4bbdfSmrg        if (!extra) {
43035c4bbdfSmrg            return BadAlloc;
43135c4bbdfSmrg        }
43235c4bbdfSmrg    }
43335c4bbdfSmrg    else
43435c4bbdfSmrg        extra = NULL;
43535c4bbdfSmrg
43635c4bbdfSmrg    crtcs = (RRCrtc *)extra;
43735c4bbdfSmrg    outputs = (RROutput *)(crtcs + total_crtcs);
43835c4bbdfSmrg    modeinfos = (xRRModeInfo *)(outputs + total_outputs);
43935c4bbdfSmrg    names = (CARD8 *)(modeinfos + total_modes);
44035c4bbdfSmrg
44135c4bbdfSmrg    crtc_count = 0;
44235c4bbdfSmrg    output_count = 0;
44335c4bbdfSmrg    mode_count = 0;
44435c4bbdfSmrg
44535c4bbdfSmrg    pScrPriv = rrGetScrPriv(pScreen);
44635c4bbdfSmrg    if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
44735c4bbdfSmrg        has_primary = 1;
44835c4bbdfSmrg        primary_crtc = pScrPriv->primaryOutput->crtc;
44935c4bbdfSmrg        crtcs[0] = pScrPriv->primaryOutput->crtc->id;
45035c4bbdfSmrg        if (client->swapped)
45135c4bbdfSmrg            swapl(&crtcs[0]);
45235c4bbdfSmrg        crtc_count = 1;
45335c4bbdfSmrg    }
45435c4bbdfSmrg    update_arrays(pScreen, pScrPriv, primary_crtc, has_primary);
45535c4bbdfSmrg
456ed6184dfSmrg    xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
457ed6184dfSmrg        if (!iter->is_output_secondary)
4581b5d61b8Smrg            continue;
4591b5d61b8Smrg
46035c4bbdfSmrg        pScrPriv = rrGetScrPriv(iter);
46135c4bbdfSmrg
46235c4bbdfSmrg        update_arrays(iter, pScrPriv, primary_crtc, has_primary);
46335c4bbdfSmrg    }
46435c4bbdfSmrg
46535c4bbdfSmrg    assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
46635c4bbdfSmrg    if (client->swapped) {
46735c4bbdfSmrg        swaps(&rep.sequenceNumber);
46835c4bbdfSmrg        swapl(&rep.length);
46935c4bbdfSmrg        swapl(&rep.timestamp);
47035c4bbdfSmrg        swapl(&rep.configTimestamp);
47135c4bbdfSmrg        swaps(&rep.nCrtcs);
47235c4bbdfSmrg        swaps(&rep.nOutputs);
47335c4bbdfSmrg        swaps(&rep.nModes);
47435c4bbdfSmrg        swaps(&rep.nbytesNames);
47535c4bbdfSmrg    }
47635c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetScreenResourcesReply), &rep);
47735c4bbdfSmrg    if (extraLen) {
47835c4bbdfSmrg        WriteToClient(client, extraLen, extra);
47935c4bbdfSmrg        free(extra);
48005b261ecSmrg    }
48105b261ecSmrg    return Success;
48205b261ecSmrg}
48305b261ecSmrg
4844642e01fSmrgstatic int
4854642e01fSmrgrrGetScreenResources(ClientPtr client, Bool query)
48605b261ecSmrg{
48705b261ecSmrg    REQUEST(xRRGetScreenResourcesReq);
48835c4bbdfSmrg    xRRGetScreenResourcesReply rep;
48935c4bbdfSmrg    WindowPtr pWin;
49035c4bbdfSmrg    ScreenPtr pScreen;
49135c4bbdfSmrg    rrScrPrivPtr pScrPriv;
49235c4bbdfSmrg    CARD8 *extra;
49335c4bbdfSmrg    unsigned long extraLen;
49435c4bbdfSmrg    int i, rc, has_primary = 0;
49535c4bbdfSmrg    RRCrtc *crtcs;
49635c4bbdfSmrg    RROutput *outputs;
49735c4bbdfSmrg    xRRModeInfo *modeinfos;
49835c4bbdfSmrg    CARD8 *names;
49935c4bbdfSmrg
50005b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
5016747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
50205b261ecSmrg    if (rc != Success)
50335c4bbdfSmrg        return rc;
50435c4bbdfSmrg
50505b261ecSmrg    pScreen = pWin->drawable.pScreen;
50605b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
50735c4bbdfSmrg
5084642e01fSmrg    if (query && pScrPriv)
50935c4bbdfSmrg        if (!RRGetInfo(pScreen, query))
51035c4bbdfSmrg            return BadAlloc;
51105b261ecSmrg
512ed6184dfSmrg    if (pScreen->output_secondarys)
51335c4bbdfSmrg        return rrGetMultiScreenResources(client, query, pScreen);
51435c4bbdfSmrg
51535c4bbdfSmrg    if (!pScrPriv) {
51635c4bbdfSmrg        rep = (xRRGetScreenResourcesReply) {
51735c4bbdfSmrg            .type = X_Reply,
51835c4bbdfSmrg            .sequenceNumber = client->sequence,
51935c4bbdfSmrg            .length = 0,
52035c4bbdfSmrg            .timestamp = currentTime.milliseconds,
52135c4bbdfSmrg            .configTimestamp = currentTime.milliseconds,
52235c4bbdfSmrg            .nCrtcs = 0,
52335c4bbdfSmrg            .nOutputs = 0,
52435c4bbdfSmrg            .nModes = 0,
52535c4bbdfSmrg            .nbytesNames = 0
52635c4bbdfSmrg        };
52735c4bbdfSmrg        extra = NULL;
52835c4bbdfSmrg        extraLen = 0;
52905b261ecSmrg    }
53035c4bbdfSmrg    else {
53135c4bbdfSmrg        RRModePtr *modes;
53235c4bbdfSmrg        int num_modes;
53335c4bbdfSmrg
53435c4bbdfSmrg        modes = RRModesForScreen(pScreen, &num_modes);
53535c4bbdfSmrg        if (!modes)
53635c4bbdfSmrg            return BadAlloc;
53735c4bbdfSmrg
53835c4bbdfSmrg        rep = (xRRGetScreenResourcesReply) {
53935c4bbdfSmrg            .type = X_Reply,
54035c4bbdfSmrg            .sequenceNumber = client->sequence,
54135c4bbdfSmrg            .length = 0,
54235c4bbdfSmrg            .timestamp = pScrPriv->lastSetTime.milliseconds,
54335c4bbdfSmrg            .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
54435c4bbdfSmrg            .nCrtcs = pScrPriv->numCrtcs,
54535c4bbdfSmrg            .nOutputs = pScrPriv->numOutputs,
54635c4bbdfSmrg            .nModes = num_modes,
54735c4bbdfSmrg            .nbytesNames = 0
54835c4bbdfSmrg        };
54935c4bbdfSmrg
55035c4bbdfSmrg
55135c4bbdfSmrg        for (i = 0; i < num_modes; i++)
55235c4bbdfSmrg            rep.nbytesNames += modes[i]->mode.nameLength;
55335c4bbdfSmrg
55435c4bbdfSmrg        rep.length = (pScrPriv->numCrtcs +
55535c4bbdfSmrg                      pScrPriv->numOutputs +
55635c4bbdfSmrg                      num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
55735c4bbdfSmrg                      bytes_to_int32(rep.nbytesNames));
55835c4bbdfSmrg
55935c4bbdfSmrg        extraLen = rep.length << 2;
56035c4bbdfSmrg        if (extraLen) {
5611b5d61b8Smrg            extra = calloc(1, extraLen);
56235c4bbdfSmrg            if (!extra) {
56335c4bbdfSmrg                free(modes);
56435c4bbdfSmrg                return BadAlloc;
56535c4bbdfSmrg            }
56635c4bbdfSmrg        }
56735c4bbdfSmrg        else
56835c4bbdfSmrg            extra = NULL;
56935c4bbdfSmrg
57035c4bbdfSmrg        crtcs = (RRCrtc *) extra;
57135c4bbdfSmrg        outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs);
57235c4bbdfSmrg        modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs);
57335c4bbdfSmrg        names = (CARD8 *) (modeinfos + num_modes);
57435c4bbdfSmrg
57535c4bbdfSmrg        if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
57635c4bbdfSmrg            has_primary = 1;
57735c4bbdfSmrg            crtcs[0] = pScrPriv->primaryOutput->crtc->id;
57835c4bbdfSmrg            if (client->swapped)
57935c4bbdfSmrg                swapl(&crtcs[0]);
58035c4bbdfSmrg        }
58135c4bbdfSmrg
58235c4bbdfSmrg        for (i = 0; i < pScrPriv->numCrtcs; i++) {
58335c4bbdfSmrg            if (has_primary &&
58435c4bbdfSmrg                pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) {
58535c4bbdfSmrg                has_primary = 0;
58635c4bbdfSmrg                continue;
58735c4bbdfSmrg            }
58835c4bbdfSmrg            crtcs[i + has_primary] = pScrPriv->crtcs[i]->id;
58935c4bbdfSmrg            if (client->swapped)
59035c4bbdfSmrg                swapl(&crtcs[i + has_primary]);
59135c4bbdfSmrg        }
59235c4bbdfSmrg
59335c4bbdfSmrg        for (i = 0; i < pScrPriv->numOutputs; i++) {
59435c4bbdfSmrg            outputs[i] = pScrPriv->outputs[i]->id;
59535c4bbdfSmrg            if (client->swapped)
59635c4bbdfSmrg                swapl(&outputs[i]);
59735c4bbdfSmrg        }
59835c4bbdfSmrg
59935c4bbdfSmrg        for (i = 0; i < num_modes; i++) {
60035c4bbdfSmrg            RRModePtr mode = modes[i];
60135c4bbdfSmrg
60235c4bbdfSmrg            modeinfos[i] = mode->mode;
60335c4bbdfSmrg            if (client->swapped) {
60435c4bbdfSmrg                swapl(&modeinfos[i].id);
60535c4bbdfSmrg                swaps(&modeinfos[i].width);
60635c4bbdfSmrg                swaps(&modeinfos[i].height);
60735c4bbdfSmrg                swapl(&modeinfos[i].dotClock);
60835c4bbdfSmrg                swaps(&modeinfos[i].hSyncStart);
60935c4bbdfSmrg                swaps(&modeinfos[i].hSyncEnd);
61035c4bbdfSmrg                swaps(&modeinfos[i].hTotal);
61135c4bbdfSmrg                swaps(&modeinfos[i].hSkew);
61235c4bbdfSmrg                swaps(&modeinfos[i].vSyncStart);
61335c4bbdfSmrg                swaps(&modeinfos[i].vSyncEnd);
61435c4bbdfSmrg                swaps(&modeinfos[i].vTotal);
61535c4bbdfSmrg                swaps(&modeinfos[i].nameLength);
61635c4bbdfSmrg                swapl(&modeinfos[i].modeFlags);
61735c4bbdfSmrg            }
61835c4bbdfSmrg            memcpy(names, mode->name, mode->mode.nameLength);
61935c4bbdfSmrg            names += mode->mode.nameLength;
62035c4bbdfSmrg        }
6216747b715Smrg        free(modes);
62235c4bbdfSmrg        assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
62305b261ecSmrg    }
62435c4bbdfSmrg
62505b261ecSmrg    if (client->swapped) {
62635c4bbdfSmrg        swaps(&rep.sequenceNumber);
62735c4bbdfSmrg        swapl(&rep.length);
62835c4bbdfSmrg        swapl(&rep.timestamp);
62935c4bbdfSmrg        swapl(&rep.configTimestamp);
63035c4bbdfSmrg        swaps(&rep.nCrtcs);
63135c4bbdfSmrg        swaps(&rep.nOutputs);
63235c4bbdfSmrg        swaps(&rep.nModes);
63335c4bbdfSmrg        swaps(&rep.nbytesNames);
63435c4bbdfSmrg    }
63535c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *) &rep);
63635c4bbdfSmrg    if (extraLen) {
63735c4bbdfSmrg        WriteToClient(client, extraLen, (char *) extra);
63835c4bbdfSmrg        free(extra);
63905b261ecSmrg    }
6406747b715Smrg    return Success;
64105b261ecSmrg}
64205b261ecSmrg
6434642e01fSmrgint
64435c4bbdfSmrgProcRRGetScreenResources(ClientPtr client)
6454642e01fSmrg{
6464642e01fSmrg    return rrGetScreenResources(client, TRUE);
6474642e01fSmrg}
64835c4bbdfSmrg
6494642e01fSmrgint
65035c4bbdfSmrgProcRRGetScreenResourcesCurrent(ClientPtr client)
6514642e01fSmrg{
6524642e01fSmrg    return rrGetScreenResources(client, FALSE);
6534642e01fSmrg}
6544642e01fSmrg
65505b261ecSmrgtypedef struct _RR10Data {
65605b261ecSmrg    RRScreenSizePtr sizes;
65735c4bbdfSmrg    int nsize;
65835c4bbdfSmrg    int nrefresh;
65935c4bbdfSmrg    int size;
66035c4bbdfSmrg    CARD16 refresh;
66105b261ecSmrg} RR10DataRec, *RR10DataPtr;
66205b261ecSmrg
66305b261ecSmrg/*
66405b261ecSmrg * Convert 1.2 monitor data into 1.0 screen data
66505b261ecSmrg */
66605b261ecSmrgstatic RR10DataPtr
66735c4bbdfSmrgRR10GetData(ScreenPtr pScreen, RROutputPtr output)
66805b261ecSmrg{
66935c4bbdfSmrg    RR10DataPtr data;
67005b261ecSmrg    RRScreenSizePtr size;
67135c4bbdfSmrg    int nmode = output->numModes + output->numUserModes;
67235c4bbdfSmrg    int o, os, l, r;
67305b261ecSmrg    RRScreenRatePtr refresh;
67435c4bbdfSmrg    CARD16 vRefresh;
67535c4bbdfSmrg    RRModePtr mode;
67635c4bbdfSmrg    Bool *used;
67705b261ecSmrg
67805b261ecSmrg    /* Make sure there is plenty of space for any combination */
67935c4bbdfSmrg    data = malloc(sizeof(RR10DataRec) +
68035c4bbdfSmrg                  sizeof(RRScreenSize) * nmode +
68135c4bbdfSmrg                  sizeof(RRScreenRate) * nmode + sizeof(Bool) * nmode);
68205b261ecSmrg    if (!data)
68335c4bbdfSmrg        return NULL;
68405b261ecSmrg    size = (RRScreenSizePtr) (data + 1);
68505b261ecSmrg    refresh = (RRScreenRatePtr) (size + nmode);
68605b261ecSmrg    used = (Bool *) (refresh + nmode);
68735c4bbdfSmrg    memset(used, '\0', sizeof(Bool) * nmode);
68805b261ecSmrg    data->sizes = size;
68905b261ecSmrg    data->nsize = 0;
69005b261ecSmrg    data->nrefresh = 0;
69105b261ecSmrg    data->size = 0;
69205b261ecSmrg    data->refresh = 0;
69335c4bbdfSmrg
69405b261ecSmrg    /*
69505b261ecSmrg     * find modes not yet listed
69605b261ecSmrg     */
69735c4bbdfSmrg    for (o = 0; o < output->numModes + output->numUserModes; o++) {
69835c4bbdfSmrg        if (used[o])
69935c4bbdfSmrg            continue;
70035c4bbdfSmrg
70135c4bbdfSmrg        if (o < output->numModes)
70235c4bbdfSmrg            mode = output->modes[o];
70335c4bbdfSmrg        else
70435c4bbdfSmrg            mode = output->userModes[o - output->numModes];
70535c4bbdfSmrg
70635c4bbdfSmrg        l = data->nsize;
70735c4bbdfSmrg        size[l].id = data->nsize;
70835c4bbdfSmrg        size[l].width = mode->mode.width;
70935c4bbdfSmrg        size[l].height = mode->mode.height;
71035c4bbdfSmrg        if (output->mmWidth && output->mmHeight) {
71135c4bbdfSmrg            size[l].mmWidth = output->mmWidth;
71235c4bbdfSmrg            size[l].mmHeight = output->mmHeight;
71335c4bbdfSmrg        }
71435c4bbdfSmrg        else {
71535c4bbdfSmrg            size[l].mmWidth = pScreen->mmWidth;
71635c4bbdfSmrg            size[l].mmHeight = pScreen->mmHeight;
71735c4bbdfSmrg        }
71835c4bbdfSmrg        size[l].nRates = 0;
71935c4bbdfSmrg        size[l].pRates = &refresh[data->nrefresh];
72035c4bbdfSmrg        data->nsize++;
72135c4bbdfSmrg
72235c4bbdfSmrg        /*
72335c4bbdfSmrg         * Find all modes with matching size
72435c4bbdfSmrg         */
72535c4bbdfSmrg        for (os = o; os < output->numModes + output->numUserModes; os++) {
72635c4bbdfSmrg            if (os < output->numModes)
72735c4bbdfSmrg                mode = output->modes[os];
72835c4bbdfSmrg            else
72935c4bbdfSmrg                mode = output->userModes[os - output->numModes];
73035c4bbdfSmrg            if (mode->mode.width == size[l].width &&
73135c4bbdfSmrg                mode->mode.height == size[l].height) {
73235c4bbdfSmrg                vRefresh = RRVerticalRefresh(&mode->mode);
73335c4bbdfSmrg                used[os] = TRUE;
73435c4bbdfSmrg
73535c4bbdfSmrg                for (r = 0; r < size[l].nRates; r++)
73635c4bbdfSmrg                    if (vRefresh == size[l].pRates[r].rate)
73735c4bbdfSmrg                        break;
73835c4bbdfSmrg                if (r == size[l].nRates) {
73935c4bbdfSmrg                    size[l].pRates[r].rate = vRefresh;
74035c4bbdfSmrg                    size[l].pRates[r].mode = mode;
74135c4bbdfSmrg                    size[l].nRates++;
74235c4bbdfSmrg                    data->nrefresh++;
74335c4bbdfSmrg                }
74435c4bbdfSmrg                if (mode == output->crtc->mode) {
74535c4bbdfSmrg                    data->size = l;
74635c4bbdfSmrg                    data->refresh = vRefresh;
74735c4bbdfSmrg                }
74835c4bbdfSmrg            }
74935c4bbdfSmrg        }
75005b261ecSmrg    }
75105b261ecSmrg    return data;
75205b261ecSmrg}
75305b261ecSmrg
75405b261ecSmrgint
75535c4bbdfSmrgProcRRGetScreenInfo(ClientPtr client)
75605b261ecSmrg{
75705b261ecSmrg    REQUEST(xRRGetScreenInfoReq);
75835c4bbdfSmrg    xRRGetScreenInfoReply rep;
75935c4bbdfSmrg    WindowPtr pWin;
76035c4bbdfSmrg    int rc;
76135c4bbdfSmrg    ScreenPtr pScreen;
76235c4bbdfSmrg    rrScrPrivPtr pScrPriv;
76335c4bbdfSmrg    CARD8 *extra;
76435c4bbdfSmrg    unsigned long extraLen;
76535c4bbdfSmrg    RROutputPtr output;
76605b261ecSmrg
76705b261ecSmrg    REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
7686747b715Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
76905b261ecSmrg    if (rc != Success)
77035c4bbdfSmrg        return rc;
77105b261ecSmrg
77205b261ecSmrg    pScreen = pWin->drawable.pScreen;
77305b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
77435c4bbdfSmrg
77505b261ecSmrg    if (pScrPriv)
77635c4bbdfSmrg        if (!RRGetInfo(pScreen, TRUE))
77735c4bbdfSmrg            return BadAlloc;
77835c4bbdfSmrg
77935c4bbdfSmrg    output = RRFirstOutput(pScreen);
78035c4bbdfSmrg
78135c4bbdfSmrg    if (!pScrPriv || !output) {
78235c4bbdfSmrg        rep = (xRRGetScreenInfoReply) {
78335c4bbdfSmrg            .type = X_Reply,
78435c4bbdfSmrg            .setOfRotations = RR_Rotate_0,
78535c4bbdfSmrg            .sequenceNumber = client->sequence,
78635c4bbdfSmrg            .length = 0,
78735c4bbdfSmrg            .root = pWin->drawable.pScreen->root->drawable.id,
78835c4bbdfSmrg            .timestamp = currentTime.milliseconds,
78935c4bbdfSmrg            .configTimestamp = currentTime.milliseconds,
79035c4bbdfSmrg            .nSizes = 0,
79135c4bbdfSmrg            .sizeID = 0,
79235c4bbdfSmrg            .rotation = RR_Rotate_0,
79335c4bbdfSmrg            .rate = 0,
79435c4bbdfSmrg            .nrateEnts = 0
79535c4bbdfSmrg        };
79635c4bbdfSmrg        extra = 0;
79735c4bbdfSmrg        extraLen = 0;
79805b261ecSmrg    }
79935c4bbdfSmrg    else {
80035c4bbdfSmrg        int i, j;
80135c4bbdfSmrg        xScreenSizes *size;
80235c4bbdfSmrg        CARD16 *rates;
80335c4bbdfSmrg        CARD8 *data8;
80435c4bbdfSmrg        Bool has_rate = RRClientKnowsRates(client);
80535c4bbdfSmrg        RR10DataPtr pData;
80635c4bbdfSmrg        RRScreenSizePtr pSize;
80735c4bbdfSmrg
80835c4bbdfSmrg        pData = RR10GetData(pScreen, output);
80935c4bbdfSmrg        if (!pData)
81035c4bbdfSmrg            return BadAlloc;
81135c4bbdfSmrg
81235c4bbdfSmrg        rep = (xRRGetScreenInfoReply) {
81335c4bbdfSmrg            .type = X_Reply,
81435c4bbdfSmrg            .setOfRotations = output->crtc->rotations,
81535c4bbdfSmrg            .sequenceNumber = client->sequence,
81635c4bbdfSmrg            .length = 0,
81735c4bbdfSmrg            .root = pWin->drawable.pScreen->root->drawable.id,
81835c4bbdfSmrg            .timestamp = pScrPriv->lastSetTime.milliseconds,
81935c4bbdfSmrg            .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
82035c4bbdfSmrg            .rotation = output->crtc->rotation,
82135c4bbdfSmrg            .nSizes = pData->nsize,
82235c4bbdfSmrg            .nrateEnts = pData->nrefresh + pData->nsize,
82335c4bbdfSmrg            .sizeID = pData->size,
82435c4bbdfSmrg            .rate = pData->refresh
82535c4bbdfSmrg        };
82635c4bbdfSmrg
82735c4bbdfSmrg        extraLen = rep.nSizes * sizeof(xScreenSizes);
82835c4bbdfSmrg        if (has_rate)
82935c4bbdfSmrg            extraLen += rep.nrateEnts * sizeof(CARD16);
83035c4bbdfSmrg
83135c4bbdfSmrg        if (extraLen) {
83235c4bbdfSmrg            extra = (CARD8 *) malloc(extraLen);
83335c4bbdfSmrg            if (!extra) {
83435c4bbdfSmrg                free(pData);
83535c4bbdfSmrg                return BadAlloc;
83635c4bbdfSmrg            }
83735c4bbdfSmrg        }
83835c4bbdfSmrg        else
83935c4bbdfSmrg            extra = NULL;
84035c4bbdfSmrg
84135c4bbdfSmrg        /*
84235c4bbdfSmrg         * First comes the size information
84335c4bbdfSmrg         */
84435c4bbdfSmrg        size = (xScreenSizes *) extra;
84535c4bbdfSmrg        rates = (CARD16 *) (size + rep.nSizes);
84635c4bbdfSmrg        for (i = 0; i < pData->nsize; i++) {
84735c4bbdfSmrg            pSize = &pData->sizes[i];
84835c4bbdfSmrg            size->widthInPixels = pSize->width;
84935c4bbdfSmrg            size->heightInPixels = pSize->height;
85035c4bbdfSmrg            size->widthInMillimeters = pSize->mmWidth;
85135c4bbdfSmrg            size->heightInMillimeters = pSize->mmHeight;
85235c4bbdfSmrg            if (client->swapped) {
85335c4bbdfSmrg                swaps(&size->widthInPixels);
85435c4bbdfSmrg                swaps(&size->heightInPixels);
85535c4bbdfSmrg                swaps(&size->widthInMillimeters);
85635c4bbdfSmrg                swaps(&size->heightInMillimeters);
85735c4bbdfSmrg            }
85835c4bbdfSmrg            size++;
85935c4bbdfSmrg            if (has_rate) {
86035c4bbdfSmrg                *rates = pSize->nRates;
86135c4bbdfSmrg                if (client->swapped) {
86235c4bbdfSmrg                    swaps(rates);
86335c4bbdfSmrg                }
86435c4bbdfSmrg                rates++;
86535c4bbdfSmrg                for (j = 0; j < pSize->nRates; j++) {
86635c4bbdfSmrg                    *rates = pSize->pRates[j].rate;
86735c4bbdfSmrg                    if (client->swapped) {
86835c4bbdfSmrg                        swaps(rates);
86935c4bbdfSmrg                    }
87035c4bbdfSmrg                    rates++;
87135c4bbdfSmrg                }
87235c4bbdfSmrg            }
87335c4bbdfSmrg        }
8746747b715Smrg        free(pData);
87505b261ecSmrg
87635c4bbdfSmrg        data8 = (CARD8 *) rates;
87735c4bbdfSmrg
87835c4bbdfSmrg        if (data8 - (CARD8 *) extra != extraLen)
87935c4bbdfSmrg            FatalError("RRGetScreenInfo bad extra len %ld != %ld\n",
88035c4bbdfSmrg                       (unsigned long) (data8 - (CARD8 *) extra), extraLen);
88135c4bbdfSmrg        rep.length = bytes_to_int32(extraLen);
88205b261ecSmrg    }
88305b261ecSmrg    if (client->swapped) {
88435c4bbdfSmrg        swaps(&rep.sequenceNumber);
88535c4bbdfSmrg        swapl(&rep.length);
88635c4bbdfSmrg        swapl(&rep.timestamp);
88735c4bbdfSmrg        swapl(&rep.configTimestamp);
88835c4bbdfSmrg        swaps(&rep.rotation);
88935c4bbdfSmrg        swaps(&rep.nSizes);
89035c4bbdfSmrg        swaps(&rep.sizeID);
89135c4bbdfSmrg        swaps(&rep.rate);
89235c4bbdfSmrg        swaps(&rep.nrateEnts);
89335c4bbdfSmrg    }
89435c4bbdfSmrg    WriteToClient(client, sizeof(xRRGetScreenInfoReply), &rep);
89535c4bbdfSmrg    if (extraLen) {
89635c4bbdfSmrg        WriteToClient(client, extraLen, extra);
89735c4bbdfSmrg        free(extra);
89805b261ecSmrg    }
8996747b715Smrg    return Success;
90005b261ecSmrg}
90105b261ecSmrg
90205b261ecSmrgint
90335c4bbdfSmrgProcRRSetScreenConfig(ClientPtr client)
90405b261ecSmrg{
90505b261ecSmrg    REQUEST(xRRSetScreenConfigReq);
90605b261ecSmrg    xRRSetScreenConfigReply rep;
90735c4bbdfSmrg    DrawablePtr pDraw;
90835c4bbdfSmrg    int rc;
90935c4bbdfSmrg    ScreenPtr pScreen;
91035c4bbdfSmrg    rrScrPrivPtr pScrPriv;
91135c4bbdfSmrg    TimeStamp time;
91235c4bbdfSmrg    int i;
91335c4bbdfSmrg    Rotation rotation;
91435c4bbdfSmrg    int rate;
91535c4bbdfSmrg    Bool has_rate;
91635c4bbdfSmrg    CARD8 status;
91735c4bbdfSmrg    RROutputPtr output;
91835c4bbdfSmrg    RRCrtcPtr crtc;
91935c4bbdfSmrg    RRModePtr mode;
92035c4bbdfSmrg    RR10DataPtr pData = NULL;
92135c4bbdfSmrg    RRScreenSizePtr pSize;
92235c4bbdfSmrg    int width, height;
92335c4bbdfSmrg
92435c4bbdfSmrg    UpdateCurrentTime();
92535c4bbdfSmrg
92635c4bbdfSmrg    if (RRClientKnowsRates(client)) {
92735c4bbdfSmrg        REQUEST_SIZE_MATCH(xRRSetScreenConfigReq);
92835c4bbdfSmrg        has_rate = TRUE;
92905b261ecSmrg    }
93035c4bbdfSmrg    else {
93135c4bbdfSmrg        REQUEST_SIZE_MATCH(xRR1_0SetScreenConfigReq);
93235c4bbdfSmrg        has_rate = FALSE;
93305b261ecSmrg    }
93435c4bbdfSmrg
93505b261ecSmrg    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
93605b261ecSmrg    if (rc != Success)
93735c4bbdfSmrg        return rc;
93805b261ecSmrg
93905b261ecSmrg    pScreen = pDraw->pScreen;
94005b261ecSmrg
94105b261ecSmrg    pScrPriv = rrGetScrPriv(pScreen);
94235c4bbdfSmrg
94305b261ecSmrg    time = ClientTimeToServerTime(stuff->timestamp);
94435c4bbdfSmrg
94535c4bbdfSmrg    if (!pScrPriv) {
94635c4bbdfSmrg        time = currentTime;
94735c4bbdfSmrg        status = RRSetConfigFailed;
94835c4bbdfSmrg        goto sendReply;
94935c4bbdfSmrg    }
95035c4bbdfSmrg    if (!RRGetInfo(pScreen, FALSE))
95135c4bbdfSmrg        return BadAlloc;
95235c4bbdfSmrg
95335c4bbdfSmrg    output = RRFirstOutput(pScreen);
95435c4bbdfSmrg    if (!output) {
95535c4bbdfSmrg        time = currentTime;
95635c4bbdfSmrg        status = RRSetConfigFailed;
95735c4bbdfSmrg        goto sendReply;
95805b261ecSmrg    }
95905b261ecSmrg
96005b261ecSmrg    crtc = output->crtc;
96105b261ecSmrg
96205b261ecSmrg    /*
96305b261ecSmrg     * If the client's config timestamp is not the same as the last config
96405b261ecSmrg     * timestamp, then the config information isn't up-to-date and
96505b261ecSmrg     * can't even be validated.
96605b261ecSmrg     *
96705b261ecSmrg     * Note that the client only knows about the milliseconds part of the
96805b261ecSmrg     * timestamp, so using CompareTimeStamps here would cause randr to suddenly
96905b261ecSmrg     * stop working after several hours have passed (freedesktop bug #6502).
97005b261ecSmrg     */
97135c4bbdfSmrg    if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds) {
97235c4bbdfSmrg        status = RRSetConfigInvalidConfigTime;
97335c4bbdfSmrg        goto sendReply;
97405b261ecSmrg    }
97535c4bbdfSmrg
97635c4bbdfSmrg    pData = RR10GetData(pScreen, output);
97705b261ecSmrg    if (!pData)
97835c4bbdfSmrg        return BadAlloc;
97935c4bbdfSmrg
98035c4bbdfSmrg    if (stuff->sizeID >= pData->nsize) {
98135c4bbdfSmrg        /*
98235c4bbdfSmrg         * Invalid size ID
98335c4bbdfSmrg         */
98435c4bbdfSmrg        client->errorValue = stuff->sizeID;
98535c4bbdfSmrg        free(pData);
98635c4bbdfSmrg        return BadValue;
98705b261ecSmrg    }
98805b261ecSmrg    pSize = &pData->sizes[stuff->sizeID];
98935c4bbdfSmrg
99005b261ecSmrg    /*
99105b261ecSmrg     * Validate requested rotation
99205b261ecSmrg     */
99305b261ecSmrg    rotation = (Rotation) stuff->rotation;
99405b261ecSmrg
99505b261ecSmrg    /* test the rotation bits only! */
99605b261ecSmrg    switch (rotation & 0xf) {
99705b261ecSmrg    case RR_Rotate_0:
99805b261ecSmrg    case RR_Rotate_90:
99905b261ecSmrg    case RR_Rotate_180:
100005b261ecSmrg    case RR_Rotate_270:
100135c4bbdfSmrg        break;
100205b261ecSmrg    default:
100335c4bbdfSmrg        /*
100435c4bbdfSmrg         * Invalid rotation
100535c4bbdfSmrg         */
100635c4bbdfSmrg        client->errorValue = stuff->rotation;
100735c4bbdfSmrg        free(pData);
100835c4bbdfSmrg        return BadValue;
100905b261ecSmrg    }
101005b261ecSmrg
101135c4bbdfSmrg    if ((~crtc->rotations) & rotation) {
101235c4bbdfSmrg        /*
101335c4bbdfSmrg         * requested rotation or reflection not supported by screen
101435c4bbdfSmrg         */
101535c4bbdfSmrg        client->errorValue = stuff->rotation;
101635c4bbdfSmrg        free(pData);
101735c4bbdfSmrg        return BadMatch;
101805b261ecSmrg    }
101905b261ecSmrg
102005b261ecSmrg    /*
102105b261ecSmrg     * Validate requested refresh
102205b261ecSmrg     */
102305b261ecSmrg    if (has_rate)
102435c4bbdfSmrg        rate = (int) stuff->rate;
102505b261ecSmrg    else
102635c4bbdfSmrg        rate = 0;
102735c4bbdfSmrg
102835c4bbdfSmrg    if (rate) {
102935c4bbdfSmrg        for (i = 0; i < pSize->nRates; i++) {
103035c4bbdfSmrg            if (pSize->pRates[i].rate == rate)
103135c4bbdfSmrg                break;
103235c4bbdfSmrg        }
103335c4bbdfSmrg        if (i == pSize->nRates) {
103435c4bbdfSmrg            /*
103535c4bbdfSmrg             * Invalid rate
103635c4bbdfSmrg             */
103735c4bbdfSmrg            client->errorValue = rate;
103835c4bbdfSmrg            free(pData);
103935c4bbdfSmrg            return BadValue;
104035c4bbdfSmrg        }
104135c4bbdfSmrg        mode = pSize->pRates[i].mode;
104205b261ecSmrg    }
104305b261ecSmrg    else
104435c4bbdfSmrg        mode = pSize->pRates[0].mode;
104535c4bbdfSmrg
104605b261ecSmrg    /*
104705b261ecSmrg     * Make sure the requested set-time is not older than
104805b261ecSmrg     * the last set-time
104905b261ecSmrg     */
105035c4bbdfSmrg    if (CompareTimeStamps(time, pScrPriv->lastSetTime) < 0) {
105135c4bbdfSmrg        status = RRSetConfigInvalidTime;
105235c4bbdfSmrg        goto sendReply;
105305b261ecSmrg    }
105405b261ecSmrg
105505b261ecSmrg    /*
105605b261ecSmrg     * If the screen size is changing, adjust all of the other outputs
105705b261ecSmrg     * to fit the new size, mirroring as much as possible
105805b261ecSmrg     */
105905b261ecSmrg    width = mode->mode.width;
106005b261ecSmrg    height = mode->mode.height;
10618223e2f2Smrg    if (width < pScrPriv->minWidth || pScrPriv->maxWidth < width) {
106235c4bbdfSmrg        client->errorValue = width;
106335c4bbdfSmrg        free(pData);
106435c4bbdfSmrg        return BadValue;
10658223e2f2Smrg    }
10668223e2f2Smrg    if (height < pScrPriv->minHeight || pScrPriv->maxHeight < height) {
106735c4bbdfSmrg        client->errorValue = height;
106835c4bbdfSmrg        free(pData);
106935c4bbdfSmrg        return BadValue;
107035c4bbdfSmrg    }
107135c4bbdfSmrg
107235c4bbdfSmrg    if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
107335c4bbdfSmrg        width = mode->mode.height;
107435c4bbdfSmrg        height = mode->mode.width;
107535c4bbdfSmrg    }
107635c4bbdfSmrg
107735c4bbdfSmrg    if (width != pScreen->width || height != pScreen->height) {
107835c4bbdfSmrg        int c;
107935c4bbdfSmrg
108035c4bbdfSmrg        for (c = 0; c < pScrPriv->numCrtcs; c++) {
108135c4bbdfSmrg            if (!RRCrtcSet(pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
108235c4bbdfSmrg                           0, NULL)) {
108335c4bbdfSmrg                status = RRSetConfigFailed;
108435c4bbdfSmrg                /* XXX recover from failure */
108535c4bbdfSmrg                goto sendReply;
108635c4bbdfSmrg            }
108735c4bbdfSmrg        }
108835c4bbdfSmrg        if (!RRScreenSizeSet(pScreen, width, height,
108935c4bbdfSmrg                             pScreen->mmWidth, pScreen->mmHeight)) {
109035c4bbdfSmrg            status = RRSetConfigFailed;
109135c4bbdfSmrg            /* XXX recover from failure */
109235c4bbdfSmrg            goto sendReply;
109335c4bbdfSmrg        }
109435c4bbdfSmrg    }
109535c4bbdfSmrg
109635c4bbdfSmrg    if (!RRCrtcSet(crtc, mode, 0, 0, stuff->rotation, 1, &output))
109735c4bbdfSmrg        status = RRSetConfigFailed;
109852397711Smrg    else {
109935c4bbdfSmrg        pScrPriv->lastSetTime = time;
110035c4bbdfSmrg        status = RRSetConfigSuccess;
110152397711Smrg    }
110205b261ecSmrg
110305b261ecSmrg    /*
110405b261ecSmrg     * XXX Configure other crtcs to mirror as much as possible
110505b261ecSmrg     */
110635c4bbdfSmrg
110735c4bbdfSmrg sendReply:
110835c4bbdfSmrg
11096747b715Smrg    free(pData);
111005b261ecSmrg
111135c4bbdfSmrg    rep = (xRRSetScreenConfigReply) {
111235c4bbdfSmrg        .type = X_Reply,
111335c4bbdfSmrg        .status = status,
111435c4bbdfSmrg        .sequenceNumber = client->sequence,
111535c4bbdfSmrg        .length = 0,
111605b261ecSmrg
111735c4bbdfSmrg        .newTimestamp = pScrPriv->lastSetTime.milliseconds,
111835c4bbdfSmrg        .newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds,
111935c4bbdfSmrg        .root = pDraw->pScreen->root->drawable.id,
112035c4bbdfSmrg        /* .subpixelOrder = ?? */
112135c4bbdfSmrg    };
112205b261ecSmrg
112335c4bbdfSmrg    if (client->swapped) {
112435c4bbdfSmrg        swaps(&rep.sequenceNumber);
112535c4bbdfSmrg        swapl(&rep.length);
112635c4bbdfSmrg        swapl(&rep.newTimestamp);
112735c4bbdfSmrg        swapl(&rep.newConfigTimestamp);
112835c4bbdfSmrg        swapl(&rep.root);
112905b261ecSmrg    }
113035c4bbdfSmrg    WriteToClient(client, sizeof(xRRSetScreenConfigReply), &rep);
113105b261ecSmrg
11326747b715Smrg    return Success;
113305b261ecSmrg}
113405b261ecSmrg
113505b261ecSmrgstatic CARD16
113635c4bbdfSmrgRR10CurrentSizeID(ScreenPtr pScreen)
113705b261ecSmrg{
113835c4bbdfSmrg    CARD16 sizeID = 0xffff;
113935c4bbdfSmrg    RROutputPtr output = RRFirstOutput(pScreen);
114035c4bbdfSmrg
114135c4bbdfSmrg    if (output) {
114235c4bbdfSmrg        RR10DataPtr data = RR10GetData(pScreen, output);
114335c4bbdfSmrg
114435c4bbdfSmrg        if (data) {
114535c4bbdfSmrg            int i;
114635c4bbdfSmrg
114735c4bbdfSmrg            for (i = 0; i < data->nsize; i++)
114835c4bbdfSmrg                if (data->sizes[i].width == pScreen->width &&
114935c4bbdfSmrg                    data->sizes[i].height == pScreen->height) {
115035c4bbdfSmrg                    sizeID = (CARD16) i;
115135c4bbdfSmrg                    break;
115235c4bbdfSmrg                }
115335c4bbdfSmrg            free(data);
115435c4bbdfSmrg        }
115505b261ecSmrg    }
115605b261ecSmrg    return sizeID;
115705b261ecSmrg}
1158