📄 xwin.c
字号:
/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. User interface services - X Window System Copyright (C) Matthew Chapman 1999-2008 Copyright 2007 Pierre Ossman <ossman@cendio.se> 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 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 <X11/Xlib.h>#include <X11/Xutil.h>#include <X11/Xproto.h>#include <unistd.h>#include <sys/time.h>#include <time.h>#include <errno.h>#include <strings.h>#include "rdesktop.h"#include "xproto.h"extern int g_width;extern int g_height;extern int g_xpos;extern int g_ypos;extern int g_pos;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. */extern int g_server_depth;extern int g_win_button_size;Display *g_display;Time g_last_gesturetime;static int g_x_socket;static Screen *g_screen;Window g_wnd;/* SeamlessRDP support */typedef struct _seamless_group{ Window wnd; unsigned long id; unsigned int refcnt;} seamless_group;typedef struct _seamless_window{ Window wnd; unsigned long id; unsigned long behind; seamless_group *group; int xoffset, yoffset; int width, height; int state; /* normal/minimized/maximized. */ unsigned int desktop; struct timeval *position_timer; 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 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 */static RD_BOOL g_seamless_broken_restack = False; /* WM does not properly restack */extern RD_BOOL g_seamless_rdp;extern uint32 g_embed_wnd;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;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 as far as we're concerned. */static int g_depth;/* Bits-per-Pixel of the pixmaps we'll be using to draw on our window. This may be larger than g_depth, in which case some of the bits would be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */static int g_bpp;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[32];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 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 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, e.g.: RDP(LE) <-> host(BE) <-> X-Server(LE) ('host' is the machine running rdesktop; the host simply memcpy's so its endianess doesn't matter) */static RD_BOOL g_no_translate_image = False;/* endianness */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 RD_BOOL g_ownbackstore;static Pixmap g_backstore = 0;/* Moving in single app mode */static RD_BOOL g_moving_wnd;static int g_move_x_offset = 0;static int g_move_y_offset = 0;static RD_BOOL g_using_full_workarea = False;#ifdef WITH_RDPSNDextern RD_BOOL g_rdpsnd;#endif/* MWM decorations */#define MWM_HINTS_DECORATIONS (1L << 1)#define PROP_MOTIF_WM_HINTS_ELEMENTS 5typedef struct{ unsigned long flags; unsigned long functions; unsigned long decorations; long inputMode; unsigned long status;}PropMotifWmHints;typedef struct{ uint32 red; uint32 green; uint32 blue;}PixelColour;#define ON_ALL_SEAMLESS_WINDOWS(func, args) \ do { \ seamless_window *sw; \ XRectangle rect; \ if (!g_seamless_windows) break; \ 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 voidseamless_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 voidseamless_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); \}#define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\{ \ XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \}#define FILL_POLYGON(p,np)\{ \ 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)\{ \ switch (m) \ { \ 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); \ ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \ if (g_ownbackstore) \ XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \ break; \ } \}/* colour maps */extern RD_BOOL g_owncolmap;static Colormap g_xcolmap;static uint32 *g_colmap = NULL;#define TRANSLATE(col) ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )#define SET_FOREGROUND(col) XSetForeground(g_display, g_gc, TRANSLATE(col));#define SET_BACKGROUND(col) XSetBackground(g_display, g_gc, TRANSLATE(col));static int rop2_map[] = { GXclear, /* 0 */ GXnor, /* DPon */ GXandInverted, /* DPna */ GXcopyInverted, /* Pn */ GXandReverse, /* PDna */ GXinvert, /* Dn */ GXxor, /* DPx */ GXnand, /* DPan */ GXand, /* DPa */ GXequiv, /* DPxn */ GXnoop, /* D */ GXorInverted, /* DPno */ GXcopy, /* P */ GXorReverse, /* PDno */ GXor, /* DPo */ GXset /* 1 */};#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 *sw_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 *sw_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 voidsw_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; sw->group->refcnt--; if (sw->group->refcnt == 0) { XDestroyWindow(g_display, sw->group->wnd); xfree(sw->group); } xfree(sw->position_timer); xfree(sw); return; } prevnext = &sw->next; } return;}/* Move all windows except wnd to new desktop */static voidsw_all_to_desktop(Window wnd, unsigned int desktop){ seamless_window *sw; for (sw = g_seamless_windows; sw; sw = sw->next) { if (sw->wnd == wnd) continue; if (sw->desktop != desktop) { ewmh_move_to_desktop(sw->wnd, desktop); sw->desktop = desktop; } }}/* Send our position */static voidsw_update_position(seamless_window * sw){ XWindowAttributes wa; int x, y; Window child_return; unsigned int serial; XGetWindowAttributes(g_display, sw->wnd, &wa); XTranslateCoordinates(g_display, sw->wnd, wa.root, -wa.border_width, -wa.border_width, &x, &y, &child_return); serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0); sw->outstanding_position = True; sw->outpos_serial = serial; sw->outpos_xoffset = x; sw->outpos_yoffset = y; sw->outpos_width = wa.width; sw->outpos_height = wa.height;}/* Check if it's time to send our position */static voidsw_check_timers(){ seamless_window *sw; struct timeval now; gettimeofday(&now, NULL); for (sw = g_seamless_windows; sw; sw = sw->next) { if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <)) { timerclear(sw->position_timer); sw_update_position(sw); } }}static voidsw_restack_window(seamless_window * sw, unsigned long behind){ seamless_window *sw_above; /* Remove window from stack */ for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next) { if (sw_above->behind == sw->id) break; } if (sw_above) sw_above->behind = sw->behind; /* And then add it at the new position */ for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next) { if (sw_above->behind == behind) break; } if (sw_above) sw_above->behind = sw->id; sw->behind = behind;}static voidsw_handle_restack(seamless_window * sw){ Status status; Window root, parent, *children; unsigned int nchildren, i; seamless_window *sw_below; status = XQueryTree(g_display, RootWindowOfScreen(g_screen), &root, &parent, &children, &nchildren); if (!status || !nchildren) return; sw_below = NULL; i = 0; while (children[i] != sw->wnd) { i++; if (i >= nchildren) goto end; } for (i++; i < nchildren; i++) { sw_below = sw_get_window_by_wnd(children[i]); if (sw_below) break; } if (!sw_below && !sw->behind) goto end; if (sw_below && (sw_below->id == sw->behind)) goto end; if (sw_below) { seamless_send_zchange(sw->id, sw_below->id, 0); sw_restack_window(sw, sw_below->id); } else { seamless_send_zchange(sw->id, 0, 0); sw_restack_window(sw, 0); } end: XFree(children);}static seamless_group *sw_find_group(unsigned long id, RD_BOOL dont_create){ seamless_window *sw; seamless_group *sg; XSetWindowAttributes attribs; for (sw = g_seamless_windows; sw; sw = sw->next) { if (sw->group->id == id) return sw->group; } if (dont_create) return NULL; sg = xmalloc(sizeof(seamless_group)); sg->wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs); sg->id = id; sg->refcnt = 0; return sg;}static voidmwm_hide_decorations(Window wnd){ PropMotifWmHints motif_hints; Atom hintsatom; /* setup the property */ motif_hints.flags = MWM_HINTS_DECORATIONS; motif_hints.decorations = 0; /* get the atom for the property */ hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False); if (!hintsatom) { warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n"); return; } XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace, (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);}typedef struct _sw_configurenotify_context{ Window window; unsigned long serial;} sw_configurenotify_context;/* Predicate procedure for sw_wait_configurenotify */static Boolsw_configurenotify_p(Display * display, XEvent * xevent, XPointer arg){ sw_configurenotify_context *context = (sw_configurenotify_context *) arg; if (xevent->xany.type == ConfigureNotify && xevent->xconfigure.window == context->window && xevent->xany.serial >= context->serial) return True; return False;}/* Wait for a ConfigureNotify, with a equal or larger serial, on the specified window. The event will be removed from the queue. We could use XMaskEvent(StructureNotifyMask), but we would then risk throwing away crucial events like DestroyNotify. After a ConfigureWindow, according to ICCCM section 4.1.5, we should recieve a ConfigureNotify, either a real or synthetic one. This indicates that the configure has been "completed". However, some WMs such as several versions of Metacity fails to send synthetic events. See bug http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a timeout to avoid a hang. Tk uses the same approach. */static voidsw_wait_configurenotify(Window wnd, unsigned long serial){ XEvent xevent; sw_configurenotify_context context;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -