1160 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1160 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Copyright © 2006 Keith Packard
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
 * documentation for any purpose is hereby granted without fee, provided that
 | 
						|
 * the above copyright notice appear in all copies and that both that copyright
 | 
						|
 * notice and this permission notice appear in supporting documentation, and
 | 
						|
 * that the name of the copyright holders not be used in advertising or
 | 
						|
 * publicity pertaining to distribution of the software without specific,
 | 
						|
 * written prior permission.  The copyright holders make no representations
 | 
						|
 * about the suitability of this software for any purpose.  It is provided "as
 | 
						|
 * is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
						|
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
						|
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
						|
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
						|
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | 
						|
 * OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
#include <dix-config.h>
 | 
						|
 | 
						|
#include "dix/dix_priv.h"
 | 
						|
#include "randr/randrstr_priv.h"
 | 
						|
 | 
						|
static CARD16
 | 
						|
 RR10CurrentSizeID(ScreenPtr pScreen);
 | 
						|
 | 
						|
/*
 | 
						|
 * Edit connection information block so that new clients
 | 
						|
 * see the current screen size on connect
 | 
						|
 */
 | 
						|
static void
 | 
						|
RREditConnectionInfo(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    xConnSetup *connSetup;
 | 
						|
    char *vendor;
 | 
						|
    xPixmapFormat *formats;
 | 
						|
    xWindowRoot *root;
 | 
						|
    xDepth *depth;
 | 
						|
    xVisualType *visual;
 | 
						|
    int screen = 0;
 | 
						|
    int d;
 | 
						|
 | 
						|
    if (ConnectionInfo == NULL)
 | 
						|
        return;
 | 
						|
 | 
						|
    connSetup = (xConnSetup *) ConnectionInfo;
 | 
						|
    vendor = (char *) connSetup + sizeof(xConnSetup);
 | 
						|
    formats = (xPixmapFormat *) ((char *) vendor +
 | 
						|
                                 pad_to_int32(connSetup->nbytesVendor));
 | 
						|
    root = (xWindowRoot *) ((char *) formats +
 | 
						|
                            sizeof(xPixmapFormat) *
 | 
						|
                            screenInfo.numPixmapFormats);
 | 
						|
    while (screen != pScreen->myNum) {
 | 
						|
        depth = (xDepth *) ((char *) root + sizeof(xWindowRoot));
 | 
						|
        for (d = 0; d < root->nDepths; d++) {
 | 
						|
            visual = (xVisualType *) ((char *) depth + sizeof(xDepth));
 | 
						|
            depth = (xDepth *) ((char *) visual +
 | 
						|
                                depth->nVisuals * sizeof(xVisualType));
 | 
						|
        }
 | 
						|
        root = (xWindowRoot *) ((char *) depth);
 | 
						|
        screen++;
 | 
						|
    }
 | 
						|
    root->pixWidth = pScreen->width;
 | 
						|
    root->pixHeight = pScreen->height;
 | 
						|
    root->mmWidth = pScreen->mmWidth;
 | 
						|
    root->mmHeight = pScreen->mmHeight;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RRSendConfigNotify(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    WindowPtr pWin = pScreen->root;
 | 
						|
    xEvent event = {
 | 
						|
        .u.configureNotify.window = pWin->drawable.id,
 | 
						|
        .u.configureNotify.aboveSibling = None,
 | 
						|
        .u.configureNotify.x = 0,
 | 
						|
        .u.configureNotify.y = 0,
 | 
						|
 | 
						|
    /* XXX xinerama stuff ? */
 | 
						|
 | 
						|
        .u.configureNotify.width = pWin->drawable.width,
 | 
						|
        .u.configureNotify.height = pWin->drawable.height,
 | 
						|
        .u.configureNotify.borderWidth = wBorderWidth(pWin),
 | 
						|
        .u.configureNotify.override = pWin->overrideRedirect
 | 
						|
    };
 | 
						|
    event.u.u.type = ConfigureNotify;
 | 
						|
    DeliverEvents(pWin, &event, 1, NullWindow);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
RRDeliverScreenEvent(ClientPtr client, WindowPtr pWin, ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    rrScrPriv(pScreen);
 | 
						|
    RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL;
 | 
						|
    WindowPtr pRoot = pScreen->root;
 | 
						|
 | 
						|
    xRRScreenChangeNotifyEvent se = {
 | 
						|
        .type = RRScreenChangeNotify + RREventBase,
 | 
						|
        .rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0),
 | 
						|
        .timestamp = pScrPriv->lastSetTime.milliseconds,
 | 
						|
        .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
 | 
						|
        .root = pRoot->drawable.id,
 | 
						|
        .window = pWin->drawable.id,
 | 
						|
        .subpixelOrder = PictureGetSubpixelOrder(pScreen),
 | 
						|
 | 
						|
        .sizeID = RR10CurrentSizeID(pScreen)
 | 
						|
    };
 | 
						|
 | 
						|
    if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) {
 | 
						|
        se.widthInPixels = pScreen->height;
 | 
						|
        se.heightInPixels = pScreen->width;
 | 
						|
        se.widthInMillimeters = pScreen->mmHeight;
 | 
						|
        se.heightInMillimeters = pScreen->mmWidth;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        se.widthInPixels = pScreen->width;
 | 
						|
        se.heightInPixels = pScreen->height;
 | 
						|
        se.widthInMillimeters = pScreen->mmWidth;
 | 
						|
        se.heightInMillimeters = pScreen->mmHeight;
 | 
						|
    }
 | 
						|
 | 
						|
    WriteEventsToClient(client, 1, (xEvent *) &se);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Notify the extension that the screen size has been changed.
 | 
						|
 * The driver is responsible for calling this whenever it has changed
 | 
						|
 * the size of the screen
 | 
						|
 */
 | 
						|
void
 | 
						|
RRScreenSizeNotify(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    rrScrPriv(pScreen);
 | 
						|
    /*
 | 
						|
     * Deliver ConfigureNotify events when root changes
 | 
						|
     * pixel size
 | 
						|
     */
 | 
						|
    if (pScrPriv->width == pScreen->width &&
 | 
						|
        pScrPriv->height == pScreen->height &&
 | 
						|
        pScrPriv->mmWidth == pScreen->mmWidth &&
 | 
						|
        pScrPriv->mmHeight == pScreen->mmHeight)
 | 
						|
        return;
 | 
						|
 | 
						|
    pScrPriv->width = pScreen->width;
 | 
						|
    pScrPriv->height = pScreen->height;
 | 
						|
    pScrPriv->mmWidth = pScreen->mmWidth;
 | 
						|
    pScrPriv->mmHeight = pScreen->mmHeight;
 | 
						|
    RRSetChanged(pScreen);
 | 
						|
/*    pScrPriv->sizeChanged = TRUE; */
 | 
						|
 | 
						|
    RRTellChanged(pScreen);
 | 
						|
    RRSendConfigNotify(pScreen);
 | 
						|
    RREditConnectionInfo(pScreen);
 | 
						|
 | 
						|
    RRPointerScreenConfigured(pScreen);
 | 
						|
    /*
 | 
						|
     * Fix pointer bounds and location
 | 
						|
     */
 | 
						|
    ScreenRestructured(pScreen);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Request that the screen be resized
 | 
						|
 */
 | 
						|
Bool
 | 
						|
RRScreenSizeSet(ScreenPtr pScreen,
 | 
						|
                CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight)
 | 
						|
{
 | 
						|
    rrScrPriv(pScreen);
 | 
						|
 | 
						|
#if RANDR_12_INTERFACE
 | 
						|
    if (pScrPriv->rrScreenSetSize) {
 | 
						|
        return (*pScrPriv->rrScreenSetSize) (pScreen,
 | 
						|
                                             width, height, mmWidth, mmHeight);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
#if RANDR_10_INTERFACE
 | 
						|
    if (pScrPriv->rrSetConfig) {
 | 
						|
        return TRUE;            /* can't set size separately */
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Retrieve valid screen size range
 | 
						|
 */
 | 
						|
int
 | 
						|
ProcRRGetScreenSizeRange(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xRRGetScreenSizeRangeReq);
 | 
						|
    xRRGetScreenSizeRangeReply rep;
 | 
						|
    WindowPtr pWin;
 | 
						|
    ScreenPtr pScreen;
 | 
						|
    rrScrPrivPtr pScrPriv;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xRRGetScreenSizeRangeReq);
 | 
						|
    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    pScreen = pWin->drawable.pScreen;
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
 | 
						|
    rep = (xRRGetScreenSizeRangeReply) {
 | 
						|
        .type = X_Reply,
 | 
						|
        .pad = 0,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .length = 0
 | 
						|
    };
 | 
						|
 | 
						|
    if (pScrPriv) {
 | 
						|
        if (!RRGetInfo(pScreen, FALSE))
 | 
						|
            return BadAlloc;
 | 
						|
        rep.minWidth = pScrPriv->minWidth;
 | 
						|
        rep.minHeight = pScrPriv->minHeight;
 | 
						|
        rep.maxWidth = pScrPriv->maxWidth;
 | 
						|
        rep.maxHeight = pScrPriv->maxHeight;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        rep.maxWidth = rep.minWidth = pScreen->width;
 | 
						|
        rep.maxHeight = rep.minHeight = pScreen->height;
 | 
						|
    }
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
        swaps(&rep.minWidth);
 | 
						|
        swaps(&rep.minHeight);
 | 
						|
        swaps(&rep.maxWidth);
 | 
						|
        swaps(&rep.maxHeight);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), &rep);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ProcRRSetScreenSize(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xRRSetScreenSizeReq);
 | 
						|
    WindowPtr pWin;
 | 
						|
    ScreenPtr pScreen;
 | 
						|
    rrScrPrivPtr pScrPriv;
 | 
						|
    int i, rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
 | 
						|
    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    pScreen = pWin->drawable.pScreen;
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
    if (!pScrPriv)
 | 
						|
        return BadMatch;
 | 
						|
 | 
						|
    if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width) {
 | 
						|
        client->errorValue = stuff->width;
 | 
						|
        return BadValue;
 | 
						|
    }
 | 
						|
    if (stuff->height < pScrPriv->minHeight ||
 | 
						|
        pScrPriv->maxHeight < stuff->height) {
 | 
						|
        client->errorValue = stuff->height;
 | 
						|
        return BadValue;
 | 
						|
    }
 | 
						|
    for (i = 0; i < pScrPriv->numCrtcs; i++) {
 | 
						|
        RRCrtcPtr crtc = pScrPriv->crtcs[i];
 | 
						|
        RRModePtr mode = crtc->mode;
 | 
						|
 | 
						|
        if (!RRCrtcIsLeased(crtc) && mode) {
 | 
						|
            int source_width = mode->mode.width;
 | 
						|
            int source_height = mode->mode.height;
 | 
						|
            Rotation rotation = crtc->rotation;
 | 
						|
 | 
						|
            if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
 | 
						|
                source_width = mode->mode.height;
 | 
						|
                source_height = mode->mode.width;
 | 
						|
            }
 | 
						|
 | 
						|
            if (crtc->x + source_width > stuff->width ||
 | 
						|
                crtc->y + source_height > stuff->height)
 | 
						|
                return BadMatch;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0) {
 | 
						|
        client->errorValue = 0;
 | 
						|
        return BadValue;
 | 
						|
    }
 | 
						|
    if (!RRScreenSizeSet(pScreen,
 | 
						|
                         stuff->width, stuff->height,
 | 
						|
                         stuff->widthInMillimeters,
 | 
						|
                         stuff->heightInMillimeters)) {
 | 
						|
        return BadMatch;
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#define update_totals(gpuscreen, pScrPriv) do {       \
 | 
						|
    total_crtcs += pScrPriv->numCrtcs;                \
 | 
						|
    total_outputs += pScrPriv->numOutputs;            \
 | 
						|
    modes = RRModesForScreen(gpuscreen, &num_modes);  \
 | 
						|
    if (!modes)                                       \
 | 
						|
        return BadAlloc;                              \
 | 
						|
    for (j = 0; j < num_modes; j++)                   \
 | 
						|
        total_name_len += modes[j]->mode.nameLength;  \
 | 
						|
    total_modes += num_modes;                         \
 | 
						|
    free(modes);                                      \
 | 
						|
} while(0)
 | 
						|
 | 
						|
static inline void swap_modeinfos(xRRModeInfo *modeinfos, int i)
 | 
						|
{
 | 
						|
    swapl(&modeinfos[i].id);
 | 
						|
    swaps(&modeinfos[i].width);
 | 
						|
    swaps(&modeinfos[i].height);
 | 
						|
    swapl(&modeinfos[i].dotClock);
 | 
						|
    swaps(&modeinfos[i].hSyncStart);
 | 
						|
    swaps(&modeinfos[i].hSyncEnd);
 | 
						|
    swaps(&modeinfos[i].hTotal);
 | 
						|
    swaps(&modeinfos[i].hSkew);
 | 
						|
    swaps(&modeinfos[i].vSyncStart);
 | 
						|
    swaps(&modeinfos[i].vSyncEnd);
 | 
						|
    swaps(&modeinfos[i].vTotal);
 | 
						|
    swaps(&modeinfos[i].nameLength);
 | 
						|
    swapl(&modeinfos[i].modeFlags);
 | 
						|
}
 | 
						|
 | 
						|
#define update_arrays(gpuscreen, pScrPriv, primary_crtc, has_primary) do {            \
 | 
						|
    for (j = 0; j < pScrPriv->numCrtcs; j++) {             \
 | 
						|
        if (has_primary && \
 | 
						|
            primary_crtc == pScrPriv->crtcs[j]) { \
 | 
						|
            has_primary = 0;   \
 | 
						|
            continue; \
 | 
						|
        }\
 | 
						|
        crtcs[crtc_count] = pScrPriv->crtcs[j]->id;        \
 | 
						|
        if (client->swapped)                               \
 | 
						|
            swapl(&crtcs[crtc_count]);                     \
 | 
						|
        crtc_count++;                                      \
 | 
						|
    }                                                      \
 | 
						|
    for (j = 0; j < pScrPriv->numOutputs; j++) {           \
 | 
						|
        outputs[output_count] = pScrPriv->outputs[j]->id;  \
 | 
						|
        if (client->swapped)                               \
 | 
						|
            swapl(&outputs[output_count]);                 \
 | 
						|
        output_count++;                                    \
 | 
						|
    }                                                      \
 | 
						|
    {                                                      \
 | 
						|
        RRModePtr mode;                                    \
 | 
						|
        modes = RRModesForScreen(gpuscreen, &num_modes);   \
 | 
						|
        for (j = 0; j < num_modes; j++) {                  \
 | 
						|
            mode = modes[j];                               \
 | 
						|
            modeinfos[mode_count] = mode->mode;            \
 | 
						|
            if (client->swapped) {                         \
 | 
						|
                swap_modeinfos(modeinfos, mode_count);     \
 | 
						|
            }                                              \
 | 
						|
            memcpy(names, mode->name, mode->mode.nameLength); \
 | 
						|
            names += mode->mode.nameLength;                \
 | 
						|
            mode_count++;                                  \
 | 
						|
        }                                                  \
 | 
						|
        free(modes);                                       \
 | 
						|
    }                                                      \
 | 
						|
    } while (0)
 | 
						|
 | 
						|
static int
 | 
						|
rrGetMultiScreenResources(ClientPtr client, Bool query, ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    int j;
 | 
						|
    int total_crtcs, total_outputs, total_modes, total_name_len;
 | 
						|
    int crtc_count, output_count, mode_count;
 | 
						|
    ScreenPtr iter;
 | 
						|
    rrScrPrivPtr pScrPriv;
 | 
						|
    int num_modes;
 | 
						|
    RRModePtr *modes;
 | 
						|
    xRRGetScreenResourcesReply rep;
 | 
						|
    unsigned long extraLen;
 | 
						|
    CARD8 *extra;
 | 
						|
    RRCrtc *crtcs;
 | 
						|
    RRCrtcPtr primary_crtc = NULL;
 | 
						|
    RROutput *outputs;
 | 
						|
    xRRModeInfo *modeinfos;
 | 
						|
    CARD8 *names;
 | 
						|
    int has_primary = 0;
 | 
						|
 | 
						|
    /* we need to iterate all the GPU primarys and all their output secondarys */
 | 
						|
    total_crtcs = 0;
 | 
						|
    total_outputs = 0;
 | 
						|
    total_modes = 0;
 | 
						|
    total_name_len = 0;
 | 
						|
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
 | 
						|
    if (query && pScrPriv)
 | 
						|
        if (!RRGetInfo(pScreen, query))
 | 
						|
            return BadAlloc;
 | 
						|
 | 
						|
    update_totals(pScreen, pScrPriv);
 | 
						|
 | 
						|
    xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
 | 
						|
        if (!iter->is_output_secondary)
 | 
						|
            continue;
 | 
						|
 | 
						|
        pScrPriv = rrGetScrPriv(iter);
 | 
						|
 | 
						|
        if (query)
 | 
						|
          if (!RRGetInfo(iter, query))
 | 
						|
            return BadAlloc;
 | 
						|
        update_totals(iter, pScrPriv);
 | 
						|
    }
 | 
						|
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
    rep = (xRRGetScreenResourcesReply) {
 | 
						|
        .type = X_Reply,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .length = 0,
 | 
						|
        .timestamp = pScrPriv->lastSetTime.milliseconds,
 | 
						|
        .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
 | 
						|
        .nCrtcs = total_crtcs,
 | 
						|
        .nOutputs = total_outputs,
 | 
						|
        .nModes = total_modes,
 | 
						|
        .nbytesNames = total_name_len
 | 
						|
    };
 | 
						|
 | 
						|
    rep.length = (total_crtcs + total_outputs +
 | 
						|
                  total_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
 | 
						|
                  bytes_to_int32(total_name_len));
 | 
						|
 | 
						|
    extraLen = rep.length << 2;
 | 
						|
    if (extraLen) {
 | 
						|
        extra = malloc(extraLen);
 | 
						|
        if (!extra) {
 | 
						|
            return BadAlloc;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
        extra = NULL;
 | 
						|
 | 
						|
    crtcs = (RRCrtc *)extra;
 | 
						|
    outputs = (RROutput *)(crtcs + total_crtcs);
 | 
						|
    modeinfos = (xRRModeInfo *)(outputs + total_outputs);
 | 
						|
    names = (CARD8 *)(modeinfos + total_modes);
 | 
						|
 | 
						|
    crtc_count = 0;
 | 
						|
    output_count = 0;
 | 
						|
    mode_count = 0;
 | 
						|
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
    if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
 | 
						|
        has_primary = 1;
 | 
						|
        primary_crtc = pScrPriv->primaryOutput->crtc;
 | 
						|
        crtcs[0] = pScrPriv->primaryOutput->crtc->id;
 | 
						|
        if (client->swapped)
 | 
						|
            swapl(&crtcs[0]);
 | 
						|
        crtc_count = 1;
 | 
						|
    }
 | 
						|
    update_arrays(pScreen, pScrPriv, primary_crtc, has_primary);
 | 
						|
 | 
						|
    xorg_list_for_each_entry(iter, &pScreen->secondary_list, secondary_head) {
 | 
						|
        if (!iter->is_output_secondary)
 | 
						|
            continue;
 | 
						|
 | 
						|
        pScrPriv = rrGetScrPriv(iter);
 | 
						|
 | 
						|
        update_arrays(iter, pScrPriv, primary_crtc, has_primary);
 | 
						|
    }
 | 
						|
 | 
						|
    assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
        swapl(&rep.timestamp);
 | 
						|
        swapl(&rep.configTimestamp);
 | 
						|
        swaps(&rep.nCrtcs);
 | 
						|
        swaps(&rep.nOutputs);
 | 
						|
        swaps(&rep.nModes);
 | 
						|
        swaps(&rep.nbytesNames);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof(xRRGetScreenResourcesReply), &rep);
 | 
						|
    if (extraLen) {
 | 
						|
        WriteToClient(client, extraLen, extra);
 | 
						|
        free(extra);
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
rrGetScreenResources(ClientPtr client, Bool query)
 | 
						|
{
 | 
						|
    REQUEST(xRRGetScreenResourcesReq);
 | 
						|
    xRRGetScreenResourcesReply rep;
 | 
						|
    WindowPtr pWin;
 | 
						|
    ScreenPtr pScreen;
 | 
						|
    rrScrPrivPtr pScrPriv;
 | 
						|
    CARD8 *extra;
 | 
						|
    unsigned long extraLen;
 | 
						|
    int i, rc, has_primary = 0;
 | 
						|
    RRCrtc *crtcs;
 | 
						|
    RROutput *outputs;
 | 
						|
    xRRModeInfo *modeinfos;
 | 
						|
    CARD8 *names;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
 | 
						|
    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    pScreen = pWin->drawable.pScreen;
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
 | 
						|
    if (query && pScrPriv)
 | 
						|
        if (!RRGetInfo(pScreen, query))
 | 
						|
            return BadAlloc;
 | 
						|
 | 
						|
    if (pScreen->output_secondarys)
 | 
						|
        return rrGetMultiScreenResources(client, query, pScreen);
 | 
						|
 | 
						|
    if (!pScrPriv) {
 | 
						|
        rep = (xRRGetScreenResourcesReply) {
 | 
						|
            .type = X_Reply,
 | 
						|
            .sequenceNumber = client->sequence,
 | 
						|
            .length = 0,
 | 
						|
            .timestamp = currentTime.milliseconds,
 | 
						|
            .configTimestamp = currentTime.milliseconds,
 | 
						|
            .nCrtcs = 0,
 | 
						|
            .nOutputs = 0,
 | 
						|
            .nModes = 0,
 | 
						|
            .nbytesNames = 0
 | 
						|
        };
 | 
						|
        extra = NULL;
 | 
						|
        extraLen = 0;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        RRModePtr *modes;
 | 
						|
        int num_modes;
 | 
						|
 | 
						|
        modes = RRModesForScreen(pScreen, &num_modes);
 | 
						|
        if (!modes)
 | 
						|
            return BadAlloc;
 | 
						|
 | 
						|
        rep = (xRRGetScreenResourcesReply) {
 | 
						|
            .type = X_Reply,
 | 
						|
            .sequenceNumber = client->sequence,
 | 
						|
            .length = 0,
 | 
						|
            .timestamp = pScrPriv->lastSetTime.milliseconds,
 | 
						|
            .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
 | 
						|
            .nCrtcs = pScrPriv->numCrtcs,
 | 
						|
            .nOutputs = pScrPriv->numOutputs,
 | 
						|
            .nModes = num_modes,
 | 
						|
            .nbytesNames = 0
 | 
						|
        };
 | 
						|
 | 
						|
 | 
						|
        for (i = 0; i < num_modes; i++)
 | 
						|
            rep.nbytesNames += modes[i]->mode.nameLength;
 | 
						|
 | 
						|
        rep.length = (pScrPriv->numCrtcs +
 | 
						|
                      pScrPriv->numOutputs +
 | 
						|
                      num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
 | 
						|
                      bytes_to_int32(rep.nbytesNames));
 | 
						|
 | 
						|
        extraLen = rep.length << 2;
 | 
						|
        if (extraLen) {
 | 
						|
            extra = calloc(1, extraLen);
 | 
						|
            if (!extra) {
 | 
						|
                free(modes);
 | 
						|
                return BadAlloc;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
            extra = NULL;
 | 
						|
 | 
						|
        crtcs = (RRCrtc *) extra;
 | 
						|
        outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs);
 | 
						|
        modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs);
 | 
						|
        names = (CARD8 *) (modeinfos + num_modes);
 | 
						|
 | 
						|
        if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
 | 
						|
            has_primary = 1;
 | 
						|
            crtcs[0] = pScrPriv->primaryOutput->crtc->id;
 | 
						|
            if (client->swapped)
 | 
						|
                swapl(&crtcs[0]);
 | 
						|
        }
 | 
						|
 | 
						|
        for (i = 0; i < pScrPriv->numCrtcs; i++) {
 | 
						|
            if (has_primary &&
 | 
						|
                pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) {
 | 
						|
                has_primary = 0;
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            crtcs[i + has_primary] = pScrPriv->crtcs[i]->id;
 | 
						|
            if (client->swapped)
 | 
						|
                swapl(&crtcs[i + has_primary]);
 | 
						|
        }
 | 
						|
 | 
						|
        for (i = 0; i < pScrPriv->numOutputs; i++) {
 | 
						|
            outputs[i] = pScrPriv->outputs[i]->id;
 | 
						|
            if (client->swapped)
 | 
						|
                swapl(&outputs[i]);
 | 
						|
        }
 | 
						|
 | 
						|
        for (i = 0; i < num_modes; i++) {
 | 
						|
            RRModePtr mode = modes[i];
 | 
						|
 | 
						|
            modeinfos[i] = mode->mode;
 | 
						|
            if (client->swapped) {
 | 
						|
                swapl(&modeinfos[i].id);
 | 
						|
                swaps(&modeinfos[i].width);
 | 
						|
                swaps(&modeinfos[i].height);
 | 
						|
                swapl(&modeinfos[i].dotClock);
 | 
						|
                swaps(&modeinfos[i].hSyncStart);
 | 
						|
                swaps(&modeinfos[i].hSyncEnd);
 | 
						|
                swaps(&modeinfos[i].hTotal);
 | 
						|
                swaps(&modeinfos[i].hSkew);
 | 
						|
                swaps(&modeinfos[i].vSyncStart);
 | 
						|
                swaps(&modeinfos[i].vSyncEnd);
 | 
						|
                swaps(&modeinfos[i].vTotal);
 | 
						|
                swaps(&modeinfos[i].nameLength);
 | 
						|
                swapl(&modeinfos[i].modeFlags);
 | 
						|
            }
 | 
						|
            memcpy(names, mode->name, mode->mode.nameLength);
 | 
						|
            names += mode->mode.nameLength;
 | 
						|
        }
 | 
						|
        free(modes);
 | 
						|
        assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
 | 
						|
    }
 | 
						|
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
        swapl(&rep.timestamp);
 | 
						|
        swapl(&rep.configTimestamp);
 | 
						|
        swaps(&rep.nCrtcs);
 | 
						|
        swaps(&rep.nOutputs);
 | 
						|
        swaps(&rep.nModes);
 | 
						|
        swaps(&rep.nbytesNames);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *) &rep);
 | 
						|
    if (extraLen) {
 | 
						|
        WriteToClient(client, extraLen, (char *) extra);
 | 
						|
        free(extra);
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ProcRRGetScreenResources(ClientPtr client)
 | 
						|
{
 | 
						|
    return rrGetScreenResources(client, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ProcRRGetScreenResourcesCurrent(ClientPtr client)
 | 
						|
{
 | 
						|
    return rrGetScreenResources(client, FALSE);
 | 
						|
}
 | 
						|
 | 
						|
typedef struct _RR10Data {
 | 
						|
    RRScreenSizePtr sizes;
 | 
						|
    int nsize;
 | 
						|
    int nrefresh;
 | 
						|
    int size;
 | 
						|
    CARD16 refresh;
 | 
						|
} RR10DataRec, *RR10DataPtr;
 | 
						|
 | 
						|
/*
 | 
						|
 * Convert 1.2 monitor data into 1.0 screen data
 | 
						|
 */
 | 
						|
static RR10DataPtr
 | 
						|
RR10GetData(ScreenPtr pScreen, RROutputPtr output)
 | 
						|
{
 | 
						|
    RR10DataPtr data;
 | 
						|
    RRScreenSizePtr size;
 | 
						|
    int nmode = output->numModes + output->numUserModes;
 | 
						|
    int o, os, l, r;
 | 
						|
    RRScreenRatePtr refresh;
 | 
						|
    CARD16 vRefresh;
 | 
						|
    RRModePtr mode;
 | 
						|
    Bool *used;
 | 
						|
 | 
						|
    /* Make sure there is plenty of space for any combination */
 | 
						|
    data = malloc(sizeof(RR10DataRec) +
 | 
						|
                  sizeof(RRScreenSize) * nmode +
 | 
						|
                  sizeof(RRScreenRate) * nmode + sizeof(Bool) * nmode);
 | 
						|
    if (!data)
 | 
						|
        return NULL;
 | 
						|
    size = (RRScreenSizePtr) (data + 1);
 | 
						|
    refresh = (RRScreenRatePtr) (size + nmode);
 | 
						|
    used = (Bool *) (refresh + nmode);
 | 
						|
    memset(used, '\0', sizeof(Bool) * nmode);
 | 
						|
    data->sizes = size;
 | 
						|
    data->nsize = 0;
 | 
						|
    data->nrefresh = 0;
 | 
						|
    data->size = 0;
 | 
						|
    data->refresh = 0;
 | 
						|
 | 
						|
    /*
 | 
						|
     * find modes not yet listed
 | 
						|
     */
 | 
						|
    for (o = 0; o < output->numModes + output->numUserModes; o++) {
 | 
						|
        if (used[o])
 | 
						|
            continue;
 | 
						|
 | 
						|
        if (o < output->numModes)
 | 
						|
            mode = output->modes[o];
 | 
						|
        else
 | 
						|
            mode = output->userModes[o - output->numModes];
 | 
						|
 | 
						|
        l = data->nsize;
 | 
						|
        size[l].id = data->nsize;
 | 
						|
        size[l].width = mode->mode.width;
 | 
						|
        size[l].height = mode->mode.height;
 | 
						|
        if (output->mmWidth && output->mmHeight) {
 | 
						|
            size[l].mmWidth = output->mmWidth;
 | 
						|
            size[l].mmHeight = output->mmHeight;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            size[l].mmWidth = pScreen->mmWidth;
 | 
						|
            size[l].mmHeight = pScreen->mmHeight;
 | 
						|
        }
 | 
						|
        size[l].nRates = 0;
 | 
						|
        size[l].pRates = &refresh[data->nrefresh];
 | 
						|
        data->nsize++;
 | 
						|
 | 
						|
        /*
 | 
						|
         * Find all modes with matching size
 | 
						|
         */
 | 
						|
        for (os = o; os < output->numModes + output->numUserModes; os++) {
 | 
						|
            if (os < output->numModes)
 | 
						|
                mode = output->modes[os];
 | 
						|
            else
 | 
						|
                mode = output->userModes[os - output->numModes];
 | 
						|
            if (mode->mode.width == size[l].width &&
 | 
						|
                mode->mode.height == size[l].height) {
 | 
						|
                vRefresh = RRVerticalRefresh(&mode->mode);
 | 
						|
                used[os] = TRUE;
 | 
						|
 | 
						|
                for (r = 0; r < size[l].nRates; r++)
 | 
						|
                    if (vRefresh == size[l].pRates[r].rate)
 | 
						|
                        break;
 | 
						|
                if (r == size[l].nRates) {
 | 
						|
                    size[l].pRates[r].rate = vRefresh;
 | 
						|
                    size[l].pRates[r].mode = mode;
 | 
						|
                    size[l].nRates++;
 | 
						|
                    data->nrefresh++;
 | 
						|
                }
 | 
						|
                if (mode == output->crtc->mode) {
 | 
						|
                    data->size = l;
 | 
						|
                    data->refresh = vRefresh;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return data;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ProcRRGetScreenInfo(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xRRGetScreenInfoReq);
 | 
						|
    xRRGetScreenInfoReply rep;
 | 
						|
    WindowPtr pWin;
 | 
						|
    int rc;
 | 
						|
    ScreenPtr pScreen;
 | 
						|
    rrScrPrivPtr pScrPriv;
 | 
						|
    CARD8 *extra;
 | 
						|
    unsigned long extraLen;
 | 
						|
    RROutputPtr output;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
 | 
						|
    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    pScreen = pWin->drawable.pScreen;
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
 | 
						|
    if (pScrPriv)
 | 
						|
        if (!RRGetInfo(pScreen, TRUE))
 | 
						|
            return BadAlloc;
 | 
						|
 | 
						|
    output = RRFirstOutput(pScreen);
 | 
						|
 | 
						|
    if (!pScrPriv || !output) {
 | 
						|
        rep = (xRRGetScreenInfoReply) {
 | 
						|
            .type = X_Reply,
 | 
						|
            .setOfRotations = RR_Rotate_0,
 | 
						|
            .sequenceNumber = client->sequence,
 | 
						|
            .length = 0,
 | 
						|
            .root = pWin->drawable.pScreen->root->drawable.id,
 | 
						|
            .timestamp = currentTime.milliseconds,
 | 
						|
            .configTimestamp = currentTime.milliseconds,
 | 
						|
            .nSizes = 0,
 | 
						|
            .sizeID = 0,
 | 
						|
            .rotation = RR_Rotate_0,
 | 
						|
            .rate = 0,
 | 
						|
            .nrateEnts = 0
 | 
						|
        };
 | 
						|
        extra = 0;
 | 
						|
        extraLen = 0;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        int i, j;
 | 
						|
        xScreenSizes *size;
 | 
						|
        CARD16 *rates;
 | 
						|
        CARD8 *data8;
 | 
						|
        Bool has_rate = RRClientKnowsRates(client);
 | 
						|
        RR10DataPtr pData;
 | 
						|
        RRScreenSizePtr pSize;
 | 
						|
 | 
						|
        pData = RR10GetData(pScreen, output);
 | 
						|
        if (!pData)
 | 
						|
            return BadAlloc;
 | 
						|
 | 
						|
        rep = (xRRGetScreenInfoReply) {
 | 
						|
            .type = X_Reply,
 | 
						|
            .setOfRotations = output->crtc->rotations,
 | 
						|
            .sequenceNumber = client->sequence,
 | 
						|
            .length = 0,
 | 
						|
            .root = pWin->drawable.pScreen->root->drawable.id,
 | 
						|
            .timestamp = pScrPriv->lastSetTime.milliseconds,
 | 
						|
            .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
 | 
						|
            .rotation = output->crtc->rotation,
 | 
						|
            .nSizes = pData->nsize,
 | 
						|
            .nrateEnts = pData->nrefresh + pData->nsize,
 | 
						|
            .sizeID = pData->size,
 | 
						|
            .rate = pData->refresh
 | 
						|
        };
 | 
						|
 | 
						|
        extraLen = rep.nSizes * sizeof(xScreenSizes);
 | 
						|
        if (has_rate)
 | 
						|
            extraLen += rep.nrateEnts * sizeof(CARD16);
 | 
						|
 | 
						|
        if (extraLen) {
 | 
						|
            extra = (CARD8 *) malloc(extraLen);
 | 
						|
            if (!extra) {
 | 
						|
                free(pData);
 | 
						|
                return BadAlloc;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
            extra = NULL;
 | 
						|
 | 
						|
        /*
 | 
						|
         * First comes the size information
 | 
						|
         */
 | 
						|
        size = (xScreenSizes *) extra;
 | 
						|
        rates = (CARD16 *) (size + rep.nSizes);
 | 
						|
        for (i = 0; i < pData->nsize; i++) {
 | 
						|
            pSize = &pData->sizes[i];
 | 
						|
            size->widthInPixels = pSize->width;
 | 
						|
            size->heightInPixels = pSize->height;
 | 
						|
            size->widthInMillimeters = pSize->mmWidth;
 | 
						|
            size->heightInMillimeters = pSize->mmHeight;
 | 
						|
            if (client->swapped) {
 | 
						|
                swaps(&size->widthInPixels);
 | 
						|
                swaps(&size->heightInPixels);
 | 
						|
                swaps(&size->widthInMillimeters);
 | 
						|
                swaps(&size->heightInMillimeters);
 | 
						|
            }
 | 
						|
            size++;
 | 
						|
            if (has_rate) {
 | 
						|
                *rates = pSize->nRates;
 | 
						|
                if (client->swapped) {
 | 
						|
                    swaps(rates);
 | 
						|
                }
 | 
						|
                rates++;
 | 
						|
                for (j = 0; j < pSize->nRates; j++) {
 | 
						|
                    *rates = pSize->pRates[j].rate;
 | 
						|
                    if (client->swapped) {
 | 
						|
                        swaps(rates);
 | 
						|
                    }
 | 
						|
                    rates++;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        free(pData);
 | 
						|
 | 
						|
        data8 = (CARD8 *) rates;
 | 
						|
 | 
						|
        if (data8 - (CARD8 *) extra != extraLen)
 | 
						|
            FatalError("RRGetScreenInfo bad extra len %ld != %ld\n",
 | 
						|
                       (unsigned long) (data8 - (CARD8 *) extra), extraLen);
 | 
						|
        rep.length = bytes_to_int32(extraLen);
 | 
						|
    }
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
        swapl(&rep.timestamp);
 | 
						|
        swapl(&rep.configTimestamp);
 | 
						|
        swaps(&rep.rotation);
 | 
						|
        swaps(&rep.nSizes);
 | 
						|
        swaps(&rep.sizeID);
 | 
						|
        swaps(&rep.rate);
 | 
						|
        swaps(&rep.nrateEnts);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof(xRRGetScreenInfoReply), &rep);
 | 
						|
    if (extraLen) {
 | 
						|
        WriteToClient(client, extraLen, extra);
 | 
						|
        free(extra);
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ProcRRSetScreenConfig(ClientPtr client)
 | 
						|
{
 | 
						|
    REQUEST(xRRSetScreenConfigReq);
 | 
						|
    xRRSetScreenConfigReply rep;
 | 
						|
    DrawablePtr pDraw;
 | 
						|
    int rc;
 | 
						|
    ScreenPtr pScreen;
 | 
						|
    rrScrPrivPtr pScrPriv;
 | 
						|
    TimeStamp time;
 | 
						|
    int i;
 | 
						|
    Rotation rotation;
 | 
						|
    int rate;
 | 
						|
    Bool has_rate;
 | 
						|
    CARD8 status;
 | 
						|
    RROutputPtr output;
 | 
						|
    RRCrtcPtr crtc;
 | 
						|
    RRModePtr mode;
 | 
						|
    RR10DataPtr pData = NULL;
 | 
						|
    RRScreenSizePtr pSize;
 | 
						|
    int width, height;
 | 
						|
 | 
						|
    UpdateCurrentTime();
 | 
						|
 | 
						|
    if (RRClientKnowsRates(client)) {
 | 
						|
        REQUEST_SIZE_MATCH(xRRSetScreenConfigReq);
 | 
						|
        has_rate = TRUE;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        REQUEST_SIZE_MATCH(xRR1_0SetScreenConfigReq);
 | 
						|
        has_rate = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
 | 
						|
    if (rc != Success)
 | 
						|
        return rc;
 | 
						|
 | 
						|
    pScreen = pDraw->pScreen;
 | 
						|
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
 | 
						|
    time = ClientTimeToServerTime(stuff->timestamp);
 | 
						|
 | 
						|
    if (!pScrPriv) {
 | 
						|
        time = currentTime;
 | 
						|
        status = RRSetConfigFailed;
 | 
						|
        goto sendReply;
 | 
						|
    }
 | 
						|
    if (!RRGetInfo(pScreen, FALSE))
 | 
						|
        return BadAlloc;
 | 
						|
 | 
						|
    output = RRFirstOutput(pScreen);
 | 
						|
    if (!output) {
 | 
						|
        time = currentTime;
 | 
						|
        status = RRSetConfigFailed;
 | 
						|
        goto sendReply;
 | 
						|
    }
 | 
						|
 | 
						|
    crtc = output->crtc;
 | 
						|
 | 
						|
    /*
 | 
						|
     * If the client's config timestamp is not the same as the last config
 | 
						|
     * timestamp, then the config information isn't up-to-date and
 | 
						|
     * can't even be validated.
 | 
						|
     *
 | 
						|
     * Note that the client only knows about the milliseconds part of the
 | 
						|
     * timestamp, so using CompareTimeStamps here would cause randr to suddenly
 | 
						|
     * stop working after several hours have passed (freedesktop bug #6502).
 | 
						|
     */
 | 
						|
    if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds) {
 | 
						|
        status = RRSetConfigInvalidConfigTime;
 | 
						|
        goto sendReply;
 | 
						|
    }
 | 
						|
 | 
						|
    pData = RR10GetData(pScreen, output);
 | 
						|
    if (!pData)
 | 
						|
        return BadAlloc;
 | 
						|
 | 
						|
    if (stuff->sizeID >= pData->nsize) {
 | 
						|
        /*
 | 
						|
         * Invalid size ID
 | 
						|
         */
 | 
						|
        client->errorValue = stuff->sizeID;
 | 
						|
        free(pData);
 | 
						|
        return BadValue;
 | 
						|
    }
 | 
						|
    pSize = &pData->sizes[stuff->sizeID];
 | 
						|
 | 
						|
    /*
 | 
						|
     * Validate requested rotation
 | 
						|
     */
 | 
						|
    rotation = (Rotation) stuff->rotation;
 | 
						|
 | 
						|
    /* test the rotation bits only! */
 | 
						|
    switch (rotation & 0xf) {
 | 
						|
    case RR_Rotate_0:
 | 
						|
    case RR_Rotate_90:
 | 
						|
    case RR_Rotate_180:
 | 
						|
    case RR_Rotate_270:
 | 
						|
        break;
 | 
						|
    default:
 | 
						|
        /*
 | 
						|
         * Invalid rotation
 | 
						|
         */
 | 
						|
        client->errorValue = stuff->rotation;
 | 
						|
        free(pData);
 | 
						|
        return BadValue;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((~crtc->rotations) & rotation) {
 | 
						|
        /*
 | 
						|
         * requested rotation or reflection not supported by screen
 | 
						|
         */
 | 
						|
        client->errorValue = stuff->rotation;
 | 
						|
        free(pData);
 | 
						|
        return BadMatch;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * Validate requested refresh
 | 
						|
     */
 | 
						|
    if (has_rate)
 | 
						|
        rate = (int) stuff->rate;
 | 
						|
    else
 | 
						|
        rate = 0;
 | 
						|
 | 
						|
    if (rate) {
 | 
						|
        for (i = 0; i < pSize->nRates; i++) {
 | 
						|
            if (pSize->pRates[i].rate == rate)
 | 
						|
                break;
 | 
						|
        }
 | 
						|
        if (i == pSize->nRates) {
 | 
						|
            /*
 | 
						|
             * Invalid rate
 | 
						|
             */
 | 
						|
            client->errorValue = rate;
 | 
						|
            free(pData);
 | 
						|
            return BadValue;
 | 
						|
        }
 | 
						|
        mode = pSize->pRates[i].mode;
 | 
						|
    }
 | 
						|
    else
 | 
						|
        mode = pSize->pRates[0].mode;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Make sure the requested set-time is not older than
 | 
						|
     * the last set-time
 | 
						|
     */
 | 
						|
    if (CompareTimeStamps(time, pScrPriv->lastSetTime) < 0) {
 | 
						|
        status = RRSetConfigInvalidTime;
 | 
						|
        goto sendReply;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * If the screen size is changing, adjust all of the other outputs
 | 
						|
     * to fit the new size, mirroring as much as possible
 | 
						|
     */
 | 
						|
    width = mode->mode.width;
 | 
						|
    height = mode->mode.height;
 | 
						|
    if (width < pScrPriv->minWidth || pScrPriv->maxWidth < width) {
 | 
						|
        client->errorValue = width;
 | 
						|
        free(pData);
 | 
						|
        return BadValue;
 | 
						|
    }
 | 
						|
    if (height < pScrPriv->minHeight || pScrPriv->maxHeight < height) {
 | 
						|
        client->errorValue = height;
 | 
						|
        free(pData);
 | 
						|
        return BadValue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
 | 
						|
        width = mode->mode.height;
 | 
						|
        height = mode->mode.width;
 | 
						|
    }
 | 
						|
 | 
						|
    if (width != pScreen->width || height != pScreen->height) {
 | 
						|
        int c;
 | 
						|
 | 
						|
        for (c = 0; c < pScrPriv->numCrtcs; c++) {
 | 
						|
            if (!RRCrtcSet(pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
 | 
						|
                           0, NULL)) {
 | 
						|
                status = RRSetConfigFailed;
 | 
						|
                /* XXX recover from failure */
 | 
						|
                goto sendReply;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (!RRScreenSizeSet(pScreen, width, height,
 | 
						|
                             pScreen->mmWidth, pScreen->mmHeight)) {
 | 
						|
            status = RRSetConfigFailed;
 | 
						|
            /* XXX recover from failure */
 | 
						|
            goto sendReply;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!RRCrtcSet(crtc, mode, 0, 0, stuff->rotation, 1, &output))
 | 
						|
        status = RRSetConfigFailed;
 | 
						|
    else {
 | 
						|
        pScrPriv->lastSetTime = time;
 | 
						|
        status = RRSetConfigSuccess;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * XXX Configure other crtcs to mirror as much as possible
 | 
						|
     */
 | 
						|
 | 
						|
 sendReply:
 | 
						|
 | 
						|
    free(pData);
 | 
						|
 | 
						|
    rep = (xRRSetScreenConfigReply) {
 | 
						|
        .type = X_Reply,
 | 
						|
        .status = status,
 | 
						|
        .sequenceNumber = client->sequence,
 | 
						|
        .length = 0,
 | 
						|
 | 
						|
        .newTimestamp = pScrPriv->lastSetTime.milliseconds,
 | 
						|
        .newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds,
 | 
						|
        .root = pDraw->pScreen->root->drawable.id,
 | 
						|
        /* .subpixelOrder = ?? */
 | 
						|
    };
 | 
						|
 | 
						|
    if (client->swapped) {
 | 
						|
        swaps(&rep.sequenceNumber);
 | 
						|
        swapl(&rep.length);
 | 
						|
        swapl(&rep.newTimestamp);
 | 
						|
        swapl(&rep.newConfigTimestamp);
 | 
						|
        swapl(&rep.root);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof(xRRSetScreenConfigReply), &rep);
 | 
						|
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static CARD16
 | 
						|
RR10CurrentSizeID(ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    CARD16 sizeID = 0xffff;
 | 
						|
    RROutputPtr output = RRFirstOutput(pScreen);
 | 
						|
 | 
						|
    if (output) {
 | 
						|
        RR10DataPtr data = RR10GetData(pScreen, output);
 | 
						|
 | 
						|
        if (data) {
 | 
						|
            int i;
 | 
						|
 | 
						|
            for (i = 0; i < data->nsize; i++)
 | 
						|
                if (data->sizes[i].width == pScreen->width &&
 | 
						|
                    data->sizes[i].height == pScreen->height) {
 | 
						|
                    sizeID = (CARD16) i;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            free(data);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return sizeID;
 | 
						|
}
 |