summaryrefslogtreecommitdiffstats
path: root/x11vnc/xwrappers.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/xwrappers.c')
-rw-r--r--x11vnc/xwrappers.c697
1 files changed, 697 insertions, 0 deletions
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
+}
+
+