summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/vmware.c56
-rw-r--r--src/vmware.h8
-rw-r--r--src/vmwarectrl.c50
3 files changed, 105 insertions, 9 deletions
diff --git a/src/vmware.c b/src/vmware.c
index 069cf2c..5275441 100644
--- a/src/vmware.c
+++ b/src/vmware.c
@@ -306,7 +306,7 @@ vmwareSendSVGACmdUpdate(VMWAREPtr pVMWARE, BoxPtr pBB)
vmwareWriteWordToFIFO(pVMWARE, pBB->y2 - pBB->y1);
}
-static void
+void
vmwareSendSVGACmdUpdateFullScreen(VMWAREPtr pVMWARE)
{
BoxRec BB;
@@ -1163,8 +1163,40 @@ VMWAREModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool rebuildPixmap)
vgaHWProtect(pScrn, FALSE);
/*
- * XXX -- If we want to check that we got the mode we asked for, this
- * would be a good place.
+ * Push the new Xinerama state to X clients and the hardware,
+ * synchronously with the mode change. Note that this must happen
+ * AFTER we write the new width and height to the hardware
+ * registers, since updating the WIDTH and HEIGHT registers will
+ * reset the device's multimon topology.
+ */
+ vmwareNextXineramaState(pVMWARE);
+
+ return TRUE;
+}
+
+void
+vmwareNextXineramaState(VMWAREPtr pVMWARE)
+{
+ VMWARERegPtr vmwareReg = &pVMWARE->ModeReg;
+
+ /*
+ * Switch to the next Xinerama state (from pVMWARE->xineramaNextState).
+ *
+ * This new state will be available to X clients via the Xinerama
+ * extension, and we push the new state to the virtual hardware,
+ * in order to configure a number of virtual monitors within the
+ * device's framebuffer.
+ *
+ * This function can be called at any time, but it should usually be
+ * called just after a mode switch. This is for two reasons:
+ *
+ * 1) We don't want X clients to see a Xinerama topology and a video
+ * mode that are inconsistent with each other, so we'd like to switch
+ * both at the same time.
+ *
+ * 2) We must set the host's display topology registers after setting
+ * the new video mode, since writes to WIDTH/HEIGHT will reset the
+ * hardware display topology.
*/
/*
@@ -1178,7 +1210,14 @@ VMWAREModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool rebuildPixmap)
pVMWARE->xineramaNextState = NULL;
pVMWARE->xineramaNextNumOutputs = 0;
+
} else {
+ /*
+ * There is no next state pending. Switch back to
+ * single-monitor mode. This is necessary for resetting the
+ * Xinerama state if we get a mode change which doesn't
+ * follow a VMwareCtrlDoSetTopology call.
+ */
VMWAREXineramaPtr basicState =
(VMWAREXineramaPtr)xcalloc(1, sizeof (VMWAREXineramaRec));
if (basicState) {
@@ -1195,7 +1234,8 @@ VMWAREModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool rebuildPixmap)
}
/*
- * Update host's view of guest topology.
+ * Update host's view of guest topology. This tells the device
+ * how we're carving up its framebuffer into virtual screens.
*/
if (pVMWARE->vmwareCapability & SVGA_CAP_DISPLAY_TOPOLOGY) {
if (pVMWARE->xinerama) {
@@ -1223,14 +1263,13 @@ VMWAREModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool rebuildPixmap)
vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_IS_PRIMARY, TRUE);
vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_POSITION_X, 0);
vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_POSITION_Y, 0);
- vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_WIDTH, mode->HDisplay);
- vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_HEIGHT, mode->VDisplay);
+ vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_WIDTH, vmwareReg->svga_reg_width);
+ vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_HEIGHT, vmwareReg->svga_reg_height);
}
+ /* Done. */
vmwareWriteReg(pVMWARE, SVGA_REG_DISPLAY_ID, SVGA_INVALID_DISPLAY_ID);
}
-
- return TRUE;
}
static void
@@ -1436,6 +1475,7 @@ VMWAREAddDisplayMode(ScrnInfoPtr pScrn,
DisplayModeRec *mode;
mode = xalloc(sizeof(DisplayModeRec));
+ memset(mode, 0, sizeof *mode);
mode->name = xalloc(strlen(name) + 1);
strcpy(mode->name, name);
diff --git a/src/vmware.h b/src/vmware.h
index b906ff2..a3502dd 100644
--- a/src/vmware.h
+++ b/src/vmware.h
@@ -245,6 +245,10 @@ void vmwareSendSVGACmdUpdate(
VMWAREPtr pVMWARE, BoxPtr pBB
);
+void vmwareSendSVGACmdUpdateFullScreen(
+ VMWAREPtr pVMWARE
+ );
+
DisplayModeRec *VMWAREAddDisplayMode(
ScrnInfoPtr pScrn,
const char *name,
@@ -257,6 +261,10 @@ Bool vmwareIsRegionEqual(
const RegionPtr reg2
);
+void vmwareNextXineramaState(
+ VMWAREPtr pVMWARE
+ );
+
/* vmwarecurs.c */
Bool vmwareCursorInit(
ScreenPtr pScr
diff --git a/src/vmwarectrl.c b/src/vmwarectrl.c
index 634b9ca..d9ceaa4 100644
--- a/src/vmwarectrl.c
+++ b/src/vmwarectrl.c
@@ -282,11 +282,59 @@ VMwareCtrlDoSetTopology(ScrnInfoPtr pScrn,
if (xineramaState) {
memcpy(xineramaState, extents, number * sizeof (VMWAREXineramaRec));
+ /*
+ * Make this the new pending Xinerama state. Normally we'll
+ * wait until the next mode switch in order to synchronously
+ * push this state out to X clients and the virtual hardware.
+ *
+ * However, if we're already in the right video mode, there
+ * will be no mode change. In this case, push it out
+ * immediately.
+ */
xfree(pVMWARE->xineramaNextState);
pVMWARE->xineramaNextState = xineramaState;
pVMWARE->xineramaNextNumOutputs = number;
- return VMwareCtrlDoSetRes(pScrn, maxX, maxY, FALSE);
+ if (maxX == pVMWARE->ModeReg.svga_reg_width &&
+ maxY == pVMWARE->ModeReg.svga_reg_height) {
+
+ /*
+ * XXX:
+ *
+ * There are problems with trying to set a Xinerama state
+ * without a mode switch. The biggest one is that
+ * applications typically won't notice a topology change
+ * that occurs without a mode switch. If you run "xdpyinfo
+ * -ext XINERAMA" after one such topology change, it will
+ * report the new data, but apps (like the GNOME Panel)
+ * will not notice until the next mode change.
+ *
+ * I don't think there's any good solution to this... as
+ * far as I know, even on a non-virtualized machine
+ * there's no way for an app to find out if the Xinerama
+ * opology changes without a resolution change also
+ * occurring. There might be some cheats we can take, like
+ * swithcing to a new mode with the same resolution and a
+ * different (fake) refresh rate, or temporarily switching
+ * to an intermediate mode. Ick.
+ *
+ * The other annoyance here is that when we reprogram the
+ * SVGA device's monitor topology registers, it may
+ * rearrange those monitors on the host's screen, but they
+ * will still have the old contents. This might be
+ * correct, but it isn't guaranteed to match what's on X's
+ * framebuffer at the moment. So we'll send a
+ * full-framebuffer update rect afterwards.
+ */
+
+ vmwareNextXineramaState(pVMWARE);
+ vmwareSendSVGACmdUpdateFullScreen(pVMWARE);
+
+ return TRUE;
+ } else {
+ return VMwareCtrlDoSetRes(pScrn, maxX, maxY, FALSE);
+ }
+
} else {
return FALSE;
}