With the introduction of Windows 7 Ultimate and Server 2008 R2, RDP has the
capability to truly use multiple monitors, communicating monitor information
to the server, so that taskbar position, Shift+StartKey window moving, etc
work as they would natively.

I've attached a patch which implements this support in freerdp. It's pretty
rough; I have a number of questions:

   - I'm using Xinerama under X11 to determine monitor position. Is this the
   best way to do it? Is it okay to depend on the Xinerama extension at compile
   time? (If it's not enabled, we fall back to previous behavior.)
   - Currently, this functionality is enabled when the -f switch is used on
   the commandline. Does this seem like a reasonable check?
   - I have no idea what I'm doing with the configure.ac library check. Can
   someone help me?
   - According to MS documentation, the primary monitor must be at position
   (0, 0), and all other monitors are relative to this. Since the coordinates
   are specified as unsigned 32-bit ints, this implies that all monitors must
   be the the right/bottom of the primary monitor. In practice, the official
   Windows RDP client allows monitors left of the primary monitor. Any ideas on
   how to specify this in the CS_MONITOR structure?

I'd appreciate any feedback anybody has on the patch. Once it gets cleaned
up, I'll submit it for inclusion.

Note: versions of Windows 7 other than Ultimate such as Home or Professional
do not support multiple monitors when acting as hosts. This is an
intentional move by Microsoft to upsell to the Ultimate edition.

Thanks!
Josh Nisly
diff --git a/X11/xf_win.c b/X11/xf_win.c
index b3e3d49..baaa7c2 100644
--- a/X11/xf_win.c
+++ b/X11/xf_win.c
@@ -25,6 +25,9 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 
+
+#include <X11/extensions/Xinerama.h>
+
 #ifdef USE_XCURSOR
 #include <X11/Xcursor/Xcursor.h>
 #endif
@@ -998,6 +1001,10 @@ xf_get_pixmap_info(xfInfo * xfi)
 int
 xf_pre_connect(xfInfo * xfi)
 {
+	XineramaScreenInfo * screen_info = NULL;
+	int ignored, ignored2;
+	int n;
+
 	xf_assign_callbacks(xfi->inst);
 	xfi->display = XOpenDisplay(NULL);
 	if (xfi->display == NULL)
@@ -1012,10 +1019,36 @@ xf_pre_connect(xfInfo * xfi)
 	xfi->xserver_be = (ImageByteOrder(xfi->display) == MSBFirst);
 	xf_kb_inst_init(xfi);
 
+	xfi->settings->num_monitors = 0;
 	if (xfi->fullscreen)
 	{
 		xfi->settings->width = WidthOfScreen(xfi->screen);
 		xfi->settings->height = HeightOfScreen(xfi->screen);
+
+		
+		if (XineramaQueryExtension(xfi->display, &ignored, &ignored2))
+		{
+			if (XineramaIsActive(xfi->display))
+			{
+				screen_info = XineramaQueryScreens(xfi->display, &xfi->settings->num_monitors);
+				if (xfi->settings->num_monitors > 16)
+					xfi->settings->num_monitors = 0;
+
+				if (xfi->settings->num_monitors)
+				{
+					for (n = 0; n < xfi->settings->num_monitors; n++)
+					{
+						xfi->settings->monitors[n].x = screen_info[n].x_org;
+						xfi->settings->monitors[n].y = screen_info[n].y_org;
+						xfi->settings->monitors[n].width = screen_info[n].width;
+						xfi->settings->monitors[n].height = screen_info[n].height;
+						xfi->settings->monitors[n].is_primary = screen_info[n].x_org == 0 &&
+																screen_info[n].y_org == 0;
+					}
+				}
+				XFree(screen_info);
+			}
+		}
 	}
 
 	return 0;
diff --git a/configure.ac b/configure.ac
index 07c136b..17bd027 100644
--- a/configure.ac
+++ b/configure.ac
@@ -913,6 +913,12 @@ else
 fi
 
 #
+# Xinerama
+#
+#AC_CHECK_LIB(X11, XOpenDisplay, [X_LIBS="$X_LIBS -lX11"])
+AC_CHECK_LIB(Xinerama, XOpenDisplay, [X_LIBS="$X_LIBS -lXinerama"])
+
+#
 # DirectFB (optionally built when --with-dfb specified)
 #
 dfb="no"
diff --git a/include/freerdp/rdpset.h b/include/freerdp/rdpset.h
index ec06a80..aa22274 100644
--- a/include/freerdp/rdpset.h
+++ b/include/freerdp/rdpset.h
@@ -35,6 +35,15 @@ struct rdp_ext_set
 	void * data; /* plugin data */
 };
 
+struct rdp_monitor
+{
+	int x;
+	int y;
+	int width;
+	int height;
+	int is_primary;
+};
+
 struct rdp_set
 {
 	int tls;
@@ -75,6 +84,8 @@ struct rdp_set
 	int num_channels;
 	struct rdp_chan channels[16];
 	struct rdp_ext_set extensions[16];
+	int num_monitors;
+	struct rdp_monitor monitors[16];
 };
 
 #endif
diff --git a/libfreerdp/secure.c b/libfreerdp/secure.c
index 6bcdc30..007fc54 100644
--- a/libfreerdp/secure.c
+++ b/libfreerdp/secure.c
@@ -489,6 +489,32 @@ sec_out_client_cluster_data(rdpSec * sec, rdpSet * settings, STREAM s)
 	out_uint32_le(s, sec->rdp->redirect_session_id); /* RedirectedSessionID */
 }
 
+static void
+sec_out_client_monitor_data(rdpSec * sec, rdpSet * settings, STREAM s)
+{
+	int length, n;
+	if (settings->num_monitors <= 1)
+		return;
+
+	DEBUG("Setting monitor data...\n");
+	out_uint16_le(s, UDH_CS_MONITOR);	/* User Data Header type */
+
+	length = 12 + (20 * settings->num_monitors);
+	out_uint16_le(s, length);
+	out_uint32_le(s, 0); /* flags (unused) */
+	out_uint32_le(s, settings->num_monitors); /* monitorCount */
+	for (n = 0; n < settings->num_monitors; n++)
+	{
+		out_uint32_le(s, settings->monitors[n].x); /* left */
+		out_uint32_le(s, settings->monitors[n].y); /* top */
+		out_uint32_le(s, settings->monitors[n].x + 
+						 settings->monitors[n].width-1); /* right */
+		out_uint32_le(s, settings->monitors[n].y +
+						 settings->monitors[n].height-1); /* bottom */
+		out_uint32_le(s, settings->monitors[n].is_primary ? 1 : 0); /* isPrimary */
+	}
+}
+
 void
 sec_out_gcc_conference_create_request(rdpSec * sec, STREAM s)
 {
@@ -503,6 +529,7 @@ sec_out_gcc_conference_create_request(rdpSec * sec, STREAM s)
 	sec_out_client_cluster_data(sec, settings, s);
 	sec_out_client_security_data(sec, settings, s);
 	sec_out_client_network_data(sec, settings, s);
+	sec_out_client_monitor_data(sec, settings, s);
 	length = (s->p - s->data) - 23;
 	s->p = s->data;
 
------------------------------------------------------------------------------
The modern datacenter depends on network connectivity to access resources
and provide services. The best practices for maximizing a physical server's
connectivity to a physical network are well understood - see how these
rules translate into the virtual world? 
http://p.sf.net/sfu/oracle-sfdevnlfb
_______________________________________________
Freerdp-devel mailing list
Freerdp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freerdp-devel

Reply via email to