Add xinerama support to the vmware video driver. (Better late than never).
authorPhilip Langdale <philipl@fido2.homeip.net>
Wed, 11 Oct 2006 17:57:57 +0000 (10:57 -0700)
committerPhilip Langdale <philipl@fido2.homeip.net>
Wed, 11 Oct 2006 17:57:57 +0000 (10:57 -0700)
With this change, the VMWARE_CTRL extension is updated so that it can
receive topology updates at runtime. I will add some sample client code
separately.

I also intend to add support for a static initial topology defined in
xorg.conf but I haven't got around to it yet due to hating to write
string parsing code.

configure.ac
src/Makefile.am
src/vmware.c
src/vmware.h
src/vmwarectrl.c
src/vmwarectrl.h
src/vmwarectrlproto.h
src/vmwarexinerama.c [new file with mode: 0644]

index 99b996f..37273cd 100644 (file)
@@ -22,7 +22,7 @@
 
 AC_PREREQ(2.57)
 AC_INIT([xf86-video-vmware],
-        10.13.0,
+        10.13.99,
         [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
         xf86-video-vmware)
 
index f940770..b7857b9 100644 (file)
@@ -46,4 +46,5 @@ vmware_drv_la_SOURCES = \
          vmwarexaa.c \
          vmwarectrl.c \
          vmwarectrl.h \
-         vmwarectrlproto.h
+         vmwarectrlproto.h \
+         vmwarexinerama.c
index e08bc38..7f93120 100644 (file)
@@ -82,7 +82,7 @@ char rcsId_vmware[] =
 #define VMWARE_DRIVER_NAME "vmware"
 #define VMWARE_MAJOR_VERSION   10
 #define VMWARE_MINOR_VERSION   13
-#define VMWARE_PATCHLEVEL      0
+#define VMWARE_PATCHLEVEL      99
 #define VMWARE_DRIVER_VERSION \
    (VMWARE_MAJOR_VERSION * 65536 + VMWARE_MINOR_VERSION * 256 + VMWARE_PATCHLEVEL)
 
@@ -164,12 +164,16 @@ static XF86ModuleVersionInfo vmwareVersRec = {
 
 typedef enum {
     OPTION_HW_CURSOR,
-    OPTION_NOACCEL
+    OPTION_NOACCEL,
+    OPTION_XINERAMA,
+    OPTION_STATIC_XINERAMA,
 } VMWAREOpts;
 
 static const OptionInfoRec VMWAREOptions[] = {
     { OPTION_HW_CURSOR, "HWcursor",     OPTV_BOOLEAN,   {0},    FALSE },
     { OPTION_NOACCEL,   "NoAccel",      OPTV_BOOLEAN,   {0},    FALSE },
+    { OPTION_XINERAMA,  "Xinerama",     OPTV_BOOLEAN,   {0},    FALSE },
+    { OPTION_STATIC_XINERAMA, "StaticXinerama", OPTV_BOOLEAN, {0}, FALSE },
     { -1,               NULL,           OPTV_NONE,      {0},    FALSE }
 };
 
@@ -431,6 +435,7 @@ VMWAREPreInit(ScrnInfoPtr pScrn, int flags)
     int i;
     ClockRange* clockRanges;
     IOADDRESS domainIOBase = 0;
+    Bool useXinerama = TRUE;
 
 #ifndef BUILD_FOR_420
     domainIOBase = pScrn->domainIOBase;
@@ -743,6 +748,18 @@ VMWAREPreInit(ScrnInfoPtr pScrn, int flags)
     }
     pScrn->videoRam = pVMWARE->videoRam / 1024;
     pScrn->memPhysBase = pVMWARE->memPhysBase;
+
+    /*
+     * Init xinerama preferences.
+     */
+    useXinerama = xf86ReturnOptValBool(options, OPTION_XINERAMA, TRUE);
+    if (useXinerama && !(pVMWARE->vmwareCapability & SVGA_CAP_MULTIMON)) {
+       useXinerama = FALSE;
+       xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Xinerama is not not supported by "
+                                               "the current virtual hardware\n");
+    }
+    pVMWARE->xineramaStatic = xf86ReturnOptValBool(options, OPTION_STATIC_XINERAMA, FALSE);
+
     xfree(options);
 
     {
@@ -815,6 +832,30 @@ VMWAREPreInit(ScrnInfoPtr pScrn, int flags)
         xf86LoaderReqSymLists(vmwareXaaSymbols, NULL);
     }
 
+    /* Initialise VMWARE_CTRL extension. */
+    VMwareCtrl_ExtInit(pScrn);
+
+    /* Initialise Xinerama extension. */
+    if (useXinerama) {
+       VMwareXinerama_ExtInit(pScrn);
+    }
+
+    if (pVMWARE->xinerama && pVMWARE->xineramaStatic) {
+#if 0
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting up static Xinerama topology.\n");
+      pVMWARE->xineramaState = (VMWAREXineramaPtr)xcalloc(pVMWARE->xineramaNumOutputs,
+                                                          sizeof (VMWAREXineramaRec));
+      if (!pVMWARE->xineramaState) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                    "Failed to initialize VMware Xinerama state.\n");
+      } else {
+         /* XXX: Apply static xinerama topology from config file. */
+      }
+#else
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\"StaticXinerama\" is not supported yet.\n");
+#endif
+    }
+
     return TRUE;
 }
 
@@ -989,6 +1030,33 @@ VMWAREModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
         }
     }
 
+    /*
+     * Update Xinerama info appropriately.
+     */
+    if (pVMWARE->xinerama && !pVMWARE->xineramaStatic) {
+       if (pVMWARE->xineramaNextState) {
+          Xfree(pVMWARE->xineramaState);
+          pVMWARE->xineramaState = pVMWARE->xineramaNextState;
+          pVMWARE->xineramaNumOutputs = pVMWARE->xineramaNextNumOutputs;
+
+          pVMWARE->xineramaNextState = NULL;
+          pVMWARE->xineramaNextNumOutputs = 0;
+       } else {
+          VMWAREXineramaPtr basicState =
+             (VMWAREXineramaPtr)xcalloc(1, sizeof (VMWAREXineramaRec));
+          if (basicState) {
+             basicState->x_org = 0;
+             basicState->y_org = 0;
+             basicState->width = vmwareReg->svga_reg_width;
+             basicState->height = vmwareReg->svga_reg_height;
+
+             Xfree(pVMWARE->xineramaState);
+             pVMWARE->xineramaState = basicState;
+             pVMWARE->xineramaNumOutputs = 1;
+          }
+       }
+    }
+
     return TRUE;
 }
 
@@ -1427,8 +1495,6 @@ VMWAREScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
      */
     pVMWARE->dynMode1 = NULL;
     pVMWARE->dynMode2 = NULL;
-       
-    VMwareCtrl_ExtInit(pScrn);
 
 #if VMWARE_DRIVER_FUNC
     pScrn->DriverFunc = VMWareDriverFunc;
index 4b98ebb..7f138a6 100644 (file)
@@ -14,6 +14,8 @@
 #include "xf86_OSproc.h"
 #include "xf86Resources.h"
 
+#include <X11/extensions/panoramiXproto.h>
+
 #include "compiler.h"          /* inb/outb */
 
 #include "xf86PciInfo.h"       /* pci vendor id */
@@ -52,6 +54,8 @@ typedef struct {
     CARD32 svga_reg_id;
 } VMWARERegRec, *VMWARERegPtr;
 
+typedef xXineramaScreenInfo VMWAREXineramaRec, *VMWAREXineramaPtr;
+
 typedef struct {
     EntityInfoPtr pEnt;
     pciVideoPtr PciInfo;
@@ -138,6 +142,18 @@ typedef struct {
     SVGASurface* curPict;
     int op;
 
+    /*
+     * Xinerama state
+     */
+    Bool xinerama;
+    Bool xineramaStatic;
+
+    VMWAREXineramaPtr xineramaState;
+    unsigned int xineramaNumOutputs;
+
+    VMWAREXineramaPtr xineramaNextState;
+    unsigned int xineramaNextNumOutputs;
+
 } VMWARERec, *VMWAREPtr;
 
 #define VMWAREPTR(p) ((VMWAREPtr)((p)->driverPrivate))
@@ -254,8 +270,10 @@ void vmwareXAACloseScreen(
    ScreenPtr pScreen
    );
 
-/* vmware_ctl.c */
+/* vmwarectrl.c */
 void VMwareCtrl_ExtInit(ScrnInfoPtr pScrn);
 
+/* vmwarexinerama.c */
+void VMwareXinerama_ExtInit(ScrnInfoPtr pScrn);
 
 #endif
index 7d3e564..413e673 100644 (file)
 
 #define NEED_REPLIES
 #define NEED_EVENTS
-#include <X11/X.h>
 #include "dixstruct.h"
 #include "extnsionst.h"
+#include <X11/X.h>
+#include <X11/extensions/panoramiXproto.h>
 
 #include "vmware.h"
 #include "vmwarectrlproto.h"
@@ -216,6 +217,119 @@ VMwareCtrlSetRes(ClientPtr client)
 /*
  *----------------------------------------------------------------------------
  *
+ * VMwareCtrlDoSetTopology --
+ *
+ *      Set the custom topology and set a dynamic mode to the bounding box
+ *      of the passed topology.
+ *
+ * Results:
+ *      TRUE on success, FALSE otherwise.
+ *
+ * Side effects:
+ *      One dynamic mode and the pending xinerama state will be updated if
+ *      successful.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VMwareCtrlDoSetTopology(ScrnInfoPtr pScrn,
+                        xXineramaScreenInfo *extents,
+                        unsigned long number)
+{
+   VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
+
+   if (pVMWARE && pVMWARE->xinerama) { 
+      VMWAREXineramaPtr xineramaState;
+      short maxX = 0;
+      short maxY = 0;
+      size_t i;
+
+      for (i = 0; i < number; i++) {
+         maxX = MAX(maxX, extents[i].x_org + extents[i].width);
+         maxY = MAX(maxY, extents[i].y_org + extents[i].height);
+      }
+
+      xineramaState = (VMWAREXineramaPtr)xcalloc(number, sizeof(VMWAREXineramaRec));
+      if (xineramaState) {
+         memcpy(xineramaState, extents, number * sizeof (VMWAREXineramaRec));
+
+         Xfree(pVMWARE->xineramaNextState);
+         pVMWARE->xineramaNextState = xineramaState;
+         pVMWARE->xineramaNextNumOutputs = number;
+
+         return VMwareCtrlDoSetRes(pScrn, maxX, maxY);
+      } else {
+         return FALSE;
+      }
+   } else {
+      return FALSE;
+   }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrlSetTopology --
+ *
+ *      Implementation of SetTopology command handler. Initialises and sends a
+ *      reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareCtrlSetTopology(ClientPtr client)
+{
+   REQUEST(xVMwareCtrlSetTopologyReq);
+   xVMwareCtrlSetTopologyReply rep = { 0, };
+   ScrnInfoPtr pScrn;
+   ExtensionEntry *ext;
+   register int n;
+   xXineramaScreenInfo *extents;
+   size_t i;
+
+   REQUEST_AT_LEAST_SIZE(xVMwareCtrlSetTopologyReq);
+
+   if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
+      return BadMatch;
+   }
+
+   pScrn = ext->extPrivate;
+   if (pScrn->scrnIndex != stuff->screen) {
+      return BadMatch;
+   }
+
+   extents = (xXineramaScreenInfo *)(stuff + 1);
+   if (!VMwareCtrlDoSetTopology(pScrn, extents, stuff->number)) {
+      return BadValue;
+   }
+
+   rep.type = X_Reply;
+   rep.length = (sizeof(xVMwareCtrlSetTopologyReply) - sizeof(xGenericReply)) >> 2;
+   rep.sequenceNumber = client->sequence;
+   rep.screen = stuff->screen;
+   if (client->swapped) {
+      swaps(&rep.sequenceNumber, n);
+      swapl(&rep.length, n);
+      swapl(&rep.screen, n);
+   }
+   WriteToClient(client, sizeof(xVMwareCtrlSetTopologyReply), (char *)&rep);
+
+   return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
  * VMwareCtrlDispatch --
  *
  *      Dispatcher for VMWARE_CTRL commands. Calls the correct handler for
@@ -240,6 +354,8 @@ VMwareCtrlDispatch(ClientPtr client)
       return VMwareCtrlQueryVersion(client);
    case X_VMwareCtrlSetRes:
       return VMwareCtrlSetRes(client);
+   case X_VMwareCtrlSetTopology:
+      return VMwareCtrlSetTopology(client);
    }
    return BadRequest;
 }
@@ -313,6 +429,41 @@ SVMwareCtrlSetRes(ClientPtr client)
 /*
  *----------------------------------------------------------------------------
  *
+ * SVMwareCtrlSetTopology --
+ *
+ *      Wrapper for SetTopology handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareCtrlSetTopology(ClientPtr client)
+{
+   register int n;
+
+   REQUEST(xVMwareCtrlSetTopologyReq);
+   REQUEST_SIZE_MATCH(xVMwareCtrlSetTopologyReq);
+
+   swaps(&stuff->length, n);
+   swapl(&stuff->screen, n);
+   swapl(&stuff->number, n);
+   /* Each extent is a struct of shorts. */
+   SwapRestS(stuff);
+
+   return VMwareCtrlSetTopology(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
  * SVMwareCtrlDispatch --
  *
  *      Wrapper for dispatcher that handles input from other-endian clients.
@@ -336,6 +487,8 @@ SVMwareCtrlDispatch(ClientPtr client)
       return SVMwareCtrlQueryVersion(client);
    case X_VMwareCtrlSetRes:
       return SVMwareCtrlSetRes(client);
+   case X_VMwareCtrlSetTopology:
+      return SVMwareCtrlSetTopology(client);
    }
    return BadRequest;
 }
index f264494..a671ae1 100644 (file)
 #define VMWARE_CTRL_PROTOCOL_NAME "VMWARE_CTRL"
 
 #define VMWARE_CTRL_MAJOR_VERSION 0
-#define VMWARE_CTRL_MINOR_VERSION 1
+#define VMWARE_CTRL_MINOR_VERSION 2
 
 #define X_VMwareCtrlQueryVersion 0
 #define X_VMwareCtrlSetRes 1
+#define X_VMwareCtrlSetTopology 2
 
 #endif /* _VMWARE_CTRL_H_ */
index ecff744..76f157f 100644 (file)
@@ -44,6 +44,8 @@
  * Requests and Replies
  */
 
+/* Version 0.1 definitions. */
+
 typedef struct {
    CARD8  reqType;           /* always X_VMwareCtrlReqCode */
    CARD8  VMwareCtrlReqType; /* always X_VMwareCtrlQueryVersion */
@@ -85,11 +87,36 @@ typedef struct {
    CARD32 screen B32;
    CARD32 x B32;
    CARD32 y B32;
-   CARD32  pad2 B32;
-   CARD32  pad3 B32;
-   CARD32  pad4 B32;
+   CARD32 pad2 B32;
+   CARD32 pad3 B32;
+   CARD32 pad4 B32;
 } xVMwareCtrlSetResReply;
 #define sz_xVMwareCtrlSetResReply 32
 
+/* Version 0.2 definitions. */
+
+typedef struct {
+   CARD8  reqType;           /* always X_VMwareCtrlReqCode */
+   CARD8  VMwareCtrlReqType; /* always X_VMwareCtrlSetTopology */
+   CARD16 length B16;
+   CARD32 screen B32;
+   CARD32 number B32;
+   CARD32 pad1   B32;
+} xVMwareCtrlSetTopologyReq;
+#define sz_xVMwareCtrlSetTopologyReq 16
+
+typedef struct {
+   BYTE   type; /* X_Reply */
+   BYTE   pad1;
+   CARD16 sequenceNumber B16;
+   CARD32 length B32;
+   CARD32 screen B32;
+   CARD32 pad2   B32;
+   CARD32 pad3   B32;
+   CARD32 pad4   B32;
+   CARD32 pad5   B32;
+   CARD32 pad6   B32;
+} xVMwareCtrlSetTopologyReply;
+#define sz_xVMwareCtrlSetTopologyReply 32
 
 #endif /* _VMWARE_CTRL_PROTO_H_ */
diff --git a/src/vmwarexinerama.c b/src/vmwarexinerama.c
new file mode 100644 (file)
index 0000000..fe137ad
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * Copyright 2006 by VMware, Inc.
+ *
+ * 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
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmwarexinerama.c --
+ *
+ *      The implementation of the Xinerama protocol extension.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define NEED_REPLIES
+#define NEED_EVENTS
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include <X11/X.h>
+#include <X11/extensions/panoramiXproto.h>
+
+#include "vmware.h"
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareXineramaQueryVersion --
+ *
+ *      Implementation of QueryVersion command handler. Initialises and
+ *      sends a reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareXineramaQueryVersion(ClientPtr client)
+{
+    xPanoramiXQueryVersionReply          rep;
+    register int                 n;
+
+    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.majorVersion = 1;
+    rep.minorVersion = 0;
+    if(client->swapped) {
+        swaps(&rep.sequenceNumber, n);
+        swapl(&rep.length, n);
+        swaps(&rep.majorVersion, n);
+        swaps(&rep.minorVersion, n);
+    }
+    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
+    return (client->noClientException);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareXineramaGetState --
+ *
+ *      Implementation of GetState command handler. Initialises and
+ *      sends a reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareXineramaGetState(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetStateReq);
+    WindowPtr                  pWin;
+    xPanoramiXGetStateReply    rep;
+    register int               n;
+    ExtensionEntry *ext;
+    ScrnInfoPtr pScrn;
+    VMWAREPtr pVMWARE;
+
+    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
+    pWin = LookupWindow(stuff->window, client);
+    if(!pWin) return BadWindow;
+
+    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
+       return BadMatch;
+    }
+    pScrn = ext->extPrivate;
+    pVMWARE = VMWAREPTR(pScrn);
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.state = pVMWARE->xinerama;
+    if(client->swapped) {
+       swaps (&rep.sequenceNumber, n);
+       swapl (&rep.length, n);
+       swaps (&rep.state, n);
+    }
+    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
+    return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareXineramaGetScreenCount --
+ *
+ *      Implementation of GetScreenCount command handler. Initialises and
+ *      sends a reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareXineramaGetScreenCount(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetScreenCountReq);
+    WindowPtr                          pWin;
+    xPanoramiXGetScreenCountReply      rep;
+    register int                       n;
+    ExtensionEntry *ext;
+    ScrnInfoPtr pScrn;
+    VMWAREPtr pVMWARE;
+
+    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
+    pWin = LookupWindow(stuff->window, client);
+    if(!pWin) return BadWindow;
+
+    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
+       return BadMatch;
+    }
+    pScrn = ext->extPrivate;
+    pVMWARE = VMWAREPTR(pScrn);
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.ScreenCount = pVMWARE->xineramaNumOutputs;
+    if(client->swapped) {
+       swaps(&rep.sequenceNumber, n);
+       swapl(&rep.length, n);
+       swaps(&rep.ScreenCount, n);
+    }
+    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
+    return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareXineramaGetScreenSize --
+ *
+ *      Implementation of GetScreenSize command handler. Initialises and
+ *      sends a reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareXineramaGetScreenSize(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetScreenSizeReq);
+    WindowPtr                          pWin;
+    xPanoramiXGetScreenSizeReply       rep;
+    register int                       n;
+    ExtensionEntry *ext;
+    ScrnInfoPtr pScrn;
+    VMWAREPtr pVMWARE;
+
+    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
+    pWin = LookupWindow (stuff->window, client);
+    if(!pWin)  return BadWindow;
+
+    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
+       return BadMatch;
+    }
+    pScrn = ext->extPrivate;
+    pVMWARE = VMWAREPTR(pScrn);
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.width  = pVMWARE->xineramaState[stuff->screen].width;
+    rep.height  = pVMWARE->xineramaState[stuff->screen].height;
+    if(client->swapped) {
+       swaps(&rep.sequenceNumber, n);
+       swapl(&rep.length, n);
+       swaps(&rep.width, n);
+       swaps(&rep.height, n);
+    }
+    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
+    return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareXineramaIsActive --
+ *
+ *      Implementation of IsActive command handler. Initialises and
+ *      sends a reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareXineramaIsActive(ClientPtr client)
+{
+    xXineramaIsActiveReply     rep;
+    ExtensionEntry *ext;
+    ScrnInfoPtr pScrn;
+    VMWAREPtr pVMWARE;
+
+    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
+
+    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
+       return BadMatch;
+    }
+    pScrn = ext->extPrivate;
+    pVMWARE = VMWAREPTR(pScrn);
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    rep.state = pVMWARE->xinerama;
+    if(client->swapped) {
+       register int n;
+       swaps(&rep.sequenceNumber, n);
+       swapl(&rep.length, n);
+       swapl(&rep.state, n);
+    }
+    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
+    return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareXineramaQueryScreens --
+ *
+ *      Implementation of QueryScreens command handler. Initialises and
+ *      sends a reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareXineramaQueryScreens(ClientPtr client)
+{
+    xXineramaQueryScreensReply rep;
+    ExtensionEntry *ext;
+    ScrnInfoPtr pScrn;
+    VMWAREPtr pVMWARE;
+
+    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
+
+    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
+       return BadMatch;
+    }
+    pScrn = ext->extPrivate;
+    pVMWARE = VMWAREPTR(pScrn);
+
+    rep.type = X_Reply;
+    rep.sequenceNumber = client->sequence;
+    rep.number = pVMWARE->xinerama ? pVMWARE->xineramaNumOutputs : 0;
+    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
+    if(client->swapped) {
+       register int n;
+       swaps(&rep.sequenceNumber, n);
+       swapl(&rep.length, n);
+       swapl(&rep.number, n);
+    }
+    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
+
+    if(pVMWARE->xinerama) {
+       xXineramaScreenInfo scratch;
+       int i;
+
+       for(i = 0; i < pVMWARE->xineramaNumOutputs; i++) {
+         scratch.x_org  = pVMWARE->xineramaState[i].x_org;
+         scratch.y_org  = pVMWARE->xineramaState[i].y_org;
+         scratch.width  = pVMWARE->xineramaState[i].width;
+         scratch.height = pVMWARE->xineramaState[i].height;
+         if(client->swapped) {
+            register int n;
+            swaps(&scratch.x_org, n);
+            swaps(&scratch.y_org, n);
+            swaps(&scratch.width, n);
+            swaps(&scratch.height, n);
+         }
+         WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
+       }
+    }
+
+    return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareXineramaDispatch --
+ *
+ *      Dispatcher for Xinerama commands. Calls the correct handler for
+ *      each command type.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of individual command handlers.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareXineramaDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+    switch (stuff->data) {
+       case X_PanoramiXQueryVersion:
+            return VMwareXineramaQueryVersion(client);
+       case X_PanoramiXGetState:
+            return VMwareXineramaGetState(client);
+       case X_PanoramiXGetScreenCount:
+            return VMwareXineramaGetScreenCount(client);
+       case X_PanoramiXGetScreenSize:
+            return VMwareXineramaGetScreenSize(client);
+       case X_XineramaIsActive:
+            return VMwareXineramaIsActive(client);
+       case X_XineramaQueryScreens:
+            return VMwareXineramaQueryScreens(client);
+    }
+    return BadRequest;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareXineramaQueryVersion --
+ *
+ *      Wrapper for QueryVersion handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareXineramaQueryVersion (ClientPtr client)
+{
+    REQUEST(xPanoramiXQueryVersionReq);
+    register int n;
+    swaps(&stuff->length,n);
+    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
+    return VMwareXineramaQueryVersion(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareXineramaGetState --
+ *
+ *      Wrapper for GetState handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareXineramaGetState(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetStateReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
+    return VMwareXineramaGetState(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareXineramaGetScreenCount --
+ *
+ *      Wrapper for GetScreenCount handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareXineramaGetScreenCount(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetScreenCountReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
+    return VMwareXineramaGetScreenCount(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareXineramaGetScreenSize --
+ *
+ *      Wrapper for GetScreenSize handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareXineramaGetScreenSize(ClientPtr client)
+{
+    REQUEST(xPanoramiXGetScreenSizeReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
+    return VMwareXineramaGetScreenSize(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareXineramaIsActive --
+ *
+ *      Wrapper for IsActive handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareXineramaIsActive(ClientPtr client)
+{
+    REQUEST(xXineramaIsActiveReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
+    return VMwareXineramaIsActive(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareXineramaQueryScreens --
+ *
+ *      Wrapper for QueryScreens handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareXineramaQueryScreens(ClientPtr client)
+{
+    REQUEST(xXineramaQueryScreensReq);
+    register int n;
+    swaps (&stuff->length, n);
+    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
+    return VMwareXineramaQueryScreens(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareXineramaDispatch --
+ *
+ *      Wrapper for dispatcher that handles input from other-endian clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of individual command handlers.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareXineramaDispatch(ClientPtr client)
+{
+    REQUEST(xReq);
+    switch (stuff->data) {
+       case X_PanoramiXQueryVersion:
+            return SVMwareXineramaQueryVersion(client);
+       case X_PanoramiXGetState:
+            return SVMwareXineramaGetState(client);
+       case X_PanoramiXGetScreenCount:
+            return SVMwareXineramaGetScreenCount(client);
+       case X_PanoramiXGetScreenSize:
+            return SVMwareXineramaGetScreenSize(client);
+       case X_XineramaIsActive:
+            return SVMwareXineramaIsActive(client);
+       case X_XineramaQueryScreens:
+            return SVMwareXineramaQueryScreens(client);
+    }
+    return BadRequest;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareXineramaResetProc --
+ *
+ *      Cleanup handler called when the extension is removed.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VMwareXineramaResetProc(ExtensionEntry* extEntry)
+{
+    /* Called by CloseDownExtensions() */
+
+   ScrnInfoPtr pScrn = extEntry->extPrivate;
+   VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
+
+   if (pVMWARE->xineramaState) {
+      Xfree(pVMWARE->xineramaState);
+      pVMWARE->xineramaState = NULL;
+      pVMWARE->xineramaNumOutputs = 0;
+      pVMWARE->xinerama = FALSE;
+   }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrl_ExitInit --
+ *
+ *      Initialiser for the Xinerama protocol extension.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Protocol extension will be registered if successful.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+VMwareXinerama_ExtInit(ScrnInfoPtr pScrn)
+{
+   ExtensionEntry *myext;
+   VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
+
+#ifdef PANORAMIX
+   if(!noPanoramiXExtension) {
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                 "Built-in Xinerama active, not initializing VMware Xinerama\n");
+      pVMWARE->xinerama = FALSE;
+      return;
+   }
+#endif
+
+   if (!(myext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
+      if (!(myext = AddExtension(PANORAMIX_PROTOCOL_NAME, 0, 0,
+                                 VMwareXineramaDispatch,
+                                 SVMwareXineramaDispatch,
+                                 VMwareXineramaResetProc,
+                                 StandardMinorOpcode))) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                    "Failed to add VMware Xinerama extension.\n");
+         return;
+      }
+
+      pVMWARE->xinerama = TRUE;
+
+      myext->extPrivate = pScrn;
+
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                 "Initialized VMware Xinerama extension.\n");
+   }
+}