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