From 71f2ec79180185a6c3db0c87f9d53c491dc31e76 Mon Sep 17 00:00:00 2001 From: runge Date: Mon, 9 Jan 2006 01:54:38 +0000 Subject: x11vnc: the big split. --- x11vnc/xwrappers.c | 697 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 697 insertions(+) create mode 100644 x11vnc/xwrappers.c (limited to 'x11vnc/xwrappers.c') diff --git a/x11vnc/xwrappers.c b/x11vnc/xwrappers.c new file mode 100644 index 0000000..a99d519 --- /dev/null +++ b/x11vnc/xwrappers.c @@ -0,0 +1,697 @@ +/* -- xwrappers.c -- */ + +#include "x11vnc.h" +#include "xrecord.h" +#include "keyboard.h" + +int xshm_present = 0; +int xtest_present = 0; +int xtrap_present = 0; +int xrecord_present = 0; +int xkb_present = 0; +int xinerama_present = 0; + +int keycode_state[256]; +int rootshift = 0; +int clipshift = 0; + + +int guess_bits_per_color(int bits_per_pixel); + +Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y, + unsigned long mask); +XImage *XShmCreateImage_wr(Display* disp, Visual* vis, unsigned int depth, + int format, char* data, XShmSegmentInfo* shminfo, unsigned int width, + unsigned int height); +Status XShmAttach_wr(Display *disp, XShmSegmentInfo *shminfo); +Status XShmDetach_wr(Display *disp, XShmSegmentInfo *shminfo); +Bool XShmQueryExtension_wr(Display *disp); + +XImage *xreadscreen(Display *disp, Drawable d, int x, int y, + unsigned int width, unsigned int height, Bool show_cursor); +XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y, + unsigned int width, unsigned int height, unsigned long plane_mask, + int format, XImage *dest_image, int dest_x, int dest_y); +XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y, + unsigned int width, unsigned int height, unsigned long plane_mask, + int format); +XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth, + int format, int offset, char *data, unsigned int width, + unsigned int height, int bitmap_pad, int bytes_per_line); +void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h); +void init_track_keycode_state(void); + +void XTRAP_FakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, + unsigned long delay); +void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, + unsigned long delay); +void XTRAP_FakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, + unsigned long delay); +void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, + unsigned long delay); +void XTRAP_FakeMotionEvent_wr(Display* dpy, int screen, int x, int y, + unsigned long delay); +void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y, + unsigned long delay); + +Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w); +Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor); +Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj, + int *min); +void XTestDiscard_wr(Display *dpy); +Bool XETrapQueryExtension_wr(Display *dpy, int *ev, int *er, int *op); +int XTestGrabControl_wr(Display *dpy, Bool impervious); +int XTRAP_GrabControl_wr(Display *dpy, Bool impervious); +void disable_grabserver(Display *in_dpy, int change); + +Bool XRecordQueryVersion_wr(Display *dpy, int *maj, int *min); + + +static void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h); +static void upup_downdown_warning(KeyCode key, Bool down); + + +/* + * used in rfbGetScreen and rfbNewFramebuffer: and estimate to the number + * of bits per color, of course for some visuals, e.g. 565, the number + * is not the same for each color. This is just a sane default. + */ +int guess_bits_per_color(int bits_per_pixel) { + int bits_per_color; + + /* first guess, spread them "evenly" over R, G, and B */ + bits_per_color = bits_per_pixel/3; + if (bits_per_color < 1) { + bits_per_color = 1; /* 1bpp, 2bpp... */ + } + + /* choose safe values for usual cases: */ + if (bits_per_pixel == 8) { + bits_per_color = 2; + } else if (bits_per_pixel == 15 || bits_per_pixel == 16) { + bits_per_color = 5; + } else if (bits_per_pixel == 24 || bits_per_pixel == 32) { + bits_per_color = 8; + } + return bits_per_color; +} + +/* + * Kludge to interpose image gets and limit to a subset rectangle of + * the rootwin. This is the -sid option trying to work around invisible + * saveUnders menu, etc, windows. Also -clip option. + */ + +#define ADJUST_ROOTSHIFT \ + if (rootshift && subwin) { \ + d = rootwin; \ + x += off_x; \ + y += off_y; \ + } \ + if (clipshift) { \ + x += coff_x; \ + y += coff_y; \ + } + +/* + * Wrappers for Image related X calls + */ +Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y, + unsigned long mask) { + + ADJUST_ROOTSHIFT + + /* Note: the Solaris overlay stuff is all non-shm (using_shm = 0) */ + +#if LIBVNCSERVER_HAVE_XSHM + return XShmGetImage(disp, d, image, x, y, mask); +#else + return (Status) 0; +#endif +} + +XImage *XShmCreateImage_wr(Display* disp, Visual* vis, unsigned int depth, + int format, char* data, XShmSegmentInfo* shminfo, unsigned int width, + unsigned int height) { + +#if LIBVNCSERVER_HAVE_XSHM + return XShmCreateImage(disp, vis, depth, format, data, shminfo, + width, height); +#else + return (XImage *) 0; +#endif +} + +Status XShmAttach_wr(Display *disp, XShmSegmentInfo *shminfo) { +#if LIBVNCSERVER_HAVE_XSHM + return XShmAttach(disp, shminfo); +#else + return (Status) 0; +#endif +} + +Status XShmDetach_wr(Display *disp, XShmSegmentInfo *shminfo) { +#if LIBVNCSERVER_HAVE_XSHM + return XShmDetach(disp, shminfo); +#else + return (Status) 0; +#endif +} + +Bool XShmQueryExtension_wr(Display *disp) { +#if LIBVNCSERVER_HAVE_XSHM + return XShmQueryExtension(disp); +#else + return False; +#endif +} + +/* wrapper for overlay screen reading: */ + +XImage *xreadscreen(Display *disp, Drawable d, int x, int y, + unsigned int width, unsigned int height, Bool show_cursor) { +#ifdef SOLARIS_OVERLAY + return XReadScreen(disp, d, x, y, width, height, + show_cursor); +#else +# ifdef IRIX_OVERLAY + { unsigned long hints = 0, hints_ret; + if (show_cursor) hints |= XRD_READ_POINTER; + return XReadDisplay(disp, d, x, y, width, height, + hints, &hints_ret); + } +# else + /* unused vars warning: */ + if (disp || d || x || y || width || height || show_cursor) {} + + return NULL; +# endif +#endif +} + +XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y, + unsigned int width, unsigned int height, unsigned long plane_mask, + int format, XImage *dest_image, int dest_x, int dest_y) { + + ADJUST_ROOTSHIFT + + if (overlay && dest_x == 0 && dest_y == 0) { + size_t size = dest_image->height * dest_image->bytes_per_line; + XImage *xi; + + xi = xreadscreen(disp, d, x, y, width, height, + (Bool) overlay_cursor); + + if (! xi) return NULL; + + /* + * There is extra overhead from memcpy and free... + * this is not like the real XGetSubImage(). We hope + * this significant overhead is still small compared to + * the time to retrieve the fb data. + */ + memcpy(dest_image->data, xi->data, size); + + XDestroyImage(xi); + return (dest_image); + } + return XGetSubImage(disp, d, x, y, width, height, plane_mask, + format, dest_image, dest_x, dest_y); +} + +XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y, + unsigned int width, unsigned int height, unsigned long plane_mask, + int format) { + + ADJUST_ROOTSHIFT + + if (overlay) { + return xreadscreen(disp, d, x, y, width, height, + (Bool) overlay_cursor); + } + return XGetImage(disp, d, x, y, width, height, plane_mask, format); +} + +XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth, + int format, int offset, char *data, unsigned int width, + unsigned int height, int bitmap_pad, int bytes_per_line) { + /* + * This is a kludge to get a created XImage to exactly match what + * XReadScreen returns: we noticed the rgb masks are different + * from XCreateImage with the high color visual (red mask <-> + * blue mask). Note we read from the root window(!) then free + * the data. + */ + + if (raw_fb) { /* raw_fb hack */ + XImage *xi; + xi = (XImage *) malloc(sizeof(XImage)); + memset(xi, 0, sizeof(XImage)); + xi->depth = depth; + xi->bits_per_pixel = (depth == 24) ? 32 : depth; + xi->format = format; + xi->xoffset = offset; + xi->data = data; + xi->width = width; + xi->height = height; + xi->bitmap_pad = bitmap_pad; + xi->bytes_per_line = bytes_per_line ? bytes_per_line : + xi->width * xi->bits_per_pixel / 8; + return xi; + } + + if (overlay) { + XImage *xi; + xi = xreadscreen(disp, window, 0, 0, width, height, False); + if (xi == NULL) { + return xi; + } + if (xi->data != NULL) { + free(xi->data); + } + xi->data = data; + return xi; + } + + return XCreateImage(disp, visual, depth, format, offset, data, + width, height, bitmap_pad, bytes_per_line); +} + +static void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h) { + char *src, *dst; + unsigned int line; + int pixelsize = bpp/8; + int bpl = wdpy_x * pixelsize; + + if (clipshift) { + x += coff_x; + y += coff_y; + } + if (! raw_fb_seek) { + src = raw_fb_addr + raw_fb_offset + bpl*y + pixelsize*x; + dst = dest->data; + + for (line = 0; line < h; line++) { + memcpy(dst, src, w * pixelsize); + src += bpl; + dst += dest->bytes_per_line; + } + } else{ + int n, len, del, sz = w * pixelsize; + off_t off = (off_t) (raw_fb_offset + bpl*y + pixelsize*x); + + lseek(raw_fb_fd, off, SEEK_SET); + dst = dest->data; + + for (line = 0; line < h; line++) { + len = sz; + del = 0; + while (len > 0) { + n = read(raw_fb_fd, dst + del, len); + + if (n > 0) { + del += n; + len -= n; + } else if (n == 0) { + break; + } else { + /* overkill... */ + if (errno != EINTR && errno != EAGAIN) { + break; + } + } + } + if (bpl > sz) { + off = (off_t) (bpl - sz); + lseek(raw_fb_fd, off, SEEK_CUR); + } + dst += dest->bytes_per_line; + } + } +} + +void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h) { + /* default (w=0, h=0) is the fill the entire XImage */ + if (w < 1) { + w = dest->width; + } + if (h < 1) { + h = dest->height; + } + + if (use_snapfb && snap_fb && dest != snaprect) { + char *src, *dst; + unsigned int line; + int pixelsize = bpp/8; + + src = snap->data + snap->bytes_per_line*y + pixelsize*x; + dst = dest->data; + for (line = 0; line < h; line++) { + memcpy(dst, src, w * pixelsize); + src += snap->bytes_per_line; + dst += dest->bytes_per_line; + } + + } else if (raw_fb) { + copy_raw_fb(dest, x, y, w, h); + + } else if (using_shm && (int) w == dest->width && + (int) h == dest->height) { + XShmGetImage_wr(dpy, window, dest, x, y, AllPlanes); + + } else { + XGetSubImage_wr(dpy, window, x, y, w, h, AllPlanes, + ZPixmap, dest, 0, 0); + } +} + +#define DEBUG_SKIPPED_INPUT(dbg, str) \ + if (dbg) { \ + rfbLog("skipped input: %s\n", str); \ + } + +void init_track_keycode_state(void) { + int i; + for (i=0; i<256; i++) { + keycode_state[i] = 0; + } + get_keystate(keycode_state); +} + +static void upup_downdown_warning(KeyCode key, Bool down) { + if ((down ? 1:0) == keycode_state[(int) key]) { + rfbLog("XTestFakeKeyEvent: keycode=0x%x \"%s\" is *already* " + "%s\n", key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)), + down ? "down":"up"); + } +} + +/* + * wrappers for XTestFakeKeyEvent, etc.. + * also for XTrap equivalents XESimulateXEventRequest + */ + +void XTRAP_FakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, + unsigned long delay) { + + if (! xtrap_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTRAP"); + return; + } + /* unused vars warning: */ + if (dpy || key || down || delay) {} + +#if LIBVNCSERVER_HAVE_LIBXTRAP + XESimulateXEventRequest(trap_ctx, down ? KeyPress : KeyRelease, + key, 0, 0, 0); + if (debug_keyboard) { + upup_downdown_warning(key, down); + } + keycode_state[(int) key] = down ? 1 : 0; +#else + DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTRAP-build"); +#endif +} + +void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, + unsigned long delay) { + static int first = 1; + if (debug_keyboard) { + rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n", + key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)), + down ? "down":"up"); + } + if (first) { + init_track_keycode_state(); + first = 0; + } + if (down) { + last_keyboard_keycode = -key; + } else { + last_keyboard_keycode = key; + } + + if (xtrap_input) { + XTRAP_FakeKeyEvent_wr(dpy, key, down, delay); + return; + } + + if (! xtest_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTEST"); + return; + } + if (debug_keyboard) { + rfbLog("calling XTestFakeKeyEvent(%d, %d) %.4f\n", + key, down, dnow() - x11vnc_start); + } +#if LIBVNCSERVER_HAVE_XTEST + XTestFakeKeyEvent(dpy, key, down, delay); + if (debug_keyboard) { + upup_downdown_warning(key, down); + } + keycode_state[(int) key] = down ? 1 : 0; +#endif +} + +void XTRAP_FakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, + unsigned long delay) { + + if (! xtrap_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTRAP"); + return; + } + /* unused vars warning: */ + if (dpy || button || is_press || delay) {} + +#if LIBVNCSERVER_HAVE_LIBXTRAP + XESimulateXEventRequest(trap_ctx, + is_press ? ButtonPress : ButtonRelease, button, 0, 0, 0); +#else + DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTRAP-build"); +#endif +} + +void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, + unsigned long delay) { + + if (xtrap_input) { + XTRAP_FakeButtonEvent_wr(dpy, button, is_press, delay); + return; + } + + if (! xtest_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTEST"); + return; + } + if (debug_pointer) { + rfbLog("calling XTestFakeButtonEvent(%d, %d) %.4f\n", + button, is_press, dnow() - x11vnc_start); + } +#if LIBVNCSERVER_HAVE_XTEST + XTestFakeButtonEvent(dpy, button, is_press, delay); +#endif +} + +void XTRAP_FakeMotionEvent_wr(Display* dpy, int screen, int x, int y, + unsigned long delay) { + + if (! xtrap_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "motion: no-XTRAP"); + return; + } + /* unused vars warning: */ + if (dpy || screen || x || y || delay) {} + +#if LIBVNCSERVER_HAVE_LIBXTRAP + XESimulateXEventRequest(trap_ctx, MotionNotify, 0, x, y, 0); +#else + DEBUG_SKIPPED_INPUT(debug_keyboard, "motion: no-XTRAP-build"); +#endif +} + +void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y, + unsigned long delay) { + + if (xtrap_input) { + XTRAP_FakeMotionEvent_wr(dpy, screen, x, y, delay); + return; + } + + if (debug_pointer) { + rfbLog("calling XTestFakeMotionEvent(%d, %d) %.4f\n", + x, y, dnow() - x11vnc_start); + } +#if LIBVNCSERVER_HAVE_XTEST + XTestFakeMotionEvent(dpy, screen, x, y, delay); +#endif +} + +Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w) { + if (! xtest_present) { + return False; + } +#if LIBVNCSERVER_HAVE_XTEST + return XTestCompareCurrentCursorWithWindow(dpy, w); +#else + return False; +#endif +} + +Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor) { + if (! xtest_present) { + return False; + } +#if LIBVNCSERVER_HAVE_XTEST + return XTestCompareCursorWithWindow(dpy, w, cursor); +#else + return False; +#endif +} + +Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj, + int *min) { +#if LIBVNCSERVER_HAVE_XTEST + return XTestQueryExtension(dpy, ev, er, maj, min); +#else + return False; +#endif +} + +void XTestDiscard_wr(Display *dpy) { + if (! xtest_present) { + return; + } +#if LIBVNCSERVER_HAVE_XTEST + XTestDiscard(dpy); +#endif +} + +Bool XETrapQueryExtension_wr(Display *dpy, int *ev, int *er, int *op) { +#if LIBVNCSERVER_HAVE_LIBXTRAP + return XETrapQueryExtension(dpy, (INT32 *)ev, (INT32 *)er, + (INT32 *)op); +#else + /* unused vars warning: */ + if (dpy || ev || er || op) {} + return False; +#endif +} + +int XTestGrabControl_wr(Display *dpy, Bool impervious) { + if (! xtest_present) { + return 0; + } +#if LIBVNCSERVER_HAVE_XTEST && LIBVNCSERVER_HAVE_XTESTGRABCONTROL + XTestGrabControl(dpy, impervious); + return 1; +#else + return 0; +#endif +} + +int XTRAP_GrabControl_wr(Display *dpy, Bool impervious) { + if (! xtrap_present) { + /* unused vars warning: */ + if (dpy || impervious) {} + return 0; + } +#if LIBVNCSERVER_HAVE_LIBXTRAP + else { + ReqFlags requests; + + if (! impervious) { + if (trap_ctx) { + XEFreeTC(trap_ctx); + } + trap_ctx = NULL; + return 1; + } + + if (! trap_ctx) { + trap_ctx = XECreateTC(dpy, 0, NULL); + if (! trap_ctx) { + rfbLog("DEC-XTRAP XECreateTC failed. Watch " + "out for XGrabServer from wm's\n"); + return 0; + } + XEStartTrapRequest(trap_ctx); + memset(requests, 0, sizeof(requests)); + BitTrue(requests, X_GrabServer); + BitTrue(requests, X_UngrabServer); + XETrapSetRequests(trap_ctx, True, requests); + XETrapSetGrabServer(trap_ctx, True); + } + return 1; + } +#endif + return 0; +} + +void disable_grabserver(Display *in_dpy, int change) { + int ok = 0; + static int didmsg = 0; + + if (debug_grabs) { + fprintf(stderr, "disable_grabserver/%d %.5f\n", + xserver_grabbed, dnowx()); + didmsg = 0; + } + + if (! xtrap_input) { + if (XTestGrabControl_wr(in_dpy, True)) { + if (change) { + XTRAP_GrabControl_wr(in_dpy, False); + } + if (! didmsg) { + rfbLog("GrabServer control via XTEST.\n"); + didmsg = 1; + } + ok = 1; + } else { + if (XTRAP_GrabControl_wr(in_dpy, True)) { + ok = 1; + if (! didmsg) { + rfbLog("Using DEC-XTRAP for protection" + " from XGrabServer.\n"); + didmsg = 1; + } + } + } + } else { + if (XTRAP_GrabControl_wr(in_dpy, True)) { + if (change) { + XTestGrabControl_wr(in_dpy, False); + } + if (! didmsg) { + rfbLog("GrabServer control via DEC-XTRAP.\n"); + didmsg = 1; + } + ok = 1; + } else { + if (XTestGrabControl_wr(in_dpy, True)) { + ok = 1; + if (! didmsg) { + rfbLog("DEC-XTRAP XGrabServer " + "protection not available, " + "using XTEST.\n"); + didmsg = 1; + } + } + } + } + if (! ok && ! didmsg) { + rfbLog("No XTEST or DEC-XTRAP protection from XGrabServer.\n"); + rfbLog("Deadlock if your window manager calls XGrabServer!!\n"); + } + XFlush(in_dpy); +} + +Bool XRecordQueryVersion_wr(Display *dpy, int *maj, int *min) { +#if LIBVNCSERVER_HAVE_RECORD + return XRecordQueryVersion(dpy, maj, min); +#else + return False; +#endif +} + + -- cgit v1.2.1