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