Patch for multiple monitors

Harold L Hunt II huntharo@msu.edu
Tue Apr 1 00:00:00 GMT 2003


Nick,

Wow!  I like it alot!

I am currently trying to get a build of Kensuke's latest multiwindow 
patch posted and a patch to xwinclip to handle the -display parameter.  
Once I get those done I will start merging your patch.  Or, I may merge 
them both at once, but it would probably be wiser to wait so we have two 
versions to assign bug blame :)

Thanks for the patch,

Harold

Nick Crabtree wrote:

Hi,

I attach a patch for multiple monitors, diffed against
xwin-20021107-0015. I have added a command-line flag -multiplemonitors
which activates the extra code.

This works on my machine in both windowed and rootless modes for engines
1, 2 and 4. It does not work in fullscreen mode because the defaults for
the fullscreen dimensions are calculated before the command line
parameters are parsed (as far as I could figure out).

It should be possible to make this behaviour the default (SM_CXSCREEN ==
SM_CXVIRTUALSCREEN etc. if there is only one monitor), which would
remove many of the if {} else {} blocks, and also might make fullscreen
mode work

My machine is running Windows 2000. Both my graphics cards are set at
1600x1200 32bit colour. It's great - I'm running KDE in rootless mode,
and I get the kicker across the bottom of both monitors, and I can drag
X windows from one monitor to the other ...

Comments?

Nick

diff -uw ./InitOutput.c
../../x-devel/build/opt/programs/Xserver/hw/xwin/InitOutput.c
--- ./InitOutput.c	2002-11-07 05:21:18.000000000 +0000
+++ ../../x-devel/build/opt/programs/Xserver/hw/xwin/InitOutput.c
2003-01-09 16:51:10.000000000 +0000
@@ -114,7 +114,8 @@
  /* Zero the memory used for storing the screen info */
  ZeroMemory (g_ScreenInfo, MAXSCREENS * sizeof (winScreenInfo));

-  /* Get default width and height */
+  /* Get default width and height. These will just be for the primary
+     monitor in the case that we have multiple monitors. */
  dwWidth = GetSystemMetrics (SM_CXSCREEN);
  dwHeight = GetSystemMetrics (SM_CYSCREEN);

@@ -139,6 +140,7 @@
      g_ScreenInfo[i].fFullScreen = FALSE;
      g_ScreenInfo[i].fDecoration = TRUE;
      g_ScreenInfo[i].fRootless = FALSE;
+      g_ScreenInfo[i].fMultiplemonitors = FALSE;
      g_ScreenInfo[i].fLessPointer = FALSE;
      g_ScreenInfo[i].fScrollbars = FALSE;
      g_ScreenInfo[i].iE3BTimeout = WIN_E3B_OFF;
@@ -303,6 +305,10 @@
  ErrorF ("-rootless\n"
	  "\tEXPERIMENTAL: Run the server in pseudo-rootless mode.\n");

+  ErrorF ("-multiplemonitors\n"
+	  "\tEXPERIMENTAL: Use the entire virtual screen if multiple\n"
+	  "\tmonitors are present.\n");
+
  ErrorF ("-scrollbars\n"
	  "\tIn windowed mode, allow screens bigger than the Windows
desktop.\n"
	  "\tMoreover, if the window has decorations, one can now
resize\n"
@@ -653,6 +659,32 @@
    }

  /*
+   * Look for the '-multiplemonitors' argument
+   */
+  if (strcmp (argv[i], "-multiplemonitors") == 0)
+    {
+      /* Is this parameter attached to a screen or is it global? */
+      if (-1 == g_iLastScreen)
+	{
+	  int			j;
+
+	  /* Parameter is for all screens */
+	  for (j = 0; j < MAXSCREENS; j++)
+	    {
+	      g_ScreenInfo[j].fMultiplemonitors = TRUE;
+	    }
+	}
+      else
+	{
+	  /* Parameter is for a single screen */
+	  g_ScreenInfo[g_iLastScreen].fMultiplemonitors = TRUE;
+	}
+
+      /* Indicate that we have processed this argument */
+      return 1;
+    }
+
+  /*
   * Look for the '-scrollbars' argument
   */
  if (strcmp (argv[i], "-scrollbars") == 0)
diff -uw ./win.h ../../x-devel/build/opt/programs/Xserver/hw/xwin/win.h
--- ./win.h	2002-11-07 05:33:17.000000000 +0000
+++ ../../x-devel/build/opt/programs/Xserver/hw/xwin/win.h
2003-01-09 16:51:38.000000000 +0000
@@ -390,6 +390,7 @@
  Bool			fFullScreen;
  Bool			fDecoration;
  Bool			fRootless;
+  Bool                  fMultiplemonitors;
  Bool			fLessPointer;
  Bool			fScrollbars;
  int			iE3BTimeout;
diff -uw ./wincreatewnd.c
../../x-devel/build/opt/programs/Xserver/hw/xwin/wincreatewnd.c
--- ./wincreatewnd.c	2002-10-19 04:56:52.000000000 +0100
+++ ../../x-devel/build/opt/programs/Xserver/hw/xwin/wincreatewnd.c
2003-01-10 15:11:26.000000000 +0000
@@ -31,16 +31,17 @@

#include "win.h"
#include "shellapi.h"

/*
 * Local function prototypes
 */

static Bool
+winGetWorkArea (RECT *prcWorkArea, winScreenInfo *pScreenInfo);
+static Bool
winAdjustForAutoHide (RECT *prcWorkArea);

-
/*
 * Create a full screen window
 */
@@ -155,7 +156,7 @@
  RegisterClass (&wc);

  /* Get size of work area */
-  SystemParametersInfo (SPI_GETWORKAREA, 0, &rcWorkArea, 0);
+  winGetWorkArea (&rcWorkArea, pScreenInfo);

  /* Adjust for auto-hide taskbars */
  winAdjustForAutoHide (&rcWorkArea);
@@ -206,10 +207,18 @@
	   * In this case we have to ignore the requested width and
height
	   * and instead use the largest possible window that we can.
	   */
+	  if (pScreenInfo->fMultiplemonitors)
+	    {
+	      iWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN);
+	      iHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+	    }
+	  else
+	    {
	  iWidth = GetSystemMetrics (SM_CXSCREEN);
	  iHeight = GetSystemMetrics (SM_CYSCREEN);
	}
    }
+    }
  else
    {
      /* By default, we are creating a window that is as large as
possible */
@@ -217,6 +226,12 @@
      ErrorF ("winCreateBoundingWindowWindowed - User did not give "
	      "height and width\n");
#endif
+      /* Defaults are wrong if we have multiple monitors */
+      if (pScreenInfo->fMultiplemonitors)
+	{
+	  iWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN);
+	  iHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+	}
    }

  /* Clean up the scrollbars flag, if necessary */
@@ -368,6 +383,59 @@


/*
+ * Find the work area of all attached monitors
+ */
+static Bool
+winGetWorkArea (RECT *prcWorkArea, winScreenInfo *pScreenInfo)
+{
+  /* SPI_GETWORKAREA only gets the work area of the primary screen. */
+  SystemParametersInfo (SPI_GETWORKAREA, 0, prcWorkArea, 0);
+  if (pScreenInfo->fMultiplemonitors)
+    {
+      int iPrimaryWidth, iPrimaryHeight, iWidth, iHeight;
+      int iLeft, iTop, iPrimaryNonWorkAreaWidth,
iPrimaryNonWorkAreaHeight;
+      
+      ErrorF ("winGetWorkArea - Original WorkArea: %d %d %d %d\n",
+	      prcWorkArea->top, prcWorkArea->left,
+	      prcWorkArea->bottom, prcWorkArea->right);
+      /* Get info on full virtual screen */
+      iWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN);
+      iHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+      ErrorF("winGetWorkArea - Virtual screen is %d x %d\n", iWidth,
iHeight);
+      iLeft = GetSystemMetrics (SM_XVIRTUALSCREEN);
+      iTop = GetSystemMetrics (SM_YVIRTUALSCREEN);
+      ErrorF("winGetWorkArea - Virtual screen origin is %d, %d\n",
iLeft, iTop);
+
+      /* Get info on primary screen */
+      iPrimaryWidth = GetSystemMetrics (SM_CXSCREEN);
+      iPrimaryHeight = GetSystemMetrics (SM_CYSCREEN);
+      ErrorF("winGetWorkArea - Primary screen is %d x %d\n",
iPrimaryWidth, iPrimaryHeight);
+
+      /* Work out how much of the primary screen we aren't using */
+      iPrimaryNonWorkAreaWidth = iPrimaryWidth - (prcWorkArea->right -
prcWorkArea->left);
+      iPrimaryNonWorkAreaHeight = iPrimaryHeight - (prcWorkArea->bottom
- prcWorkArea->top);
+
+      /* Update the rectangle to include all monitors */
+      if (iLeft < 0) 
+	{
+	  prcWorkArea->left = iLeft;
+	}
+      if (iTop < 0) 
+	{
+	  prcWorkArea->top = iTop;
+	}
+      prcWorkArea->right = prcWorkArea->left + iWidth -
iPrimaryNonWorkAreaWidth;
+      prcWorkArea->bottom = prcWorkArea->top + iHeight -
iPrimaryNonWorkAreaHeight;
+	
+      ErrorF ("winGetWorkArea - Adjusted WorkArea for multiple
monitors: %d %d %d %d\n",
+	      prcWorkArea->top, prcWorkArea->left,
+	      prcWorkArea->bottom, prcWorkArea->right);
+    }
+  return TRUE;
+}
+
+
+/*
 * Adjust the client area so that any auto-hide toolbars
 * will work correctly.
 */
diff -uw ./winscrinit.c
../../x-devel/build/opt/programs/Xserver/hw/xwin/winscrinit.c
--- ./winscrinit.c	2002-11-07 05:21:18.000000000 +0000
+++ ../../x-devel/build/opt/programs/Xserver/hw/xwin/winscrinit.c
2003-01-10 09:27:45.000000000 +0000
@@ -113,6 +113,16 @@
#endif
    }

+  /* Check all monitors have the same display depth if we are using
+     multiple monitors */
+  if (pScreenInfo->fMultiplemonitors 
+      && ! GetSystemMetrics (SM_SAMEDISPLAYFORMAT))
+    {
+      ErrorF ("Monitors do not all have same pixel format / display
depth.\n"
+	      "Using primary display only.\n");
+      pScreenInfo->fMultiplemonitors = FALSE;
+    }
+  
  /* Create display window */
  if (!(*pScreenPriv->pwinCreateBoundingWindow) (pScreen))
    {
@@ -123,8 +133,28 @@

  /* Store the initial height, width, and depth of the display */
  hdc = GetDC (pScreenPriv->hwndScreen);
+  /* Are we using multiple monitors? */
+  if (pScreenInfo->fMultiplemonitors)
+    {
+      pScreenPriv->dwLastWindowsWidth = GetSystemMetrics
(SM_CXVIRTUALSCREEN);
+      pScreenPriv->dwLastWindowsHeight = GetSystemMetrics
(SM_CYVIRTUALSCREEN);
+      /* In this case, some of the defaults set in
+	 winInitializeDefaultScreens() are not correct ... */
+      if (!pScreenInfo->fUserGaveHeightAndWidth)
+	{
+	  pScreenInfo->dwWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN);
+	  pScreenInfo->dwHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+	  pScreenInfo->dwWidth_mm = (pScreenInfo->dwWidth /
WIN_DEFAULT_DPI)
+	    * 25.4;
+	  pScreenInfo->dwHeight_mm = (pScreenInfo->dwHeight /
WIN_DEFAULT_DPI)
+	    * 25.4;
+	}
+    }
+  else
+    {
  pScreenPriv->dwLastWindowsWidth = GetSystemMetrics (SM_CXSCREEN);
  pScreenPriv->dwLastWindowsHeight = GetSystemMetrics (SM_CYSCREEN);
+    }
  pScreenPriv->dwLastWindowsBitsPixel
    = GetDeviceCaps (hdc, BITSPIXEL);
  ReleaseDC (pScreenPriv->hwndScreen, hdc);
diff -uw ./winshaddd.c
../../x-devel/build/opt/programs/Xserver/hw/xwin/winshaddd.c
--- ./winshaddd.c	2002-10-19 04:56:53.000000000 +0100
+++ ../../x-devel/build/opt/programs/Xserver/hw/xwin/winshaddd.c
2003-01-10 09:48:28.000000000 +0000
@@ -230,6 +230,7 @@
    {
      DDSURFACEDESC	ddsdCurrent;
      DWORD		dwRefreshRateCurrent = 0;
+      DWORD             dwWidth, dwHeight;
      HDC		hdc = NULL;

      /* Set the cooperative level to full screen */
@@ -289,8 +290,18 @@
	}

      /* Only change the video mode when different than current mode */
-      if (pScreenInfo->dwWidth != GetSystemMetrics (SM_CXSCREEN)
-	  || pScreenInfo->dwHeight != GetSystemMetrics (SM_CYSCREEN)
+      if (pScreenInfo->fMultiplemonitors)
+	{
+	  dwWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN);
+	  dwHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+	}
+      else
+	{
+	  dwWidth = GetSystemMetrics (SM_CXSCREEN);
+	  dwHeight = GetSystemMetrics (SM_CYSCREEN);
+	}
+      if (pScreenInfo->dwWidth != dwWidth
+	  || pScreenInfo->dwHeight != dwHeight
	  || pScreenInfo->dwBPP != GetDeviceCaps (hdc, BITSPIXEL)
	  || pScreenInfo->dwRefreshRate != 0)
	{
diff -uw ./winshadddnl.c
../../x-devel/build/opt/programs/Xserver/hw/xwin/winshadddnl.c
--- ./winshadddnl.c	2002-10-19 04:56:53.000000000 +0100
+++ ../../x-devel/build/opt/programs/Xserver/hw/xwin/winshadddnl.c
2003-01-10 09:51:55.000000000 +0000
@@ -248,6 +248,7 @@
    {
      DDSURFACEDESC2	ddsdCurrent;
      DWORD		dwRefreshRateCurrent = 0;
+      DWORD             dwWidth, dwHeight;
      HDC		hdc = NULL;

      /* Set the cooperative level to full screen */
@@ -307,8 +308,18 @@
	}

      /* Only change the video mode when different than current mode */
-      if (pScreenInfo->dwWidth != GetSystemMetrics (SM_CXSCREEN)
-	  || pScreenInfo->dwHeight != GetSystemMetrics (SM_CYSCREEN)
+      if (pScreenInfo->fMultiplemonitors)
+	{
+	  dwWidth = GetSystemMetrics (SM_CXVIRTUALSCREEN);
+	  dwHeight = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+	}
+      else
+	{
+	  dwWidth = GetSystemMetrics (SM_CXSCREEN);
+	  dwHeight = GetSystemMetrics (SM_CYSCREEN);
+	}
+      if (pScreenInfo->dwWidth != dwWidth
+	  || pScreenInfo->dwHeight != dwHeight
	  || pScreenInfo->dwBPP != GetDeviceCaps (hdc, BITSPIXEL)
	  || pScreenInfo->dwRefreshRate != 0)
	{
diff -uw ./winwndproc.c
../../x-devel/build/opt/programs/Xserver/hw/xwin/winwndproc.c
--- ./winwndproc.c	2002-10-19 04:56:53.000000000 +0100
+++ ../../x-devel/build/opt/programs/Xserver/hw/xwin/winwndproc.c
2003-01-10 09:45:48.000000000 +0000
@@ -137,8 +137,20 @@
	   * We do this here for future compatibility in case we
	   * ever allow switching from fullscreen to windowed mode.
	   */
-	  s_pScreenPriv->dwLastWindowsWidth = GetSystemMetrics
(SM_CXSCREEN);
-	  s_pScreenPriv->dwLastWindowsHeight = GetSystemMetrics
(SM_CYSCREEN);
+	  if (s_pScreenInfo->fMultiplemonitors)
+	    {	
+	      s_pScreenPriv->dwLastWindowsWidth 
+                = GetSystemMetrics (SM_CXVIRTUALSCREEN);
+	      s_pScreenPriv->dwLastWindowsHeight 
+                = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+	    }
+	  else
+	    {
+	      s_pScreenPriv->dwLastWindowsWidth
+                = GetSystemMetrics (SM_CXSCREEN);
+	      s_pScreenPriv->dwLastWindowsHeight
+                = GetSystemMetrics (SM_CYSCREEN);
+	    }
	  s_pScreenPriv->dwLastWindowsBitsPixel
	    = GetDeviceCaps (s_pScreenPriv->hdcScreen, BITSPIXEL);

	  break;
@@ -280,8 +292,18 @@
	}

      /* Store the new display dimensions and depth */
+      if (s_pScreenInfo->fMultiplemonitors)
+	{	
+	  s_pScreenPriv->dwLastWindowsWidth
+            = GetSystemMetrics (SM_CXVIRTUALSCREEN);
+	  s_pScreenPriv->dwLastWindowsHeight
+            = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+	}
+      else
+	{
      s_pScreenPriv->dwLastWindowsWidth = GetSystemMetrics
(SM_CXSCREEN);
      s_pScreenPriv->dwLastWindowsHeight = GetSystemMetrics
(SM_CYSCREEN);
+	}
      s_pScreenPriv->dwLastWindowsBitsPixel
	= GetDeviceCaps (s_pScreenPriv->hdcScreen, BITSPIXEL);
      break;

 



More information about the Cygwin-xfree mailing list