diff options
Diffstat (limited to 'x11vnc/xrecord.c')
-rw-r--r-- | x11vnc/xrecord.c | 2084 |
1 files changed, 0 insertions, 2084 deletions
diff --git a/x11vnc/xrecord.c b/x11vnc/xrecord.c deleted file mode 100644 index 87e15b9..0000000 --- a/x11vnc/xrecord.c +++ /dev/null @@ -1,2084 +0,0 @@ -/* - Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> - All rights reserved. - -This file is part of x11vnc. - -x11vnc 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. - -x11vnc 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 x11vnc; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA -or see <http://www.gnu.org/licenses/>. - -In addition, as a special exception, Karl J. Runge -gives permission to link the code of its release of x11vnc with the -OpenSSL project's "OpenSSL" library (or with modified versions of it -that use the same license as the "OpenSSL" library), and distribute -the linked executables. You must obey the GNU General Public License -in all respects for all of the code used other than "OpenSSL". If you -modify this file, you may extend this exception to your version of the -file, but you are not obligated to do so. If you do not wish to do -so, delete this exception statement from your version. -*/ - -/* -- xrecord.c -- */ - -#include "x11vnc.h" -#include "xwrappers.h" -#include "win_utils.h" -#include "cleanup.h" -#include "userinput.h" -#include "winattr_t.h" -#include "scrollevent_t.h" -#include "unixpw.h" - -#define SCR_EV_MAX 128 -scroll_event_t scr_ev[SCR_EV_MAX]; -int scr_ev_cnt; - -int xrecording = 0; -int xrecord_set_by_keys = 0; -int xrecord_set_by_mouse = 0; -Window xrecord_focus_window = None; -Window xrecord_wm_window = None; -Window xrecord_ptr_window = None; -KeySym xrecord_keysym = NoSymbol; - -#define NAMEINFO 2048 -char xrecord_name_info[NAMEINFO]; - -#define SCR_ATTR_CACHE 8 -winattr_t scr_attr_cache[SCR_ATTR_CACHE]; -static double attr_cache_max_age = 1.5; - -Display *rdpy_data = NULL; /* Data connection for RECORD */ -Display *rdpy_ctrl = NULL; /* Control connection for RECORD */ - -Display *gdpy_ctrl = NULL; -Display *gdpy_data = NULL; -int xserver_grabbed = 0; - -int trap_record_xerror(Display *, XErrorEvent *); - -void initialize_xrecord(void); -void zerodisp_xrecord(void); -void shutdown_xrecord(void); -int xrecord_skip_keysym(rfbKeySym keysym); -int xrecord_skip_button(int newb, int old); -int xrecord_scroll_keysym(rfbKeySym keysym); -void check_xrecord_reset(int force); -void xrecord_watch(int start, int setby); - - -#if LIBVNCSERVER_HAVE_RECORD -static XRecordRange *rr_CA = NULL; -static XRecordRange *rr_CW = NULL; -static XRecordRange *rr_GS = NULL; -static XRecordRange *rr_scroll[10]; -static XRecordContext rc_scroll; -static XRecordClientSpec rcs_scroll; -static XRecordRange *rr_grab[10]; -static XRecordContext rc_grab; -static XRecordClientSpec rcs_grab; -#endif -static XErrorEvent *trapped_record_xerror_event; - -static void xrecord_grabserver(int start); -static int xrecord_vi_scroll_keysym(rfbKeySym keysym); -static int xrecord_emacs_scroll_keysym(rfbKeySym keysym); -static int lookup_attr_cache(Window win, int *cache_index, int *next_index); -#if LIBVNCSERVER_HAVE_RECORD -static void record_CA(XPointer ptr, XRecordInterceptData *rec_data); -static void record_CW(XPointer ptr, XRecordInterceptData *rec_data); -static void record_switch(XPointer ptr, XRecordInterceptData *rec_data); -static void record_grab(XPointer ptr, XRecordInterceptData *rec_data); -static void shutdown_record_context(XRecordContext rc, int bequiet, int reopen); -#endif -static void check_xrecord_grabserver(void); - - -int trap_record_xerror(Display *d, XErrorEvent *error) { - trapped_record_xerror = 1; - trapped_record_xerror_event = error; - - if (d) {} /* unused vars warning: */ - - return 0; -} - -static void xrecord_grabserver(int start) { - XErrorHandler old_handler = NULL; - int rc = 0; - - if (debug_grabs) { - fprintf(stderr, "xrecord_grabserver%d/%d %.5f\n", - xserver_grabbed, start, dnowx()); - } - - if (! gdpy_ctrl || ! gdpy_data) { - return; - } -#if LIBVNCSERVER_HAVE_RECORD - if (!start) { - if (! rc_grab) { - return; - } - XRecordDisableContext(gdpy_ctrl, rc_grab); - XRecordFreeContext(gdpy_ctrl, rc_grab); - XFlush_wr(gdpy_ctrl); - rc_grab = 0; - return; - } - - xserver_grabbed = 0; - - rr_grab[0] = rr_GS; - rcs_grab = XRecordAllClients; - - rc_grab = XRecordCreateContext(gdpy_ctrl, 0, &rcs_grab, 1, rr_grab, 1); - trapped_record_xerror = 0; - old_handler = XSetErrorHandler(trap_record_xerror); - - XSync(gdpy_ctrl, True); - - if (! rc_grab || trapped_record_xerror) { - XCloseDisplay_wr(gdpy_ctrl); - XCloseDisplay_wr(gdpy_data); - gdpy_ctrl = NULL; - gdpy_data = NULL; - XSetErrorHandler(old_handler); - return; - } - rc = XRecordEnableContextAsync(gdpy_data, rc_grab, record_grab, NULL); - if (!rc || trapped_record_xerror) { - XCloseDisplay_wr(gdpy_ctrl); - XCloseDisplay_wr(gdpy_data); - gdpy_ctrl = NULL; - gdpy_data = NULL; - XSetErrorHandler(old_handler); - return; - } - XFlush_wr(gdpy_data); - XSetErrorHandler(old_handler); -#else - if (!rc || !old_handler) {} -#endif - if (debug_grabs) { - fprintf(stderr, "xrecord_grabserver-done: %.5f\n", dnowx()); - } -} - -void zerodisp_xrecord(void) { - rdpy_data = NULL; - rdpy_ctrl = NULL; - gdpy_data = NULL; - gdpy_ctrl = NULL; -} - -void initialize_xrecord(void) { - use_xrecord = 0; - if (! xrecord_present) { - return; - } - if (nofb) { - return; - } - if (noxrecord) { - return; - } - RAWFB_RET_VOID -#if LIBVNCSERVER_HAVE_RECORD - - if (rr_CA) XFree_wr(rr_CA); - if (rr_CW) XFree_wr(rr_CW); - if (rr_GS) XFree_wr(rr_GS); - - rr_CA = XRecordAllocRange(); - rr_CW = XRecordAllocRange(); - rr_GS = XRecordAllocRange(); - if (!rr_CA || !rr_CW || !rr_GS) { - return; - } - /* protocol request ranges: */ - rr_CA->core_requests.first = X_CopyArea; - rr_CA->core_requests.last = X_CopyArea; - - rr_CW->core_requests.first = X_ConfigureWindow; - rr_CW->core_requests.last = X_ConfigureWindow; - - rr_GS->core_requests.first = X_GrabServer; - rr_GS->core_requests.last = X_UngrabServer; - - X_LOCK; - /* open a 2nd control connection to DISPLAY: */ - if (rdpy_data) { - XCloseDisplay_wr(rdpy_data); - rdpy_data = NULL; - } - if (rdpy_ctrl) { - XCloseDisplay_wr(rdpy_ctrl); - rdpy_ctrl = NULL; - } - rdpy_ctrl = XOpenDisplay_wr(DisplayString(dpy)); - if (!rdpy_ctrl) { - fprintf(stderr, "rdpy_ctrl open failed: %s / %s / %s / %s\n", getenv("DISPLAY"), DisplayString(dpy), getenv("XAUTHORITY"), getenv("XAUTHORIT_")); - } - XSync(dpy, True); - XSync(rdpy_ctrl, True); - /* open datalink connection to DISPLAY: */ - rdpy_data = XOpenDisplay_wr(DisplayString(dpy)); - if (!rdpy_data) { - fprintf(stderr, "rdpy_data open failed\n"); - } - if (!rdpy_ctrl || ! rdpy_data) { - X_UNLOCK; - return; - } - disable_grabserver(rdpy_ctrl, 0); - disable_grabserver(rdpy_data, 0); - - use_xrecord = 1; - - /* - * now set up the GrabServer watcher. We get GrabServer - * deadlock in XRecordCreateContext() even with XTestGrabServer - * in place, why? Not sure, so we manually watch for grabs... - */ - if (gdpy_data) { - XCloseDisplay_wr(gdpy_data); - gdpy_data = NULL; - } - if (gdpy_ctrl) { - XCloseDisplay_wr(gdpy_ctrl); - gdpy_ctrl = NULL; - } - xserver_grabbed = 0; - - gdpy_ctrl = XOpenDisplay_wr(DisplayString(dpy)); - if (!gdpy_ctrl) { - fprintf(stderr, "gdpy_ctrl open failed\n"); - } - XSync(dpy, True); - XSync(gdpy_ctrl, True); - gdpy_data = XOpenDisplay_wr(DisplayString(dpy)); - if (!gdpy_data) { - fprintf(stderr, "gdpy_data open failed\n"); - } - if (gdpy_ctrl && gdpy_data) { - disable_grabserver(gdpy_ctrl, 0); - disable_grabserver(gdpy_data, 0); - xrecord_grabserver(1); - } - X_UNLOCK; -#endif -} - -void shutdown_xrecord(void) { -#if LIBVNCSERVER_HAVE_RECORD - - if (debug_grabs) { - fprintf(stderr, "shutdown_xrecord%d %.5f\n", - xserver_grabbed, dnowx()); - } - - if (rr_CA) XFree_wr(rr_CA); - if (rr_CW) XFree_wr(rr_CW); - if (rr_GS) XFree_wr(rr_GS); - - rr_CA = NULL; - rr_CW = NULL; - rr_GS = NULL; - - X_LOCK; - if (rdpy_ctrl && rc_scroll) { - XRecordDisableContext(rdpy_ctrl, rc_scroll); - XRecordFreeContext(rdpy_ctrl, rc_scroll); - XSync(rdpy_ctrl, False); - rc_scroll = 0; - } - - if (gdpy_ctrl && rc_grab) { - XRecordDisableContext(gdpy_ctrl, rc_grab); - XRecordFreeContext(gdpy_ctrl, rc_grab); - XSync(gdpy_ctrl, False); - rc_grab = 0; - } - - if (rdpy_data) { - XCloseDisplay_wr(rdpy_data); - rdpy_data = NULL; - } - if (rdpy_ctrl) { - XCloseDisplay_wr(rdpy_ctrl); - rdpy_ctrl = NULL; - } - if (gdpy_data) { - XCloseDisplay_wr(gdpy_data); - gdpy_data = NULL; - } - if (gdpy_ctrl) { - XCloseDisplay_wr(gdpy_ctrl); - gdpy_ctrl = NULL; - } - xserver_grabbed = 0; - X_UNLOCK; -#endif - use_xrecord = 0; - - if (debug_grabs) { - fprintf(stderr, "shutdown_xrecord-done: %.5f\n", dnowx()); - } -} - -int xrecord_skip_keysym(rfbKeySym keysym) { - KeySym sym = (KeySym) keysym; - int ok = -1, matched = 0; - - if (scroll_key_list) { - int k, exclude = 0; - if (scroll_key_list[0]) { - exclude = 1; - } - k = 1; - while (scroll_key_list[k] != NoSymbol) { - if (scroll_key_list[k++] == sym) { - matched = 1; - break; - } - } - if (exclude) { - if (matched) { - return 1; - } else { - ok = 1; - } - } else { - if (matched) { - ok = 1; - } else { - ok = 0; - } - } - } - if (ok == 1) { - return 0; - } else if (ok == 0) { - return 1; - } - - /* apply various heuristics: */ - - if (IsModifierKey(sym)) { - /* Shift, Control, etc, usu. generate no scrolls */ - return 1; - } - if (sym == XK_space && scroll_term) { - /* space in a terminal is usu. full page... */ - Window win; - static Window prev_top = None; - int size = 256; - static char name[256]; - - X_LOCK; - win = query_pointer(rootwin); - X_UNLOCK; - if (win != None && win != rootwin) { - if (prev_top != None && win == prev_top) { - ; /* use cached result */ - } else { - prev_top = win; - X_LOCK; - win = descend_pointer(6, win, name, size); - X_UNLOCK; - } - if (match_str_list(name, scroll_term)) { - return 1; - } - } - } - - /* TBD use typing_rate() so */ - return 0; -} - -int xrecord_skip_button(int new_button, int old) { - /* unused vars warning: */ - if (new_button || old) {} - - return 0; -} - -static int xrecord_vi_scroll_keysym(rfbKeySym keysym) { - KeySym sym = (KeySym) keysym; - if (sym == XK_J || sym == XK_j || sym == XK_K || sym == XK_k) { - return 1; /* vi */ - } - if (sym == XK_D || sym == XK_d || sym == XK_U || sym == XK_u) { - return 1; /* Ctrl-d/u */ - } - if (sym == XK_Z || sym == XK_z) { - return 1; /* zz, zt, zb .. */ - } - return 0; -} - -static int xrecord_emacs_scroll_keysym(rfbKeySym keysym) { - KeySym sym = (KeySym) keysym; - if (sym == XK_N || sym == XK_n || sym == XK_P || sym == XK_p) { - return 1; /* emacs */ - } - /* Must be some more ... */ - return 0; -} - -int xrecord_scroll_keysym(rfbKeySym keysym) { - KeySym sym = (KeySym) keysym; - /* X11/keysymdef.h */ - - if (sym == XK_Return || sym == XK_KP_Enter || sym == XK_Linefeed) { - return 1; /* Enter */ - } - if (sym==XK_Up || sym==XK_KP_Up || sym==XK_Down || sym==XK_KP_Down) { - return 1; /* U/D arrows */ - } - if (sym == XK_Left || sym == XK_KP_Left || sym == XK_Right || - sym == XK_KP_Right) { - return 1; /* L/R arrows */ - } - if (xrecord_vi_scroll_keysym(keysym)) { - return 1; - } - if (xrecord_emacs_scroll_keysym(keysym)) { - return 1; - } - return 0; -} - -static int lookup_attr_cache(Window win, int *cache_index, int *next_index) { - double now, t, oldest = 0.0; - int i, old_index = -1, count = 0; - Window cwin; - - *cache_index = -1; - *next_index = -1; - - if (win == None) { - return 0; - } - if (attr_cache_max_age == 0.0) { - return 0; - } - - dtime0(&now); - for (i=0; i < SCR_ATTR_CACHE; i++) { - - cwin = scr_attr_cache[i].win; - t = scr_attr_cache[i].time; - - if (now > t + attr_cache_max_age) { - /* expire it even if it is the one we want */ - scr_attr_cache[i].win = cwin = None; - scr_attr_cache[i].fetched = 0; - scr_attr_cache[i].valid = 0; - } - - if (*next_index == -1 && cwin == None) { - *next_index = i; - } - if (*next_index == -1) { - /* record oldest */ - if (old_index == -1 || t < oldest) { - oldest = t; - old_index = i; - } - } - if (cwin != None) { - count++; - } - if (cwin == win) { - if (*cache_index == -1) { - *cache_index = i; - } else { - /* remove dups */ - scr_attr_cache[i].win = None; - scr_attr_cache[i].fetched = 0; - scr_attr_cache[i].valid = 0; - } - } - } - if (*next_index == -1) { - *next_index = old_index; - } - -if (0) fprintf(stderr, "lookup_attr_cache count: %d\n", count); - if (*cache_index != -1) { - return 1; - } else { - return 0; - } -} - - -static XID xrecord_seq = 0; -static double xrecord_start = 0.0; - -#if LIBVNCSERVER_HAVE_RECORD -static void record_CA(XPointer ptr, XRecordInterceptData *rec_data) { - xCopyAreaReq *req; - Window src = None, dst = None, c; - XWindowAttributes attr, attr2; - int src_x, src_y, dst_x, dst_y, rx, ry, rx2, ry2; - int good = 1, dx = 0, dy = 0, k=0, i; - unsigned int w, h; - int dba = 0, db = debug_scroll; - int cache_index, next_index, valid; - static int must_equal = -1; - - if (dba || db) { - if (rec_data->category == XRecordFromClient) { - req = (xCopyAreaReq *) rec_data->data; - if (req->reqType == X_CopyArea) { - src = req->srcDrawable; - dst = req->dstDrawable; - } - } - } - -if (dba || db > 1) fprintf(stderr, "record_CA-%d id_base: 0x%lx ptr: 0x%lx " - "seq: 0x%lx rc: 0x%lx cat: %d swapped: %d 0x%lx/0x%lx\n", k++, - rec_data->id_base, (unsigned long) ptr, xrecord_seq, rc_scroll, - rec_data->category, rec_data->client_swapped, src, dst); - - if (! xrecording) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if (rec_data->id_base == 0) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if ((XID) ptr != xrecord_seq) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if (rec_data->category != XRecordFromClient) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - req = (xCopyAreaReq *) rec_data->data; - - if (req->reqType != X_CopyArea) { - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if (must_equal < 0) { - must_equal = 0; - if (getenv("X11VNC_SCROLL_MUST_EQUAL")) { - must_equal = 1; - } - } - -/* - -xterm, gnome-terminal, others. - -Note we miss the X_ImageText8 that clears the block cursor. So there is a -short period of time with a painting error: two cursors, one above the other. - - X_ImageText8 - draw: 0x8c00017 nChars: 1, gc: 0x8c00013, x: 101, y: 585, chars=' ' - X_ClearArea - window: 0x8c00018, x: 2, y: 217, w: 10, h: 5 - X_FillPoly - draw: 0x8c00018 gc: 0x8c0000a, shape: 0, coordMode: 0, - X_FillPoly - draw: 0x8c00018 gc: 0x8c0000b, shape: 0, coordMode: 0, - X_CopyArea - src: 0x8c00017, dst: 0x8c00017, gc: 0x8c00013, srcX: 17, srcY: 15, dstX: 17, dstY: 2, w: 480, h: 572 - X_ChangeWindowAttributes - X_ClearArea - window: 0x8c00017, x: 17, y: 574, w: 480, h: 13 - X_ChangeWindowAttributes - - */ - - src = req->srcDrawable; - dst = req->dstDrawable; - src_x = req->srcX; - src_y = req->srcY; - dst_x = req->dstX; - dst_y = req->dstY; - w = req->width; - h = req->height; - - if (w*h < (unsigned int) scrollcopyrect_min_area) { - if (db > 1) fprintf(stderr, "record_CA scroll area too small.\n"); - good = 0; - } else if (!src || !dst) { - if (db > 1) fprintf(stderr, "record_CA null src or dst.\n"); - good = 0; - } else if (scr_ev_cnt >= SCR_EV_MAX) { - if (db > 1) fprintf(stderr, "record_CA null too many scr events.\n"); - good = 0; - } else if (must_equal && src != dst) { - if (db > 1) fprintf(stderr, "record_CA src not equal dst.\n"); - good = 0; - } - - if (src == dst) { - dx = dst_x - src_x; - dy = dst_y - src_y; - - if (dx != 0 && dy != 0) { - good = 0; - } - } - -if (!good && (dba || db > 1)) fprintf(stderr, "record_CA-x src_x: %d src_y: %d " - "dst_x: %d dst_y: %d w: %d h: %d scr_ev_cnt: %d 0x%lx/0x%lx\n", - src_x, src_y, dst_x, dst_y, w, h, scr_ev_cnt, src, dst); - - if (! good) { - return; - } - -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - /* - * after all of the above succeeds, now contact X server. - * we try to get away with some caching here. - */ - if (lookup_attr_cache(src, &cache_index, &next_index)) { - i = cache_index; - attr.x = scr_attr_cache[i].x; - attr.y = scr_attr_cache[i].y; - attr.width = scr_attr_cache[i].width; - attr.height = scr_attr_cache[i].height; - attr.map_state = scr_attr_cache[i].map_state; - rx = scr_attr_cache[i].rx; - ry = scr_attr_cache[i].ry; - valid = scr_attr_cache[i].valid; - - } else { - valid = valid_window(src, &attr, 1); - - if (valid) { - if (!xtranslate(src, rootwin, 0, 0, &rx, &ry, &c, 1)) { - valid = 0; - } - } - if (next_index >= 0) { - i = next_index; - scr_attr_cache[i].win = src; - scr_attr_cache[i].fetched = 1; - scr_attr_cache[i].valid = valid; - scr_attr_cache[i].time = dnow(); - if (valid) { - scr_attr_cache[i].x = attr.x; - scr_attr_cache[i].y = attr.y; - scr_attr_cache[i].width = attr.width; - scr_attr_cache[i].height = attr.height; - scr_attr_cache[i].border_width = attr.border_width; - scr_attr_cache[i].depth = attr.depth; - scr_attr_cache[i].class = attr.class; - scr_attr_cache[i].backing_store = - attr.backing_store; - scr_attr_cache[i].map_state = attr.map_state; - - scr_attr_cache[i].rx = rx; - scr_attr_cache[i].ry = ry; - } - } - } - - if (! valid) { - if (db > 1) fprintf(stderr, "record_CA not valid-1.\n"); - return; - } -if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); - - if (attr.map_state != IsViewable) { - if (db > 1) fprintf(stderr, "record_CA not viewable-1.\n"); - return; - } - - /* recent gdk/gtk windows use different src and dst. for compositing? */ - if (src != dst) { - if (lookup_attr_cache(dst, &cache_index, &next_index)) { - i = cache_index; - attr2.x = scr_attr_cache[i].x; - attr2.y = scr_attr_cache[i].y; - attr2.width = scr_attr_cache[i].width; - attr2.height = scr_attr_cache[i].height; - attr2.map_state = scr_attr_cache[i].map_state; - rx2 = scr_attr_cache[i].rx; - ry2 = scr_attr_cache[i].ry; - valid = scr_attr_cache[i].valid; - - } else { - valid = valid_window(dst, &attr2, 1); - - if (valid) { - if (!xtranslate(dst, rootwin, 0, 0, &rx2, &ry2, &c, 1)) { - valid = 0; - } - } - if (next_index >= 0) { - i = next_index; - scr_attr_cache[i].win = dst; - scr_attr_cache[i].fetched = 1; - scr_attr_cache[i].valid = valid; - scr_attr_cache[i].time = dnow(); - if (valid) { - scr_attr_cache[i].x = attr2.x; - scr_attr_cache[i].y = attr2.y; - scr_attr_cache[i].width = attr2.width; - scr_attr_cache[i].height = attr2.height; - scr_attr_cache[i].border_width = attr2.border_width; - scr_attr_cache[i].depth = attr2.depth; - scr_attr_cache[i].class = attr2.class; - scr_attr_cache[i].backing_store = - attr2.backing_store; - scr_attr_cache[i].map_state = attr2.map_state; - - scr_attr_cache[i].rx = rx2; - scr_attr_cache[i].ry = ry2; - } - } - } - -if (dba || db > 1) fprintf(stderr, "record_CA-? src_x: %d src_y: %d " - "dst_x: %d dst_y: %d w: %d h: %d scr_ev_cnt: %d 0x%lx/0x%lx\n", - src_x, src_y, dst_x, dst_y, w, h, scr_ev_cnt, src, dst); - - if (! valid) { - if (db > 1) fprintf(stderr, "record_CA not valid-2.\n"); - return; - } - if (attr2.map_state != IsViewable) { - if (db > 1) fprintf(stderr, "record_CA not viewable-2.\n"); - return; - } - dst_x = dst_x - (rx - rx2); - dst_y = dst_y - (ry - ry2); - - dx = dst_x - src_x; - dy = dst_y - src_y; - - if (dx != 0 && dy != 0) { - return; - } - } - - - if (0 || dba || db) { - double st, dt; - st = (double) rec_data->server_time/1000.0; - dt = (dnow() - servertime_diff) - st; - fprintf(stderr, "record_CA-%d *FOUND_SCROLL: src: 0x%lx dx: %d dy: %d " - "x: %d y: %d w: %d h: %d st: %.4f %.4f %.4f\n", k++, src, dx, dy, - src_x, src_y, w, h, st, dt, dnowx()); - } - - i = scr_ev_cnt; - - scr_ev[i].win = src; - scr_ev[i].frame = None; - scr_ev[i].dx = dx; - scr_ev[i].dy = dy; - scr_ev[i].x = rx + dst_x; - scr_ev[i].y = ry + dst_y; - scr_ev[i].w = w; - scr_ev[i].h = h; - scr_ev[i].t = ((double) rec_data->server_time)/1000.0; - scr_ev[i].win_x = rx; - scr_ev[i].win_y = ry; - scr_ev[i].win_w = attr.width; - scr_ev[i].win_h = attr.height; - scr_ev[i].new_x = 0; - scr_ev[i].new_y = 0; - scr_ev[i].new_w = 0; - scr_ev[i].new_h = 0; - - if (dx == 0) { - if (dy > 0) { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = ry + src_y; - scr_ev[i].new_w = w; - scr_ev[i].new_h = dy; - } else { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = ry + dst_y + h; - scr_ev[i].new_w = w; - scr_ev[i].new_h = -dy; - } - } else if (dy == 0) { - if (dx > 0) { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = rx + src_y; - scr_ev[i].new_w = dx; - scr_ev[i].new_h = h; - } else { - scr_ev[i].new_x = rx + dst_x + w; - scr_ev[i].new_y = ry + src_y; - scr_ev[i].new_w = -dx; - scr_ev[i].new_h = h; - } - } - - scr_ev_cnt++; -} - -typedef struct cw_event { - Window win; - int x, y, w, h; -} cw_event_t; - -#define MAX_CW 128 -static cw_event_t cw_events[MAX_CW]; - -static void record_CW(XPointer ptr, XRecordInterceptData *rec_data) { - xConfigureWindowReq *req; - Window win = None, c; - Window src = None, dst = None; - XWindowAttributes attr; - int absent = 0x100000; - int src_x, src_y, dst_x, dst_y, rx, ry; - int good = 1, dx, dy, k=0, i, j, match, list[3]; - int f_x, f_y, f_w, f_h; - int x, y, w, h; - int x0, y0, w0, h0, x1, y1, w1, h1, x2, y2, w2, h2; - static int index = 0; - unsigned int vals[4]; - unsigned tmask; - char *data; - int dba = 0, db = debug_scroll; - int cache_index, next_index, valid; - - if (db) { - if (rec_data->category == XRecordFromClient) { - req = (xConfigureWindowReq *) rec_data->data; - if (req->reqType == X_ConfigureWindow) { - src = req->window; - } - } - } - -if (dba || db > 1) fprintf(stderr, "record_CW-%d id_base: 0x%lx ptr: 0x%lx " - "seq: 0x%lx rc: 0x%lx cat: %d swapped: %d 0x%lx/0x%lx\n", k++, - rec_data->id_base, (unsigned long) ptr, xrecord_seq, rc_scroll, - rec_data->category, rec_data->client_swapped, src, dst); - - - if (! xrecording) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if ((XID) ptr != xrecord_seq) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (rec_data->id_base == 0) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (rec_data->category == XRecordStartOfData) { - index = 0; - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (rec_data->category != XRecordFromClient) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (rec_data->client_swapped) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - req = (xConfigureWindowReq *) rec_data->data; - - if (req->reqType != X_ConfigureWindow) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - tmask = req->mask; - - tmask &= ~CWX; - tmask &= ~CWY; - tmask &= ~CWWidth; - tmask &= ~CWHeight; - - if (tmask) { - /* require no more than these 4 flags */ - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - f_x = req->mask & CWX; - f_y = req->mask & CWY; - f_w = req->mask & CWWidth; - f_h = req->mask & CWHeight; - - if (! f_x || ! f_y) { - if (f_w && f_h) { - ; /* netscape 4.x style */ - } else { - return; - } - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if ( (f_w && !f_h) || (!f_w && f_h) ) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - for (i=0; i<4; i++) { - vals[i] = 0; - } - - data = (char *)req; - data += sz_xConfigureWindowReq; - - for (i=0; i<req->length; i++) { - unsigned int v; - /* - * We use unsigned int for the values. There were - * some crashes on 64bit machines with unsigned longs. - * Need to check that X protocol sends 32bit values. - */ - v = *( (unsigned int *) data); -if (db > 1) fprintf(stderr, " vals[%d] 0x%x/%d\n", i, v, v); - vals[i] = v; - data += sizeof(unsigned int); - } - - if (index >= MAX_CW) { - int i, j; - - /* FIXME, circular, etc. */ - for (i=0; i<2; i++) { - j = MAX_CW - 2 + i; - cw_events[i].win = cw_events[j].win; - cw_events[i].x = cw_events[j].x; - cw_events[i].y = cw_events[j].y; - cw_events[i].w = cw_events[j].w; - cw_events[i].h = cw_events[j].h; - } - index = 2; - } - - if (! f_x && ! f_y) { - /* netscape 4.x style CWWidth,CWHeight */ - vals[2] = vals[0]; - vals[3] = vals[1]; - vals[0] = 0; - vals[1] = 0; - } - - cw_events[index].win = req->window; - - if (! f_x) { - cw_events[index].x = absent; - } else { - cw_events[index].x = (int) vals[0]; - } - if (! f_y) { - cw_events[index].y = absent; - } else { - cw_events[index].y = (int) vals[1]; - } - - if (! f_w) { - cw_events[index].w = absent; - } else { - cw_events[index].w = (int) vals[2]; - } - if (! f_h) { - cw_events[index].h = absent; - } else { - cw_events[index].h = (int) vals[3]; - } - - x = cw_events[index].x; - y = cw_events[index].y; - w = cw_events[index].w; - h = cw_events[index].h; - win = cw_events[index].win; - -if (dba || db) fprintf(stderr, " record_CW ind: %d win: 0x%lx x: %d y: %d w: %d h: %d\n", - index, win, x, y, w, h); - - index++; - - if (index < 3) { - good = 0; - } else if (w != absent && h != absent && - w*h < scrollcopyrect_min_area) { - good = 0; - } - - if (! good) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - match = 0; - for (j=index - 1; j >= 0; j--) { - if (cw_events[j].win == win) { - list[match++] = j; - } - if (match >= 3) { - break; - } - } - - if (match != 3) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - -/* - -Mozilla: - -Up arrow: window moves down a bit (dy > 0): - - X_ConfigureWindow - length: 7, window: 0x2e000cd, mask: 0xf, v0 0, v1 -18, v2 760, v3 906, v4 327692, v5 48234701, v6 3, - CW-mask: CWX,CWY,CWWidth,CWHeight, - X_ConfigureWindow - length: 5, window: 0x2e000cd, mask: 0x3, v0 0, v1 0, v2 506636, v3 48234701, v4 48234511, - CW-mask: CWX,CWY, - X_ConfigureWindow - length: 7, window: 0x2e000cd, mask: 0xf, v0 0, v1 0, v2 760, v3 888, v4 65579, v5 0, v6 108009, - CW-mask: CWX,CWY,CWWidth,CWHeight, - -Down arrow: window moves up a bit (dy < 0): - - X_ConfigureWindow - length: 7, window: 0x2e000cd, mask: 0xf, v0 0, v1 0, v2 760, v3 906, v4 327692, v5 48234701, v6 262147, - CW-mask: CWX,CWY,CWWidth,CWHeight, - X_ConfigureWindow - length: 5, window: 0x2e000cd, mask: 0x3, v0 0, v1 -18, v2 506636, v3 48234701, v4 48234511, - CW-mask: CWX,CWY, - X_ConfigureWindow - length: 7, window: 0x2e000cd, mask: 0xf, v0 0, v1 0, v2 760, v3 888, v4 96555, v5 48265642, v6 48265262, - CW-mask: CWX,CWY,CWWidth,CWHeight, - - -Netscape 4.x - -Up arrow: -71.76142 0.01984 X_ConfigureWindow - length: 7, window: 0x9800488, mask: 0xf, v0 0, v1 -15, v2 785, v3 882, v4 327692, v5 159384712, v6 1769484, - CW-mask: CWX,CWY,CWWidth,CWHeight, -71.76153 0.00011 X_ConfigureWindow - length: 5, window: 0x9800488, mask: 0xc, v0 785, v1 867, v2 329228, v3 159384712, v4 159383555, - CW-mask: CWWidth,CWHeight, - XXX,XXX -71.76157 0.00003 X_ConfigureWindow - length: 5, window: 0x9800488, mask: 0x3, v0 0, v1 0, v2 131132, v3 159385313, v4 328759, - CW-mask: CWX,CWY, - XXX,XXX - -Down arrow: -72.93147 0.01990 X_ConfigureWindow - length: 5, window: 0x9800488, mask: 0xc, v0 785, v1 882, v2 328972, v3 159384712, v4 159383555, - CW-mask: CWWidth,CWHeight, - XXX,XXX -72.93156 0.00009 X_ConfigureWindow - length: 5, window: 0x9800488, mask: 0x3, v0 0, v1 -15, v2 458764, v3 159384712, v4 159383567, - CW-mask: CWX,CWY, -72.93160 0.00004 X_ConfigureWindow - length: 7, window: 0x9800488, mask: 0xf, v0 0, v1 0, v2 785, v3 867, v4 131132, v5 159385335, v6 328759, - CW-mask: CWX,CWY,CWWidth,CWHeight, - - -sadly, probably need to handle some more... - - */ - x0 = cw_events[list[2]].x; - y0 = cw_events[list[2]].y; - w0 = cw_events[list[2]].w; - h0 = cw_events[list[2]].h; - - x1 = cw_events[list[1]].x; - y1 = cw_events[list[1]].y; - w1 = cw_events[list[1]].w; - h1 = cw_events[list[1]].h; - - x2 = cw_events[list[0]].x; - y2 = cw_events[list[0]].y; - w2 = cw_events[list[0]].w; - h2 = cw_events[list[0]].h; - - /* see NS4 XXX's above: */ - if (w2 == absent || h2 == absent) { - /* up arrow */ - if (w2 == absent) { - w2 = w1; - } - if (h2 == absent) { - h2 = h1; - } - } - if (x1 == absent || y1 == absent) { - /* up arrow */ - if (x1 == absent) { - x1 = x2; - } - if (y1 == absent) { - y1 = y2; - } - } - if (x0 == absent || y0 == absent) { - /* down arrow */ - if (x0 == absent) { - /* hmmm... what to do */ - x0 = x2; - } - if (y0 == absent) { - y0 = y2; - } - } - -if (dba) fprintf(stderr, "%d/%d/%d/%d %d/%d/%d/%d %d/%d/%d/%d\n", x0, y0, w0, h0, x1, y1, w1, h1, x2, y2, w2, h2); - - dy = y1 - y0; - dx = x1 - x0; - - src_x = x2; - src_y = y2; - w = w2; - h = h2; - - /* check w and h before we modify them */ - if (w <= 0 || h <= 0) { - good = 0; - } else if (w == absent || h == absent) { - good = 0; - } - if (! good) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (dy > 0) { - h -= dy; - } else { - h += dy; - src_y -= dy; - } - if (dx > 0) { - w -= dx; - } else { - w += dx; - src_x -= dx; - } - - dst_x = src_x + dx; - dst_y = src_y + dy; - - if (x0 == absent || x1 == absent || x2 == absent) { - good = 0; - } else if (y0 == absent || y1 == absent || y2 == absent) { - good = 0; - } else if (dx != 0 && dy != 0) { - good = 0; - } else if (w0 - w2 != nabs(dx)) { - good = 0; - } else if (h0 - h2 != nabs(dy)) { - good = 0; - } else if (scr_ev_cnt >= SCR_EV_MAX) { - good = 0; - } - - if (! good) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - /* - * geometry OK. - * after all of the above succeeds, now contact X server. - */ - if (lookup_attr_cache(win, &cache_index, &next_index)) { - i = cache_index; - attr.x = scr_attr_cache[i].x; - attr.y = scr_attr_cache[i].y; - attr.width = scr_attr_cache[i].width; - attr.height = scr_attr_cache[i].height; - attr.map_state = scr_attr_cache[i].map_state; - rx = scr_attr_cache[i].rx; - ry = scr_attr_cache[i].ry; - valid = scr_attr_cache[i].valid; - -if (0) fprintf(stderr, "lookup_attr_cache hit: %2d %2d 0x%lx %d\n", - cache_index, next_index, win, valid); - - } else { - valid = valid_window(win, &attr, 1); - -if (0) fprintf(stderr, "lookup_attr_cache MISS: %2d %2d 0x%lx %d\n", - cache_index, next_index, win, valid); - - if (valid) { - if (!xtranslate(win, rootwin, 0, 0, &rx, &ry, &c, 1)) { - valid = 0; - } - } - if (next_index >= 0) { - i = next_index; - scr_attr_cache[i].win = win; - scr_attr_cache[i].fetched = 1; - scr_attr_cache[i].valid = valid; - scr_attr_cache[i].time = dnow(); - if (valid) { - scr_attr_cache[i].x = attr.x; - scr_attr_cache[i].y = attr.y; - scr_attr_cache[i].width = attr.width; - scr_attr_cache[i].height = attr.height; - scr_attr_cache[i].depth = attr.depth; - scr_attr_cache[i].class = attr.class; - scr_attr_cache[i].backing_store = - attr.backing_store; - scr_attr_cache[i].map_state = attr.map_state; - - scr_attr_cache[i].rx = rx; - scr_attr_cache[i].ry = ry; - } - } - } - - if (! valid) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (attr.map_state != IsViewable) { - return; - } -if (db > 1) fprintf(stderr, "record_CW-%d\n", k++); - - if (0 || dba || db) { - double st, dt; - st = (double) rec_data->server_time/1000.0; - dt = (dnow() - servertime_diff) - st; - fprintf(stderr, "record_CW-%d *FOUND_SCROLL: win: 0x%lx dx: %d dy: %d " - "x: %d y: %d w: %d h: %d st: %.4f dt: %.4f %.4f\n", k++, win, - dx, dy, src_x, src_y, w, h, st, dt, dnowx()); - } - - i = scr_ev_cnt; - - scr_ev[i].win = win; - scr_ev[i].frame = None; - scr_ev[i].dx = dx; - scr_ev[i].dy = dy; - scr_ev[i].x = rx + dst_x; - scr_ev[i].y = ry + dst_y; - scr_ev[i].w = w; - scr_ev[i].h = h; - scr_ev[i].t = ((double) rec_data->server_time)/1000.0; - scr_ev[i].win_x = rx; - scr_ev[i].win_y = ry; - scr_ev[i].win_w = attr.width; - scr_ev[i].win_h = attr.height; - scr_ev[i].new_x = 0; - scr_ev[i].new_y = 0; - scr_ev[i].new_w = 0; - scr_ev[i].new_h = 0; - - if (dx == 0) { - if (dy > 0) { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = ry + src_y; - scr_ev[i].new_w = w; - scr_ev[i].new_h = dy; - } else { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = ry + dst_y + h; - scr_ev[i].new_w = w; - scr_ev[i].new_h = -dy; - } - } else if (dy == 0) { - if (dx > 0) { - scr_ev[i].new_x = rx + src_x; - scr_ev[i].new_y = rx + src_y; - scr_ev[i].new_w = dx; - scr_ev[i].new_h = h; - } else { - scr_ev[i].new_x = rx + dst_x + w; - scr_ev[i].new_y = ry + src_y; - scr_ev[i].new_w = -dx; - scr_ev[i].new_h = h; - } - } - - /* indicate we have a new one */ - scr_ev_cnt++; - - index = 0; -} - -static void record_switch(XPointer ptr, XRecordInterceptData *rec_data) { - static int first = 1; - xReq *req; - - if (first) { - int i; - for (i=0; i<SCR_ATTR_CACHE; i++) { - scr_attr_cache[i].win = None; - scr_attr_cache[i].fetched = 0; - scr_attr_cache[i].valid = 0; - scr_attr_cache[i].time = 0.0; - } - first = 0; - } - - /* should handle control msgs, start/stop/etc */ - if (rec_data->category == XRecordStartOfData) { - record_CW(ptr, rec_data); - } else if (rec_data->category == XRecordEndOfData) { - ; - } else if (rec_data->category == XRecordClientStarted) { - ; - } else if (rec_data->category == XRecordClientDied) { - ; - } else if (rec_data->category == XRecordFromServer) { - ; - } - - if (rec_data->category != XRecordFromClient) { - XRecordFreeData(rec_data); - return; - } - - req = (xReq *) rec_data->data; - - if (req->reqType == X_CopyArea) { - record_CA(ptr, rec_data); - } else if (req->reqType == X_ConfigureWindow) { - record_CW(ptr, rec_data); - } else { - ; - } - XRecordFreeData(rec_data); -} - -static void record_grab(XPointer ptr, XRecordInterceptData *rec_data) { - xReq *req; - int db = 0; - - if (debug_grabs) db = 1; - - /* should handle control msgs, start/stop/etc */ - if (rec_data->category == XRecordStartOfData) { - ; - } else if (rec_data->category == XRecordEndOfData) { - ; - } else if (rec_data->category == XRecordClientStarted) { - ; - } else if (rec_data->category == XRecordClientDied) { - ; - } else if (rec_data->category == XRecordFromServer) { - ; - } - - if (rec_data->category != XRecordFromClient) { - XRecordFreeData(rec_data); - return; - } - - req = (xReq *) rec_data->data; - - if (req->reqType == X_GrabServer) { - double now = dnowx(); - xserver_grabbed++; - if (db) rfbLog("X server Grabbed: %d %.5f\n", xserver_grabbed, now); - if (xserver_grabbed > 1) { - /* - * some apps do multiple grabs... very unlikely - * two apps will be doing it at same time. - */ - xserver_grabbed = 1; - } - } else if (req->reqType == X_UngrabServer) { - double now = dnowx(); - xserver_grabbed--; - if (xserver_grabbed < 0) { - xserver_grabbed = 0; - } - if (db) rfbLog("X server Un-Grabbed: %d %.5f\n", xserver_grabbed, now); - } else { - ; - } - XRecordFreeData(rec_data); - - /* unused vars warning: */ - if (ptr) {} -} -#endif - -static void check_xrecord_grabserver(void) { -#if LIBVNCSERVER_HAVE_RECORD - int last_val, cnt = 0, i, max = 10; - double d; - if (!gdpy_ctrl || !gdpy_data) { - return; - } - if (unixpw_in_progress) return; - - dtime0(&d); - XFlush_wr(gdpy_ctrl); - for (i=0; i<max; i++) { - last_val = xserver_grabbed; - XRecordProcessReplies(gdpy_data); - if (xserver_grabbed != last_val) { - cnt++; - } else if (i > 2) { - break; - } - } - if (cnt) { - XFlush_wr(gdpy_ctrl); - } - if (debug_grabs && cnt > 0) { - d = dtime(&d); -fprintf(stderr, "check_xrecord_grabserver: cnt=%d i=%d %.4f\n", cnt, i, d); - } -#endif -} - -#if LIBVNCSERVER_HAVE_RECORD -static void shutdown_record_context(XRecordContext rc, int bequiet, int reopen) { - int ret1, ret2; - int verb = (!bequiet && !quiet); - - RAWFB_RET_VOID - if (0 || debug_scroll) { - rfbLog("shutdown_record_context(0x%lx, %d, %d)\n", rc, - bequiet, reopen); - verb = 1; - } - - ret1 = XRecordDisableContext(rdpy_ctrl, rc); - if (!ret1 && verb) { - rfbLog("XRecordDisableContext(0x%lx) failed.\n", rc); - } - ret2 = XRecordFreeContext(rdpy_ctrl, rc); - if (!ret2 && verb) { - rfbLog("XRecordFreeContext(0x%lx) failed.\n", rc); - } - XFlush_wr(rdpy_ctrl); - - if (reopen == 2 && ret1 && ret2) { - reopen = 0; /* 2 means reopen only on failure */ - } - if (reopen && gdpy_ctrl) { - check_xrecord_grabserver(); - if (xserver_grabbed) { - rfbLog("shutdown_record_context: skip reopen," - " server grabbed\n"); - reopen = 0; - } - } - if (reopen) { - char *dpystr = DisplayString(dpy); - - if (debug_scroll) { - rfbLog("closing RECORD data connection.\n"); - } - XCloseDisplay_wr(rdpy_data); - rdpy_data = NULL; - - if (debug_scroll) { - rfbLog("closing RECORD control connection.\n"); - } - XCloseDisplay_wr(rdpy_ctrl); - rdpy_ctrl = NULL; - - rdpy_ctrl = XOpenDisplay_wr(dpystr); - - if (! rdpy_ctrl) { - rfbLog("Failed to reopen RECORD control connection:" - "%s\n", dpystr); - rfbLog(" disabling RECORD scroll detection.\n"); - use_xrecord = 0; - return; - } - XSync(dpy, False); - - disable_grabserver(rdpy_ctrl, 0); - XSync(rdpy_ctrl, True); - - rdpy_data = XOpenDisplay_wr(dpystr); - - if (! rdpy_data) { - rfbLog("Failed to reopen RECORD data connection:" - "%s\n", dpystr); - rfbLog(" disabling RECORD scroll detection.\n"); - XCloseDisplay_wr(rdpy_ctrl); - rdpy_ctrl = NULL; - use_xrecord = 0; - return; - } - disable_grabserver(rdpy_data, 0); - - if (debug_scroll || (! bequiet && reopen == 2)) { - rfbLog("reopened RECORD data and control display" - " connections: %s\n", dpystr); - } - } -} -#endif - -void check_xrecord_reset(int force) { - static double last_reset = 0.0; - int reset_time = 60, require_idle = 10; - int reset_time2 = 600, require_idle2 = 40; - double now = 0.0; - XErrorHandler old_handler = NULL; - - if (gdpy_ctrl) { - X_LOCK; - check_xrecord_grabserver(); - X_UNLOCK; - } else { - /* more dicey if not watching grabserver */ - reset_time = reset_time2; - require_idle = require_idle2; - } - - if (!use_xrecord) { - return; - } - if (xrecording) { - return; - } - if (button_mask) { - return; - } - if (xserver_grabbed) { - return; - } - - if (unixpw_in_progress) return; - -#if LIBVNCSERVER_HAVE_RECORD - if (! rc_scroll) { - return; - } - now = dnow(); - if (last_reset == 0.0) { - last_reset = now; - return; - } - /* - * try to wait for a break in input to reopen the displays - * this is only to avoid XGrabServer deadlock on the repopens. - */ - if (force) { - ; - } else if (now < last_reset + reset_time) { - return; - } else if (now < last_pointer_click_time + require_idle) { - return; - } else if (now < last_keyboard_time + require_idle) { - return; - } - X_LOCK; - trapped_record_xerror = 0; - old_handler = XSetErrorHandler(trap_record_xerror); - - /* unlikely, but check again since we will definitely be doing it. */ - if (gdpy_ctrl) { - check_xrecord_grabserver(); - if (xserver_grabbed) { - XSetErrorHandler(old_handler); - X_UNLOCK; - return; - } - } - - shutdown_record_context(rc_scroll, 0, 1); - rc_scroll = 0; - - XSetErrorHandler(old_handler); - X_UNLOCK; - - last_reset = now; -#else - if (!old_handler || now == 0.0 || !last_reset || !force) {} -#endif -} - -#define RECORD_ERROR_MSG(tag) \ - if (! quiet) { \ - static int cnt = 0; \ - static time_t last = 0; \ - int show = 0; \ - cnt++; \ - if (debug_scroll || cnt < 20) { \ - show = 1; \ - } else if (cnt == 20) { \ - last = time(NULL); \ - rfbLog("disabling RECORD XError messages for 600s\n"); \ - show = 1; \ - } else if (time(NULL) > last + 600) { \ - cnt = 0; \ - show = 1; \ - } \ - if (show) { \ - rfbLog("trapped RECORD XError: %s %s %d/%d/%d (0x%lx)\n", \ - tag, xerror_string(trapped_record_xerror_event), \ - (int) trapped_record_xerror_event->error_code, \ - (int) trapped_record_xerror_event->request_code, \ - (int) trapped_record_xerror_event->minor_code, \ - (int) trapped_record_xerror_event->resourceid); \ - } \ - } - -void xrecord_watch(int start, int setby) { -#if LIBVNCSERVER_HAVE_RECORD - Window focus, wm, c, clast; - static double create_time = 0.0; - int rc; - int do_shutdown = 0; - int reopen_dpys = 1; - XErrorHandler old_handler = NULL; - static Window last_win = None, last_result = None; -#endif - int db = debug_scroll; - double now; - static double last_error = 0.0; - -if (0) db = 1; - - if (nofb) { - xrecording = 0; - return; - } - if (use_threads) { - /* XXX not working. Still? Painting errors. */ - static int first = 1; - if (first) { - if (use_xrecord && !getenv("XRECORD_THREADS")) { - rfbLog("xrecord_watch: disabling scroll detection in -threads mode.\n"); - rfbLog("xrecord_watch: Set -env XRECORD_THREADS=1 to enable it.\n"); - use_xrecord = 0; - xrecording = 0; - } - first = 0; - } - if (!use_xrecord && !xrecording) { - return; - } - } - - dtime0(&now); - if (now < last_error + 0.5) { - return; - } - - if (gdpy_ctrl) { - X_LOCK; - check_xrecord_grabserver(); - X_UNLOCK; - if (xserver_grabbed) { -if (db || debug_grabs) fprintf(stderr, "xrecord_watch: %d/%d out xserver_grabbed\n", start, setby); - return; - } - } - -#if LIBVNCSERVER_HAVE_RECORD - if (! start) { - int shut_reopen = 2, shut_time = 25; -if (db || debug_grabs) fprintf(stderr, "XRECORD OFF: %d/%d %.4f\n", xrecording, setby, now - x11vnc_start); - xrecording = 0; - if (! rc_scroll) { - xrecord_focus_window = None; - xrecord_wm_window = None; - xrecord_ptr_window = None; - xrecord_keysym = NoSymbol; - rcs_scroll = 0; - return; - } - - if (! do_shutdown && now > create_time + shut_time) { - /* XXX unstable if we keep a RECORD going forever */ - do_shutdown = 1; - } - - SCR_LOCK; - - if (do_shutdown) { -if (db > 1) fprintf(stderr, "=== shutdown-scroll 0x%lx\n", rc_scroll); - X_LOCK; - trapped_record_xerror = 0; - old_handler = XSetErrorHandler(trap_record_xerror); - - shutdown_record_context(rc_scroll, 0, shut_reopen); - rc_scroll = 0; - - /* - * n.b. there is a grabserver issue wrt - * XRecordCreateContext() even though rdpy_ctrl - * is set imprevious to grabs. Perhaps a bug - * in the X server or library... - * - * If there are further problems, a thought - * to recreate rc_scroll right after the - * reopen. - */ - - if (! use_xrecord) { - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - return; - } - - XRecordProcessReplies(rdpy_data); - - if (trapped_record_xerror) { - RECORD_ERROR_MSG("shutdown"); - last_error = now; - } - - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - - } else { - if (rcs_scroll) { -if (db > 1) fprintf(stderr, "=== disab-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll); - X_LOCK; - trapped_record_xerror = 0; - old_handler = - XSetErrorHandler(trap_record_xerror); - - rcs_scroll = XRecordCurrentClients; - XRecordUnregisterClients(rdpy_ctrl, rc_scroll, - &rcs_scroll, 1); - XRecordDisableContext(rdpy_ctrl, rc_scroll); - XFlush_wr(rdpy_ctrl); - XRecordProcessReplies(rdpy_data); - - if (trapped_record_xerror) { - RECORD_ERROR_MSG("disable"); - - shutdown_record_context(rc_scroll, - 0, reopen_dpys); - rc_scroll = 0; - - last_error = now; - - if (! use_xrecord) { - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - return; - } - } - XSetErrorHandler(old_handler); - X_UNLOCK; - } - } - - SCR_UNLOCK; - /* - * XXX if we do a XFlush_wr(rdpy_ctrl) here we get: - * - - X Error of failed request: XRecordBadContext - Major opcode of failed request: 145 (RECORD) - Minor opcode of failed request: 5 (XRecordEnableContext) - Context in failed request: 0x2200013 - Serial number of failed request: 29 - Current serial number in output stream: 29 - - * - * need to figure out what is going on... since it may lead - * infrequent failures. - */ - xrecord_focus_window = None; - xrecord_wm_window = None; - xrecord_ptr_window = None; - xrecord_keysym = NoSymbol; - rcs_scroll = 0; - return; - } -if (db || debug_grabs) fprintf(stderr, "XRECORD ON: %d/%d %.4f\n", xrecording, setby, now - x11vnc_start); - - if (xrecording) { - return; - } - - if (do_shutdown && rc_scroll) { - static int didmsg = 0; - /* should not happen... */ - if (0 || !didmsg) { - rfbLog("warning: do_shutdown && rc_scroll\n"); - didmsg = 1; - } - xrecord_watch(0, SCR_NONE); - } - - xrecording = 0; - xrecord_focus_window = None; - xrecord_wm_window = None; - xrecord_ptr_window = None; - xrecord_keysym = NoSymbol; - xrecord_set_by_keys = 0; - xrecord_set_by_mouse = 0; - - /* get the window with focus and mouse pointer: */ - clast = None; - focus = None; - wm = None; - - X_LOCK; - SCR_LOCK; -#if 0 - /* - * xrecord_focus_window / focus not currently used... save a - * round trip to the X server for now. - * N.B. our heuristic is inaccurate: if he is scrolling and - * drifts off of the scrollbar onto another application we - * will catch that application, not the starting ones. - * check_xrecord_{keys,mouse} mitigates this somewhat by - * delaying calls to xrecord_watch as much as possible. - */ - XGetInputFocus(dpy, &focus, &i); -#endif - - wm = query_pointer(rootwin); - if (wm) { - c = wm; - } else { - c = rootwin; - } - - /* descend a bit to avoid wm frames: */ - if (c != rootwin && c == last_win) { - /* use cached results to avoid roundtrips: */ - clast = last_result; - } else if (scroll_good_all == NULL && scroll_skip_all == NULL) { - /* more efficient if name info not needed. */ - xrecord_name_info[0] = '\0'; - clast = descend_pointer(6, c, NULL, 0); - } else { - char *nm; - int matched_good = 0, matched_skip = 0; - - clast = descend_pointer(6, c, xrecord_name_info, NAMEINFO); -if (db) fprintf(stderr, "name_info: %s\n", xrecord_name_info); - - nm = xrecord_name_info; - - if (scroll_good_all) { - matched_good += match_str_list(nm, scroll_good_all); - } - if (setby == SCR_KEY && scroll_good_key) { - matched_good += match_str_list(nm, scroll_good_key); - } - if (setby == SCR_MOUSE && scroll_good_mouse) { - matched_good += match_str_list(nm, scroll_good_mouse); - } - if (scroll_skip_all) { - matched_skip += match_str_list(nm, scroll_skip_all); - } - if (setby == SCR_KEY && scroll_skip_key) { - matched_skip += match_str_list(nm, scroll_skip_key); - } - if (setby == SCR_MOUSE && scroll_skip_mouse) { - matched_skip += match_str_list(nm, scroll_skip_mouse); - } - - if (!matched_good && matched_skip) { - clast = None; - } - } - if (c != rootwin) { - /* cache results for possible use next call */ - last_win = c; - last_result = clast; - } - - if (!clast || clast == rootwin) { -if (db) fprintf(stderr, "--- xrecord_watch: SKIP.\n"); - X_UNLOCK; - SCR_UNLOCK; - return; - } - - /* set protocol request ranges: */ - rr_scroll[0] = rr_CA; - rr_scroll[1] = rr_CW; - - /* - * start trapping... there still are some occasional failures - * not yet understood, likely some race condition WRT the - * context being setup. - */ - trapped_record_xerror = 0; - old_handler = XSetErrorHandler(trap_record_xerror); - - if (! rc_scroll) { - /* do_shutdown case or first time in */ - - if (gdpy_ctrl) { - /* - * Even though rdpy_ctrl is impervious to grabs - * at this point, we still get deadlock, why? - * It blocks in the library find_display() call. - */ - check_xrecord_grabserver(); - if (xserver_grabbed) { - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - return; - } - } - rcs_scroll = (XRecordClientSpec) clast; - rc_scroll = XRecordCreateContext(rdpy_ctrl, 0, &rcs_scroll, 1, - rr_scroll, 2); - - if (! do_shutdown) { - XSync(rdpy_ctrl, False); - } -if (db) fprintf(stderr, "NEW rc: 0x%lx\n", rc_scroll); - if (rc_scroll) { - dtime0(&create_time); - } else { - rcs_scroll = 0; - } - - } else if (! do_shutdown) { - if (rcs_scroll) { - /* - * should have been unregistered in xrecord_watch(0)... - */ - rcs_scroll = XRecordCurrentClients; - XRecordUnregisterClients(rdpy_ctrl, rc_scroll, - &rcs_scroll, 1); - -if (db > 1) fprintf(stderr, "=2= unreg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll); - - } - - rcs_scroll = (XRecordClientSpec) clast; - -if (db > 1) fprintf(stderr, "=-= reg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scroll); - - if (!XRecordRegisterClients(rdpy_ctrl, rc_scroll, 0, - &rcs_scroll, 1, rr_scroll, 2)) { - if (1 || now > last_error + 60) { - rfbLog("failed to register client 0x%lx with" - " X RECORD context rc_scroll.\n", clast); - } - last_error = now; - rcs_scroll = 0; - /* continue on for now... */ - } - } - - XFlush_wr(rdpy_ctrl); - -if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll); - if (trapped_record_xerror) { - RECORD_ERROR_MSG("register"); - } - - if (! rc_scroll) { - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - use_xrecord = 0; - rfbLog("failed to create X RECORD context rc_scroll.\n"); - rfbLog(" switching to -noscrollcopyrect mode.\n"); - return; - } else if (! rcs_scroll || trapped_record_xerror) { - /* try again later */ - shutdown_record_context(rc_scroll, 0, reopen_dpys); - rc_scroll = 0; - last_error = now; - - XSetErrorHandler(old_handler); - X_UNLOCK; - SCR_UNLOCK; - return; - } - - xrecord_focus_window = focus; -#if 0 - /* xrecord_focus_window currently unused. */ - if (! xrecord_focus_window) { - xrecord_focus_window = clast; - } -#endif - xrecord_wm_window = wm; - if (! xrecord_wm_window) { - xrecord_wm_window = clast; - } - - xrecord_ptr_window = clast; - - xrecording = 1; - xrecord_seq++; - dtime0(&xrecord_start); - - rc = XRecordEnableContextAsync(rdpy_data, rc_scroll, record_switch, - (XPointer) xrecord_seq); - - if (!rc || trapped_record_xerror) { - if (1 || now > last_error + 60) { - rfbLog("failed to enable RECORD context " - "rc_scroll: 0x%lx rc: %d\n", rc_scroll, rc); - if (trapped_record_xerror) { - RECORD_ERROR_MSG("enable-failed"); - } - } - shutdown_record_context(rc_scroll, 0, reopen_dpys); - rc_scroll = 0; - last_error = now; - xrecording = 0; - /* continue on for now... */ - } - XSetErrorHandler(old_handler); - - /* XXX this may cause more problems than it solves... */ - if (use_xrecord) { - XFlush_wr(rdpy_data); - } - - X_UNLOCK; - SCR_UNLOCK; -#endif -} - - |