summaryrefslogtreecommitdiffstats
path: root/x11vnc/x11vnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r--x11vnc/x11vnc.c579
1 files changed, 563 insertions, 16 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index 0d30ef8..82c7f65 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -382,7 +382,7 @@ double xdamage_scheduled_mark = 0.0;
sraRegionPtr xdamage_scheduled_mark_region = NULL;
/* date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.7.2 lastmod: 2005-07-06";
+char lastmod[] = "0.7.2 lastmod: 2005-07-09";
int hack_val = 0;
/* X display info */
@@ -594,6 +594,8 @@ double dtime(double *);
double dtime0(double *);
double dnow(void);
double dnowx(void);
+double rnow(void);
+double rfac(void);
void initialize_blackouts(char *);
void initialize_blackouts_and_xinerama(void);
@@ -904,6 +906,12 @@ Display *gdpy_data = NULL; /* Ditto for GrabServer watcher */
Display *gdpy_ctrl = NULL;
int xserver_grabbed = 0;
+/* XXX CHECK BEFORE RELEASE */
+int grab_buster = 1;
+int grab_buster_delay = 20;
+int sync_tod_delay = 3;
+pid_t grab_buster_pid = 0;
+
char *client_connect = NULL; /* strings for -connect option */
char *client_connect_file = NULL;
int vnc_connect = 1; /* -vncconnect option */
@@ -3008,6 +3016,7 @@ void disable_grabserver(Display *in_dpy, int change) {
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) {
@@ -5100,6 +5109,7 @@ char *xerror_string(XErrorEvent *error) {
char *crash_stack_command1 = NULL;
char *crash_stack_command2 = NULL;
char *crash_debug_command = NULL;
+/* XXX CHECK BEFORE RELEASE */
int crash_debug = 1;
void initialize_crash_handler(void) {
@@ -11651,17 +11661,406 @@ void print_xevent_bases(void) {
fprintf(stderr, " SelClear=%d, Expose=%d\n", SelectionClear, Expose);
}
-void sync_tod_with_servertime() {
- static Atom servertime = None;
+
+void get_prop(char *str, int len, Atom prop) {
+ Atom type;
+ int format, slen, dlen, i;
+ unsigned long nitems = 0, bytes_after = 0;
+ unsigned char* data = NULL;
+
+ for (i=0; i<len; i++) {
+ str[i] = '\0';
+ }
+ if (prop == None) {
+ return;
+ }
+
+ slen = 0;
+
+ do {
+ if (XGetWindowProperty(dpy, DefaultRootWindow(dpy),
+ prop, nitems/4, len/16, False,
+ AnyPropertyType, &type, &format, &nitems, &bytes_after,
+ &data) == Success) {
+
+ dlen = nitems * (format/8);
+ if (slen + dlen > len) {
+ /* too big */
+ XFree(data);
+ break;
+ }
+ memcpy(str+slen, data, dlen);
+ slen += dlen;
+ str[slen] = '\0';
+ XFree(data);
+ }
+ } while (bytes_after > 0);
+}
+
+void bust_grab(int reset) {
+ static int bust_count = 0;
+ static time_t last_bust = 0;
+ time_t now = time(0);
+ KeyCode key;
+ int button, x, y, nb;
+
+ if (now > last_bust + 180) {
+ bust_count = 0;
+ }
+ if (reset) {
+ bust_count = 0;
+ return;
+ }
+
+ x = 0;
+ y = 0;
+ button = 0;
+ key = NoSymbol;
+
+ nb = 8;
+ if (bust_count >= 3 * nb) {
+ fprintf(stderr, "too many bust_grab's %d for me\n", bust_count);
+ exit(0);
+ }
+ if (bust_count % nb == 0) {
+ button = 1;
+ } else if (bust_count % nb == 1) {
+ button = 1;
+ } else if (bust_count % nb == 2) {
+ key = XKeysymToKeycode(dpy, XK_Escape);
+ } else if (bust_count % nb == 3) {
+ button = 3;
+ } else if (bust_count % nb == 4) {
+ key = XKeysymToKeycode(dpy, XK_space);
+ } else if (bust_count % nb == 5) {
+ x = bust_count * 23;
+ y = bust_count * 17;
+ } else if (bust_count % nb == 5) {
+ button = 2;
+ } else if (bust_count % nb == 6) {
+ key = XKeysymToKeycode(dpy, XK_a);
+ }
+
+ if (key == NoSymbol) {
+ key = XKeysymToKeycode(dpy, XK_a);
+ if (key == NoSymbol) {
+ button = 1;
+ }
+ }
+
+ bust_count++;
+
+ if (button) {
+ /* try button press+release */
+ fprintf(stderr, "**bust_grab: button%d %.4f\n",
+ button, dnowx());
+ XTestFakeButtonEvent_wr(dpy, button, True, CurrentTime);
+ XFlush(dpy);
+ usleep(50 * 1000);
+ XTestFakeButtonEvent_wr(dpy, button, False, CurrentTime);
+ } else if (x > 0) {
+ /* try button motion*/
+ int scr = DefaultScreen(dpy);
+
+ fprintf(stderr, "**bust_grab: x=%d y=%d %.4f\n", x, y,
+ dnowx());
+ XTestFakeMotionEvent_wr(dpy, scr, x, y, CurrentTime);
+ XFlush(dpy);
+ usleep(50 * 1000);
+
+ /* followed by button press */
+ button = 1;
+ fprintf(stderr, "**bust_grab: button%d\n", button);
+ XTestFakeButtonEvent_wr(dpy, button, True, CurrentTime);
+ XFlush(dpy);
+ usleep(50 * 1000);
+ XTestFakeButtonEvent_wr(dpy, button, False, CurrentTime);
+ } else {
+ /* try Escape or Space press+release */
+ fprintf(stderr, "**bust_grab: keycode: %d %.4f\n",
+ (int) key, dnowx());
+ XTestFakeKeyEvent_wr(dpy, key, True, CurrentTime);
+ XFlush(dpy);
+ usleep(50 * 1000);
+ XTestFakeKeyEvent_wr(dpy, key, False, CurrentTime);
+ }
+ XFlush(dpy);
+ last_bust = time(0);
+}
+
+typedef struct _grabwatch {
+ int pid;
+ int tick;
+ unsigned long time;
+ time_t change;
+} grabwatch_t;
+#define GRABWATCH 16
+
+int grab_npids = 1;
+
+int process_watch(char *str, int parent, int db) {
+ int i, pid, ticker, npids;
+ char diff[128];
+ unsigned long xtime;
+ static grabwatch_t watches[GRABWATCH];
+ static int first = 1;
+ time_t now = time(0);
+ static time_t last_bust = 0;
+ int too_long, problems = 0;
+
+ if (first) {
+ for (i=0; i < GRABWATCH; i++) {
+ watches[i].pid = 0;
+ watches[i].tick = 0;
+ watches[i].time = 0;
+ watches[i].change = 0;
+ }
+ first = 0;
+ }
+
+ /* record latest value of prop */
+ if (str && *str != '\0') {
+ if (sscanf(str, "%d/%d/%lu/%s", &pid, &ticker, &xtime, diff)
+ == 4) {
+ int got = -1, free = -1;
+
+ if (db) fprintf(stderr, "grab_buster %d - %d - %lu - %s"
+ "\n", pid, ticker, xtime, diff);
+
+ if (pid == parent && !strcmp(diff, "QUIT")) {
+ /* that's it. */
+ return 0;
+ }
+ if (pid == 0 || ticker == 0 || xtime == 0) {
+ /* bad prop read. */
+ goto badtickerstr;
+ }
+ for (i=0; i < GRABWATCH; i++) {
+ if (watches[i].pid == pid) {
+ got = i;
+ break;
+ }
+ if (free == -1 && watches[i].pid == 0) {
+ free = i;
+ }
+ }
+ if (got == -1) {
+ if (free == -1) {
+ /* bad news */;
+ free = GRABWATCH - 1;
+ }
+ watches[free].pid = pid;
+ watches[free].tick = ticker;
+ watches[free].time = xtime;
+ watches[free].change = now;
+ if (db) fprintf(stderr, "grab_buster free slot: %d\n", free);
+ } else {
+ if (db) fprintf(stderr, "grab_buster got slot: %d\n", got);
+ if (watches[got].tick != ticker) {
+ watches[got].change = now;
+ }
+ if (watches[got].time != xtime) {
+ watches[got].change = now;
+ }
+ watches[got].tick = ticker;
+ watches[got].time = xtime;
+ }
+ } else {
+ if (db) fprintf(stderr, "grab_buster bad prop str: %s\n", str);
+ }
+ }
+
+ badtickerstr:
+
+ too_long = grab_buster_delay;
+ if (too_long < 3 * sync_tod_delay) {
+ too_long = 3 * sync_tod_delay;
+ }
+
+ npids = 0;
+ for (i=0; i < GRABWATCH; i++) {
+ if (watches[i].pid) {
+ npids++;
+ }
+ }
+ grab_npids = npids;
+ if (npids > 4) {
+ npids = 4;
+ }
+
+ /* now check everyone we are tracking */
+ for (i=0; i < GRABWATCH; i++) {
+ int fac = 1;
+ if (!watches[i].pid) {
+ continue;
+ }
+ if (watches[i].change == 0) {
+ watches[i].change = now; /* just to be sure */
+ continue;
+ }
+
+ pid = watches[i].pid;
+
+ if (pid != parent) {
+ fac = 2;
+ }
+ if (npids > 0) {
+ fac *= npids;
+ }
+
+ if (now > watches[i].change + fac*too_long) {
+ int process_alive = 1;
+
+ fprintf(stderr, "grab_buster: problem with pid: "
+ "%d - %d/%d/%d\n", pid, (int) now,
+ (int) watches[i].change, too_long);
+
+ if (kill((pid_t) pid, 0) != 0) {
+ if (1 || errno == ESRCH) {
+ process_alive = 0;
+ }
+ }
+
+ if (!process_alive) {
+ watches[i].pid = 0;
+ watches[i].tick = 0;
+ watches[i].time = 0;
+ watches[i].change = 0;
+ fprintf(stderr, "grab_buster: pid gone: %d\n",
+ pid);
+ if (pid == parent) {
+ /* that's it */
+ return 0;
+ }
+ } else {
+ int sleep = sync_tod_delay * 1000 * 1000;
+
+ bust_grab(0);
+ problems++;
+ last_bust = now;
+ usleep(1 * sleep);
+ break;
+ }
+ }
+ }
+
+ if (!problems) {
+ bust_grab(1);
+ }
+ return 1;
+}
+
+void grab_buster_watch(int parent, char *dstr) {
+ Atom ticker_atom = None;
+ int sleep = sync_tod_delay * 921 * 1000;
+ char propval[200];
+ int ev, er, maj, min;
+ int db = 0;
+
+ if (grab_buster > 1) {
+ db = 1;
+ }
+
+ /* overwrite original dpy, we let orig connection sit unused. */
+ dpy = XOpenDisplay(dstr);
+ if (!dpy) {
+ fprintf(stderr, "grab_buster_watch: could not reopen: %s\n",
+ dstr);
+ return;
+ }
+ rfbLogEnable(0);
+
+ /* check for XTEST, etc, and then disable grabs for us */
+ if (! XTestQueryExtension_wr(dpy, &ev, &er, &maj, &min)) {
+ xtest_present = 0;
+ } else {
+ xtest_present = 1;
+ }
+ if (! XETrapQueryExtension_wr(dpy, &ev, &er, &maj)) {
+ xtrap_present = 0;
+ } else {
+ xtrap_present = 1;
+ }
+
+ if (! xtest_present && ! xtrap_present) {
+ fprintf(stderr, "grab_buster_watch: no grabserver "
+ "protection on display: %s\n", dstr);
+ return;
+ }
+ disable_grabserver(dpy, 0);
+
+ usleep(3 * sleep);
+
+ ticker_atom = XInternAtom(dpy, "X11VNC_TICKER", False);
+ if (! ticker_atom) {
+ fprintf(stderr, "grab_buster_watch: no ticker atom\n");
+ return;
+ }
+
+ while(1) {
+ int slp = sleep;
+ if (grab_npids > 1) {
+ slp = slp / 8;
+ }
+ usleep(slp);
+ usleep((int) (0.60 * rfac() * slp));
+
+ if (kill((pid_t) parent, 0) != 0) {
+ break;
+ }
+
+ get_prop(propval, 128, ticker_atom);
+ if (db) fprintf(stderr, "got_prop: %s\n", propval);
+
+ if (!process_watch(propval, parent, db)) {
+ break;
+ }
+ }
+}
+
+void spawn_grab_buster(void) {
+#if LIBVNCSERVER_HAVE_FORK
+ pid_t pid;
+ int parent = (int) getpid();
+ char *dstr = strdup(DisplayString(dpy));
+
+ XCloseDisplay(dpy);
+ dpy = NULL;
+
+ if ((pid = fork()) > 0) {
+ grab_buster_pid = pid;
+ if (! quiet) {
+ rfbLog("grab_buster pid is: %d\n", (int) pid);
+ }
+ } else if (pid == -1) {
+ fprintf(stderr, "spawn_grab_buster: could not fork\n");
+ rfbLogPerror("fork");
+ } else {
+ grab_buster_watch(parent, dstr);
+ exit(0);
+ }
+
+ dpy = XOpenDisplay(dstr);
+ if (!dpy) {
+ rfbLog("failed to reopen display %s in spawn_grab_buster\n",
+ dstr);
+ exit(1);
+ }
+#endif
+}
+
+void sync_tod_with_servertime(void) {
+ static Atom ticker_atom = None;
XEvent xev;
- char diff[64];
+ char diff[128];
static int seq = 0;
+ static unsigned long xserver_ticks = 1;
int i, db = 0;
- if (! servertime) {
- servertime = XInternAtom(dpy, "X11VNC_SERVERTIME_DIFF", False);
+ if (! ticker_atom) {
+ ticker_atom = XInternAtom(dpy, "X11VNC_TICKER", False);
}
- if (! servertime) {
+ if (! ticker_atom) {
return;
}
@@ -11670,8 +12069,9 @@ void sync_tod_with_servertime() {
;
}
- snprintf(diff, 64, "%.6f/%08d", servertime_diff, seq++);
- XChangeProperty(dpy, rootwin, servertime, XA_STRING, 8,
+ snprintf(diff, 128, "%d/%08d/%lu/%.6f", (int) getpid(), seq++,
+ xserver_ticks, servertime_diff);
+ XChangeProperty(dpy, rootwin, ticker_atom, XA_STRING, 8,
PropModeReplace, (unsigned char *) diff, strlen(diff));
XSync(dpy, False);
@@ -11680,9 +12080,10 @@ void sync_tod_with_servertime() {
for (k=0; k < 5; k++) {
while (XCheckTypedEvent(dpy, PropertyNotify, &xev)) {
- if (xev.xproperty.atom == servertime) {
+ if (xev.xproperty.atom == ticker_atom) {
double stime;
+ xserver_ticks = xev.xproperty.time;
stime = (double) xev.xproperty.time;
stime = stime/1000.0;
servertime_diff = dnow() - stime;
@@ -11793,7 +12194,7 @@ void check_autorepeat(void) {
*/
void check_xevents(void) {
XEvent xev;
- int have_clients = 0;
+ int tmp, have_clients = 0;
static int sent_some_sel = 0;
static time_t last_request = 0;
static time_t last_call = 0;
@@ -11899,7 +12300,12 @@ void check_xevents(void) {
}
}
- if (now > last_time_sync + 30) {
+ /* do this now that we have just cleared PropertyNotify */
+ tmp = 0;
+ if (rfac() < 0.6) {
+ tmp = 1;
+ }
+ if (now > last_time_sync + sync_tod_delay + tmp) {
sync_tod_with_servertime();
last_time_sync = now;
}
@@ -18289,6 +18695,9 @@ void set_nofb_params(void) {
take_naps = 0;
measure_speeds = 0;
+ /* got_grab_buster? */
+ grab_buster = 0;
+
show_cursor = 0;
show_multiple_cursors = 0;
cursor_shape_updates = 0;
@@ -19440,7 +19849,8 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
for (i=1; i< *argc; i++) {
rfbLog("\t[%d] %s\n", i, argv[i]);
}
- rfbLog("For a list of options run: x11vnc -help\n");
+ rfbLog("For a list of options run: x11vnc -opts\n");
+ rfbLog("or for the full help: x11vnc -help\n");
rfbLog("\n");
rfbLog("Here is a list of removed or obsolete"
" options:\n");
@@ -23663,9 +24073,11 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
if (connect_to_x11vnc) {
set_env("X11VNC_STARTED", "1");
}
- if (icon_mode && icon_mode_file) {
+ if (icon_mode) {
set_env("X11VNC_ICON_MODE", "1");
- set_env("X11VNC_CLIENT_FILE", icon_mode_file);
+ if (icon_mode_file) {
+ set_env("X11VNC_CLIENT_FILE", icon_mode_file);
+ }
if (icon_in_tray) {
if (tray_manager_ok) {
set_env("X11VNC_ICON_MODE", "TRAY:RUNNING");
@@ -23841,6 +24253,7 @@ void do_gui(char *opts) {
" to display on.\n");
exit(1);
}
+ fprintf(stderr, "starting gui, trying display: %s\n", gui_xdisplay);
test_dpy = XOpenDisplay(gui_xdisplay);
if (! test_dpy && auth_file) {
if (getenv("XAUTHORITY") != NULL) {
@@ -24746,6 +25159,12 @@ void draw_box(int x, int y, int w, int h, int restore) {
unsigned short us;
unsigned long ul;
+ if (clipshift) {
+ x -= coff_x;
+ y -= coff_y;
+ }
+ /* no subwin for wireframe */
+
if (max > len) {
/* create/resize storage lines: */
for (i=0; i<4; i++) {
@@ -25132,6 +25551,12 @@ if (db > 1) fprintf(stderr, "BDP %d %d %d %d %d %d %d %d %d %d %d\n",
ty2 = attr.y + attr.height;
whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
+ if (clipshift) {
+ sraRgnOffset(whole, coff_x, coff_y);
+ }
+ if (subwin) {
+ sraRgnOffset(whole, off_x, off_y);
+ }
frame = sraRgnCreateRect(tx1, ty1, tx2, ty2);
sraRgnAnd(frame, whole);
@@ -25175,6 +25600,18 @@ if (db > 1) fprintf(stderr, "BDP %d %d %d %d %d %d %d %d %d %d %d\n",
continue;
}
}
+ if (clipshift) {
+ tx1 -= coff_x;
+ ty1 -= coff_y;
+ tx2 -= coff_x;
+ ty2 -= coff_y;
+ }
+ if (subwin) {
+ tx1 -= off_x;
+ ty1 -= off_y;
+ tx2 -= off_x;
+ ty2 -= off_y;
+ }
direct_fb_copy(tx1, ty1, tx2, ty2, 1);
@@ -25354,6 +25791,12 @@ int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy,
backfill = sraRgnCreate();
whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
+ if (clipshift) {
+ sraRgnOffset(whole, coff_x, coff_y);
+ }
+ if (subwin) {
+ sraRgnOffset(whole, off_x, off_y);
+ }
win0 = scr_ev[0].win;
x0 = scr_ev[0].win_x;
@@ -25447,6 +25890,12 @@ if (db > 1) fprintf(stderr, "------------ got: %d x: %4d y: %3d"
dtime0(&tm);
tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
+ if (clipshift) {
+ sraRgnOffset(tmpregion, coff_x, coff_y);
+ }
+ if (subwin) {
+ sraRgnOffset(tmpregion, off_x, off_y);
+ }
tmpregion2 = sraRgnCreateRect(wx, wy, wx+ww, wy+wh);
sraRgnAnd(tmpregion2, whole);
sraRgnSubtract(tmpregion, tmpregion2);
@@ -25593,6 +26042,19 @@ if (db) fprintf(stderr, " EST_TOO_LARGE");
ty1 = rect.y1;
tx2 = rect.x2;
ty2 = rect.y2;
+
+ if (clipshift) {
+ tx1 -= coff_x;
+ ty1 -= coff_y;
+ tx2 -= coff_x;
+ ty2 -= coff_y;
+ }
+ if (subwin) {
+ tx1 -= off_x;
+ ty1 -= off_y;
+ tx2 -= off_x;
+ ty2 -= off_y;
+ }
tx1 = nfix(tx1, dpy_x);
ty1 = nfix(ty1, dpy_y);
tx2 = nfix(tx2, dpy_x+1);
@@ -26396,6 +26858,14 @@ if (db) fprintf(stderr, "check_xrecord_mouse: BEGIN LOOP: scr_ev_cnt: "
bdx = start_x;
bdy = start_y;
+ if (clipshift) {
+ bdx += coff_x;
+ bdy += coff_y;
+ }
+ if (subwin) {
+ bdx += off_x;
+ bdy += off_y;
+ }
bdskinny = 32;
set_bdpush(SCR_MOUSE, &last_bdpush, &bdpush);
@@ -26700,6 +27170,15 @@ int try_copyrect(Window frame, int x, int y, int w, int h, int dx, int dy,
dt_bad_check = time(0);
}
+ if (clipshift) {
+ x -= coff_x;
+ y -= coff_y;
+ }
+ if (subwin) {
+ x -= off_x;
+ y -= off_y;
+ }
+
if (dt_bad && wireframe_in_progress) {
sraRegionPtr rect;
/* send the whole thing... */
@@ -26800,6 +27279,15 @@ saw_me = 1; fprintf(stderr, " ----------\n");
continue;
}
+ if (clipshift) {
+ attr.x -= coff_x;
+ attr.y -= coff_y;
+ }
+ if (subwin) {
+ attr.x -= off_x;
+ attr.y -= off_y;
+ }
+
/*
* first subtract any overlap from the initial
* window rectangle
@@ -26853,6 +27341,13 @@ if (db2 && saw_me) continue;
if (extra_clip && ! sraRgnEmpty(extra_clip)) {
whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
+ if (clipshift) {
+ sraRgnOffset(extra_clip, -coff_x, -coff_y);
+ }
+ if (subwin) {
+ sraRgnOffset(extra_clip, -off_x, -off_y);
+ }
+
iter = sraRgnGetIterator(extra_clip);
while (sraRgnIteratorNext(iter, &rect)) {
/* clip the window to the visible screen: */
@@ -27556,8 +28051,18 @@ if (db) fprintf(stderr, "send_copyrect: %d\n", sent_copyrect);
fb_push_wait(0.1, FB_COPY);
if (now > last_time + delay) {
+ int xt = x, yt = y;
- scale_mark(x, y, x+w, y+h);
+ if (clipshift) {
+ xt -= coff_x;
+ yt -= coff_y;
+ }
+ if (subwin) {
+ xt -= off_x;
+ yt -= off_y;
+ }
+
+ scale_mark(xt, yt, xt+w, yt+h);
last_time = now;
last_copyrect_fix = now;
}
@@ -28220,6 +28725,23 @@ double dnowx(void) {
return dnow() - x11vnc_start;
}
+double rnow(void) {
+ double t = dnowx();
+ t = t - ((int) t);
+ if (t > 1.0) {
+ t = 1.0;
+ } else if (t < 0.0) {
+ t = 0.0;
+ }
+ return t;
+}
+
+double rfac(void) {
+ double f = (double) rand();
+ f = f / ((double) RAND_MAX);
+ return f;
+}
+
void measure_display_hook(rfbClientPtr cl) {
ClientData *cd = (ClientData *) cl->clientData;
dtime0(&cd->timer);
@@ -30258,6 +30780,21 @@ static void print_help(int mode) {
" currently used by the -scrollcopyrect scheme and to\n"
" monitor X server grabs.\n"
"\n"
+"-grab_buster Some of the use of the RECORD extension can leave a\n"
+"-nograb_buster tiny window for XGrabServer deadlock. This is only if\n"
+" the whole-server grabbing application expects mouse\n"
+" or keyboard input before releasing the grab. It is\n"
+" usually a window manager that does this. x11vnc takes\n"
+" care to avoid the the problem, but if caught x11vnc\n"
+" will freeze. Without -grab_buster, the only solution\n"
+" is to go the physical display and give it some input\n"
+" to satisfy the grabbing app. Or manually kill and\n"
+" restart the window manager. With -grab_buster, x11vnc\n"
+" will fork a helper thread and if x11vnc appears to be\n"
+" stuck in a grab after a period of time (20-30 sec)\n"
+" then it will inject some user input: button clicks,\n"
+" Escape, mouse motion, etc to try to break the grab.\n"
+"\n"
"-debug_grabs Turn on debugging info printout with respect to\n"
" XGrabServer() deadlock for -scrollcopyrect mode.\n"
"\n"
@@ -32062,6 +32599,10 @@ int main(int argc, char* argv[]) {
debug_tiles++;
} else if (!strcmp(arg, "-debug_grabs")) {
debug_grabs++;
+ } else if (!strcmp(arg, "-grab_buster")) {
+ grab_buster++;
+ } else if (!strcmp(arg, "-nograb_buster")) {
+ grab_buster = 0;
} else if (!strcmp(arg, "-snapfb")) {
use_snapfb = 1;
} else if (!strcmp(arg, "-rawfb")) {
@@ -32599,6 +33140,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " fixscreen: %s\n", screen_fixup_str ?
screen_fixup_str : "null");
fprintf(stderr, " noxrecord: %d\n", noxrecord);
+ fprintf(stderr, " grabbuster: %d\n", grab_buster);
fprintf(stderr, " ptr_mode: %d\n", pointer_mode);
fprintf(stderr, " inputskip: %d\n", ui_skip);
fprintf(stderr, " speeds: %s\n", speeds_str
@@ -32758,6 +33300,11 @@ int main(int argc, char* argv[]) {
}
}
+ sync_tod_with_servertime();
+ if (grab_buster) {
+ spawn_grab_buster();
+ }
+
#if LIBVNCSERVER_HAVE_LIBXFIXES
if (! XFixesQueryExtension(dpy, &xfixes_base_event_type, &er)) {
if (! quiet) {