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@
|
||||
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
|
||||
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 \
|
||||
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 \
|
||||
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
|
||||
|
||||
.PHONY: clean
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#include "rdesktop.h"
|
||||
|
||||
#define MAX_CHANNELS 5
|
||||
#define MAX_CHANNELS 6
|
||||
#define CHANNEL_CHUNK_LENGTH 1600
|
||||
#define CHANNEL_FLAG_FIRST 0x01
|
||||
#define CHANNEL_FLAG_LAST 0x02
|
||||
|
@ -412,3 +412,8 @@ enum RDP_INPUT_DEVICE
|
||||
#define exDiscReasonLicenseErrClientEncryption 0x0108
|
||||
#define exDiscReasonLicenseCantUpgradeLicense 0x0109
|
||||
#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_begin_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 */
|
||||
BOOL lspci_init(void);
|
||||
/* seamless.c */
|
||||
BOOL seamless_init(void);
|
||||
void seamless_send_sync(void);
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
|
47
rdesktop.c
47
rdesktop.c
@ -89,6 +89,7 @@ BOOL g_numlock_sync = False;
|
||||
BOOL lspci_enabled = False;
|
||||
BOOL g_owncolmap = False;
|
||||
BOOL g_ownbackstore = True; /* We can't rely on external BackingStore */
|
||||
BOOL g_seamless_rdp = False;
|
||||
uint32 g_embed_wnd;
|
||||
uint32 g_rdp5_performanceflags =
|
||||
RDP5_NO_WALLPAPER | RDP5_NO_FULLWINDOWDRAG | RDP5_NO_MENUANIMATIONS;
|
||||
@ -146,6 +147,7 @@ usage(char *program)
|
||||
#ifdef HAVE_ICONV
|
||||
fprintf(stderr, " -L: local codepage\n");
|
||||
#endif
|
||||
fprintf(stderr, " -A: enable SeamlessRDP mode\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 from client to server\n");
|
||||
@ -390,6 +392,7 @@ main(int argc, char *argv[])
|
||||
int c;
|
||||
char *locale = NULL;
|
||||
int username_option = 0;
|
||||
BOOL geometry_option = False;
|
||||
int run_count = 0; /* Session Directory support */
|
||||
BOOL continue_connect = True; /* Session Directory support */
|
||||
|
||||
@ -416,7 +419,7 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
@ -434,6 +437,10 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'A':
|
||||
g_seamless_rdp = True;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
STRNCPY(g_username, optarg, sizeof(g_username));
|
||||
username_option = 1;
|
||||
@ -484,6 +491,7 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
geometry_option = True;
|
||||
g_fullscreen = False;
|
||||
if (!strcmp(optarg, "workarea"))
|
||||
{
|
||||
@ -732,6 +740,43 @@ main(int argc, char *argv[])
|
||||
STRNCPY(server, argv[optind], sizeof(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)
|
||||
{
|
||||
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 */
|
||||
return True;
|
||||
break;
|
||||
case XK_Overlay1_Enable:
|
||||
/* Toggle SeamlessRDP */
|
||||
if (pressed)
|
||||
ui_seamless_toggle();
|
||||
break;
|
||||
|
||||
}
|
||||
return False;
|
||||
|
481
xwin.c
481
xwin.c
@ -48,12 +48,26 @@ Time g_last_gesturetime;
|
||||
static int g_x_socket;
|
||||
static Screen *g_screen;
|
||||
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;
|
||||
BOOL g_enable_compose = False;
|
||||
BOOL g_Unobscured; /* used for screenblt */
|
||||
static GC g_gc = NULL;
|
||||
static GC g_create_bitmap_gc = NULL;
|
||||
static GC g_create_glyph_gc = NULL;
|
||||
static XRectangle g_clip_rectangle;
|
||||
static Visual *g_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
|
||||
@ -133,10 +147,45 @@ typedef struct
|
||||
}
|
||||
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)\
|
||||
{ \
|
||||
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) \
|
||||
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); \
|
||||
if (g_ownbackstore) \
|
||||
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)\
|
||||
@ -159,11 +209,14 @@ PixelColour;
|
||||
{ \
|
||||
case 0: /* Outline */ \
|
||||
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) \
|
||||
XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
|
||||
break; \
|
||||
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) \
|
||||
XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
|
||||
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 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
|
||||
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;
|
||||
Atom hintsatom;
|
||||
@ -219,8 +316,9 @@ mwm_hide_decorations(void)
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
#define SPLITCOLOUR15(colour, rv) \
|
||||
@ -1298,6 +1396,8 @@ ui_init(void)
|
||||
g_IM = XOpenIM(g_display, NULL, NULL, NULL);
|
||||
|
||||
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));
|
||||
|
||||
@ -1323,6 +1423,34 @@ ui_deinit(void)
|
||||
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
|
||||
ui_create_window(void)
|
||||
{
|
||||
@ -1345,11 +1473,7 @@ ui_create_window(void)
|
||||
if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
|
||||
g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
|
||||
|
||||
attribs.background_pixel = BlackPixelOfScreen(g_screen);
|
||||
attribs.border_pixel = WhitePixelOfScreen(g_screen);
|
||||
attribs.backing_store = g_ownbackstore ? NotUseful : Always;
|
||||
attribs.override_redirect = g_fullscreen;
|
||||
attribs.colormap = g_xcolmap;
|
||||
get_window_attribs(&attribs);
|
||||
|
||||
g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
|
||||
wndheight, 0, g_depth, InputOutput, g_visual,
|
||||
@ -1357,7 +1481,10 @@ ui_create_window(void)
|
||||
CWBorderPixel, &attribs);
|
||||
|
||||
if (g_gc == NULL)
|
||||
{
|
||||
g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
|
||||
ui_reset_clip();
|
||||
}
|
||||
|
||||
if (g_create_bitmap_gc == 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);
|
||||
|
||||
if (g_hide_decorations)
|
||||
mwm_hide_decorations();
|
||||
mwm_hide_decorations(g_wnd);
|
||||
|
||||
classhints = XAllocClassHint();
|
||||
if (classhints != NULL)
|
||||
@ -1401,17 +1528,7 @@ ui_create_window(void)
|
||||
XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
get_input_mask(&input_mask);
|
||||
|
||||
if (g_IM != NULL)
|
||||
{
|
||||
@ -1424,8 +1541,9 @@ ui_create_window(void)
|
||||
}
|
||||
|
||||
XSelectInput(g_display, g_wnd, input_mask);
|
||||
if (!g_seamless_rdp)
|
||||
{
|
||||
XMapWindow(g_display, g_wnd);
|
||||
|
||||
/* wait for VisibilityNotify */
|
||||
do
|
||||
{
|
||||
@ -1433,6 +1551,7 @@ ui_create_window(void)
|
||||
}
|
||||
while (xevent.type != VisibilityNotify);
|
||||
g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
|
||||
}
|
||||
|
||||
g_focused = False;
|
||||
g_mouse_in_wnd = False;
|
||||
@ -1496,6 +1615,10 @@ xwin_toggle_fullscreen(void)
|
||||
{
|
||||
Pixmap contents = 0;
|
||||
|
||||
if (g_seamless_rdp)
|
||||
/* Turn off SeamlessRDP mode */
|
||||
ui_seamless_toggle();
|
||||
|
||||
if (!g_ownbackstore)
|
||||
{
|
||||
/* 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,
|
||||
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
|
||||
@ -1613,7 +1745,10 @@ xwin_process_events(void)
|
||||
switch (xevent.type)
|
||||
{
|
||||
case VisibilityNotify:
|
||||
g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
|
||||
if (xevent.xvisibility.window == g_wnd)
|
||||
g_Unobscured =
|
||||
xevent.xvisibility.state == VisibilityUnobscured;
|
||||
|
||||
break;
|
||||
case ClientMessage:
|
||||
/* the window manager told us to quit */
|
||||
@ -1693,8 +1828,19 @@ xwin_process_events(void)
|
||||
if (g_fullscreen && !g_focused)
|
||||
XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
|
||||
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;
|
||||
|
||||
case FocusIn:
|
||||
@ -1737,11 +1883,28 @@ xwin_process_events(void)
|
||||
break;
|
||||
|
||||
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.width,
|
||||
xevent.xexpose.height,
|
||||
xevent.xexpose.width, xevent.xexpose.height,
|
||||
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;
|
||||
|
||||
case MappingNotify:
|
||||
@ -1772,9 +1935,11 @@ xwin_process_events(void)
|
||||
xclip_handle_PropertyNotify(&xevent.xproperty);
|
||||
break;
|
||||
case MapNotify:
|
||||
if (!g_seamless_rdp)
|
||||
rdp_send_client_window_status(1);
|
||||
break;
|
||||
case UnmapNotify:
|
||||
if (!g_seamless_rdp)
|
||||
rdp_send_client_window_status(0);
|
||||
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);
|
||||
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
|
||||
{
|
||||
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);
|
||||
@ -2036,6 +2207,7 @@ ui_set_cursor(HCURSOR cursor)
|
||||
{
|
||||
g_current_cursor = (Cursor) cursor;
|
||||
XDefineCursor(g_display, g_wnd, g_current_cursor);
|
||||
ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
|
||||
}
|
||||
|
||||
void
|
||||
@ -2177,31 +2349,30 @@ ui_set_colourmap(HCOLOURMAP map)
|
||||
g_colmap = (uint32 *) map;
|
||||
}
|
||||
else
|
||||
{
|
||||
XSetWindowColormap(g_display, g_wnd, (Colormap) map);
|
||||
ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ui_set_clip(int x, int y, int cx, int cy)
|
||||
{
|
||||
XRectangle rect;
|
||||
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.width = cx;
|
||||
rect.height = cy;
|
||||
XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
|
||||
g_clip_rectangle.x = x;
|
||||
g_clip_rectangle.y = y;
|
||||
g_clip_rectangle.width = cx;
|
||||
g_clip_rectangle.height = cy;
|
||||
XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
|
||||
}
|
||||
|
||||
void
|
||||
ui_reset_clip(void)
|
||||
{
|
||||
XRectangle rect;
|
||||
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = g_width;
|
||||
rect.height = g_height;
|
||||
XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
|
||||
g_clip_rectangle.x = 0;
|
||||
g_clip_rectangle.y = 0;
|
||||
g_clip_rectangle.width = g_width;
|
||||
g_clip_rectangle.height = g_height;
|
||||
XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2282,6 +2453,9 @@ ui_patblt(uint8 opcode,
|
||||
|
||||
if (g_ownbackstore)
|
||||
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
|
||||
@ -2292,23 +2466,19 @@ ui_screenblt(uint8 opcode,
|
||||
SET_FUNCTION(opcode);
|
||||
if (g_ownbackstore)
|
||||
{
|
||||
if (g_Unobscured)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
XCopyArea(g_display, g_Unobscured ? g_wnd : 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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2319,6 +2489,9 @@ ui_memblt(uint8 opcode,
|
||||
{
|
||||
SET_FUNCTION(opcode);
|
||||
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)
|
||||
XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
|
||||
RESET_FUNCTION(opcode);
|
||||
@ -2365,6 +2538,9 @@ ui_line(uint8 opcode,
|
||||
SET_FUNCTION(opcode);
|
||||
SET_FOREGROUND(pen->colour);
|
||||
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)
|
||||
XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
|
||||
RESET_FUNCTION(opcode);
|
||||
@ -2462,6 +2638,10 @@ ui_polyline(uint8 opcode,
|
||||
if (g_ownbackstore)
|
||||
XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
|
||||
CoordModePrevious);
|
||||
|
||||
ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
|
||||
(sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
|
||||
|
||||
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 (boxcx > 1)
|
||||
{
|
||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
|
||||
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
|
||||
{
|
||||
XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
|
||||
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);
|
||||
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
|
||||
{
|
||||
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);
|
||||
@ -2751,3 +2951,178 @@ 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