xwin.c
来自「LinuxTools一书随书源代码」· C语言 代码 · 共 1,365 行 · 第 1/2 页
C
1,365 行
/* rdesktop: A Remote Desktop Protocol client. User interface services - X Window System Copyright (C) Matthew Chapman 1999-2002 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 <time.h>#include <errno.h>#include "rdesktop.h"extern int width;extern int height;extern BOOL sendmotion;extern BOOL fullscreen;extern BOOL grab_keyboard;extern BOOL hide_decorations;extern char title[];BOOL enable_compose = False;BOOL focused;BOOL mouse_in_wnd;Display *display;static int x_socket;static Screen *screen;static Window wnd;static GC gc;static Visual *visual;static int depth;static int bpp;static XIM IM;static XIC IC;static XModifierKeymap *mod_map;static Cursor current_cursor;static Atom protocol_atom, kill_atom;/* endianness */static BOOL host_be;static BOOL xserver_be;/* software backing store */static BOOL ownbackstore;static Pixmap backstore;/* MWM decorations */#define MWM_HINTS_DECORATIONS (1L << 1)#define PROP_MOTIF_WM_HINTS_ELEMENTS 5typedef struct{ uint32 flags; uint32 functions; uint32 decorations; sint32 inputMode; uint32 status;}PropMotifWmHints;#define FILL_RECTANGLE(x,y,cx,cy)\{ \ XFillRectangle(display, wnd, gc, x, y, cx, cy); \ if (ownbackstore) \ XFillRectangle(display, backstore, gc, x, y, cx, cy); \}#define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\{ \ XFillRectangle(display, ownbackstore ? backstore : wnd, gc, x, y, cx, cy); \}/* colour maps */BOOL owncolmap = False;static Colormap xcolmap;static uint32 *colmap;#define TRANSLATE(col) ( owncolmap ? col : translate_colour(colmap[col]) )#define SET_FOREGROUND(col) XSetForeground(display, gc, TRANSLATE(col));#define SET_BACKGROUND(col) XSetBackground(display, 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(display, gc, rop2_map[rop2]); }#define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(display, gc, GXcopy); }voidmwm_hide_decorations(void){ 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(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(display, wnd, hintsatom, hintsatom, 32, PropModeReplace, (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);}static voidtranslate8(uint8 * data, uint8 * out, uint8 * end){ while (out < end) *(out++) = (uint8) colmap[*(data++)];}static voidtranslate16(uint8 * data, uint16 * out, uint16 * end){ while (out < end) *(out++) = (uint16) colmap[*(data++)];}/* little endian - conversion happens when colourmap is built */static voidtranslate24(uint8 * data, uint8 * out, uint8 * end){ uint32 value; while (out < end) { value = colmap[*(data++)]; *(out++) = value; *(out++) = value >> 8; *(out++) = value >> 16; }}static voidtranslate32(uint8 * data, uint32 * out, uint32 * end){ while (out < end) *(out++) = colmap[*(data++)];}static uint8 *translate_image(int width, int height, uint8 * data){ int size = width * height * bpp / 8; uint8 *out = xmalloc(size); uint8 *end = out + size; switch (bpp) { case 8: translate8(data, out, end); break; case 16: translate16(data, (uint16 *) out, (uint16 *) end); break; case 24: translate24(data, out, end); break; case 32: translate32(data, (uint32 *) out, (uint32 *) end); break; } return out;}#define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }#define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00)); }#define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \ x = (x << 16) | (x >> 16); }static uint32translate_colour(uint32 colour){ switch (bpp) { case 16: if (host_be != xserver_be) BSWAP16(colour); break; case 24: if (xserver_be) BSWAP24(colour); break; case 32: if (host_be != xserver_be) BSWAP32(colour); break; } return colour;}BOOLget_key_state(unsigned int state, uint32 keysym){ int modifierpos, key, keysymMask = 0; int offset; KeyCode keycode = XKeysymToKeycode(display, keysym); if (keycode == NoSymbol) return False; for (modifierpos = 0; modifierpos < 8; modifierpos++) { offset = mod_map->max_keypermod * modifierpos; for (key = 0; key < mod_map->max_keypermod; key++) { if (mod_map->modifiermap[offset + key] == keycode) keysymMask |= 1 << modifierpos; } } return (state & keysymMask) ? True : False;}BOOLui_init(void){ XPixmapFormatValues *pfm; uint16 test; int i; display = XOpenDisplay(NULL); if (display == NULL) { error("Failed to open display: %s\n", XDisplayName(NULL)); return False; } x_socket = ConnectionNumber(display); screen = DefaultScreenOfDisplay(display); visual = DefaultVisualOfScreen(screen); depth = DefaultDepthOfScreen(screen); pfm = XListPixmapFormats(display, &i); if (pfm != NULL) { /* Use maximum bpp for this depth - this is generally desirable, e.g. 24 bits->32 bits. */ while (i--) { if ((pfm[i].depth == depth) && (pfm[i].bits_per_pixel > bpp)) { bpp = pfm[i].bits_per_pixel; } } XFree(pfm); } if (bpp < 8) { error("Less than 8 bpp not currently supported.\n"); XCloseDisplay(display); return False; } if (owncolmap != True) { xcolmap = DefaultColormapOfScreen(screen); if (depth <= 8) warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n"); } gc = XCreateGC(display, RootWindowOfScreen(screen), 0, NULL); if (DoesBackingStore(screen) != Always) ownbackstore = True; test = 1; host_be = !(BOOL) (*(uint8 *) (&test)); xserver_be = (ImageByteOrder(display) == MSBFirst); if ((width == 0) || (height == 0)) { /* Fetch geometry from _NET_WORKAREA */ uint32 x, y, cx, cy; if (get_current_workarea(&x, &y, &cx, &cy) == 0) { width = cx; height = cy; } else { warning("Failed to get workarea: probably your window manager does not support extended hints\n"); width = 800; height = 600; } } if (fullscreen) { width = WidthOfScreen(screen); height = HeightOfScreen(screen); } /* make sure width is a multiple of 4 */ width = (width + 3) & ~3; if (ownbackstore) { backstore = XCreatePixmap(display, RootWindowOfScreen(screen), width, height, depth); /* clear to prevent rubbish being exposed at startup */ XSetForeground(display, gc, BlackPixelOfScreen(screen)); XFillRectangle(display, backstore, gc, 0, 0, width, height); } mod_map = XGetModifierMapping(display); if (enable_compose) IM = XOpenIM(display, NULL, NULL, NULL); xkeymap_init(); return True;}voidui_deinit(void){ if (IM != NULL) XCloseIM(IM); XFreeModifiermap(mod_map); if (ownbackstore) XFreePixmap(display, backstore); XFreeGC(display, gc); XCloseDisplay(display); display = NULL;}BOOLui_create_window(void){ XSetWindowAttributes attribs; XClassHint *classhints; XSizeHints *sizehints; int wndwidth, wndheight; long input_mask, ic_input_mask; XEvent xevent; wndwidth = fullscreen ? WidthOfScreen(screen) : width; wndheight = fullscreen ? HeightOfScreen(screen) : height; attribs.background_pixel = BlackPixelOfScreen(screen); attribs.backing_store = ownbackstore ? NotUseful : Always; attribs.override_redirect = fullscreen; wnd = XCreateWindow(display, RootWindowOfScreen(screen), 0, 0, wndwidth, wndheight, 0, CopyFromParent, InputOutput, CopyFromParent, CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs); XStoreName(display, wnd, title); if (hide_decorations) mwm_hide_decorations(); classhints = XAllocClassHint(); if (classhints != NULL) { classhints->res_name = classhints->res_class = "rdesktop"; XSetClassHint(display, wnd, classhints); XFree(classhints); } sizehints = XAllocSizeHints(); if (sizehints) { sizehints->flags = PMinSize | PMaxSize; sizehints->min_width = sizehints->max_width = width; sizehints->min_height = sizehints->max_height = height; XSetWMNormalHints(display, wnd, sizehints); XFree(sizehints); } input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | VisibilityChangeMask | FocusChangeMask; if (sendmotion) input_mask |= PointerMotionMask; if (ownbackstore) input_mask |= ExposureMask; if (fullscreen || grab_keyboard) input_mask |= EnterWindowMask; if (grab_keyboard) input_mask |= LeaveWindowMask; if (IM != NULL) { IC = XCreateIC(IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, wnd, XNFocusWindow, wnd, NULL); if ((IC != NULL) && (XGetICValues(IC, XNFilterEvents, &ic_input_mask, NULL) == NULL)) input_mask |= ic_input_mask; } XSelectInput(display, wnd, input_mask); XMapWindow(display, wnd); /* wait for VisibilityNotify */ do { XMaskEvent(display, VisibilityChangeMask, &xevent); } while (xevent.type != VisibilityNotify); focused = False; mouse_in_wnd = False; /* handle the WM_DELETE_WINDOW protocol */ protocol_atom = XInternAtom(display, "WM_PROTOCOLS", True); kill_atom = XInternAtom(display, "WM_DELETE_WINDOW", True); XSetWMProtocols(display, wnd, &kill_atom, 1); return True;}voidui_destroy_window(void){ if (IC != NULL) XDestroyIC(IC); XDestroyWindow(display, wnd);}voidxwin_toggle_fullscreen(void){ Pixmap contents = 0; if (!ownbackstore) { /* need to save contents of window */ contents = XCreatePixmap(display, wnd, width, height, depth); XCopyArea(display, wnd, contents, gc, 0, 0, width, height, 0, 0); } ui_destroy_window(); fullscreen = !fullscreen; ui_create_window(); XDefineCursor(display, wnd, current_cursor); if (!ownbackstore) { XCopyArea(display, contents, wnd, gc, 0, 0, width, height, 0, 0); XFreePixmap(display, contents); }}/* Process all events in Xlib queue Returns 0 after user quit, 1 otherwise */static intxwin_process_events(void){ XEvent xevent; KeySym keysym; uint16 button, flags; uint32 ev_time; key_translation tr; char str[256]; Status status; unsigned int state; Window wdummy; int dummy; while (XPending(display) > 0) { XNextEvent(display, &xevent); if ((IC != NULL) && (XFilterEvent(&xevent, None) == True)) { DEBUG_KBD(("Filtering event\n")); continue; } flags = 0; switch (xevent.type) { case ClientMessage: /* the window manager told us to quit */ if ((xevent.xclient.message_type == protocol_atom) && (xevent.xclient.data.l[0] == kill_atom)) /* Quit */ return 0; break; case KeyPress: if (IC != NULL) /* Multi_key compatible version */ { XmbLookupString(IC, (XKeyPressedEvent *) & xevent, str, sizeof(str), &keysym, &status); if (!((status == XLookupKeySym) || (status == XLookupBoth))) { error("XmbLookupString failed with status 0x%x\n", status); break; } } else { /* Plain old XLookupString */ DEBUG_KBD(("\nNo input context, using XLookupString\n")); XLookupString((XKeyEvent *) & xevent, str, sizeof(str), &keysym, NULL); } DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym))); ev_time = time(NULL); if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True)) break; tr = xkeymap_translate_key(keysym, xevent.xkey.keycode, xevent.xkey.state); if (tr.scancode == 0) break; ensure_remote_modifiers(ev_time, tr); rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode); break; case KeyRelease: XLookupString((XKeyEvent *) & xevent, str, sizeof(str), &keysym, NULL); DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym))); ev_time = time(NULL); if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False)) break; tr = xkeymap_translate_key(keysym, xevent.xkey.keycode, xevent.xkey.state); if (tr.scancode == 0) break; rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode); break; case ButtonPress: flags = MOUSE_FLAG_DOWN; /* fall through */ case ButtonRelease: button = xkeymap_translate_button(xevent.xbutton.button); if (button == 0) break; rdp_send_input(time(NULL), RDP_INPUT_MOUSE, flags | button, xevent.xbutton.x, xevent.xbutton.y); break; case MotionNotify: if (fullscreen && !focused) XSetInputFocus(display, wnd, RevertToPointerRoot, CurrentTime); rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y); break; case FocusIn: if (xevent.xfocus.mode == NotifyGrab) break; focused = True; XQueryPointer(display, wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state); reset_modifier_keys(state); if (grab_keyboard && mouse_in_wnd) XGrabKeyboard(display, wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); break; case FocusOut: if (xevent.xfocus.mode == NotifyUngrab) break; focused = False; if (xevent.xfocus.mode == NotifyWhileGrabbed) XUngrabKeyboard(display, CurrentTime); break; case EnterNotify: /* we only register for this event when in fullscreen mode */ /* or grab_keyboard */ mouse_in_wnd = True; if (fullscreen) { XSetInputFocus(display, wnd, RevertToPointerRoot, CurrentTime); break; } if (focused) XGrabKeyboard(display, wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); break; case LeaveNotify: /* we only register for this event when grab_keyboard */ mouse_in_wnd = False; XUngrabKeyboard(display, CurrentTime); break; case Expose: XCopyArea(display, backstore, wnd, gc, xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height, xevent.xexpose.x, xevent.xexpose.y); break; case MappingNotify: /* Refresh keyboard mapping if it has changed. This is important for Xvnc, since it allocates keycodes dynamically */ if (xevent.xmapping.request == MappingKeyboard || xevent.xmapping.request == MappingModifier) XRefreshKeyboardMapping(&xevent.xmapping); if (xevent.xmapping.request == MappingModifier) { XFreeModifiermap(mod_map); mod_map = XGetModifierMapping(display); } break; } } /* Keep going */ return 1;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?