File rdesktop-NOMAD.dif of Package rdesktop

diff --git a/Makefile.in b/Makefile.in
index a904c51..d30c90d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -28,14 +28,14 @@ SOUNDOBJ    = @SOUNDOBJ@
 SCARDOBJ    = @SCARDOBJ@
 
 RDPOBJ   = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o lspci.o seamless.o ssl.o
-X11OBJ   = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o
+X11OBJ   = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o rdpx11.o
 VNCOBJ   = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o
 
 .PHONY: all
 all: $(TARGETS)
 
 rdesktop: $(X11OBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ)
-	$(CC) $(CFLAGS) -o rdesktop $(X11OBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(LDFLAGS) -lX11
+	$(CC) $(CFLAGS) -o rdesktop $(X11OBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(LDFLAGS) -lX11 -lXext
 
 rdp2vnc: $(VNCOBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) 
 	$(VNCLINK) $(CFLAGS) -o rdp2vnc $(VNCOBJ) $(SOUNDOBJ) $(RDPOBJ) $(SCARDOBJ) $(LDFLAGS) $(LDVNC)
@@ -85,7 +85,7 @@ proto:
 	iso.c licence.c mcs.c orders.c parallel.c printer.c printercache.c \
 	pstcache.c rdesktop.c rdp5.c rdp.c rdpdr.c rdpsnd.c \
 	secure.c serial.c tcp.c xclip.c xkeymap.c xwin.c lspci.c seamless.c \
-	scard.c >> proto.h
+	scard.c rdpx11.c >> proto.h
 	cat proto.tail >> proto.h
 
 .PHONY: clean
diff --git a/ewmhints.c b/ewmhints.c
index a3d67aa..7687609 100644
--- a/ewmhints.c
+++ b/ewmhints.c
@@ -36,7 +36,8 @@ extern Display *g_display;
 static Atom g_net_wm_state_maximized_vert_atom, g_net_wm_state_maximized_horz_atom,
 	g_net_wm_state_hidden_atom, g_net_wm_name_atom, g_utf8_string_atom,
 	g_net_wm_state_skip_taskbar_atom, g_net_wm_state_skip_pager_atom,
-	g_net_wm_state_modal_atom, g_net_wm_icon_atom, g_net_wm_state_above_atom;
+	g_net_wm_state_modal_atom, g_net_wm_icon_atom,
+	g_net_wm_state_above_atom, g_net_wm_state_fullscreen_atom;
 
 Atom g_net_wm_state_atom, g_net_wm_desktop_atom;
 
@@ -187,6 +188,7 @@ ewmh_init()
 	g_net_wm_state_skip_pager_atom = XInternAtom(g_display, "_NET_WM_STATE_SKIP_PAGER", False);
 	g_net_wm_state_modal_atom = XInternAtom(g_display, "_NET_WM_STATE_MODAL", False);
 	g_net_wm_state_above_atom = XInternAtom(g_display, "_NET_WM_STATE_ABOVE", False);
+	g_net_wm_state_fullscreen_atom = XInternAtom(g_display, "_NET_WM_STATE_FULLSCREEN", False);
 	g_net_wm_state_atom = XInternAtom(g_display, "_NET_WM_STATE", False);
 	g_net_wm_desktop_atom = XInternAtom(g_display, "_NET_WM_DESKTOP", False);
 	g_net_wm_name_atom = XInternAtom(g_display, "_NET_WM_NAME", False);
@@ -236,7 +238,7 @@ ewmh_get_window_state(Window w)
 }
 
 static int
-ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
+ewmh_modify_state(Window wnd, int how, Atom atom1, Atom atom2)
 {
 	Status status;
 	XEvent xevent;
@@ -259,49 +261,54 @@ ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
 
 	if (state == WithdrawnState)
 	{
-		if (add)
-		{
-			Atom atoms[2];
-
-			atoms[0] = atom1;
-			nitems = 1;
-			if (atom2)
-			{
-				atoms[1] = atom2;
-				nitems = 2;
-			}
+		Atom atoms[2];
 
-			XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
-					32, PropModeAppend, (unsigned char *) atoms, nitems);
-		}
-		else
+		if (how != _NET_WM_STATE_ADD)
 		{
 			Atom *atoms;
-			int i;
+			int i, n;
 
 			if (get_property_value(wnd, "_NET_WM_STATE", 64, &nitems, &props, 1) < 0)
 				return 0;
 
 			atoms = (Atom *) props;
+			n = nitems;
 
-			for (i = 0; i < nitems; i++)
+			for (i = 0; i < n; i++)
 			{
 				if ((atoms[i] == atom1) || (atom2 && (atoms[i] == atom2)))
 				{
-					if (i != (nitems - 1))
+					if (i != (n - 1))
 						memmove(&atoms[i], &atoms[i + 1],
-							sizeof(Atom) * (nitems - i - 1));
-					nitems--;
+							sizeof(Atom) * (n - i - 1));
+					n--;
 					i--;
 				}
 			}
 
-			XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
-					32, PropModeReplace, (unsigned char *) atoms, nitems);
+			if (n != nitems || how == _NET_WM_STATE_REMOVE)
+			{
+				XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
+						32, PropModeReplace, (unsigned char *) atoms, nitems);
+
+				XFree(props);
+				return 0;
+			}
 
 			XFree(props);
 		}
 
+		atoms[0] = atom1;
+		nitems = 1;
+		if (atom2)
+		{
+			atoms[1] = atom2;
+			nitems = 2;
+		}
+
+		XChangeProperty(g_display, wnd, g_net_wm_state_atom, XA_ATOM,
+				32, PropModeAppend, (unsigned char *) atoms, nitems);
+
 		return 0;
 	}
 
@@ -309,10 +316,7 @@ ewmh_modify_state(Window wnd, int add, Atom atom1, Atom atom2)
 	xevent.xclient.window = wnd;
 	xevent.xclient.message_type = g_net_wm_state_atom;
 	xevent.xclient.format = 32;
-	if (add)
-		xevent.xclient.data.l[0] = _NET_WM_STATE_ADD;
-	else
-		xevent.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
+	xevent.xclient.data.l[0] = how;
 	xevent.xclient.data.l[1] = atom1;
 	xevent.xclient.data.l[2] = atom2;
 	xevent.xclient.data.l[3] = 0;
@@ -542,6 +546,15 @@ ewmh_set_window_above(Window wnd)
 	return 0;
 }
 
+int
+ewmh_set_window_fullscreen(Window wnd, int action)
+{
+	if (ewmh_modify_state(wnd, action, g_net_wm_state_fullscreen_atom,
+			      0) < 0)
+		return -1;
+	return 0;
+}
+
 #endif /* MAKE_PROTO */
 
 
diff --git a/proto.h b/proto.h
index 1b6d9b2..7f2e402 100644
--- a/proto.h
+++ b/proto.h
@@ -220,6 +220,8 @@ void xclip_deinit(void);
 RD_BOOL xkeymap_from_locale(const char *locale);
 FILE *xkeymap_open(const char *filename);
 void xkeymap_init(void);
+void grab_special_keys(void);
+void ungrab_special_keys(void);
 RD_BOOL handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed);
 key_translation xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state);
 void xkeymap_send_keys(uint32 keysym, unsigned int keycode, unsigned int state, uint32 ev_time,
@@ -315,6 +317,11 @@ unsigned int seamless_send_destroy(unsigned long id);
 /* scard.c */
 void scard_lock(int lock);
 void scard_unlock(int lock);
+/* rdpx11.c */
+void rdpx11_open(void);
+RD_BOOL rdpx11_init(uint32 inflate_level, uint32 deflate_level);
+void rdpx11_add_fds(int *n, fd_set *rfds, fd_set *wfds, struct timeval *tv);
+void rdpx11_check_fds(fd_set *rfds, fd_set *wfds);
 
 /* *INDENT-OFF* */
 #ifdef __cplusplus
diff --git a/rdesktop.c b/rdesktop.c
index 93798cc..4890080 100644
--- a/rdesktop.c
+++ b/rdesktop.c
@@ -81,7 +81,7 @@ RD_BOOL g_packet_encryption = True;
 RD_BOOL g_desktop_save = True;	/* desktop save order */
 RD_BOOL g_polygon_ellipse_orders = True;	/* polygon / ellipse orders */
 RD_BOOL g_fullscreen = False;
-RD_BOOL g_grab_keyboard = True;
+RD_BOOL g_grab_keyboard = False;
 RD_BOOL g_hide_decorations = False;
 RD_BOOL g_use_rdp5 = True;
 RD_BOOL g_rdpclip = True;
@@ -107,6 +107,10 @@ uint32 g_redirect_flags = 0;
 RD_BOOL g_rdpsnd = False;
 #endif
 
+RD_BOOL g_rdpx11 = True;
+int     g_rdpx11_inflate_level = -1;
+int     g_rdpx11_deflate_level = -1;
+
 #ifdef HAVE_ICONV
 char g_codepage[16] = "";
 #endif
@@ -156,6 +160,7 @@ usage(char *program)
 	fprintf(stderr, "   -C: use private colour map\n");
 	fprintf(stderr, "   -D: hide window manager decorations\n");
 	fprintf(stderr, "   -K: keep window manager key bindings\n");
+	fprintf(stderr, "   -G: prevent window manager key bindings\n");
 	fprintf(stderr, "   -S: caption button size (single application mode)\n");
 	fprintf(stderr, "   -T: window title\n");
 	fprintf(stderr, "   -N: enable numlock syncronization\n");
@@ -208,6 +213,9 @@ usage(char *program)
 	fprintf(stderr,
 		"                   \"AKS\"              -> Device vendor name                 \n");
 #endif
+	fprintf(stderr, "   -Y: disable X11 protocol redirection\n");
+	fprintf(stderr, "   -W: x11 compression level from server to client (0-9)\n");
+	fprintf(stderr, "   -w: x11 compression level from client to server (0-9)\n");
 	fprintf(stderr, "   -0: attach to console\n");
 	fprintf(stderr, "   -4: use RDP version 4\n");
 	fprintf(stderr, "   -5: use RDP version 5 (default)\n");
@@ -450,7 +458,7 @@ main(int argc, char *argv[])
 #endif
 
 	while ((c = getopt(argc, argv,
-			   VNCOPT "Au:L:d:s:c:p:n:k:g:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
+			   VNCOPT "Au:L:d:s:c:p:n:k:g:fbBeEmzCDKGS:T:NX:a:x:Pr:YW:w:045h?")) != -1)
 	{
 		switch (c)
 		{
@@ -600,6 +608,10 @@ main(int argc, char *argv[])
 				g_grab_keyboard = False;
 				break;
 
+			case 'G':
+				g_grab_keyboard = True;
+				break;
+
 			case 'S':
 				if (!strcmp(optarg, "standard"))
 				{
@@ -772,6 +784,24 @@ main(int argc, char *argv[])
 				}
 				break;
 
+			case 'Y':
+				g_rdpx11 = False;
+				break;
+
+			case 'W':
+				g_rdpx11_inflate_level =
+					strtol(optarg, NULL, 10);
+				if (g_rdpx11_inflate_level > 9)
+					g_rdpx11_inflate_level = 9;
+				break;
+
+			case 'w':
+				g_rdpx11_deflate_level =
+					strtol(optarg, NULL, 10);
+				if (g_rdpx11_deflate_level > 9)
+					g_rdpx11_deflate_level = 9;
+				break;
+
 			case '0':
 				g_console_session = True;
 				break;
@@ -924,6 +954,21 @@ main(int argc, char *argv[])
 	if (g_lspci_enabled)
 		lspci_init();
 
+	if (g_rdpx11)
+	{
+		int compress = 0;
+
+		if (flags & RDP_LOGON_COMPRESSION)
+			compress = 6;
+
+		if (g_rdpx11_inflate_level < 0)
+			g_rdpx11_inflate_level = compress;
+		if (g_rdpx11_deflate_level < 0)
+			g_rdpx11_deflate_level = compress;
+
+		rdpx11_init(g_rdpx11_inflate_level, g_rdpx11_deflate_level);
+	}
+
 	rdpdr_init();
 
 	while (run_count < 2 && continue_connect)	/* add support for Session Directory; only reconnect once */
diff --git a/rdpx11.c b/rdpx11.c
new file mode 100644
index 0000000..420a08d
--- /dev/null
+++ b/rdpx11.c
@@ -0,0 +1,658 @@
+/*  -*- c-basic-offset: 8 -*-
+ *   rdesktop: A Remote Desktop Protocol client.
+ *   Support for the X11 "rdpx11" channel
+ *   Copyright (C) 2008 Novel Inc.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl.  All rights reserved.
+ * Copyright (c) 1999 Dug Song.  All rights reserved.
+ * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "rdesktop.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/unistd.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <zlib.h>
+#include <X11/Xlib.h>
+
+#ifdef WITH_DEBUG_RDPX11
+#define DEBUG_RDPX11(args) printf args;
+#else
+#define DEBUG_RDPX11(args)
+#endif
+
+
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+#  define MAXPATHLEN PATH_MAX
+# else /* PATH_MAX */
+#  define MAXPATHLEN 64
+/* realpath uses a fixed buffer of size MAXPATHLEN, so force use of ours */
+#  ifndef BROKEN_REALPATH
+#   define BROKEN_REALPATH 1
+#  endif /* BROKEN_REALPATH */
+# endif /* PATH_MAX */
+#endif /* MAXPATHLEN */
+
+#ifndef PATH_MAX
+# ifdef _POSIX_PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+# endif
+#endif
+
+/* Define this to be the path of the xauth program. */
+#ifdef XAUTH_PATH
+#define _PATH_XAUTH XAUTH_PATH
+#else
+#define _PATH_XAUTH "/usr/bin/xauth"
+#endif /* XAUTH_PATH */
+
+#ifndef X_UNIX_PATH
+#  ifdef __hpux
+#    define X_UNIX_PATH "/var/spool/sockets/X11/%u"
+#  else
+#    define X_UNIX_PATH "/tmp/.X11-unix/X%u"
+#  endif
+#endif /* X_UNIX_PATH */
+#define _PATH_UNIX_X X_UNIX_PATH
+
+#ifndef _PATH_DEVNULL
+# define _PATH_DEVNULL "/dev/null"
+#endif
+
+#define RDPX11_CHANNEL_RBUF (16 * 1024)
+
+#define RDPX11_OPEN_REQUEST      1
+#define RDPX11_OPEN_CONFIRMATION 2
+#define RDPX11_OPEN_FAILURE      3
+
+static VCHANNEL *rdpx11_channel;
+static int      rdpx11_socket = 0;
+static char     *xauth_location = _PATH_XAUTH;
+static int      forward_x11_trusted = 1;
+static uint32   x11_inflate_level;
+static uint32   x11_deflate_level;
+static z_stream incoming_stream;
+static z_stream outgoing_stream;
+extern Window   g_wnd;
+
+#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
+void
+x11_get_proto(const char *display, const char *xauth_path,
+	      unsigned int trusted, char **_proto, char **_data)
+{
+	char cmd[1024];
+	char line[512];
+	char xdisplay[512];
+	static char proto[512], data[512];
+	FILE *f;
+	int got_data = 0, generated = 0, do_unlink = 0, i;
+	char *xauthdir, *xauthfile;
+	struct stat st;
+
+	xauthdir = xauthfile = NULL;
+	*_proto = proto;
+	*_data = data;
+	proto[0] = data[0] = '\0';
+
+	if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) {
+		DEBUG_RDPX11(("No xauth program.\n"));
+	} else {
+		if (display == NULL) {
+			DEBUG_RDPX11(("x11_get_proto: DISPLAY not set\n"));
+			return;
+		}
+		/*
+		 * Handle FamilyLocal case where $DISPLAY does
+		 * not match an authorization entry.  For this we
+		 * just try "xauth list unix:displaynum.screennum".
+		 * XXX: "localhost" match to determine FamilyLocal
+		 *      is not perfect.
+		 */
+		if (strncmp(display, "localhost:", 10) == 0) {
+			snprintf(xdisplay, sizeof(xdisplay), "unix:%s",
+			    display + 10);
+			display = xdisplay;
+		}
+		if (trusted == 0) {
+			xauthdir = xmalloc(MAXPATHLEN);
+			xauthfile = xmalloc(MAXPATHLEN);
+			strncpy(xauthdir, "/tmp/rdpx11-XXXXXXXXXX",
+				MAXPATHLEN);
+			xauthdir[MAXPATHLEN - 1] = '\0';
+			if (mkdtemp(xauthdir) != NULL) {
+				do_unlink = 1;
+				snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile",
+				    xauthdir);
+				snprintf(cmd, sizeof(cmd),
+				    "%s -f %s generate %s " SSH_X11_PROTO
+				    " untrusted timeout 1200 2>" _PATH_DEVNULL,
+				    xauth_path, xauthfile, display);
+				DEBUG_RDPX11(("x11_get_proto: %s", cmd));
+				if (system(cmd) == 0)
+					generated = 1;
+			}
+		}
+
+		/*
+		 * When in untrusted mode, we read the cookie only if it was
+		 * successfully generated as an untrusted one in the step
+		 * above.
+		 */
+		if (trusted || generated) {
+			snprintf(cmd, sizeof(cmd),
+			    "%s %s%s list %s 2>" _PATH_DEVNULL,
+			    xauth_path,
+			    generated ? "-f " : "" ,
+			    generated ? xauthfile : "",
+			    display);
+			DEBUG_RDPX11(("x11_get_proto: %s\n", cmd));
+			f = popen(cmd, "r");
+			if (f && fgets(line, sizeof(line), f) &&
+			    sscanf(line, "%*s %511s %511s", proto, data) == 2)
+				got_data = 1;
+			if (f)
+				pclose(f);
+		} else
+			error("Warning: untrusted X11 forwarding setup failed: "
+			    "xauth key data not generated\n");
+	}
+
+	if (do_unlink) {
+		unlink(xauthfile);
+		rmdir(xauthdir);
+	}
+	if (xauthdir)
+		xfree(xauthdir);
+	if (xauthfile)
+		xfree(xauthfile);
+
+	/*
+	 * If we didn't get authentication data, just make up some
+	 * data.  The forwarding code will check the validity of the
+	 * response anyway, and substitute this data.  The X11
+	 * server, however, will ignore this fake data and use
+	 * whatever authentication mechanisms it was using otherwise
+	 * for the local connection.
+	 */
+	if (!got_data) {
+		u_int32_t rnd = 0;
+
+		warning("No xauth data; "
+			"using fake authentication data for X11 "
+			"forwarding.\n");
+		strncpy(proto, SSH_X11_PROTO, sizeof proto);
+		proto[sizeof proto - 1] = '\0';
+		for (i = 0; i < 16; i++) {
+			if (i % 4 == 0)
+				rnd = random();
+			snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",
+			    rnd & 0xff);
+			rnd >>= 8;
+		}
+	}
+}
+
+static int
+connect_local_xsocket(unsigned int dnr)
+{
+	int sock;
+	struct sockaddr_un addr;
+
+	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0)
+		error("socket: %.100s", strerror(errno));
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr);
+	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
+	{
+		int flag;
+
+		if ((flag = fcntl(sock, F_GETFL)) == -1) {
+			close(sock);
+			return -1;
+		}
+		flag |= O_NONBLOCK;
+		if (fcntl(sock, F_SETFL, flag) == -1) {
+			close(sock);
+			return -1;
+		}
+		return sock;
+	}
+	close(sock);
+	error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
+	return -1;
+}
+
+static int
+rdpx11_connect_display(const char *display)
+{
+	unsigned int display_number;
+	char buf[1024], *cp;
+	struct addrinfo hints, *ai, *aitop;
+	char strport[NI_MAXSERV];
+	int gaierr, sock = 0;
+	int opt;
+	socklen_t optlen;
+
+	/*
+	 * Check if it is a unix domain socket.  Unix domain displays are in
+	 * one of the following formats: unix:d[.s], :d[.s], ::d[.s]
+	 */
+	if (strncmp(display, "unix:", 5) == 0 ||
+	    display[0] == ':') {
+		/* Connect to the unix domain socket. */
+		if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) {
+			error("Could not parse display number from DISPLAY: %.100s",
+			    display);
+			return -1;
+		}
+		/* Create a socket. */
+		sock = connect_local_xsocket(display_number);
+		if (sock < 0)
+			return -1;
+
+		/* OK, we now have a connection to the display. */
+		return sock;
+	}
+	/*
+	 * Connect to an inet socket.  The DISPLAY value is supposedly
+	 * hostname:d[.s], where hostname may also be numeric IP address.
+	 */
+	strncpy(buf, display, sizeof(buf));
+	buf[sizeof(buf) - 1] = '\0';
+	cp = strchr(buf, ':');
+	if (!cp) {
+		error("Could not find ':' in DISPLAY: %.100s", display);
+		return -1;
+	}
+	*cp = 0;
+	/* buf now contains the host name.  But first we parse the display number. */
+	if (sscanf(cp + 1, "%u", &display_number) != 1) {
+		error("Could not parse display number from DISPLAY: %.100s",
+		    display);
+		return -1;
+	}
+
+	/* Look up the host address */
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	snprintf(strport, sizeof strport, "%u", 6000 + display_number);
+	if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
+		error("%.100s: unknown host. (%d)", buf, gaierr);
+		return -1;
+	}
+	for (ai = aitop; ai; ai = ai->ai_next) {
+		/* Create a socket. */
+		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (sock < 0) {
+			error("socket: %.100s", strerror(errno));
+			continue;
+		}
+		/* Connect it to the display. */
+		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+			error("connect %.100s port %u: %.100s", buf,
+			      6000 + display_number, strerror(errno));
+			close(sock);
+			continue;
+		}
+		/* Success */
+		break;
+	}
+	freeaddrinfo(aitop);
+	if (!ai) {
+		error("connect %.100s port %u: %.100s", buf, 6000 + display_number,
+		    strerror(errno));
+		return -1;
+	}
+
+	optlen = sizeof opt;
+	if (getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
+		warning("getsockopt TCP_NODELAY: %.100s", strerror(errno));
+		return sock;
+	}
+	if (opt == 1) {
+		warning("fd %d is TCP_NODELAY", sock);
+		return sock;
+	}
+	opt = 1;
+	DEBUG_RDPX11(("fd %d setting TCP_NODELAY", sock));
+	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
+		warning("setsockopt TCP_NODELAY: %.100s", strerror(errno));
+
+	return sock;
+}
+
+void
+rdpx11_open(void)
+{
+	const char *display;
+	STREAM     s;
+
+	/* Try to open a socket for the local X server. */
+	display = getenv("DISPLAY");
+	if (!display) {
+		error("DISPLAY not set.");
+		return;
+	}
+
+	if (!rdpx11_socket)
+	{
+		/* obtain a connection to the real X display. */
+		rdpx11_socket = rdpx11_connect_display(display);
+	}
+
+	s = channel_init(rdpx11_channel, 8);
+	if (rdpx11_socket) {
+		char *proto;
+		char *data;
+		int  len;
+		int  i;
+
+		x11_get_proto (display,
+			       xauth_location,
+			       forward_x11_trusted,
+			       &proto,
+			       &data);
+
+		len = strlen (data) / 2;
+
+		out_uint32_le(s, RDPX11_OPEN_CONFIRMATION);
+		out_uint32_le(s, g_wnd);
+		out_uint16_le(s, x11_inflate_level);
+		out_uint16_le(s, x11_deflate_level);
+		out_uint32_le(s, strlen (proto));
+		out_uint32_le(s, len);
+
+		for (i = 0; proto[i] != '\0'; i++)
+			out_uint8(s, proto[i]);
+		
+		for (i = 0; i < len; i++) {
+			unsigned int value;
+
+			if (sscanf(data + 2 * i, "%2x", &value) != 1)
+				error("rdpx11: bad authentication data: "
+				      "%.100s", data);
+
+			out_uint8(s, value);
+		}
+	} else {
+		out_uint32_le(s, RDPX11_OPEN_FAILURE);
+		out_uint32_le(s, 0);
+		out_uint32_le(s, 0);
+		out_uint32_le(s, 0);
+	}
+	s_mark_end(s);
+	channel_send(s, rdpx11_channel);
+}
+
+static int
+rdpx11_forced_write(int socket, unsigned char *buf, int size)
+{
+	int total = 0;
+	int sent;
+
+	while (total < size) {
+		sent = write(socket, buf + total, size - total);
+		if (sent == -1) {
+			if (errno == EINTR || errno == EAGAIN ||
+			    errno == EWOULDBLOCK) {
+				fd_set         rfds;
+				struct timeval time;
+
+				time.tv_sec = 0;
+				time.tv_usec = 10000;
+
+				FD_ZERO(&rfds);
+				FD_SET(socket, &rfds);
+
+				select(socket + 1, &rfds, 0, 0, &time);
+			} else {
+				return -1;
+			}
+		} else if (sent == 0) {
+			return 0;
+		} else {
+			total = total + sent;
+		}
+	}
+
+	return total;
+}
+
+/* Process new data from the virtual channel */
+static void
+rdpx11_process(STREAM s)
+{
+	if (rdpx11_socket) {
+		ssize_t len;
+
+		if (x11_inflate_level) {
+			unsigned char buf[RDPX11_CHANNEL_RBUF];
+			int           status;
+
+			incoming_stream.next_in  = s->p;
+			incoming_stream.avail_in = s->end - s->p;
+
+			do {
+				incoming_stream.next_out  = buf;
+				incoming_stream.avail_out = sizeof(buf);
+
+				status = inflate(&incoming_stream,
+						 Z_SYNC_FLUSH);
+				switch (status) {
+				case Z_OK:
+					len = sizeof(buf) -
+						incoming_stream.avail_out;
+					if (rdpx11_forced_write(rdpx11_socket,
+								buf,
+								len) <= 0)
+						rdpx11_socket = 0;
+					break;
+				case Z_BUF_ERROR:
+					break;
+				default:
+					error("rdpx11: inflate returned %d\n",
+					      status);
+				}
+			} while (status == Z_OK && rdpx11_socket);
+		} else {
+			if (rdpx11_forced_write(rdpx11_socket, s->p,
+						s->end - s->p) <= 0)
+				rdpx11_socket = 0;
+		}
+
+	} else {
+		uint8 type;
+
+		in_uint8(s, type);
+
+		switch (type) {
+		case RDPX11_OPEN_REQUEST:
+			in_uint8s(s, 3);
+			rdpx11_open ();
+			break;
+		}
+	}
+}
+
+/* Initialize this module: Register the rdpx11 channel */
+RD_BOOL
+rdpx11_init(uint32 inflate_level, uint32 deflate_level)
+{
+	rdpx11_channel = channel_register("rdpx11",
+					  CHANNEL_OPTION_INITIALIZED |
+					  CHANNEL_OPTION_ENCRYPT_RDP,
+					  rdpx11_process);
+
+	x11_inflate_level = inflate_level;
+	x11_deflate_level = deflate_level;
+
+	if (x11_deflate_level)
+		deflateInit (&outgoing_stream, x11_deflate_level);
+
+	if (x11_inflate_level)
+		inflateInit (&incoming_stream);
+
+	return (rdpx11_channel != NULL);
+}
+
+/* Send data to channel */
+static void
+rdpx11_send(void)
+{
+	STREAM        s;
+	unsigned char stack_buf[RDPX11_CHANNEL_RBUF];
+	unsigned char *buf = stack_buf;
+	int           buf_avail;
+	int           size = sizeof (stack_buf);
+	int           buf_offset = 0;
+	int           len;
+
+	do {
+		buf_avail = size - buf_offset;
+
+		len = read (rdpx11_socket, buf + buf_offset, buf_avail);
+		if (len == -1) {
+			if (errno == EINTR || errno == EAGAIN ||
+			    errno == EWOULDBLOCK) {
+				len = 0;
+			} else {
+				rdpx11_socket = 0;
+				break;
+			}
+		} else if (len == 0) {
+			rdpx11_socket = 0;
+			break;
+		}
+
+		buf_avail -= len;
+
+		if (x11_deflate_level) {
+			unsigned char out_buf[RDPX11_CHANNEL_RBUF];
+			int           out_len;
+			int           status;
+
+			if (buf_avail == 0) {
+				unsigned char *data;
+
+				if (buf != stack_buf) {
+					data = realloc(buf, size * 2);
+				} else {
+					data = malloc(size * 2);
+					if (data && buf == stack_buf)
+						memcpy(data, buf, size);
+				}
+
+				if (data) {
+					buf_offset += len;
+					buf = data;
+					size *= 2;
+					continue;
+				}
+			}
+
+			outgoing_stream.next_in  = buf;
+			outgoing_stream.avail_in = size - buf_avail;
+
+			do {
+				outgoing_stream.next_out  = out_buf;
+				outgoing_stream.avail_out = sizeof(out_buf);
+
+				status = deflate(&outgoing_stream,
+						 Z_SYNC_FLUSH);
+				switch (status) {
+				case Z_OK:
+					out_len = sizeof(out_buf) -
+						outgoing_stream.avail_out;
+					if (out_len) {
+						s = channel_init(rdpx11_channel, out_len);
+						out_uint8p(s, out_buf, out_len);
+						s_mark_end(s);
+						channel_send(s, rdpx11_channel);
+					}
+					break;
+				default:
+					error("rdpx11: deflate returned %d",
+					      status);
+				}
+			} while (outgoing_stream.avail_out == 0);
+		} else if (len) {
+			s = channel_init(rdpx11_channel, len);
+			out_uint8p(s, buf, len); s_mark_end(s);
+			channel_send(s, rdpx11_channel);
+		}
+	} while (buf_avail == 0);
+
+	if (buf != stack_buf)
+		free (buf);
+}
+
+void
+rdpx11_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
+{
+	if (rdpx11_socket)
+	{
+		FD_SET(rdpx11_socket, rfds);
+		if (rdpx11_socket > *n)
+			*n = rdpx11_socket;
+	}
+}
+
+void
+rdpx11_check_fds(fd_set * rfds, fd_set * wfds)
+{
+	if (rdpx11_socket)
+	{
+		if (FD_ISSET(rdpx11_socket, rfds))
+			rdpx11_send ();
+	}
+}
diff --git a/xkeymap.c b/xkeymap.c
index 02e2664..7c07014 100644
--- a/xkeymap.c
+++ b/xkeymap.c
@@ -503,6 +503,98 @@ reset_winkey(uint32 ev_time)
 	}
 }
 
+static const int maskTable[] = {
+    ShiftMask, LockMask, ControlMask, Mod1Mask,
+    Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
+};
+static const int maskTableSize = sizeof (maskTable) / sizeof (int);
+
+extern XModifierKeymap *g_mod_map;
+
+/* Grab special key combinations */
+void
+grab_special_keys(void)
+{
+	unsigned int altMask = 0;
+	unsigned int scrollLockMask = 0;
+	unsigned int numLockMask = 0;
+	int	     i, minKeycode, maxKeycode, keysymsPerKeycode = 0;
+	int          ignore, ignoredModMask, k;
+	KeySym*      key;
+
+	XDisplayKeycodes (g_display, &minKeycode, &maxKeycode);
+	key = XGetKeyboardMapping (g_display,
+				   minKeycode, (maxKeycode - minKeycode + 1),
+				   &keysymsPerKeycode);
+
+	if (g_mod_map && g_mod_map->max_keypermod > 0)
+	{
+		KeySym keysym;
+		int    index, size, mask;
+
+		size = maskTableSize * g_mod_map->max_keypermod;
+
+		for (i = 0; i < size; i++)
+		{
+			if (!g_mod_map->modifiermap[i])
+				continue;
+
+			index = 0;
+			do
+			{
+				keysym = XKeycodeToKeysym (g_display,
+							   g_mod_map->modifiermap[i],
+							   index++);
+			} while (!keysym && index < keysymsPerKeycode);
+
+			if (keysym)
+			{
+				mask = maskTable[i / g_mod_map->max_keypermod];
+
+				if (keysym == XK_Alt_L || keysym == XK_Alt_R)
+				{
+					altMask |= mask;
+				}
+				else if (keysym == XK_Scroll_Lock)
+				{
+					scrollLockMask |= mask;
+				}
+				else if (keysym == XK_Num_Lock)
+				{
+					numLockMask |= mask;
+				}
+			}
+		}
+	}
+
+	ignoredModMask = LockMask | scrollLockMask | numLockMask;
+
+	k = XKeysymToKeycode (g_display, XK_Return);
+	if (!k)
+		return;
+
+	for (ignore = 0; ignore <= ignoredModMask; ignore++)
+	{
+		if (ignore & ~ignoredModMask)
+			continue;
+
+		XGrabKey (g_display,
+			  k,
+			  ControlMask | altMask | ignore,
+			  g_wnd,
+			  False,
+			  GrabModeAsync,
+			  GrabModeAsync);
+	}
+}
+
+/* Ungrab special key combinations */
+void
+ungrab_special_keys(void)
+{
+	XUngrabKey(g_display, AnyKey, AnyModifier, g_wnd);
+}
+
 /* Handle special key combinations */
 RD_BOOL
 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, RD_BOOL pressed)
diff --git a/xproto.h b/xproto.h
index 69bea4d..ca037cb 100644
--- a/xproto.h
+++ b/xproto.h
@@ -12,3 +12,4 @@ int ewmh_set_window_modal(Window wnd);
 void ewmh_set_icon(Window wnd, int width, int height, const char *rgba_data);
 void ewmh_del_icon(Window wnd, int width, int height);
 int ewmh_set_window_above(Window wnd);
+int ewmh_set_window_fullscreen(Window wnd, int action);
diff --git a/xwin.c b/xwin.c
index 83e75a8..08e384d 100644
--- a/xwin.c
+++ b/xwin.c
@@ -22,6 +22,8 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xproto.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
 #include <unistd.h>
 #include <sys/time.h>
 #include <time.h>
@@ -50,6 +52,7 @@ Time g_last_gesturetime;
 static int g_x_socket;
 static Screen *g_screen;
 Window g_wnd;
+static Window g_dmx_root = None;
 
 /* SeamlessRDP support */
 typedef struct _seamless_group
@@ -107,13 +110,13 @@ static int g_depth;
 static int g_bpp;
 static XIM g_IM;
 static XIC g_IC;
-static XModifierKeymap *g_mod_map;
+XModifierKeymap *g_mod_map;
 /* Maps logical (xmodmap -pp) pointing device buttons (0-based) back
    to physical (1-based) indices. */
 static unsigned char g_pointer_log_to_phys_map[32];
 static Cursor g_current_cursor;
 static RD_HCURSOR g_null_cursor = NULL;
-static Atom g_protocol_atom, g_kill_atom;
+static Atom g_protocol_atom, g_kill_atom, g_take_focus_atom;
 extern Atom g_net_wm_state_atom;
 extern Atom g_net_wm_desktop_atom;
 static RD_BOOL g_focused;
@@ -1875,14 +1878,65 @@ ui_init(void)
 		g_ownbackstore = True;
 	}
 
+	ewmh_init();
+
 	/*
 	 * Determine desktop size
 	 */
 	if (g_fullscreen)
 	{
-		g_width = WidthOfScreen(g_screen);
+		Window wnd;
+		XEvent xevent;
+		Region region;
+		XWMHints xwmh;
+
+		g_width = WidthOfScreen(g_screen) - 100;
 		g_height = HeightOfScreen(g_screen);
 		g_using_full_workarea = True;
+
+		wnd = XCreateWindow(g_display,
+				    RootWindowOfScreen(g_screen),
+				    0, 0, g_width, g_height,
+				    0, CopyFromParent, InputOutput,
+				    CopyFromParent, 0, NULL);
+		region = XCreateRegion ();
+		if (region)
+		{
+			XShapeCombineRegion (g_display, wnd,
+					     ShapeBounding, 0, 0, region,
+					     ShapeSet);
+			XDestroyRegion (region);
+		}
+		xwmh.flags = InputHint;
+		xwmh.input = False;
+		XSetWMHints(g_display, wnd, &xwmh);
+		ewmh_set_window_fullscreen(wnd, 1);
+		ewmh_set_window_popup(wnd);
+		XSelectInput(g_display, wnd, StructureNotifyMask);
+		XMapWindow(g_display, wnd);
+
+		g_width = WidthOfScreen(g_screen);
+		g_height = HeightOfScreen(g_screen);
+
+		/* wait for MapNotify */
+		do
+		{
+			XNextEvent(g_display, &xevent);
+
+			switch (xevent.type) {
+			case ConfigureNotify:
+				if (xevent.xconfigure.window == wnd)
+				{
+					g_width  = xevent.xconfigure.width;
+					g_height = xevent.xconfigure.height;
+				}
+				break;
+			}
+		}
+		while (xevent.type != MapNotify);
+
+		XDestroyWindow(g_display, wnd);
+		XSync(g_display, True);
 	}
 	else if (g_width < 0)
 	{
@@ -1922,7 +1976,6 @@ ui_init(void)
 		g_IM = XOpenIM(g_display, NULL, NULL, NULL);
 
 	xclip_init();
-	ewmh_init();
 	if (g_seamless_rdp)
 	{
 		seamless_init();
@@ -1965,10 +2018,9 @@ static void
 get_window_attribs(XSetWindowAttributes * attribs)
 {
 	attribs->background_pixel = BlackPixelOfScreen(g_screen);
-	attribs->background_pixel = WhitePixelOfScreen(g_screen);
 	attribs->border_pixel = WhitePixelOfScreen(g_screen);
 	attribs->backing_store = g_ownbackstore ? NotUseful : Always;
-	attribs->override_redirect = g_fullscreen;
+	attribs->override_redirect = False;
 	attribs->colormap = g_xcolmap;
 }
 
@@ -1976,13 +2028,14 @@ static void
 get_input_mask(long *input_mask)
 {
 	*input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
-		VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
+		VisibilityChangeMask | FocusChangeMask | StructureNotifyMask |
+		SubstructureNotifyMask;
 
 	if (g_sendmotion)
 		*input_mask |= PointerMotionMask;
 	if (g_ownbackstore)
 		*input_mask |= ExposureMask;
-	if (g_fullscreen || g_grab_keyboard)
+	if (g_grab_keyboard)
 		*input_mask |= EnterWindowMask;
 	if (g_grab_keyboard)
 		*input_mask |= LeaveWindowMask;
@@ -2000,9 +2053,14 @@ ui_create_window(void)
 	int wndwidth, wndheight;
 	long input_mask, ic_input_mask;
 	XEvent xevent;
+	int wndx;
+	int wndy;
+	Atom protocols[2];
 
-	wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
-	wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
+	wndx = 0;
+	wndy = 0;
+	wndwidth = g_width;
+	wndheight = g_height;
 
 	/* Handle -x-y portion of geometry string */
 	if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
@@ -2010,9 +2068,15 @@ ui_create_window(void)
 	if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
 		g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
 
+	if (!g_fullscreen)
+	{
+		wndx = g_xpos;
+		wndy = g_ypos;
+	}
+
 	get_window_attribs(&attribs);
 
-	g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
+	g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), wndx, wndy, wndwidth,
 			      wndheight, 0, g_depth, InputOutput, g_visual,
 			      CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
 			      CWBorderPixel, &attribs);
@@ -2078,6 +2142,9 @@ ui_create_window(void)
 			input_mask |= ic_input_mask;
 	}
 
+	if (g_fullscreen)
+		ewmh_set_window_fullscreen(g_wnd, 1);
+
 	XSelectInput(g_display, g_wnd, input_mask);
 	XMapWindow(g_display, g_wnd);
 
@@ -2095,12 +2162,17 @@ ui_create_window(void)
 	/* handle the WM_DELETE_WINDOW protocol */
 	g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
 	g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
-	XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
+	g_take_focus_atom = XInternAtom(g_display, "WM_TAKE_FOCUS", True);
+	protocols[0] = g_kill_atom;
+	protocols[1] = g_take_focus_atom;
+	XSetWMProtocols(g_display, g_wnd, protocols, 2);
 
 	/* create invisible 1x1 cursor to be used as null cursor */
 	if (g_null_cursor == NULL)
 		g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
 
+	grab_special_keys();
+
 	if (g_seamless_rdp)
 	{
 		seamless_restack_test();
@@ -2118,9 +2190,16 @@ ui_resize_window()
 	sizehints = XAllocSizeHints();
 	if (sizehints)
 	{
-		sizehints->flags = PMinSize | PMaxSize;
-		sizehints->min_width = sizehints->max_width = g_width;
-		sizehints->min_height = sizehints->max_height = g_height;
+		if (g_dmx_root)
+		{
+			sizehints->flags = 0;
+		}
+		else
+		{
+			sizehints->flags = PMinSize | PMaxSize;
+			sizehints->min_width = sizehints->max_width = g_width;
+			sizehints->min_height = sizehints->max_height = g_height;
+		}
 		XSetWMNormalHints(g_display, g_wnd, sizehints);
 		XFree(sizehints);
 	}
@@ -2154,30 +2233,7 @@ ui_destroy_window(void)
 void
 xwin_toggle_fullscreen(void)
 {
-	Pixmap contents = 0;
-
-	if (g_seamless_active)
-		/* Turn off SeamlessRDP mode */
-		ui_seamless_toggle();
-
-	if (!g_ownbackstore)
-	{
-		/* need to save contents of window */
-		contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
-		XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
-	}
-
-	ui_destroy_window();
-	g_fullscreen = !g_fullscreen;
-	ui_create_window();
-
-	XDefineCursor(g_display, g_wnd, g_current_cursor);
-
-	if (!g_ownbackstore)
-	{
-		XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
-		XFreePixmap(g_display, contents);
-	}
+	ewmh_set_window_fullscreen(g_wnd, 2);
 }
 
 static void
@@ -2267,6 +2323,38 @@ handle_button_event(XEvent xevent, RD_BOOL down)
 	}
 }
 
+static Bool
+xwin_check_dmx_name_prop (Window wid)
+{
+    Atom          type;
+    unsigned long nItems;
+    unsigned long bytesAfter;
+    unsigned char *data = NULL;
+    int           format, result;
+
+    result = XGetWindowProperty (g_display, wid,
+				 XInternAtom (g_display, "DMX_NAME", False),
+                                 0, LONG_MAX, False, XA_STRING,
+                                 &type, &format, &nItems, &bytesAfter,
+                                 (unsigned char **) &data);
+
+    if (result != Success || !data)
+        return False;
+
+    XChangeProperty (g_display, g_wnd,
+		     XInternAtom (g_display, "XdndProxy", False),
+		     XA_WINDOW,
+		     32, PropModeReplace, (unsigned char *) &wid, 1);
+
+    XChangeProperty (g_display, g_wnd,
+		     XInternAtom (g_display, "DMX_ROOT", False),
+		     XA_WINDOW,
+		     32, PropModeReplace, (unsigned char *) &wid, 1);
+
+    XFree (data);
+
+    return True;
+}
 
 /* Process events in Xlib queue
    Returns 0 after user quit, 1 otherwise */
@@ -2300,6 +2388,17 @@ xwin_process_events(void)
 
 				break;
 			case ClientMessage:
+				/* move focus to dmx root window */
+				if ((xevent.xclient.message_type == g_protocol_atom)
+				    && ((Atom) xevent.xclient.data.l[0] == g_take_focus_atom))
+				{
+					if (g_dmx_root)
+						XSetInputFocus (g_display,
+								g_dmx_root,
+								RevertToParent,
+								xevent.xclient.data.l[1]);
+				}
+
 				/* the window manager told us to quit */
 				if ((xevent.xclient.message_type == g_protocol_atom)
 				    && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
@@ -2382,10 +2481,6 @@ xwin_process_events(void)
 					break;
 				}
 
-				if (g_fullscreen && !g_focused)
-					XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
-						       CurrentTime);
-
 				if (xevent.xmotion.window == g_wnd)
 				{
 					rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
@@ -2405,7 +2500,7 @@ xwin_process_events(void)
 					break;
 				g_focused = True;
 				reset_modifier_keys();
-				if (g_grab_keyboard && g_mouse_in_wnd)
+				if (!g_dmx_root && g_grab_keyboard && g_mouse_in_wnd)
 					XGrabKeyboard(g_display, g_wnd, True,
 						      GrabModeAsync, GrabModeAsync, CurrentTime);
 
@@ -2447,13 +2542,7 @@ xwin_process_events(void)
 				/* we only register for this event when in fullscreen mode */
 				/* or grab_keyboard */
 				g_mouse_in_wnd = True;
-				if (g_fullscreen)
-				{
-					XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
-						       CurrentTime);
-					break;
-				}
-				if (g_focused)
+				if (!g_dmx_root && g_focused)
 					XGrabKeyboard(g_display, g_wnd, True,
 						      GrabModeAsync, GrabModeAsync, CurrentTime);
 				break;
@@ -2506,6 +2595,11 @@ xwin_process_events(void)
 				{
 					xwin_refresh_pointer_map();
 				}
+				else
+				{
+					ungrab_special_keys();
+					grab_special_keys();
+				}
 
 				break;
 
@@ -2547,6 +2641,24 @@ xwin_process_events(void)
 
 				break;
 			case MapNotify:
+				if (!g_dmx_root)
+				{
+					if (xwin_check_dmx_name_prop (xevent.xmap.window))
+					{
+						XSizeHints *sizehints;
+
+						g_dmx_root = xevent.xmap.window;
+						XUngrabKeyboard(g_display, CurrentTime);
+						sizehints = XAllocSizeHints();
+						if (sizehints)
+						{
+							sizehints->flags = 0;
+							XSetWMNormalHints(g_display, g_wnd, sizehints);
+							XFree(sizehints);
+						}
+					}
+				}
+
 				if (!g_seamless_active)
 					rdp_send_client_window_status(1);
 				break;
@@ -2577,6 +2689,10 @@ xwin_process_events(void)
 
 				sw_handle_restack(sw);
 				break;
+			case DestroyNotify:
+				if (xevent.xdestroywindow.window == g_dmx_root)
+					return 0;
+				break;
 		}
 	}
 	/* Keep going */
@@ -2612,6 +2728,8 @@ ui_select(int rdp_socket)
 		tv.tv_sec = 60;
 		tv.tv_usec = 0;
 
+		rdpx11_add_fds(&n, &rfds, &wfds, &tv);
+
 #ifdef WITH_RDPSND
 		rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
 #endif
@@ -2628,6 +2746,8 @@ ui_select(int rdp_socket)
 				error("select: %s\n", strerror(errno));
 
 			case 0:
+				rdpx11_check_fds(&rfds, &wfds);
+
 #ifdef WITH_RDPSND
 				rdpsnd_check_fds(&rfds, &wfds);
 #endif
@@ -2638,6 +2758,8 @@ ui_select(int rdp_socket)
 				continue;
 		}
 
+		rdpx11_check_fds(&rfds, &wfds);
+
 #ifdef WITH_RDPSND
 		rdpsnd_check_fds(&rfds, &wfds);
 #endif
openSUSE Build Service is sponsored by