Initial support for SeamlessRDP
git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/branches/seamlessrdp-branch/rdesktop@1088 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
fddda415b1
commit
b06a70bf51
@ -25,7 +25,7 @@ LDVNC = @LDVNC@
|
|||||||
VNCLINK = @VNCLINK@
|
VNCLINK = @VNCLINK@
|
||||||
SOUNDOBJ = @SOUNDOBJ@
|
SOUNDOBJ = @SOUNDOBJ@
|
||||||
|
|
||||||
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
|
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
|
||||||
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
|
||||||
VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o
|
VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ proto:
|
|||||||
bitmap.c cache.c channels.c cliprdr.c disk.c mppc.c ewmhints.c \
|
bitmap.c cache.c channels.c cliprdr.c disk.c mppc.c ewmhints.c \
|
||||||
iso.c licence.c mcs.c orders.c parallel.c printer.c printercache.c \
|
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 rdpsnd_oss.c \
|
pstcache.c rdesktop.c rdp5.c rdp.c rdpdr.c rdpsnd.c rdpsnd_oss.c \
|
||||||
secure.c serial.c tcp.c xclip.c xkeymap.c xwin.c lspci.c >> proto.h
|
secure.c serial.c tcp.c xclip.c xkeymap.c xwin.c lspci.c seamless.c >> proto.h
|
||||||
cat proto.tail >> proto.h
|
cat proto.tail >> proto.h
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include "rdesktop.h"
|
#include "rdesktop.h"
|
||||||
|
|
||||||
#define MAX_CHANNELS 5
|
#define MAX_CHANNELS 6
|
||||||
#define CHANNEL_CHUNK_LENGTH 1600
|
#define CHANNEL_CHUNK_LENGTH 1600
|
||||||
#define CHANNEL_FLAG_FIRST 0x01
|
#define CHANNEL_FLAG_FIRST 0x01
|
||||||
#define CHANNEL_FLAG_LAST 0x02
|
#define CHANNEL_FLAG_LAST 0x02
|
||||||
|
@ -412,3 +412,8 @@ enum RDP_INPUT_DEVICE
|
|||||||
#define exDiscReasonLicenseErrClientEncryption 0x0108
|
#define exDiscReasonLicenseErrClientEncryption 0x0108
|
||||||
#define exDiscReasonLicenseCantUpgradeLicense 0x0109
|
#define exDiscReasonLicenseCantUpgradeLicense 0x0109
|
||||||
#define exDiscReasonLicenseNoRemoteConnections 0x010a
|
#define exDiscReasonLicenseNoRemoteConnections 0x010a
|
||||||
|
|
||||||
|
/* SeamlessRDP constants */
|
||||||
|
#define SEAMLESSRDP_NORMAL 0
|
||||||
|
#define SEAMLESSRDP_MINIMIZED 1
|
||||||
|
#define SEAMLESSRDP_MAXIMIZED 2
|
||||||
|
10
proto.h
10
proto.h
@ -271,8 +271,18 @@ void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy);
|
|||||||
void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy);
|
void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy);
|
||||||
void ui_begin_update(void);
|
void ui_begin_update(void);
|
||||||
void ui_end_update(void);
|
void ui_end_update(void);
|
||||||
|
void ui_seamless_toggle(void);
|
||||||
|
void ui_seamless_create_window(unsigned long id, unsigned long flags);
|
||||||
|
void ui_seamless_destroy_window(unsigned long id, unsigned long flags);
|
||||||
|
void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height,
|
||||||
|
unsigned long flags);
|
||||||
|
void ui_seamless_settitle(unsigned long id, const char *title);
|
||||||
|
void ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags);
|
||||||
/* lspci.c */
|
/* lspci.c */
|
||||||
BOOL lspci_init(void);
|
BOOL lspci_init(void);
|
||||||
|
/* seamless.c */
|
||||||
|
BOOL seamless_init(void);
|
||||||
|
void seamless_send_sync(void);
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
47
rdesktop.c
47
rdesktop.c
@ -89,6 +89,7 @@ BOOL g_numlock_sync = False;
|
|||||||
BOOL lspci_enabled = False;
|
BOOL lspci_enabled = False;
|
||||||
BOOL g_owncolmap = False;
|
BOOL g_owncolmap = False;
|
||||||
BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */
|
BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */
|
||||||
|
BOOL g_seamless_rdp = False;
|
||||||
uint32 g_embed_wnd;
|
uint32 g_embed_wnd;
|
||||||
uint32 g_rdp5_performanceflags =
|
uint32 g_rdp5_performanceflags =
|
||||||
RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
|
RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
|
||||||
@ -146,6 +147,7 @@ usage(char *program)
|
|||||||
#ifdef HAVE_ICONV
|
#ifdef HAVE_ICONV
|
||||||
fprintf(stderr, " -L: local codepage\n");
|
fprintf(stderr, " -L: local codepage\n");
|
||||||
#endif
|
#endif
|
||||||
|
fprintf(stderr, " -A: enable SeamlessRDP mode\n");
|
||||||
fprintf(stderr, " -B: use BackingStore of X-server (if available)\n");
|
fprintf(stderr, " -B: use BackingStore of X-server (if available)\n");
|
||||||
fprintf(stderr, " -e: disable encryption (French TS)\n");
|
fprintf(stderr, " -e: disable encryption (French TS)\n");
|
||||||
fprintf(stderr, " -E: disable encryption from client to server\n");
|
fprintf(stderr, " -E: disable encryption from client to server\n");
|
||||||
@ -390,6 +392,7 @@ main(int argc, char *argv[])
|
|||||||
int c;
|
int c;
|
||||||
char *locale = NULL;
|
char *locale = NULL;
|
||||||
int username_option = 0;
|
int username_option = 0;
|
||||||
|
BOOL geometry_option = False;
|
||||||
int run_count = 0; /* Session Directory support */
|
int run_count = 0; /* Session Directory support */
|
||||||
BOOL continue_connect = True; /* Session Directory support */
|
BOOL continue_connect = True; /* Session Directory support */
|
||||||
|
|
||||||
@ -416,7 +419,7 @@ main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
while ((c = getopt(argc, argv,
|
while ((c = getopt(argc, argv,
|
||||||
VNCOPT "u: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:fbBeEmzCDKS:T:NX:a:x:Pr:045h?")) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
@ -434,6 +437,10 @@ main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
case 'A':
|
||||||
|
g_seamless_rdp = True;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
STRNCPY(g_username, optarg, sizeof(g_username));
|
STRNCPY(g_username, optarg, sizeof(g_username));
|
||||||
username_option = 1;
|
username_option = 1;
|
||||||
@ -484,6 +491,7 @@ main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
|
geometry_option = True;
|
||||||
g_fullscreen = False;
|
g_fullscreen = False;
|
||||||
if (!strcmp(optarg, "workarea"))
|
if (!strcmp(optarg, "workarea"))
|
||||||
{
|
{
|
||||||
@ -732,6 +740,43 @@ main(int argc, char *argv[])
|
|||||||
STRNCPY(server, argv[optind], sizeof(server));
|
STRNCPY(server, argv[optind], sizeof(server));
|
||||||
parse_server_and_port(server);
|
parse_server_and_port(server);
|
||||||
|
|
||||||
|
if (g_seamless_rdp)
|
||||||
|
{
|
||||||
|
if (g_win_button_size)
|
||||||
|
{
|
||||||
|
error("You cannot use -S and -A at the same time\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
g_rdp5_performanceflags &= ~RDP5_NO_FULLWINDOWDRAG;
|
||||||
|
if (geometry_option)
|
||||||
|
{
|
||||||
|
error("You cannot use -g and -A at the same time\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (g_fullscreen)
|
||||||
|
{
|
||||||
|
error("You cannot use -f and -A at the same time\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (g_hide_decorations)
|
||||||
|
{
|
||||||
|
error("You cannot use -D and -A at the same time\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (g_embed_wnd)
|
||||||
|
{
|
||||||
|
error("You cannot use -X and -A at the same time\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!g_use_rdp5)
|
||||||
|
{
|
||||||
|
error("You cannot use -4 and -A at the same time\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
g_width = -100;
|
||||||
|
g_grab_keyboard = False;
|
||||||
|
}
|
||||||
|
|
||||||
if (!username_option)
|
if (!username_option)
|
||||||
{
|
{
|
||||||
pw = getpwuid(getuid());
|
pw = getpwuid(getuid());
|
||||||
|
252
seamless.c
Normal file
252
seamless.c
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
/* -*- c-basic-offset: 8 -*-
|
||||||
|
rdesktop: A Remote Desktop Protocol client.
|
||||||
|
Seamless Windows support
|
||||||
|
Copyright (C) Peter Astrand <astrand@cendio.se> 2005-2006
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rdesktop.h"
|
||||||
|
|
||||||
|
/* #define WITH_DEBUG_SEAMLESS */
|
||||||
|
|
||||||
|
#ifdef WITH_DEBUG_SEAMLESS
|
||||||
|
#define DEBUG_SEAMLESS(args) printf args;
|
||||||
|
#else
|
||||||
|
#define DEBUG_SEAMLESS(args)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern BOOL g_seamless_rdp;
|
||||||
|
static VCHANNEL *seamless_channel;
|
||||||
|
|
||||||
|
static char *
|
||||||
|
seamless_get_token(char **s)
|
||||||
|
{
|
||||||
|
char *comma, *head;
|
||||||
|
head = *s;
|
||||||
|
|
||||||
|
if (!head)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
comma = strchr(head, ',');
|
||||||
|
if (comma)
|
||||||
|
{
|
||||||
|
*comma = '\0';
|
||||||
|
*s = comma + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
seamless_process_line(const char *line, void *data)
|
||||||
|
{
|
||||||
|
char *p, *l;
|
||||||
|
char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8;
|
||||||
|
unsigned long id, flags;
|
||||||
|
char *endptr;
|
||||||
|
|
||||||
|
l = xstrdup(line);
|
||||||
|
p = l;
|
||||||
|
|
||||||
|
DEBUG_SEAMLESS(("seamlessrdp line:%s\n", p));
|
||||||
|
|
||||||
|
if (!g_seamless_rdp)
|
||||||
|
return True;
|
||||||
|
|
||||||
|
tok1 = seamless_get_token(&p);
|
||||||
|
tok2 = seamless_get_token(&p);
|
||||||
|
tok3 = seamless_get_token(&p);
|
||||||
|
tok4 = seamless_get_token(&p);
|
||||||
|
tok5 = seamless_get_token(&p);
|
||||||
|
tok6 = seamless_get_token(&p);
|
||||||
|
tok7 = seamless_get_token(&p);
|
||||||
|
tok8 = seamless_get_token(&p);
|
||||||
|
|
||||||
|
if (!strcmp("CREATE1", tok1))
|
||||||
|
{
|
||||||
|
if (!tok3)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
id = strtol(tok2, &endptr, 16);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
flags = strtol(tok3, &endptr, 16);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
ui_seamless_create_window(id, flags);
|
||||||
|
}
|
||||||
|
else if (!strcmp("DESTROY1", tok1))
|
||||||
|
{
|
||||||
|
if (!tok3)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
id = strtol(tok2, &endptr, 16);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
flags = strtol(tok3, &endptr, 16);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
ui_seamless_destroy_window(id, flags);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (!strcmp("SETICON1", tok1))
|
||||||
|
{
|
||||||
|
unimpl("SeamlessRDP SETICON1\n");
|
||||||
|
}
|
||||||
|
else if (!strcmp("POSITION1", tok1))
|
||||||
|
{
|
||||||
|
int x, y, width, height;
|
||||||
|
|
||||||
|
if (!tok7)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
id = strtol(tok2, &endptr, 16);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
x = strtol(tok3, &endptr, 10);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
y = strtol(tok4, &endptr, 10);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
width = strtol(tok5, &endptr, 10);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
height = strtol(tok6, &endptr, 10);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
flags = strtol(tok7, &endptr, 16);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
ui_seamless_move_window(id, x, y, width, height, flags);
|
||||||
|
}
|
||||||
|
else if (!strcmp("ZCHANGE1", tok1))
|
||||||
|
{
|
||||||
|
unimpl("SeamlessRDP ZCHANGE1\n");
|
||||||
|
}
|
||||||
|
else if (!strcmp("SETSTATE1", tok1))
|
||||||
|
{
|
||||||
|
unsigned int state;
|
||||||
|
|
||||||
|
if (!tok5)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
id = strtol(tok2, &endptr, 16);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
state = strtol(tok4, &endptr, 16); // XXX
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
flags = strtol(tok5, &endptr, 16);
|
||||||
|
if (*endptr)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
/* FIXME */
|
||||||
|
ui_seamless_settitle(id, tok3);
|
||||||
|
ui_seamless_setstate(id, state, flags);
|
||||||
|
}
|
||||||
|
else if (!strcmp("DEBUG1", tok1))
|
||||||
|
{
|
||||||
|
printf("SeamlessRDP:%s\n", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree(l);
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
seamless_line_handler(const char *line, void *data)
|
||||||
|
{
|
||||||
|
if (!seamless_process_line(line, data))
|
||||||
|
{
|
||||||
|
warning("SeamlessRDP: Invalid request:%s\n", line);
|
||||||
|
}
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
seamless_process(STREAM s)
|
||||||
|
{
|
||||||
|
unsigned int pkglen;
|
||||||
|
static char *rest = NULL;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
pkglen = s->end - s->p;
|
||||||
|
/* str_handle_lines requires null terminated strings */
|
||||||
|
buf = xmalloc(pkglen + 1);
|
||||||
|
STRNCPY(buf, (char *) s->p, pkglen + 1);
|
||||||
|
#if 0
|
||||||
|
printf("seamless recv:\n");
|
||||||
|
hexdump(s->p, pkglen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
str_handle_lines(buf, &rest, seamless_line_handler, NULL);
|
||||||
|
|
||||||
|
xfree(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
seamless_init(void)
|
||||||
|
{
|
||||||
|
seamless_channel =
|
||||||
|
channel_register("seamrdp", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
|
||||||
|
seamless_process);
|
||||||
|
return (seamless_channel != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
seamless_send(const char *output)
|
||||||
|
{
|
||||||
|
STREAM s;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = strlen(output);
|
||||||
|
s = channel_init(seamless_channel, len);
|
||||||
|
out_uint8p(s, output, len) s_mark_end(s);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("seamless send:\n");
|
||||||
|
hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
channel_send(s, seamless_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
seamless_send_sync()
|
||||||
|
{
|
||||||
|
seamless_send("SYNC\n");
|
||||||
|
}
|
19
seamless.h
Normal file
19
seamless.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
rdesktop: A Remote Desktop Protocol client.
|
||||||
|
Seamless Windows support
|
||||||
|
Copyright (C) Peter Astrand <astrand@cendio.se> 2005-2006
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
@ -589,6 +589,11 @@ handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pres
|
|||||||
/* Inhibit */
|
/* Inhibit */
|
||||||
return True;
|
return True;
|
||||||
break;
|
break;
|
||||||
|
case XK_Overlay1_Enable:
|
||||||
|
/* Toggle SeamlessRDP */
|
||||||
|
if (pressed)
|
||||||
|
ui_seamless_toggle();
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
return False;
|
return False;
|
||||||
|
481
xwin.c
481
xwin.c
@ -48,12 +48,26 @@ Time g_last_gesturetime;
|
|||||||
static int g_x_socket;
|
static int g_x_socket;
|
||||||
static Screen *g_screen;
|
static Screen *g_screen;
|
||||||
Window g_wnd;
|
Window g_wnd;
|
||||||
|
|
||||||
|
/* SeamlessRDP support */
|
||||||
|
typedef struct _seamless_window
|
||||||
|
{
|
||||||
|
Window wnd;
|
||||||
|
unsigned long id;
|
||||||
|
int xoffset, yoffset;
|
||||||
|
int width, height;
|
||||||
|
struct _seamless_window *next;
|
||||||
|
} seamless_window;
|
||||||
|
static seamless_window *g_seamless_windows = NULL;
|
||||||
|
extern BOOL g_seamless_rdp;
|
||||||
|
|
||||||
extern uint32 g_embed_wnd;
|
extern uint32 g_embed_wnd;
|
||||||
BOOL g_enable_compose = False;
|
BOOL g_enable_compose = False;
|
||||||
BOOL g_Unobscured; /* used for screenblt */
|
BOOL g_Unobscured; /* used for screenblt */
|
||||||
static GC g_gc = NULL;
|
static GC g_gc = NULL;
|
||||||
static GC g_create_bitmap_gc = NULL;
|
static GC g_create_bitmap_gc = NULL;
|
||||||
static GC g_create_glyph_gc = NULL;
|
static GC g_create_glyph_gc = NULL;
|
||||||
|
static XRectangle g_clip_rectangle;
|
||||||
static Visual *g_visual;
|
static Visual *g_visual;
|
||||||
/* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
|
/* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
|
||||||
This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
|
This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
|
||||||
@ -133,10 +147,45 @@ typedef struct
|
|||||||
}
|
}
|
||||||
PixelColour;
|
PixelColour;
|
||||||
|
|
||||||
|
#define ON_ALL_SEAMLESS_WINDOWS(func, args) \
|
||||||
|
do { \
|
||||||
|
seamless_window *sw; \
|
||||||
|
XRectangle rect; \
|
||||||
|
for (sw = g_seamless_windows; sw; sw = sw->next) { \
|
||||||
|
rect.x = g_clip_rectangle.x - sw->xoffset; \
|
||||||
|
rect.y = g_clip_rectangle.y - sw->yoffset; \
|
||||||
|
rect.width = g_clip_rectangle.width; \
|
||||||
|
rect.height = g_clip_rectangle.height; \
|
||||||
|
XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
|
||||||
|
func args; \
|
||||||
|
} \
|
||||||
|
XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void
|
||||||
|
seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
|
||||||
|
{
|
||||||
|
points[0].x -= xoffset;
|
||||||
|
points[0].y -= yoffset;
|
||||||
|
XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
|
||||||
|
points[0].x += xoffset;
|
||||||
|
points[0].y += yoffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
|
||||||
|
{
|
||||||
|
points[0].x -= xoffset;
|
||||||
|
points[0].y -= yoffset;
|
||||||
|
XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
|
||||||
|
points[0].x += xoffset;
|
||||||
|
points[0].y += yoffset;
|
||||||
|
}
|
||||||
|
|
||||||
#define FILL_RECTANGLE(x,y,cx,cy)\
|
#define FILL_RECTANGLE(x,y,cx,cy)\
|
||||||
{ \
|
{ \
|
||||||
XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
|
XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
|
||||||
if (g_ownbackstore) \
|
if (g_ownbackstore) \
|
||||||
XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
|
XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
|
||||||
}
|
}
|
||||||
@ -151,6 +200,7 @@ PixelColour;
|
|||||||
XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
|
XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
|
||||||
if (g_ownbackstore) \
|
if (g_ownbackstore) \
|
||||||
XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
|
XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DRAW_ELLIPSE(x,y,cx,cy,m)\
|
#define DRAW_ELLIPSE(x,y,cx,cy,m)\
|
||||||
@ -159,11 +209,14 @@ PixelColour;
|
|||||||
{ \
|
{ \
|
||||||
case 0: /* Outline */ \
|
case 0: /* Outline */ \
|
||||||
XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
|
XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
|
||||||
if (g_ownbackstore) \
|
if (g_ownbackstore) \
|
||||||
XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
|
XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
|
||||||
break; \
|
break; \
|
||||||
case 1: /* Filled */ \
|
case 1: /* Filled */ \
|
||||||
XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
|
XFillArc(g_display, g_wnd, g_gc, x, y, \
|
||||||
|
cx, cy, 0, 360*64); \
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
|
||||||
if (g_ownbackstore) \
|
if (g_ownbackstore) \
|
||||||
XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
|
XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
|
||||||
break; \
|
break; \
|
||||||
@ -201,8 +254,52 @@ static int rop2_map[] = {
|
|||||||
#define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
|
#define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
|
||||||
#define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
|
#define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
|
||||||
|
|
||||||
|
static seamless_window *
|
||||||
|
seamless_get_window_by_id(unsigned long id)
|
||||||
|
{
|
||||||
|
seamless_window *sw;
|
||||||
|
for (sw = g_seamless_windows; sw; sw = sw->next)
|
||||||
|
{
|
||||||
|
if (sw->id == id)
|
||||||
|
return sw;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static seamless_window *
|
||||||
|
seamless_get_window_by_wnd(Window wnd)
|
||||||
|
{
|
||||||
|
seamless_window *sw;
|
||||||
|
for (sw = g_seamless_windows; sw; sw = sw->next)
|
||||||
|
{
|
||||||
|
if (sw->wnd == wnd)
|
||||||
|
return sw;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mwm_hide_decorations(void)
|
seamless_remove_window(seamless_window * win)
|
||||||
|
{
|
||||||
|
seamless_window *sw, **prevnext = &g_seamless_windows;
|
||||||
|
for (sw = g_seamless_windows; sw; sw = sw->next)
|
||||||
|
{
|
||||||
|
if (sw == win)
|
||||||
|
{
|
||||||
|
*prevnext = sw->next;
|
||||||
|
xfree(sw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prevnext = &sw->next;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
mwm_hide_decorations(Window wnd)
|
||||||
{
|
{
|
||||||
PropMotifWmHints motif_hints;
|
PropMotifWmHints motif_hints;
|
||||||
Atom hintsatom;
|
Atom hintsatom;
|
||||||
@ -219,8 +316,9 @@ mwm_hide_decorations(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,
|
XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
|
||||||
(unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
|
(unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SPLITCOLOUR15(colour, rv) \
|
#define SPLITCOLOUR15(colour, rv) \
|
||||||
@ -1298,6 +1396,8 @@ ui_init(void)
|
|||||||
g_IM = XOpenIM(g_display, NULL, NULL, NULL);
|
g_IM = XOpenIM(g_display, NULL, NULL, NULL);
|
||||||
|
|
||||||
xclip_init();
|
xclip_init();
|
||||||
|
if (g_seamless_rdp)
|
||||||
|
seamless_init();
|
||||||
|
|
||||||
DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
|
DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
|
||||||
|
|
||||||
@ -1323,6 +1423,34 @@ ui_deinit(void)
|
|||||||
g_display = NULL;
|
g_display = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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->colormap = g_xcolmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_input_mask(long *input_mask)
|
||||||
|
{
|
||||||
|
*input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
||||||
|
VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
|
||||||
|
|
||||||
|
if (g_sendmotion)
|
||||||
|
*input_mask |= PointerMotionMask;
|
||||||
|
if (g_ownbackstore)
|
||||||
|
*input_mask |= ExposureMask;
|
||||||
|
if (g_fullscreen || g_grab_keyboard)
|
||||||
|
*input_mask |= EnterWindowMask;
|
||||||
|
if (g_grab_keyboard)
|
||||||
|
*input_mask |= LeaveWindowMask;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
ui_create_window(void)
|
ui_create_window(void)
|
||||||
{
|
{
|
||||||
@ -1345,11 +1473,7 @@ ui_create_window(void)
|
|||||||
if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
|
if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
|
||||||
g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
|
g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
|
||||||
|
|
||||||
attribs.background_pixel = BlackPixelOfScreen(g_screen);
|
get_window_attribs(&attribs);
|
||||||
attribs.border_pixel = WhitePixelOfScreen(g_screen);
|
|
||||||
attribs.backing_store = g_ownbackstore ? NotUseful : Always;
|
|
||||||
attribs.override_redirect = g_fullscreen;
|
|
||||||
attribs.colormap = g_xcolmap;
|
|
||||||
|
|
||||||
g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
|
g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
|
||||||
wndheight, 0, g_depth, InputOutput, g_visual,
|
wndheight, 0, g_depth, InputOutput, g_visual,
|
||||||
@ -1357,7 +1481,10 @@ ui_create_window(void)
|
|||||||
CWBorderPixel, &attribs);
|
CWBorderPixel, &attribs);
|
||||||
|
|
||||||
if (g_gc == NULL)
|
if (g_gc == NULL)
|
||||||
|
{
|
||||||
g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
|
g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
|
||||||
|
ui_reset_clip();
|
||||||
|
}
|
||||||
|
|
||||||
if (g_create_bitmap_gc == NULL)
|
if (g_create_bitmap_gc == NULL)
|
||||||
g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
|
g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
|
||||||
@ -1374,7 +1501,7 @@ ui_create_window(void)
|
|||||||
XStoreName(g_display, g_wnd, g_title);
|
XStoreName(g_display, g_wnd, g_title);
|
||||||
|
|
||||||
if (g_hide_decorations)
|
if (g_hide_decorations)
|
||||||
mwm_hide_decorations();
|
mwm_hide_decorations(g_wnd);
|
||||||
|
|
||||||
classhints = XAllocClassHint();
|
classhints = XAllocClassHint();
|
||||||
if (classhints != NULL)
|
if (classhints != NULL)
|
||||||
@ -1401,17 +1528,7 @@ ui_create_window(void)
|
|||||||
XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
|
XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
get_input_mask(&input_mask);
|
||||||
VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
|
|
||||||
|
|
||||||
if (g_sendmotion)
|
|
||||||
input_mask |= PointerMotionMask;
|
|
||||||
if (g_ownbackstore)
|
|
||||||
input_mask |= ExposureMask;
|
|
||||||
if (g_fullscreen || g_grab_keyboard)
|
|
||||||
input_mask |= EnterWindowMask;
|
|
||||||
if (g_grab_keyboard)
|
|
||||||
input_mask |= LeaveWindowMask;
|
|
||||||
|
|
||||||
if (g_IM != NULL)
|
if (g_IM != NULL)
|
||||||
{
|
{
|
||||||
@ -1424,8 +1541,9 @@ ui_create_window(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
XSelectInput(g_display, g_wnd, input_mask);
|
XSelectInput(g_display, g_wnd, input_mask);
|
||||||
|
if (!g_seamless_rdp)
|
||||||
|
{
|
||||||
XMapWindow(g_display, g_wnd);
|
XMapWindow(g_display, g_wnd);
|
||||||
|
|
||||||
/* wait for VisibilityNotify */
|
/* wait for VisibilityNotify */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -1433,6 +1551,7 @@ ui_create_window(void)
|
|||||||
}
|
}
|
||||||
while (xevent.type != VisibilityNotify);
|
while (xevent.type != VisibilityNotify);
|
||||||
g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
|
g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
|
||||||
|
}
|
||||||
|
|
||||||
g_focused = False;
|
g_focused = False;
|
||||||
g_mouse_in_wnd = False;
|
g_mouse_in_wnd = False;
|
||||||
@ -1496,6 +1615,10 @@ xwin_toggle_fullscreen(void)
|
|||||||
{
|
{
|
||||||
Pixmap contents = 0;
|
Pixmap contents = 0;
|
||||||
|
|
||||||
|
if (g_seamless_rdp)
|
||||||
|
/* Turn off SeamlessRDP mode */
|
||||||
|
ui_seamless_toggle();
|
||||||
|
|
||||||
if (!g_ownbackstore)
|
if (!g_ownbackstore)
|
||||||
{
|
{
|
||||||
/* need to save contents of window */
|
/* need to save contents of window */
|
||||||
@ -1584,8 +1707,17 @@ handle_button_event(XEvent xevent, BOOL down)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xevent.xmotion.window == g_wnd)
|
||||||
|
{
|
||||||
rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
|
rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
|
||||||
flags | button, xevent.xbutton.x, xevent.xbutton.y);
|
flags | button, xevent.xbutton.x, xevent.xbutton.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* SeamlessRDP */
|
||||||
|
rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
|
||||||
|
flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process events in Xlib queue
|
/* Process events in Xlib queue
|
||||||
@ -1613,7 +1745,10 @@ xwin_process_events(void)
|
|||||||
switch (xevent.type)
|
switch (xevent.type)
|
||||||
{
|
{
|
||||||
case VisibilityNotify:
|
case VisibilityNotify:
|
||||||
g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
|
if (xevent.xvisibility.window == g_wnd)
|
||||||
|
g_Unobscured =
|
||||||
|
xevent.xvisibility.state == VisibilityUnobscured;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ClientMessage:
|
case ClientMessage:
|
||||||
/* the window manager told us to quit */
|
/* the window manager told us to quit */
|
||||||
@ -1693,8 +1828,19 @@ xwin_process_events(void)
|
|||||||
if (g_fullscreen && !g_focused)
|
if (g_fullscreen && !g_focused)
|
||||||
XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
|
XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
|
||||||
CurrentTime);
|
CurrentTime);
|
||||||
rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
|
|
||||||
MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
|
if (xevent.xmotion.window == g_wnd)
|
||||||
|
{
|
||||||
|
rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
|
||||||
|
xevent.xmotion.x, xevent.xmotion.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* SeamlessRDP */
|
||||||
|
rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
|
||||||
|
xevent.xmotion.x_root,
|
||||||
|
xevent.xmotion.y_root);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FocusIn:
|
case FocusIn:
|
||||||
@ -1737,11 +1883,28 @@ xwin_process_events(void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Expose:
|
case Expose:
|
||||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc,
|
if (xevent.xexpose.window == g_wnd)
|
||||||
|
{
|
||||||
|
XCopyArea(g_display, g_backstore, xevent.xexpose.window,
|
||||||
|
g_gc,
|
||||||
xevent.xexpose.x, xevent.xexpose.y,
|
xevent.xexpose.x, xevent.xexpose.y,
|
||||||
xevent.xexpose.width,
|
xevent.xexpose.width, xevent.xexpose.height,
|
||||||
xevent.xexpose.height,
|
|
||||||
xevent.xexpose.x, xevent.xexpose.y);
|
xevent.xexpose.x, xevent.xexpose.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seamless_window *sw;
|
||||||
|
sw = seamless_get_window_by_wnd(xevent.xexpose.window);
|
||||||
|
if (sw)
|
||||||
|
XCopyArea(g_display, g_backstore,
|
||||||
|
xevent.xexpose.window, g_gc,
|
||||||
|
xevent.xexpose.x + sw->xoffset,
|
||||||
|
xevent.xexpose.y + sw->yoffset,
|
||||||
|
xevent.xexpose.width,
|
||||||
|
xevent.xexpose.height, xevent.xexpose.x,
|
||||||
|
xevent.xexpose.y);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MappingNotify:
|
case MappingNotify:
|
||||||
@ -1772,9 +1935,11 @@ xwin_process_events(void)
|
|||||||
xclip_handle_PropertyNotify(&xevent.xproperty);
|
xclip_handle_PropertyNotify(&xevent.xproperty);
|
||||||
break;
|
break;
|
||||||
case MapNotify:
|
case MapNotify:
|
||||||
|
if (!g_seamless_rdp)
|
||||||
rdp_send_client_window_status(1);
|
rdp_send_client_window_status(1);
|
||||||
break;
|
break;
|
||||||
case UnmapNotify:
|
case UnmapNotify:
|
||||||
|
if (!g_seamless_rdp)
|
||||||
rdp_send_client_window_status(0);
|
rdp_send_client_window_status(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1912,10 +2077,16 @@ ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * dat
|
|||||||
{
|
{
|
||||||
XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
|
XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
|
||||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
|
XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
|
||||||
|
x - sw->xoffset, y - sw->yoffset));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
|
XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
|
||||||
|
x - sw->xoffset, y - sw->yoffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
XFree(image);
|
XFree(image);
|
||||||
@ -2036,6 +2207,7 @@ ui_set_cursor(HCURSOR cursor)
|
|||||||
{
|
{
|
||||||
g_current_cursor = (Cursor) cursor;
|
g_current_cursor = (Cursor) cursor;
|
||||||
XDefineCursor(g_display, g_wnd, g_current_cursor);
|
XDefineCursor(g_display, g_wnd, g_current_cursor);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2177,31 +2349,30 @@ ui_set_colourmap(HCOLOURMAP map)
|
|||||||
g_colmap = (uint32 *) map;
|
g_colmap = (uint32 *) map;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
XSetWindowColormap(g_display, g_wnd, (Colormap) map);
|
XSetWindowColormap(g_display, g_wnd, (Colormap) map);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ui_set_clip(int x, int y, int cx, int cy)
|
ui_set_clip(int x, int y, int cx, int cy)
|
||||||
{
|
{
|
||||||
XRectangle rect;
|
g_clip_rectangle.x = x;
|
||||||
|
g_clip_rectangle.y = y;
|
||||||
rect.x = x;
|
g_clip_rectangle.width = cx;
|
||||||
rect.y = y;
|
g_clip_rectangle.height = cy;
|
||||||
rect.width = cx;
|
XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
|
||||||
rect.height = cy;
|
|
||||||
XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ui_reset_clip(void)
|
ui_reset_clip(void)
|
||||||
{
|
{
|
||||||
XRectangle rect;
|
g_clip_rectangle.x = 0;
|
||||||
|
g_clip_rectangle.y = 0;
|
||||||
rect.x = 0;
|
g_clip_rectangle.width = g_width;
|
||||||
rect.y = 0;
|
g_clip_rectangle.height = g_height;
|
||||||
rect.width = g_width;
|
XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
|
||||||
rect.height = g_height;
|
|
||||||
XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2282,6 +2453,9 @@ ui_patblt(uint8 opcode,
|
|||||||
|
|
||||||
if (g_ownbackstore)
|
if (g_ownbackstore)
|
||||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
|
XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
|
||||||
|
x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2292,23 +2466,19 @@ ui_screenblt(uint8 opcode,
|
|||||||
SET_FUNCTION(opcode);
|
SET_FUNCTION(opcode);
|
||||||
if (g_ownbackstore)
|
if (g_ownbackstore)
|
||||||
{
|
{
|
||||||
if (g_Unobscured)
|
XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
|
||||||
{
|
g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
|
||||||
XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
|
XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
|
||||||
XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
|
|
||||||
y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
|
|
||||||
XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
|
|
||||||
y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
|
XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, g_ownbackstore ? g_backstore : g_wnd,
|
||||||
|
sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
|
||||||
|
|
||||||
RESET_FUNCTION(opcode);
|
RESET_FUNCTION(opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2319,6 +2489,9 @@ ui_memblt(uint8 opcode,
|
|||||||
{
|
{
|
||||||
SET_FUNCTION(opcode);
|
SET_FUNCTION(opcode);
|
||||||
XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
|
XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, (Pixmap) src, sw->wnd, g_gc,
|
||||||
|
srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
|
||||||
if (g_ownbackstore)
|
if (g_ownbackstore)
|
||||||
XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
|
XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
|
||||||
RESET_FUNCTION(opcode);
|
RESET_FUNCTION(opcode);
|
||||||
@ -2365,6 +2538,9 @@ ui_line(uint8 opcode,
|
|||||||
SET_FUNCTION(opcode);
|
SET_FUNCTION(opcode);
|
||||||
SET_FOREGROUND(pen->colour);
|
SET_FOREGROUND(pen->colour);
|
||||||
XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
|
XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
|
||||||
|
startx - sw->xoffset, starty - sw->yoffset,
|
||||||
|
endx - sw->xoffset, endy - sw->yoffset));
|
||||||
if (g_ownbackstore)
|
if (g_ownbackstore)
|
||||||
XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
|
XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
|
||||||
RESET_FUNCTION(opcode);
|
RESET_FUNCTION(opcode);
|
||||||
@ -2462,6 +2638,10 @@ ui_polyline(uint8 opcode,
|
|||||||
if (g_ownbackstore)
|
if (g_ownbackstore)
|
||||||
XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
|
XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
|
||||||
CoordModePrevious);
|
CoordModePrevious);
|
||||||
|
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
|
||||||
|
(sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
|
||||||
|
|
||||||
RESET_FUNCTION(opcode);
|
RESET_FUNCTION(opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2682,11 +2862,25 @@ ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
|
|||||||
if (g_ownbackstore)
|
if (g_ownbackstore)
|
||||||
{
|
{
|
||||||
if (boxcx > 1)
|
if (boxcx > 1)
|
||||||
|
{
|
||||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
|
XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
|
||||||
boxy, boxcx, boxcy, boxx, boxy);
|
boxy, boxcx, boxcy, boxx, boxy);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, g_backstore, sw->wnd, g_gc,
|
||||||
|
boxx, boxy,
|
||||||
|
boxcx, boxcy,
|
||||||
|
boxx - sw->xoffset, boxy - sw->yoffset));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
|
XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
|
||||||
clipy, clipcx, clipcy, clipx, clipy);
|
clipy, clipcx, clipcy, clipx, clipy);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, g_backstore, sw->wnd, g_gc,
|
||||||
|
clipx, clipy,
|
||||||
|
clipcx, clipcy, clipx - sw->xoffset,
|
||||||
|
clipy - sw->yoffset));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2732,10 +2926,16 @@ ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
|
|||||||
{
|
{
|
||||||
XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
|
XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
|
||||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
|
XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, g_backstore, sw->wnd, g_gc,
|
||||||
|
x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
|
XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
|
||||||
|
ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
|
||||||
|
(g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
|
||||||
|
x - sw->xoffset, y - sw->yoffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
XFree(image);
|
XFree(image);
|
||||||
@ -2751,3 +2951,178 @@ void
|
|||||||
ui_end_update(void)
|
ui_end_update(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_seamless_toggle()
|
||||||
|
{
|
||||||
|
if (g_seamless_rdp)
|
||||||
|
{
|
||||||
|
/* Deactivate */
|
||||||
|
while (g_seamless_windows)
|
||||||
|
{
|
||||||
|
XDestroyWindow(g_display, g_seamless_windows->wnd);
|
||||||
|
seamless_remove_window(g_seamless_windows);
|
||||||
|
}
|
||||||
|
XMapWindow(g_display, g_wnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Activate */
|
||||||
|
if (g_win_button_size)
|
||||||
|
{
|
||||||
|
error("SeamlessRDP mode cannot be activated when using single application mode\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!g_using_full_workarea)
|
||||||
|
{
|
||||||
|
error("SeamlessRDP mode requires a session that covers the whole screen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XUnmapWindow(g_display, g_wnd);
|
||||||
|
seamless_send_sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
g_seamless_rdp = !g_seamless_rdp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_seamless_create_window(unsigned long id, unsigned long flags)
|
||||||
|
{
|
||||||
|
Window wnd;
|
||||||
|
XSetWindowAttributes attribs;
|
||||||
|
XClassHint *classhints;
|
||||||
|
long input_mask;
|
||||||
|
seamless_window *sw;
|
||||||
|
|
||||||
|
get_window_attribs(&attribs);
|
||||||
|
|
||||||
|
attribs.override_redirect = False;
|
||||||
|
|
||||||
|
/* FIXME: Do not assume that -1, -1 is outside screen Consider
|
||||||
|
wait with showing the window until STATE and others have
|
||||||
|
been recieved. */
|
||||||
|
wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, 0,
|
||||||
|
InputOutput, g_visual,
|
||||||
|
CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
|
||||||
|
CWBorderPixel, &attribs);
|
||||||
|
|
||||||
|
XStoreName(g_display, wnd, "rdesktop-seamless");
|
||||||
|
|
||||||
|
mwm_hide_decorations(wnd);
|
||||||
|
|
||||||
|
classhints = XAllocClassHint();
|
||||||
|
if (classhints != NULL)
|
||||||
|
{
|
||||||
|
classhints->res_name = classhints->res_class = "rdesktop";
|
||||||
|
XSetClassHint(g_display, wnd, classhints);
|
||||||
|
XFree(classhints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Support for Input Context:s */
|
||||||
|
|
||||||
|
get_input_mask(&input_mask);
|
||||||
|
|
||||||
|
XSelectInput(g_display, wnd, input_mask);
|
||||||
|
|
||||||
|
XMapWindow(g_display, wnd);
|
||||||
|
|
||||||
|
/* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
|
||||||
|
seamless window, we could try to close the window on the
|
||||||
|
serverside, instead of terminating rdesktop */
|
||||||
|
XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
|
||||||
|
|
||||||
|
sw = malloc(sizeof(seamless_window));
|
||||||
|
sw->wnd = wnd;
|
||||||
|
sw->id = id;
|
||||||
|
sw->xoffset = 0;
|
||||||
|
sw->yoffset = 0;
|
||||||
|
sw->width = 0;
|
||||||
|
sw->height = 0;
|
||||||
|
sw->next = g_seamless_windows;
|
||||||
|
g_seamless_windows = sw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_seamless_destroy_window(unsigned long id, unsigned long flags)
|
||||||
|
{
|
||||||
|
seamless_window *sw;
|
||||||
|
sw = seamless_get_window_by_id(id);
|
||||||
|
|
||||||
|
if (!sw)
|
||||||
|
{
|
||||||
|
warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDestroyWindow(g_display, sw->wnd);
|
||||||
|
seamless_remove_window(sw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
|
||||||
|
{
|
||||||
|
seamless_window *sw;
|
||||||
|
|
||||||
|
sw = seamless_get_window_by_id(id);
|
||||||
|
|
||||||
|
if (!sw)
|
||||||
|
{
|
||||||
|
warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!width || !height)
|
||||||
|
/* X11 windows must be at least 1x1 */
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* About MAX and MIN: Windows allows moving a window outside
|
||||||
|
the desktop. This happens, for example, when maximizing an
|
||||||
|
application. In this case, the position is set to something
|
||||||
|
like -4,-4,1288,1032. Many WMs does not allow windows
|
||||||
|
outside the desktop, however. Therefore, clip the window
|
||||||
|
ourselves. */
|
||||||
|
sw->xoffset = MAX(0, x);
|
||||||
|
sw->yoffset = MAX(0, y);
|
||||||
|
sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
|
||||||
|
sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
|
||||||
|
|
||||||
|
/* FIXME: Perhaps use ewmh_net_moveresize_window instead */
|
||||||
|
XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_seamless_settitle(unsigned long id, const char *title)
|
||||||
|
{
|
||||||
|
seamless_window *sw;
|
||||||
|
|
||||||
|
sw = seamless_get_window_by_id(id);
|
||||||
|
|
||||||
|
XStoreName(g_display, sw->wnd, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
|
||||||
|
{
|
||||||
|
seamless_window *sw;
|
||||||
|
|
||||||
|
sw = seamless_get_window_by_id(id);
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case SEAMLESSRDP_NORMAL:
|
||||||
|
case SEAMLESSRDP_MAXIMIZED:
|
||||||
|
/* FIXME */
|
||||||
|
break;
|
||||||
|
case SEAMLESSRDP_MINIMIZED:
|
||||||
|
XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warning("SeamlessRDP: Invalid state %d\n", state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user