DualView on VirtualBox Windows guest

Bookmark and Share

Situation:

Multiple displays are still scarcely supported in virtualization solutions. Theoretically, VirtualBox supports multiple displays, though it applies only to Windows guests when using VBoxHeadless (RDP access). See the User Manual for the details.

In practice it’s not that trivial to set up, and I had to spend a few days overcoming some problems on the way. My setup is Ubuntu 9.10 (Karmic Koala) host with a Windows XP guest system. One thing which should be done in the first place is to increase the video memory available to the guest.


Problem #1:

On my Linux host I currently use TwinView (NVIDIA’s Xinerama implementation). This means only one big X screen is used that spans all the physical displays. For normal operation it’s quite fine, it’s possible to have windows “in-between” and the internals take care of maximizing to one screen only etc. By the way – the Compiz plugin Put is very handy – just bind “Put To Next Output” to a hot-key to move windows between displays in an efficient manner.

At times, however, this logical separation of the screen fails to function properly. And that’s the case with vanilla rdesktop. The unpatched version will span both monitors when going into fullscreen mode. This way it’s completely unusable.

Solution #1:

Fortunately, this has been a long known bug of rdesktop. Thanks to Rasmus Jacobsen’s post, I was able to redownload the original patch with some modifications and apply it to rdesktop 1.6.0. For redundancy, here are his instructions to applying the patch:

sudo apt-get install devscripts build-essential fakeroot
sudo apt-get build-dep rdesktop
apt-get source rdesktop
cd rdesktop-1.6.0
patch  -p0 < /tmp/rdesktop-xinerama.patch
debuild -us -uc
cd ..
sudo dpkg -i rdesktop*.deb

To get it working with rdekstop 1.6.0 I had to change the line:

+ XGetWindowAttributes(g_display, parent, &win_attrib);

into

+ XGetWindowAttributes(g_display, g_wnd, &win_attrib);


The full modified version of the patch is here:

--- configure.ac.orig	2008-06-25 23:22:27.000000000 +0200
+++ configure.ac	2008-06-25 23:17:51.000000000 +0200
@@ -18,6 +18,8 @@
 AC_SEARCH_LIBS(socket, socket)
 AC_SEARCH_LIBS(inet_aton, resolv)

+AC_CHECK_LIB(Xinerama, XineramaQueryScreens, AC_DEFINE(HAVE_XINERAMA) LIBS="$LIBS -lXinerama", [], [])
+
 AC_CHECK_HEADER(sys/select.h, AC_DEFINE(HAVE_SYS_SELECT_H))
 AC_CHECK_HEADER(sys/modem.h, AC_DEFINE(HAVE_SYS_MODEM_H))
 AC_CHECK_HEADER(sys/filio.h, AC_DEFINE(HAVE_SYS_FILIO_H))
--- xwin.c.orig	2008-06-25 23:50:02.000000000 +0200
+++ xwin.c	2008-06-25 23:49:25.000000000 +0200
@@ -21,6 +21,9 @@

 #include
 #include
+#ifdef HAVE_XINERAMA
+ #include
+#endif
 #include
 #include
 #include
@@ -570,6 +573,71 @@
 #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
 #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }

+#ifdef HAVE_XINERAMA
+// IF XINERAMA LIBRARY
+
+int g_last_wnd_pos_x;
+int g_last_wnd_pos_y;
+
+void
+ScreenSize(XRectangle *screen)
+{
+	int screens;
+	int event_base;
+	int error_base;
+
+	if (XineramaQueryExtension(g_display, &amp;event_base, &amp;error_base))
+	{
+		XineramaScreenInfo *screeninfo;
+		int i;
+
+		/* Get the Xinerama screen infomation. */
+		screeninfo = XineramaQueryScreens(g_display, &amp;screens);
+
+		/* Search for the appropriate screen. */
+		i = 0;
+		while (!(screeninfo[i].x_org <= g_last_wnd_pos_x
+			&amp;&amp; screeninfo[i].y_org <= g_last_wnd_pos_y
+			&amp;&amp; screeninfo[i].x_org + screeninfo[i].width >= g_last_wnd_pos_x
+			&amp;&amp; screeninfo[i].y_org + screeninfo[i].height >= g_last_wnd_pos_y ))
+		{
+			i++;
+		}
+		if (i >= screens) i = 0;
+
+		/* Position according to the present screen. */
+		screen->x = screeninfo[i].x_org;
+		screen->y = screeninfo[i].y_org;
+		screen->width = screeninfo[i].width;
+		screen->height = screeninfo[i].height;
+
+		/* Free allocated memory. */
+		XFree(screeninfo);
+	}
+	else
+	{
+		/* Xinerama is not in use, default to the XLib screensize call. */
+		screen->x = 0;
+		screen->y = 0;
+		screen->width = WidthOfScreen(g_screen);
+		screen->height = HeightOfScreen(g_screen);
+	}
+}
+
+#else
+// IF NO XINERAMA LIBRARY
+
+void
+ScreenSize(XRectangle *screen)
+{
+	screen->x = 0;
+	screen->y = 0;
+	screen->width = WidthOfScreen(g_screen);
+	screen->height = HeightOfScreen(g_screen);
+}
+
+#endif
+
 static uint32
 translate_colour(uint32 colour)
 {
@@ -1615,17 +1683,26 @@
 	 */
 	if (g_fullscreen)
 	{
-		g_width = WidthOfScreen(g_screen);
-		g_height = HeightOfScreen(g_screen);
+		XRectangle screen;
+		ScreenSize(&amp;screen);
+
+		g_width = screen.width;
+		g_height = screen.height;
 		g_using_full_workarea = True;
 	}
 	else if (g_width < 0)
 	{
+		XRectangle screen;
+		ScreenSize(&amp;screen);
+
+		g_width = screen.width;
+		g_height = screen.height;
+
 		/* Percent of screen */
 		if (-g_width >= 100)
 			g_using_full_workarea = True;
-		g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
-		g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
+		g_width = screen.width * (-g_width) / 100;
+		g_height = screen.height * (-g_width) / 100;
 	}
 	else if (g_width == 0)
 	{
@@ -1734,14 +1811,19 @@
 	long input_mask, ic_input_mask;
 	XEvent xevent;

-	wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
-	wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
+	XRectangle screen;
+
+	ScreenSize(&amp;screen);
+	wndwidth = g_fullscreen ? screen.width : g_width;
+	wndheight = g_fullscreen ? screen.height : g_height;
+	g_xpos = g_fullscreen ? screen.x : g_xpos;
+	g_ypos = g_fullscreen ? screen.y : g_ypos;

 	/* Handle -x-y portion of geometry string */
 	if (g_xpos < 0 || (g_xpos == 0 &amp;&amp; (g_pos &amp; 2)))
-		g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
+		g_xpos = screen.width + g_xpos - g_width;
 	if (g_ypos < 0 || (g_ypos == 0 &amp;&amp; (g_pos &amp; 4)))
-		g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
+		g_ypos = screen.height + g_ypos - g_height;

 	get_window_attribs(&amp;attribs);

@@ -1882,6 +1964,11 @@
 void
 xwin_toggle_fullscreen(void)
 {
+#ifdef HAVE_XINERAMA
+	Window root, parent, *children;
+	unsigned int nchildren;
+	XWindowAttributes win_attrib;
+#endif
 	Pixmap contents = 0;

 	if (g_seamless_active)
@@ -1895,6 +1982,17 @@
 		XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
 	}

+#ifdef HAVE_XINERAMA
+	/* Find the present coordinates of the window. */
+	XGetWindowAttributes(g_display, g_wnd, &amp;win_attrib);
+	g_last_wnd_pos_x = win_attrib.x + 1;
+	g_last_wnd_pos_y = win_attrib.y + 1;
+#endif
+
 	ui_destroy_window();
 	g_fullscreen = !g_fullscreen;
 	ui_create_window();


Problem #2:

For some unknown reason, the main display of the guest did not want to resize to the full widescreen resolution of the screen. All the choices were limited to 4:3 resolutions or some weird panoramic setting (no 1680x1050). I couldn't change it through the Windows display properties nor did it auto-resize in any way.

Solution #2:

Issuing:

VBoxManage controlvm name setvideomodehint 1680 1050 32

did the trick. To be sure, I added it to the startup script.


Problem #3:

When using two instances of rdesktop concurrently, at times they have overlapping keyboard focus. I'm not sure why or how, but sometimes after going into fullscreen with one instance it will catch Ctrl+Alt+Enter sent to the other instance (thus disabling fullscreen mode instead of going with two fullscreens). This behaviour is however quite erratic - at times it behaves as it should, and another time it will annoy me for a minute or two.

Solution #3:

I don't have a foolproof solution for this. But it helps sometimes to give the focus to the Linux desktop (or taskbar) first, and then to the second instance of rdesktop. But - as said - it's not always the case. Best way to do this would be to further patch rdesktop with custom key-bindings and have separate hot-keys for both instances, but I didn't have the incentive to do this yet.

Similar posts:

0 Responses to “DualView on VirtualBox Windows guest”


  1. No Comments

Leave a Reply




Subscribe without commenting