Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:iboss32
rdesktop
rdesktop-NOMAD.dif
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor