/*
 * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina.
 *
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation on the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * Authors:
 *   Rickard E. (Rik) Faith <faith@redhat.com>
 *
 */

/** \file
 * This file implements the server-side part of the DMX protocol. A
 * vector of fucntions is provided at extension initialization time, so
 * most all of the useful functions in this file are declared static and
 * do not appear in the doxygen documentation.
 *
 * Much of the low-level work is done by functions in \a dmxextension.c
 *
 * Please see the Client-to-Server DMX Extension to the X Protocol
 * document for details about the protocol.  */

#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif

#include <X11/X.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "os.h"
#include "dixstruct.h"
#include "extnsionst.h"
#include "opaque.h"

#include "dmxextension.h"
#include <X11/extensions/dmxproto.h>
#include <X11/extensions/dmx.h>
#include "protocol-versions.h"

#ifdef PANORAMIX
#include "panoramiX.h"
extern unsigned long XRT_WINDOW;
extern int           PanoramiXNumScreens;
#endif

extern void DMXExtensionInit(void);

static unsigned char DMXCode;

static DISPATCH_PROC(ProcDMXDispatch);
static DISPATCH_PROC(ProcDMXQueryVersion);
static DISPATCH_PROC(ProcDMXSync);
static DISPATCH_PROC(ProcDMXForceWindowCreation);
static DISPATCH_PROC(ProcDMXGetScreenCount);
static DISPATCH_PROC(ProcDMXGetScreenAttributes);
static DISPATCH_PROC(ProcDMXChangeScreensAttributes);
static DISPATCH_PROC(ProcDMXAddScreen);
static DISPATCH_PROC(ProcDMXRemoveScreen);
static DISPATCH_PROC(ProcDMXGetWindowAttributes);
static DISPATCH_PROC(ProcDMXGetDesktopAttributes);
static DISPATCH_PROC(ProcDMXChangeDesktopAttributes);
static DISPATCH_PROC(ProcDMXGetInputCount);
static DISPATCH_PROC(ProcDMXGetInputAttributes);
static DISPATCH_PROC(ProcDMXAddInput);
static DISPATCH_PROC(ProcDMXRemoveInput);

static DISPATCH_PROC(SProcDMXDispatch);
static DISPATCH_PROC(SProcDMXQueryVersion);
static DISPATCH_PROC(SProcDMXSync);
static DISPATCH_PROC(SProcDMXForceWindowCreation);
static DISPATCH_PROC(SProcDMXGetScreenCount);
static DISPATCH_PROC(SProcDMXGetScreenAttributes);
static DISPATCH_PROC(SProcDMXChangeScreensAttributes);
static DISPATCH_PROC(SProcDMXAddScreen);
static DISPATCH_PROC(SProcDMXRemoveScreen);
static DISPATCH_PROC(SProcDMXGetWindowAttributes);
static DISPATCH_PROC(SProcDMXGetDesktopAttributes);
static DISPATCH_PROC(SProcDMXChangeDesktopAttributes);
static DISPATCH_PROC(SProcDMXGetInputCount);
static DISPATCH_PROC(SProcDMXGetInputAttributes);
static DISPATCH_PROC(SProcDMXAddInput);
static DISPATCH_PROC(SProcDMXRemoveInput);

static int _DMXXineramaActive(void)
{
#ifdef PANORAMIX
    return !noPanoramiXExtension;
#endif
    return 0;
}

/** Initialize the extension. */
void DMXExtensionInit(void)
{
    ExtensionEntry *extEntry;
    
    if ((extEntry = AddExtension(DMX_EXTENSION_NAME, 0, 0,
                                 ProcDMXDispatch, SProcDMXDispatch,
                                 NULL, StandardMinorOpcode)))
	DMXCode = extEntry->base;
}

static void dmxSetScreenAttribute(int bit, DMXScreenAttributesPtr attr,
                                  CARD32 value)
{
    switch (1 << bit) {
    case DMXScreenWindowWidth:   attr->screenWindowWidth   = value; break;
    case DMXScreenWindowHeight:  attr->screenWindowHeight  = value; break;
    case DMXScreenWindowXoffset: attr->screenWindowXoffset = value; break;
    case DMXScreenWindowYoffset: attr->screenWindowYoffset = value; break;
    case DMXRootWindowWidth:     attr->rootWindowWidth     = value; break;
    case DMXRootWindowHeight:    attr->rootWindowHeight    = value; break;
    case DMXRootWindowXoffset:   attr->rootWindowXoffset   = value; break;
    case DMXRootWindowYoffset:   attr->rootWindowYoffset   = value; break;
    case DMXRootWindowXorigin:   attr->rootWindowXorigin   = value; break;
    case DMXRootWindowYorigin:   attr->rootWindowYorigin   = value; break;
    }
}

static int dmxFetchScreenAttributes(unsigned int mask,
                                    DMXScreenAttributesPtr attr,
                                    CARD32 *value_list)
{
    int    i;
    CARD32 *value = value_list;
    int    count  = 0;
        
    for (i = 0; i < 32; i++) {
        if (mask & (1 << i)) {
            dmxSetScreenAttribute(i, attr, *value);
            ++value;
            ++count;
        }
    }
    return count;
}

static void dmxSetDesktopAttribute(int bit, DMXDesktopAttributesPtr attr,
                                   CARD32 value)
{
    switch (1 << bit) {
    case DMXDesktopWidth:  attr->width  = value; break;
    case DMXDesktopHeight: attr->height = value; break;
    case DMXDesktopShiftX: attr->shiftX = value; break;
    case DMXDesktopShiftY: attr->shiftY = value; break;
    }
}

static int dmxFetchDesktopAttributes(unsigned int mask,
                                     DMXDesktopAttributesPtr attr,
                                     CARD32 *value_list)
{
    int    i;
    CARD32 *value = value_list;
    int    count  = 0;
        
    for (i = 0; i < 32; i++) {
        if (mask & (1 << i)) {
            dmxSetDesktopAttribute(i, attr, *value);
	    ++value;
            ++count;
        }
    }
    return count;
}

static void dmxSetInputAttribute(int bit, DMXInputAttributesPtr attr,
                                 CARD32 value)
{
    switch (1 << bit) {
    case DMXInputType:           attr->inputType      = value;   break;
    case DMXInputPhysicalScreen: attr->physicalScreen = value;   break;
    case DMXInputSendsCore:      attr->sendsCore      = !!value; break;
    }
}

static int dmxFetchInputAttributes(unsigned int mask,
                                   DMXInputAttributesPtr attr,
                                   CARD32 *value_list)
{
    int    i;
    CARD32 *value = value_list;
    int    count  = 0;

    for (i = 0; i < 32; i++) {
        if (mask & (1 << i)) {
            dmxSetInputAttribute(i, attr, *value);
            ++value;
            ++count;
        }
    }
    return count;
}

static int ProcDMXQueryVersion(ClientPtr client)
{
    xDMXQueryVersionReply rep;
    int                   n;

    REQUEST_SIZE_MATCH(xDMXQueryVersionReq);

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.majorVersion   = SERVER_DMX_MAJOR_VERSION;
    rep.minorVersion   = SERVER_DMX_MINOR_VERSION;
    rep.patchVersion   = SERVER_DMX_PATCH_VERSION;
    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
	swapl(&rep.majorVersion, n);
	swapl(&rep.minorVersion, n);
	swapl(&rep.patchVersion, n);
    }
    WriteToClient(client, sizeof(xDMXQueryVersionReply), (char *)&rep);
    return Success;
}

static int ProcDMXSync(ClientPtr client)
{
    xDMXSyncReply rep;
    int           n;

    REQUEST_SIZE_MATCH(xDMXSyncReq);

    dmxFlushPendingSyncs();

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.status         = 0;
    if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.status, n);
    }
    WriteToClient(client, sizeof(xDMXSyncReply), (char *)&rep);
    return Success;
}

static int ProcDMXForceWindowCreation(ClientPtr client)
{
    xDMXForceWindowCreationReply rep;
    REQUEST(xDMXForceWindowCreationReq);
    WindowPtr     pWin;
    int           n;

    REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq);

#ifdef PANORAMIX
    if (!noPanoramiXExtension) {
        PanoramiXRes *win;
        int          i;

        if (!(win = SecurityLookupIDByType(client, stuff->window, XRT_WINDOW,
                                           DixReadAccess)))
            return -1;           /* BadWindow */

        FOR_NSCREENS(i) {
            if (Success != dixLookupWindow(&pWin, win->info[i].id, client,
					   DixReadAccess))
                return -1;       /* BadWindow */

            dmxForceWindowCreation(pWin);
        }
        goto doreply;
    }
#endif

    if (Success != dixLookupWindow(&pWin, stuff->window, client,
				   DixReadAccess))
        return -1;               /* BadWindow */

    dmxForceWindowCreation(pWin);
  doreply:
    dmxFlushPendingSyncs();
    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.status         = 0;
    if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.status, n);
    }
    WriteToClient(client, sizeof(xDMXForceWindowCreationReply), (char *)&rep);
    return Success;
}

static int ProcDMXGetScreenCount(ClientPtr client)
{
    xDMXGetScreenCountReply rep;
    int                     n;

    REQUEST_SIZE_MATCH(xDMXGetScreenCountReq);

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.screenCount    = dmxGetNumScreens();
    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.screenCount, n);
    }
    WriteToClient(client, sizeof(xDMXGetScreenCountReply), (char *)&rep);
    return Success;
}

static int ProcDMXGetScreenAttributes(ClientPtr client)
{
    REQUEST(xDMXGetScreenAttributesReq);
    xDMXGetScreenAttributesReply rep;
    int                          n;
    int                          length;
    int                          paddedLength;
    DMXScreenAttributesRec       attr;

    REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq);

    if (stuff->physicalScreen < 0
        || stuff->physicalScreen >= dmxGetNumScreens()) return BadValue;

    if (!dmxGetScreenAttributes(stuff->physicalScreen, &attr))
        return BadValue;

    rep.logicalScreen       = attr.logicalScreen;
    rep.screenWindowWidth   = attr.screenWindowWidth;
    rep.screenWindowHeight  = attr.screenWindowHeight;
    rep.screenWindowXoffset = attr.screenWindowXoffset;
    rep.screenWindowYoffset = attr.screenWindowYoffset;
    rep.rootWindowWidth     = attr.rootWindowWidth;
    rep.rootWindowHeight    = attr.rootWindowHeight;
    rep.rootWindowXoffset   = attr.rootWindowXoffset;
    rep.rootWindowYoffset   = attr.rootWindowYoffset;
    rep.rootWindowXorigin   = attr.rootWindowXorigin;
    rep.rootWindowYorigin   = attr.rootWindowYorigin;
                                 
    length                  = attr.displayName ? strlen(attr.displayName) : 0;
    paddedLength            = pad_to_int32(length);
    rep.type                = X_Reply;
    rep.sequenceNumber      = client->sequence;
    rep.length              = bytes_to_int32((sizeof(xDMXGetScreenAttributesReply) - sizeof(xGenericReply))
                                             + paddedLength);
    rep.displayNameLength   = length;

    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.displayNameLength, n);
        swapl(&rep.logicalScreen, n);
        swaps(&rep.screenWindowWidth, n);
        swaps(&rep.screenWindowHeight, n);
        swaps(&rep.screenWindowXoffset, n);
        swaps(&rep.screenWindowYoffset, n);
        swaps(&rep.rootWindowWidth, n);
        swaps(&rep.rootWindowHeight, n);
        swaps(&rep.rootWindowXoffset, n);
        swaps(&rep.rootWindowYoffset, n);
        swaps(&rep.rootWindowXorigin, n);
        swaps(&rep.rootWindowYorigin, n);
    }
    WriteToClient(client, sizeof(xDMXGetScreenAttributesReply), (char *)&rep);
    if (length) WriteToClient(client, length, (char *)attr.displayName);
    return Success;
}

static int ProcDMXChangeScreensAttributes(ClientPtr client)
{
    REQUEST(xDMXChangeScreensAttributesReq);
    xDMXChangeScreensAttributesReply rep;
    int                              n;
    int                              status = DMX_BAD_XINERAMA;
    unsigned int                     mask   = 0;
    unsigned int                     i;
    CARD32                           *screen_list;
    CARD32                           *mask_list;
    CARD32                           *value_list;
    DMXScreenAttributesPtr           attribs;
    int                              errorScreen = 0;
    unsigned int                     len;
    int                              ones = 0;
    

    REQUEST_AT_LEAST_SIZE(xDMXChangeScreensAttributesReq);
    len = client->req_len - bytes_to_int32(sizeof(xDMXChangeScreensAttributesReq));
    if (len < stuff->screenCount + stuff->maskCount)
        return BadLength;

    screen_list = (CARD32 *)(stuff + 1);
    mask_list   = &screen_list[stuff->screenCount];
    value_list  = &mask_list[stuff->maskCount];

    for (i = 0; i < stuff->maskCount; i++) ones += Ones(mask_list[i]);
    if (len != stuff->screenCount + stuff->maskCount + ones)
        return BadLength;
    
    if (!_DMXXineramaActive()) goto noxinerama;

    if (!(attribs = malloc(stuff->screenCount * sizeof(*attribs))))
        return BadAlloc;

    for (i = 0; i < stuff->screenCount; i++) {
        int count;
        
        if (i < stuff->maskCount) mask = mask_list[i];
        dmxGetScreenAttributes(screen_list[i], &attribs[i]);
        count = dmxFetchScreenAttributes(mask, &attribs[i], value_list);
        value_list += count;
    }

#if PANORAMIX
    status = dmxConfigureScreenWindows(stuff->screenCount,
				       screen_list,
				       attribs,
				       &errorScreen);
#endif

    free(attribs);

    if (status == BadValue) return status;

  noxinerama:
    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.status         = status;
    rep.errorScreen    = errorScreen;
    if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.status, n);
        swapl(&rep.errorScreen, n);
    }
    WriteToClient(client,
                  sizeof(xDMXChangeScreensAttributesReply),
                  (char *)&rep);
    return Success;
}

static int ProcDMXAddScreen(ClientPtr client)
{
    REQUEST(xDMXAddScreenReq);
    xDMXAddScreenReply     rep;
    int                    n;
    int                    status = 0;
    CARD32                 *value_list;
    DMXScreenAttributesRec attr;
    int                    count;
    char                   *name;
    int                    len;
    int                    paddedLength;

    REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq);
    paddedLength = pad_to_int32(stuff->displayNameLength);
    len          = client->req_len - bytes_to_int32(sizeof(xDMXAddScreenReq));
    if (len != Ones(stuff->valueMask) + paddedLength/4)
        return BadLength;

    memset(&attr, 0, sizeof(attr));
    dmxGetScreenAttributes(stuff->physicalScreen, &attr);
    value_list = (CARD32 *)(stuff + 1);
    count      = dmxFetchScreenAttributes(stuff->valueMask, &attr, value_list);
    
    if (!(name = malloc(stuff->displayNameLength + 1 + 4)))
        return BadAlloc;
    memcpy(name, &value_list[count], stuff->displayNameLength);
    name[stuff->displayNameLength] = '\0';
    attr.displayName = name;

    status = dmxAttachScreen(stuff->physicalScreen, &attr);

    free(name);

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.status         = status;
    rep.physicalScreen = stuff->physicalScreen;
    if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.status, n);
        swapl(&rep.physicalScreen, n);
    }
    WriteToClient(client,
                  sizeof(xDMXAddScreenReply),
                  (char *)&rep);
    return Success;
}

static int ProcDMXRemoveScreen(ClientPtr client)
{
    REQUEST(xDMXRemoveScreenReq);
    xDMXRemoveScreenReply rep;
    int                   n;
    int                   status = 0;

    REQUEST_SIZE_MATCH(xDMXRemoveScreenReq);

    status = dmxDetachScreen(stuff->physicalScreen);

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.status         = status;
    if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.status, n);
    }
    WriteToClient(client,
                  sizeof(xDMXRemoveScreenReply),
                  (char *)&rep);
    return Success;
}


#ifdef PANORAMIX
static int dmxPopulatePanoramiX(ClientPtr client, Window window,
                                CARD32 *screens, CARD32 *windows,
                                xRectangle *pos, xRectangle *vis)
{
    WindowPtr              pWin;
    PanoramiXRes           *win;
    int                    i;
    int                    count = 0;
    DMXWindowAttributesRec attr;
    
    if (!(win = SecurityLookupIDByType(client, window, XRT_WINDOW,
                                       DixReadAccess)))
        return -1;               /* BadWindow */
    
    FOR_NSCREENS(i) {
        if (Success != dixLookupWindow(&pWin, win->info[i].id, client,
				       DixReadAccess))
            return -1;          /* BadWindow */
        if (dmxGetWindowAttributes(pWin, &attr)) {
            screens[count] = attr.screen;
            windows[count] = attr.window;
            pos[count]     = attr.pos;
            vis[count]     = attr.vis;
            ++count;            /* Only count existing windows */
        }
    }
    return count;
}
#endif

static int dmxPopulate(ClientPtr client, Window window, CARD32 *screens,
                       CARD32 *windows, xRectangle *pos, xRectangle *vis)
{
    WindowPtr              pWin;
    DMXWindowAttributesRec attr;

#ifdef PANORAMIX
    if (!noPanoramiXExtension)
        return dmxPopulatePanoramiX(client, window, screens, windows,
                                    pos, vis);
#endif
    
    if (Success != dixLookupWindow(&pWin, window, client, DixReadAccess))
        return -1;               /* BadWindow */

    dmxGetWindowAttributes(pWin, &attr);
    *screens = attr.screen;
    *windows = attr.window;
    *pos     = attr.pos;
    *vis     = attr.vis;
    return 1;
}

static int dmxMaxNumScreens(void)
{
#ifdef PANORAMIX
    if (!noPanoramiXExtension) return PanoramiXNumScreens;
#endif
    return 1;
}

static int ProcDMXGetWindowAttributes(ClientPtr client)
{
    REQUEST(xDMXGetWindowAttributesReq);
    xDMXGetWindowAttributesReply rep;
    int                          i, n;
    CARD32                       *screens;
    CARD32                       *windows;
    xRectangle                   *pos, *vis;
    int                          count = dmxMaxNumScreens();

    REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq);

    if (!(screens = malloc(count * sizeof(*screens))))
        return BadAlloc;
    if (!(windows = malloc(count * sizeof(*windows)))) {
        free(screens);
        return BadAlloc;
    }
    if (!(pos = malloc(count * sizeof(*pos)))) {
        free(windows);
        free(screens);
        return BadAlloc;
    }
    if (!(vis = malloc(count * sizeof(*vis)))) {
        free(pos);
        free(windows);
        free(screens);
        return BadAlloc;
    }

    if ((count = dmxPopulate(client, stuff->window, screens, windows,
                             pos, vis)) < 0) {
        free(vis);
        free(pos);
        free(windows);
        free(screens);
        return BadWindow;
    }

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = count * 6;
    rep.screenCount    = count;
    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.screenCount, n);
        for (i = 0; i < count; i++) {
            swapl(&screens[i], n);
            swapl(&windows[i], n);
            
            swaps(&pos[i].x, n);
            swaps(&pos[i].y, n);
            swaps(&pos[i].width, n);
            swaps(&pos[i].height, n);
            
            swaps(&vis[i].x, n);
            swaps(&vis[i].y, n);
            swaps(&vis[i].width, n);
            swaps(&vis[i].height, n);
        }
    }

    dmxFlushPendingSyncs();

    WriteToClient(client, sizeof(xDMXGetWindowAttributesReply), (char *)&rep);
    if (count) {
        WriteToClient(client, count * sizeof(*screens), (char *)screens);
        WriteToClient(client, count * sizeof(*windows), (char *)windows);
        WriteToClient(client, count * sizeof(*pos),     (char *)pos);
        WriteToClient(client, count * sizeof(*vis),     (char *)vis);
    }

    free(vis);
    free(pos);
    free(windows);
    free(screens);

    return Success;
}

static int ProcDMXGetDesktopAttributes(ClientPtr client)
{
    xDMXGetDesktopAttributesReply rep;
    int                           n;
    DMXDesktopAttributesRec       attr;

    REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq);

    dmxGetDesktopAttributes(&attr);

    rep.width               = attr.width;
    rep.height              = attr.height;
    rep.shiftX              = attr.shiftX;
    rep.shiftY              = attr.shiftY;

    rep.type                = X_Reply;
    rep.sequenceNumber      = client->sequence;
    rep.length              = 0;

    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.width, n);
        swapl(&rep.height, n);
        swapl(&rep.shiftX, n);
        swapl(&rep.shiftY, n);
    }
    WriteToClient(client, sizeof(xDMXGetDesktopAttributesReply), (char *)&rep);
    return Success;
}

static int ProcDMXChangeDesktopAttributes(ClientPtr client)
{
    REQUEST(xDMXChangeDesktopAttributesReq);
    xDMXChangeDesktopAttributesReply rep;
    int                              n;
    int                              status = DMX_BAD_XINERAMA;
    CARD32                           *value_list;
    DMXDesktopAttributesRec          attr;
    int                              len;

    REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq);
    len = client->req_len - (sizeof(xDMXChangeDesktopAttributesReq) >> 2);
    if (len != Ones(stuff->valueMask))
        return BadLength;

    if (!_DMXXineramaActive()) goto noxinerama;

    value_list = (CARD32 *)(stuff + 1);
    
    dmxGetDesktopAttributes(&attr);
    dmxFetchDesktopAttributes(stuff->valueMask, &attr, value_list);

#if PANORAMIX
    status = dmxConfigureDesktop(&attr);
#endif
    if (status == BadValue) return status;

  noxinerama:
    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.status         = status;
    if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.status, n);
    }
    WriteToClient(client,
                  sizeof(xDMXChangeDesktopAttributesReply),
                  (char *)&rep);
    return Success;
}

static int ProcDMXGetInputCount(ClientPtr client)
{
    xDMXGetInputCountReply rep;
    int                     n;

    REQUEST_SIZE_MATCH(xDMXGetInputCountReq);

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.inputCount     = dmxGetInputCount();
    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.inputCount, n);
    }
    WriteToClient(client, sizeof(xDMXGetInputCountReply), (char *)&rep);
    return Success;
}

static int ProcDMXGetInputAttributes(ClientPtr client)
{
    REQUEST(xDMXGetInputAttributesReq);
    xDMXGetInputAttributesReply rep;
    int                          n;
    int                          length;
    int                          paddedLength;
    DMXInputAttributesRec        attr;

    REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq);

    if (dmxGetInputAttributes(stuff->deviceId, &attr)) return BadValue;
    rep.inputType      = attr.inputType;
    rep.physicalScreen = attr.physicalScreen;
    rep.physicalId     = attr.physicalId;
    rep.isCore         = attr.isCore;
    rep.sendsCore      = attr.sendsCore;
    rep.detached       = attr.detached;
    
    length             = attr.name ? strlen(attr.name) : 0;
    paddedLength       = pad_to_int32(length);
    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = bytes_to_int32(paddedLength);
    rep.nameLength     = length;
    if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.inputType, n);
        swapl(&rep.physicalScreen, n);
        swapl(&rep.physicalId, n);
        swapl(&rep.nameLength, n);
    }
    WriteToClient(client, sizeof(xDMXGetInputAttributesReply), (char *)&rep);
    if (length) WriteToClient(client, length, (char *)attr.name);
    return Success;
}

static int ProcDMXAddInput(ClientPtr client)
{
    REQUEST(xDMXAddInputReq);
    xDMXAddInputReply      rep;
    int                    n;
    int                    status = 0;
    CARD32                 *value_list;
    DMXInputAttributesRec  attr;
    int                    count;
    char                   *name;
    int                    len;
    int                    paddedLength;
    int                    id     = -1;

    REQUEST_AT_LEAST_SIZE(xDMXAddInputReq);
    paddedLength = pad_to_int32(stuff->displayNameLength);
    len          = client->req_len - (sizeof(xDMXAddInputReq) >> 2);
    if (len != Ones(stuff->valueMask) + paddedLength/4)
        return BadLength;

    memset(&attr, 0, sizeof(attr));
    value_list = (CARD32 *)(stuff + 1);
    count      = dmxFetchInputAttributes(stuff->valueMask, &attr, value_list);
    
    if (!(name = malloc(stuff->displayNameLength + 1 + 4)))
        return BadAlloc;
    memcpy(name, &value_list[count], stuff->displayNameLength);
    name[stuff->displayNameLength] = '\0';
    attr.name = name;

    status = dmxAddInput(&attr, &id);

    free(name);

    if (status) return status;

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.status         = status;
    rep.physicalId     = id;
    if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.status, n);
        swapl(&rep.physicalId, n);
    }
    WriteToClient(client, sizeof(xDMXAddInputReply), (char *)&rep);
    return Success;
}

static int ProcDMXRemoveInput(ClientPtr client)
{
    REQUEST(xDMXRemoveInputReq);
    xDMXRemoveInputReply     rep;
    int                      n;
    int                      status = 0;

    REQUEST_SIZE_MATCH(xDMXRemoveInputReq);

    status = dmxRemoveInput(stuff->physicalId);

    if (status) return status;

    rep.type           = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length         = 0;
    rep.status         = status;
    if (client->swapped) {
        swaps(&rep.sequenceNumber, n);
        swapl(&rep.length, n);
        swapl(&rep.status, n);
    }
    WriteToClient(client, sizeof(xDMXRemoveInputReply), (char *)&rep);
    return Success;
}

static int ProcDMXDispatch(ClientPtr client)
{
    REQUEST(xReq);

    switch (stuff->data) {
    case X_DMXQueryVersion:         return ProcDMXQueryVersion(client);
    case X_DMXSync:                 return ProcDMXSync(client);
    case X_DMXForceWindowCreation:  return ProcDMXForceWindowCreation(client);
    case X_DMXGetScreenCount:       return ProcDMXGetScreenCount(client);
    case X_DMXGetScreenAttributes:  return ProcDMXGetScreenAttributes(client);
    case X_DMXChangeScreensAttributes:
        return ProcDMXChangeScreensAttributes(client);
    case X_DMXAddScreen:            return ProcDMXAddScreen(client);
    case X_DMXRemoveScreen:         return ProcDMXRemoveScreen(client);
    case X_DMXGetWindowAttributes:  return ProcDMXGetWindowAttributes(client);
    case X_DMXGetDesktopAttributes: return ProcDMXGetDesktopAttributes(client);
    case X_DMXChangeDesktopAttributes:
        return ProcDMXChangeDesktopAttributes(client);
    case X_DMXGetInputCount:        return ProcDMXGetInputCount(client);
    case X_DMXGetInputAttributes:   return ProcDMXGetInputAttributes(client);
    case X_DMXAddInput:             return ProcDMXAddInput(client);
    case X_DMXRemoveInput:          return ProcDMXRemoveInput(client);
        
    case X_DMXGetScreenInformationDEPRECATED:
    case X_DMXForceWindowCreationDEPRECATED:
    case X_DMXReconfigureScreenDEPRECATED:
        return BadImplementation;

    default:                        return BadRequest;
    }
}

static int SProcDMXQueryVersion(ClientPtr client)
{
    int n;
    REQUEST(xDMXQueryVersionReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXQueryVersionReq);
    return ProcDMXQueryVersion(client);
}

static int SProcDMXSync(ClientPtr client)
{
    int n;
    REQUEST(xDMXSyncReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXSyncReq);
    return ProcDMXSync(client);
}

static int SProcDMXForceWindowCreation(ClientPtr client)
{
    int n;
    REQUEST(xDMXForceWindowCreationReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq);
    swaps(&stuff->window, n);
    return ProcDMXForceWindowCreation(client);
}

static int SProcDMXGetScreenCount(ClientPtr client)
{
    int n;
    REQUEST(xDMXGetScreenCountReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXGetScreenCountReq);
    return ProcDMXGetScreenCount(client);
}

static int SProcDMXGetScreenAttributes(ClientPtr client)
{
    int n;
    REQUEST(xDMXGetScreenAttributesReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq);
    swapl(&stuff->physicalScreen, n);
    return ProcDMXGetScreenAttributes(client);
}

static int SProcDMXChangeScreensAttributes(ClientPtr client)
{
    int n;
    REQUEST(xDMXChangeScreensAttributesReq);

    swaps(&stuff->length, n);
    REQUEST_AT_LEAST_SIZE(xDMXGetScreenAttributesReq);
    swapl(&stuff->screenCount, n);
    swapl(&stuff->maskCount, n);
    SwapRestL(stuff);
    return ProcDMXGetScreenAttributes(client);
}

static int SProcDMXAddScreen(ClientPtr client)
{
    int n;
    int paddedLength;
    REQUEST(xDMXAddScreenReq);

    swaps(&stuff->length, n);
    REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq);
    swapl(&stuff->displayNameLength, n);
    swapl(&stuff->valueMask, n);
    paddedLength = pad_to_int32(stuff->displayNameLength);
    SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4);
    return ProcDMXAddScreen(client);
}

static int SProcDMXRemoveScreen(ClientPtr client)
{
    int n;
    REQUEST(xDMXRemoveScreenReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXRemoveScreenReq);
    swapl(&stuff->physicalScreen, n);
    return ProcDMXRemoveScreen(client);
}

static int SProcDMXGetWindowAttributes(ClientPtr client)
{
    int n;
    REQUEST(xDMXGetWindowAttributesReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq);
    swapl(&stuff->window, n);
    return ProcDMXGetWindowAttributes(client);
}

static int SProcDMXGetDesktopAttributes(ClientPtr client)
{
    int n;
    REQUEST(xDMXGetDesktopAttributesReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq);
    return ProcDMXGetDesktopAttributes(client);
}

static int SProcDMXChangeDesktopAttributes(ClientPtr client)
{
    int n;
    REQUEST(xDMXChangeDesktopAttributesReq);

    swaps(&stuff->length, n);
    REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq);
    swapl(&stuff->valueMask, n);
    SwapRestL(stuff);
    return ProcDMXChangeDesktopAttributes(client);
}

static int SProcDMXGetInputCount(ClientPtr client)
{
    int n;
    REQUEST(xDMXGetInputCountReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXGetInputCountReq);
    return ProcDMXGetInputCount(client);
}

static int SProcDMXGetInputAttributes(ClientPtr client)
{
    int n;
    REQUEST(xDMXGetInputAttributesReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq);
    swapl(&stuff->deviceId, n);
    return ProcDMXGetInputAttributes(client);
}

static int SProcDMXAddInput(ClientPtr client)
{
    int n;
    int paddedLength;
    REQUEST(xDMXAddInputReq);

    swaps(&stuff->length, n);
    REQUEST_AT_LEAST_SIZE(xDMXAddInputReq);
    swapl(&stuff->displayNameLength, n);
    swapl(&stuff->valueMask, n);
    paddedLength = pad_to_int32(stuff->displayNameLength);
    SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4);
    return ProcDMXAddInput(client);
}

static int SProcDMXRemoveInput(ClientPtr client)
{
    int n;
    REQUEST(xDMXRemoveInputReq);

    swaps(&stuff->length, n);
    REQUEST_SIZE_MATCH(xDMXRemoveInputReq);
    swapl(&stuff->physicalId, n);
    return ProcDMXRemoveInput(client);
}

static int SProcDMXDispatch (ClientPtr client)
{
    REQUEST(xReq);

    switch (stuff->data) {
    case X_DMXQueryVersion:         return SProcDMXQueryVersion(client);
    case X_DMXSync:                 return SProcDMXSync(client);
    case X_DMXForceWindowCreation:  return SProcDMXForceWindowCreation(client);
    case X_DMXGetScreenCount:       return SProcDMXGetScreenCount(client);
    case X_DMXGetScreenAttributes:  return SProcDMXGetScreenAttributes(client);
    case X_DMXChangeScreensAttributes:
        return SProcDMXChangeScreensAttributes(client);
    case X_DMXAddScreen:            return SProcDMXAddScreen(client);
    case X_DMXRemoveScreen:         return SProcDMXRemoveScreen(client);
    case X_DMXGetWindowAttributes:  return SProcDMXGetWindowAttributes(client);
    case X_DMXGetDesktopAttributes:
        return SProcDMXGetDesktopAttributes(client);
    case X_DMXChangeDesktopAttributes:
        return SProcDMXChangeDesktopAttributes(client);
    case X_DMXGetInputCount:        return SProcDMXGetInputCount(client);
    case X_DMXGetInputAttributes:   return SProcDMXGetInputAttributes(client);
    case X_DMXAddInput:             return SProcDMXAddInput(client);
    case X_DMXRemoveInput:          return SProcDMXRemoveInput(client);
        
    case X_DMXGetScreenInformationDEPRECATED:
    case X_DMXForceWindowCreationDEPRECATED:
    case X_DMXReconfigureScreenDEPRECATED:
        return BadImplementation;

    default:                        return BadRequest;
    }
}
