--- sourceforge.net/trunk/rdesktop/xwin.c 2007/01/04 23:38:35 1370 +++ sourceforge.net/trunk/rdesktop/xwin.c 2007/08/30 04:47:36 1417 @@ -2,6 +2,7 @@ rdesktop: A Remote Desktop Protocol client. User interface services - X Window System Copyright (C) Matthew Chapman 1999-2007 + Copyright 2007 Pierre Ossman for Cendio AB 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 @@ -20,9 +21,7 @@ #include #include -#define BOOL XPROTO_BOOL #include -#undef BOOL #include #include #include @@ -36,10 +35,10 @@ extern int g_xpos; extern int g_ypos; extern int g_pos; -extern BOOL g_sendmotion; -extern BOOL g_fullscreen; -extern BOOL g_grab_keyboard; -extern BOOL g_hide_decorations; +extern RD_BOOL g_sendmotion; +extern RD_BOOL g_fullscreen; +extern RD_BOOL g_grab_keyboard; +extern RD_BOOL g_hide_decorations; extern char g_title[]; /* Color depth of the RDP session. As of RDP 5.1, it may be 8, 15, 16 or 24. */ @@ -71,23 +70,27 @@ unsigned int desktop; struct timeval *position_timer; - BOOL outstanding_position; + RD_BOOL outstanding_position; unsigned int outpos_serial; int outpos_xoffset, outpos_yoffset; int outpos_width, outpos_height; + unsigned int icon_size; + unsigned int icon_offset; + char icon_buffer[32 * 32 * 4]; + struct _seamless_window *next; } seamless_window; static seamless_window *g_seamless_windows = NULL; static unsigned long g_seamless_focused = 0; -static BOOL g_seamless_started = False; /* Server end is up and running */ -static BOOL g_seamless_active = False; /* We are currently in seamless mode */ -static BOOL g_seamless_hidden = False; /* Desktop is hidden on server */ -extern BOOL g_seamless_rdp; +static RD_BOOL g_seamless_started = False; /* Server end is up and running */ +static RD_BOOL g_seamless_active = False; /* We are currently in seamless mode */ +static RD_BOOL g_seamless_hidden = False; /* Desktop is hidden on server */ +extern RD_BOOL g_seamless_rdp; extern uint32 g_embed_wnd; -BOOL g_enable_compose = False; -BOOL g_Unobscured; /* used for screenblt */ +RD_BOOL g_enable_compose = False; +RD_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; @@ -104,20 +107,23 @@ static XIM g_IM; static XIC g_IC; static 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[16]; static Cursor g_current_cursor; static RD_HCURSOR g_null_cursor = NULL; static Atom g_protocol_atom, g_kill_atom; extern Atom g_net_wm_state_atom; extern Atom g_net_wm_desktop_atom; -static BOOL g_focused; -static BOOL g_mouse_in_wnd; +static RD_BOOL g_focused; +static RD_BOOL g_mouse_in_wnd; /* Indicates that: 1) visual has 15, 16 or 24 depth and the same color channel masks as its RDP equivalent (implies X server is LE), 2) host is LE This will trigger an optimization whose real value is questionable. */ -static BOOL g_compatible_arch; +static RD_BOOL g_compatible_arch; /* Indicates whether RDP's bitmaps and our XImages have the same binary format. If so, we can avoid an expensive translation. Note that this can be true when g_compatible_arch is false, @@ -128,26 +134,26 @@ ('host' is the machine running rdesktop; the host simply memcpy's so its endianess doesn't matter) */ -static BOOL g_no_translate_image = False; +static RD_BOOL g_no_translate_image = False; /* endianness */ -static BOOL g_host_be; -static BOOL g_xserver_be; +static RD_BOOL g_host_be; +static RD_BOOL g_xserver_be; static int g_red_shift_r, g_blue_shift_r, g_green_shift_r; static int g_red_shift_l, g_blue_shift_l, g_green_shift_l; /* software backing store */ -extern BOOL g_ownbackstore; +extern RD_BOOL g_ownbackstore; static Pixmap g_backstore = 0; /* Moving in single app mode */ -static BOOL g_moving_wnd; +static RD_BOOL g_moving_wnd; static int g_move_x_offset = 0; static int g_move_y_offset = 0; -static BOOL g_using_full_workarea = False; +static RD_BOOL g_using_full_workarea = False; #ifdef WITH_RDPSND -extern BOOL g_rdpsnd; +extern RD_BOOL g_rdpsnd; #endif /* MWM decorations */ @@ -248,7 +254,7 @@ } /* colour maps */ -extern BOOL g_owncolmap; +extern RD_BOOL g_owncolmap; static Colormap g_xcolmap; static uint32 *g_colmap = NULL; @@ -472,7 +478,7 @@ static seamless_group * -sw_find_group(unsigned long id, BOOL dont_create) +sw_find_group(unsigned long id, RD_BOOL dont_create) { seamless_window *sw; seamless_group *sg; @@ -577,6 +583,7 @@ SPLITCOLOUR16(colour, pc); break; case 24: + case 32: SPLITCOLOUR24(colour, pc); break; default: @@ -1185,6 +1192,13 @@ is only set for compatible depths, but the RDP depth might've changed during connection negotiations. */ + + /* todo */ + if (g_server_depth == 32 && g_depth == 24) + { + return data; + } + if (g_no_translate_image) { if ((g_depth == 15 && g_server_depth == 15) || @@ -1262,7 +1276,23 @@ return out; } -BOOL +static void +xwin_refresh_pointer_map(void) +{ + unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)]; + int i, pointer_buttons; + + pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map)); + for (i = 0; i < pointer_buttons; ++i) + { + /* This might produce multiple logical buttons mapping + to a single physical one, but hey, that's + life... */ + g_pointer_log_to_phys_map[phys_to_log_map[i] - 1] = i + 1; + } +} + +RD_BOOL get_key_state(unsigned int state, uint32 keysym) { int modifierpos, key, keysymMask = 0; @@ -1310,7 +1340,7 @@ return weight; } -static BOOL +static RD_BOOL select_visual(int screen_num) { XPixmapFormatValues *pfm; @@ -1349,7 +1379,7 @@ for (i = 0; i < visuals_count; ++i) { XVisualInfo *visual_info = &vmatches[i]; - BOOL can_translate_to_bpp = False; + RD_BOOL can_translate_to_bpp = False; int j; /* Try to find a no-translation visual that'll @@ -1521,7 +1551,7 @@ return g_old_error_handler(dpy, eev); } -BOOL +RD_BOOL ui_init(void) { int screen_num; @@ -1535,7 +1565,7 @@ { uint16 endianess_test = 1; - g_host_be = !(BOOL) (*(uint8 *) (&endianess_test)); + g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test)); } g_old_error_handler = XSetErrorHandler(error_handler); @@ -1616,6 +1646,7 @@ g_width = (g_width + 3) & ~3; g_mod_map = XGetModifierMapping(g_display); + xwin_refresh_pointer_map(); xkeymap_init(); @@ -1687,7 +1718,7 @@ *input_mask |= LeaveWindowMask; } -BOOL +RD_BOOL ui_create_window(void) { uint8 null_pointer_mask[1] = { 0x80 }; @@ -1735,6 +1766,7 @@ } XStoreName(g_display, g_wnd, g_title); + ewmh_set_wm_name(g_wnd, g_title); if (g_hide_decorations) mwm_hide_decorations(g_wnd); @@ -1874,10 +1906,16 @@ } static void -handle_button_event(XEvent xevent, BOOL down) +handle_button_event(XEvent xevent, RD_BOOL down) { uint16 button, flags = 0; g_last_gesturetime = xevent.xbutton.time; + /* Reverse the pointer button mapping, e.g. in the case of + "left-handed mouse mode"; the RDP session expects to + receive physical buttons (true in mstsc as well) and + logical button behavior depends on the remote desktop's own + mouse settings */ + xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1]; button = xkeymap_translate_button(xevent.xbutton.button); if (button == 0) return; @@ -2165,6 +2203,12 @@ XFreeModifiermap(g_mod_map); g_mod_map = XGetModifierMapping(g_display); } + + if (xevent.xmapping.request == MappingPointer) + { + xwin_refresh_pointer_map(); + } + break; /* clipboard stuff */ @@ -2248,7 +2292,7 @@ int n; fd_set rfds, wfds; struct timeval tv; - BOOL s_timeout = False; + RD_BOOL s_timeout = False; while (True) { @@ -2292,7 +2336,7 @@ /* Abort serial read calls */ if (s_timeout) - rdpdr_check_fds(&rfds, &wfds, (BOOL) True); + rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True); continue; } @@ -2300,7 +2344,7 @@ rdpsnd_check_fds(&rfds, &wfds); #endif - rdpdr_check_fds(&rfds, &wfds, (BOOL) False); + rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False); if (FD_ISSET(rdp_socket, &rfds)) return 1; @@ -3219,7 +3263,7 @@ return; image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0, - (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8); + (char *) data, cx, cy, g_bpp, 0); if (g_ownbackstore) { @@ -3253,7 +3297,7 @@ void -ui_seamless_begin(BOOL hidden) +ui_seamless_begin(RD_BOOL hidden) { if (!g_seamless_rdp) return; @@ -3421,15 +3465,13 @@ XSetWMProtocols(g_display, wnd, &g_kill_atom, 1); sw = xmalloc(sizeof(seamless_window)); + + memset(sw, 0, sizeof(seamless_window)); + sw->wnd = wnd; sw->id = id; - sw->behind = 0; sw->group = sw_find_group(group, False); sw->group->refcnt++; - sw->xoffset = 0; - sw->yoffset = 0; - sw->width = 0; - sw->height = 0; sw->state = SEAMLESSRDP_NOTYETMAPPED; sw->desktop = 0; sw->position_timer = xmalloc(sizeof(struct timeval)); @@ -3496,6 +3538,93 @@ } +void +ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk, + const char *data, int chunk_len) +{ + seamless_window *sw; + + if (!g_seamless_active) + return; + + sw = sw_get_window_by_id(id); + if (!sw) + { + warning("ui_seamless_seticon: No information for window 0x%lx\n", id); + return; + } + + if (chunk == 0) + { + if (sw->icon_size) + warning("ui_seamless_seticon: New icon started before previous completed\n"); + + if (strcmp(format, "RGBA") != 0) + { + warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format); + return; + } + + sw->icon_size = width * height * 4; + if (sw->icon_size > 32 * 32 * 4) + { + warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size); + sw->icon_size = 0; + return; + } + + sw->icon_offset = 0; + } + else + { + if (!sw->icon_size) + return; + } + + if (chunk_len > (sw->icon_size - sw->icon_offset)) + { + warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n", + chunk_len, sw->icon_size - sw->icon_offset); + sw->icon_size = 0; + return; + } + + memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len); + sw->icon_offset += chunk_len; + + if (sw->icon_offset == sw->icon_size) + { + ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer); + sw->icon_size = 0; + } +} + + +void +ui_seamless_delicon(unsigned long id, const char *format, int width, int height) +{ + seamless_window *sw; + + if (!g_seamless_active) + return; + + sw = sw_get_window_by_id(id); + if (!sw) + { + warning("ui_seamless_seticon: No information for window 0x%lx\n", id); + return; + } + + if (strcmp(format, "RGBA") != 0) + { + warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format); + return; + } + + ewmh_del_icon(sw->wnd, width, height); +} + + void ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags) {