📄 xwin.c
字号:
/* rdesktop: A Remote Desktop Protocol client. User interface services - X-Windows Copyright (C) Matthew Chapman 1999-2001 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;static Display *display;static int x_socket;static Window wnd;static GC gc;static Visual *visual;static int depth;static int bpp;/* endianness */static BOOL host_be;static BOOL xserver_be;/* software backing store */static BOOL ownbackstore;static Pixmap backstore;#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); \}/* colour maps */static BOOL owncolmap;static Colormap xcolmap;static uint32 white;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); }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;}BOOLui_create_window(char *title){ XSetWindowAttributes attribs; XClassHint *classhints; XSizeHints *sizehints; unsigned long input_mask; XPixmapFormatValues *pfm; Screen *screen; uint16 test; int i; display = XOpenDisplay(NULL); if (display == NULL) { error("Failed to open display\n"); 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 (depth <= 8) owncolmap = True; else xcolmap = DefaultColormapOfScreen(screen); test = 1; host_be = !(BOOL)(*(uint8 *)(&test)); xserver_be = (ImageByteOrder(display) == MSBFirst); white = WhitePixelOfScreen(screen); attribs.background_pixel = BlackPixelOfScreen(screen); attribs.backing_store = DoesBackingStore(screen); if (attribs.backing_store == NotUseful) ownbackstore = True; if (fullscreen) { attribs.override_redirect = True; width = WidthOfScreen(screen); height = HeightOfScreen(screen); } else { attribs.override_redirect = False; } width = (width + 3) & ~3; /* make width a multiple of 32 bits */ wnd = XCreateWindow(display, RootWindowOfScreen(screen), 0, 0, width, height, 0, CopyFromParent, InputOutput, CopyFromParent, CWBackingStore | CWBackPixel | CWOverrideRedirect, &attribs); XStoreName(display, wnd, title); 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 | EnterWindowMask | LeaveWindowMask; if (sendmotion) input_mask |= PointerMotionMask; if (ownbackstore) input_mask |= ExposureMask; XSelectInput(display, wnd, input_mask); gc = XCreateGC(display, wnd, 0, NULL); if (ownbackstore) backstore = XCreatePixmap(display, wnd, width, height, depth); XMapWindow(display, wnd); return True;}voidui_destroy_window(){ if (ownbackstore) XFreePixmap(display, backstore); XFreeGC(display, gc); XDestroyWindow(display, wnd); XCloseDisplay(display); display = NULL;}static uint8xwin_translate_key(unsigned long key){ DEBUG(("KEY(code=0x%lx)\n", key)); if ((key > 8) && (key <= 0x60)) return (key - 8); switch (key) { case 0x61: /* home */ return 0x47 | 0x80; case 0x62: /* up arrow */ return 0x48 | 0x80; case 0x63: /* page up */ return 0x49 | 0x80; case 0x64: /* left arrow */ return 0x4b | 0x80; case 0x66: /* right arrow */ return 0x4d | 0x80; case 0x67: /* end */ return 0x4f | 0x80; case 0x68: /* down arrow */ return 0x50 | 0x80; case 0x69: /* page down */ return 0x51 | 0x80; case 0x6a: /* insert */ return 0x52 | 0x80; case 0x6b: /* delete */ return 0x53 | 0x80; case 0x6c: /* keypad enter */ return 0x1c | 0x80; case 0x6d: /* right ctrl */ return 0x1d | 0x80; case 0x6f: /* ctrl - print screen */ return 0x37 | 0x80; case 0x70: /* keypad '/' */ return 0x35 | 0x80; case 0x71: /* right alt */ return 0x38 | 0x80; case 0x72: /* ctrl break */ return 0x46 | 0x80; case 0x73: /* left window key */ return 0xff; /* real scancode is 5b */ case 0x74: /* right window key */ return 0xff; /* real scancode is 5c */ case 0x75: /* menu key */ return 0x5d | 0x80; } return 0;}static uint16xwin_translate_mouse(unsigned long button){ switch (button) { case Button1: /* left */ return MOUSE_FLAG_BUTTON1; case Button2: /* middle */ return MOUSE_FLAG_BUTTON3; case Button3: /* right */ return MOUSE_FLAG_BUTTON2; } return 0;}static voidxwin_process_events(){ XEvent event; uint8 scancode; uint16 button; uint32 ev_time; if (display == NULL) return; while (XCheckWindowEvent(display, wnd, ~0, &event)) { ev_time = time(NULL); switch (event.type) { case KeyPress: scancode = xwin_translate_key(event.xkey.keycode); if (scancode == 0) break; rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, scancode, 0); break; case KeyRelease: scancode = xwin_translate_key(event.xkey.keycode); if (scancode == 0) break; rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, scancode, 0); break; case ButtonPress: button = xwin_translate_mouse(event.xbutton.button); if (button == 0) break; rdp_send_input(ev_time, RDP_INPUT_MOUSE, button | MOUSE_FLAG_DOWN, event.xbutton.x, event.xbutton.y); break; case ButtonRelease: button = xwin_translate_mouse(event.xbutton.button); if (button == 0) break; rdp_send_input(ev_time, RDP_INPUT_MOUSE, button, event.xbutton.x, event.xbutton.y); break; case MotionNotify: rdp_send_input(ev_time, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, event.xmotion.x, event.xmotion.y); break; case EnterNotify: XGrabKeyboard(display, wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); break; case LeaveNotify: XUngrabKeyboard(display, CurrentTime); break; case Expose: XCopyArea(display, backstore, wnd, gc, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height, event.xexpose.x, event.xexpose.y); break; } }}voidui_select(int rdp_socket){ int n = (rdp_socket > x_socket) ? rdp_socket+1 : x_socket+1; fd_set rfds; XFlush(display); FD_ZERO(&rfds); while (True) { FD_ZERO(&rfds); FD_SET(rdp_socket, &rfds); FD_SET(x_socket, &rfds); switch (select(n, &rfds, NULL, NULL, NULL)) { case -1: error("select: %s\n", strerror(errno)); case 0: continue; } if (FD_ISSET(x_socket, &rfds)) xwin_process_events(); if (FD_ISSET(rdp_socket, &rfds)) return; }}voidui_move_pointer(int x, int y){ XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);}HBITMAPui_create_bitmap(int width, int height, uint8 *data){ XImage *image; Pixmap bitmap; uint8 *tdata; tdata = (owncolmap ? data : translate_image(width, height, data)); bitmap = XCreatePixmap(display, wnd, width, height, depth); image = XCreateImage(display, visual, depth, ZPixmap, 0, tdata, width, height, 8, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -