x11vnc: -grab_buster for XGrabServer deadlock; fix scrolls and copyrect for -clip and -id

pull/1/head
runge 20 years ago
parent 8fcf086132
commit ad02e15542

@ -1,3 +1,7 @@
2005-07-09 Karl Runge <runge@karlrunge.com>
* x11vnc: -grab_buster for breaking XGrabServer deadlock, fix
scrolls and copyrect for -clip and -id cases.
2005-07-06 Karl Runge <runge@karlrunge.com>
* x11vnc: -gui tray now embeds in systray; more improvements to gui.

@ -1,3 +1,8 @@
2005-07-09 Karl Runge <runge@karlrunge.com>
* add -grab_buster helper thread to break up grabs (might not be
need any longer due to gett XFlush-ing). Fix scrolls and
copyrect for -clip and -id cases.
2005-07-06 Karl Runge <runge@karlrunge.com>
* many improvements to the gui. now embeds into system tray ok.
x11vnc -debug_grabs, -printgui, -nosync

@ -1,5 +1,5 @@
x11vnc README file Date: Wed Jul 6 22:35:15 EDT 2005
x11vnc README file Date: Sat Jul 9 00:07:21 EDT 2005
The following information is taken from these URLs:
@ -577,10 +577,10 @@ make
I don't have any formal beta-testers for the releases of x11vnc, so
I'd appreciate any additional testing very much!
I'd like to release version 0.7.2 in Jun/Jul/2005 sometime, here is
I'd like to release version 0.7.2 in Jun-Jul/2005 sometime, here is
the current tarball:
RC-6 lastmod: 2005-07-07 [51]x11vnc-0.7.2beta.tar.gz
RC-6 lastmod: 2005-07-08 [51]x11vnc-0.7.2beta.tar.gz
There are also some Linux, Solaris, and other OS test binaries
[52]here. Please kick the tires and report bugs, performance
@ -4548,7 +4548,7 @@ x11vnc: a VNC server for real X displays
Here are all of x11vnc command line options:
% x11vnc -opts (see below for -help long descriptions)
x11vnc: allow VNC connections to real X11 displays. 0.7.2 lastmod: 2005-07-06
x11vnc: allow VNC connections to real X11 displays. 0.7.2 lastmod: 2005-07-09
x11vnc options:
-display disp -auth file
@ -4602,7 +4602,8 @@ x11vnc options:
-scr_keys list -scr_term list
-scr_keyrepeat lo-hi -scr_parms string
-fixscreen string -debug_scroll
-noxrecord -debug_grabs
-noxrecord -grab_buster
-nograb_buster -debug_grabs
-pointer_mode n -input_skip n
-speeds rd,bw,lat -wmdt string
-debug_pointer -debug_keyboard
@ -4648,7 +4649,7 @@ libvncserver options:
% x11vnc -help
x11vnc: allow VNC connections to real X11 displays. 0.7.2 lastmod: 2005-07-06
x11vnc: allow VNC connections to real X11 displays. 0.7.2 lastmod: 2005-07-09
Typical usage is:
@ -5730,6 +5731,21 @@ Options:
currently used by the -scrollcopyrect scheme and to
monitor X server grabs.
-grab_buster Some of the use of the RECORD extension can leave a
-nograb_buster tiny window for XGrabServer deadlock. This is only if
the whole-server grabbing application expects mouse
or keyboard input before releasing the grab. It is
usually a window manager that does this. x11vnc takes
care to avoid the the problem, but if caught x11vnc
will freeze. Without -grab_buster, the only solution
is to go the physical display and give it some input
to satisfy the grabbing app. Or manually kill and
restart the window manager. With -grab_buster, x11vnc
will fork a helper thread and if x11vnc appears to be
stuck in a grab after a period of time (20-30 sec)
then it will inject some user input: button clicks,
Escape, mouse motion, etc to try to break the grab.
-debug_grabs Turn on debugging info printout with respect to
XGrabServer() deadlock for -scrollcopyrect mode.

@ -403,7 +403,7 @@ After selecting a VNC client from the \"Clients -> current\" menu,
you will be presented with a dialog that shows the information
about the VNC client.
You can chose to disconnect the client by clicking on the
You can choose to disconnect the client by clicking on the
\"Disconnect\" checkbox and pressing \"OK\". There will be a
confirmation dialog to doublecheck.
@ -500,8 +500,8 @@ to apply the changes, or press \"Cancel\" to skip applying them.
remote-control commands.
- \"Ask for Confirmation\" toggles whether a popup menu will be presented
at the X display when a new VNC viewer attempts to connects. The person
sitting at the X display can chose to accept or reject the connection
at the X display when a new VNC viewer attempts to connect. The person
sitting at the X display can choose to accept or reject the connection
or accept the connection in View-Only mode. It corresponds to the
\"-R accept:popup\" and \"-R accept:\" remote-control commands.
@ -540,7 +540,7 @@ the ViewOnly log in aspect: \"Password\" is still required to log in.
set helptext(Misc-Tuning:) "
x11vnc has what seems like hundreds of tuning parameters. In this
sub-menu we place some lesser used ones. Mostly likely you'll want to
sub-menu we place some lesser used ones. Most likely you'll want to
leave them at their default values, but you can try them out quickly
with the gui to see if they improve things.
"
@ -625,7 +625,7 @@ A brief Background on pixels, color, and visuals:
mappings and so provide less variation in kinds of colors.
A visual's \"depth\" is how many of the pixels are used in the
actual recipe. This may sound wasteful (i.t. not using some of the
actual recipe. This may sound wasteful (i.e. not using some of the
bits), but for 32bpp (4 billion colors) that is too much and nearly
always only 24 for them are used. The most common Visual seems to
be depth 24 TrueColor at 32bpp. This provides 16 million colors
@ -645,7 +645,7 @@ a speedup is achieved because writing graphics data to, say, the 8bit
visual does not destroy the image data in the 24bit visual. Evidently
popup menus can be done very quickly this way: they use the 8bit visual
and when the popup goes away the graphics data in the 24bit visual is
immediately reexposed without having the application redrawing it.
immediately reexposed without having the application redraw it.
Also, some legacy applications can only use 8bpp visuals. But in these
days of high color graphics and web browsers one would like the rest
@ -681,7 +681,7 @@ is shared.
Note if the application pops up multiple windows they are not tracked
and shared. So this is not application sharing. The application has to
be very simple (e.g. a simple terminal or the image window on a webcam)
for this mode to be useable.
for this mode to be usable.
"
set helptext(ResizeRotate:) "
This sub-menu has some options regarding screens that support the X
@ -722,7 +722,7 @@ the screen are still slow today).
This sub-menu has some options for the x11vnc Scroll detection and
CopyRect speedup scheme.
For this mode, x11vnc \"spies\" on communication be the X server and
For this mode, x11vnc \"spies\" on communication between the X server and
applications using the RECORD extension. It looks for various patterns
to detect a scrolled window. This only works for some applications,
fortunately some important ones.
@ -2037,9 +2037,11 @@ proc update_menu_vars {{query ""}} {
}
foreach piece $query_result_list {
#puts stderr "UMV: $piece"
if {[regexp {^([^:][^:]*):(.*)$} $piece m0 item val]} {
if {[info exists menu_var($item)]} {
set old $menu_var($item)
#puts stderr " $old"
if {$val == "N/A"} {
continue
}
@ -2885,6 +2887,11 @@ proc make_menu_items {} {
global bfont ffont beginner_mode simple_gui_created
global helptext helpremote helplabel
# some tweaks...
if {![info exists menu_var(deny)]} {
set menu_var(deny) 0
}
set case "";
set L_casc ""
set L_casc_count 0
@ -3234,7 +3241,14 @@ proc do_props {{msg ""}} {
global have_labelframes ffont bfont
global props_buttons icon_noadvanced
if ![info exists props_accept] {
if [info exists menu_var(deny)] {
if {$menu_var(deny) == $unset_str || $menu_var(deny) == 0} {
set props_accept 1
} else {
set props_accept 0
}
} else {
set menu_var(deny) 0
set props_accept 1
}
set prop0_accept $props_accept
@ -3729,15 +3743,18 @@ proc make_icon {} {
global tray_embed tray_running env
global x11vnc_client_file client_tail client_str saved_clients_str
global client_balloon_id
global bfont sfont ffont
global bfont sfont snfont ffont
global icon_minimal gui_start_mode
global window_view_posted menu_var x11vnc_gui_geom
set min_x 24
set min_y 24
set font $bfont
set mfont $font
if {$tray_embed} {
set font $sfont
set mfont $snfont
}
if {[info exists env(X11VNC_ICON_FONT)]} {
set font $env(X11VNC_ICON_FONT)
@ -3768,15 +3785,16 @@ proc make_icon {} {
label $l -text $lab -borderwidth $bw -font $font
icon_win_cfg 0
set window_view_posted 0
pack $l -fill both -expand 1
set menu "$l.menu"
menu $menu -tearoff 0 -postcommand {set window_view_posted 0}
$menu add command -font $font -label "Properties" -command do_props
$menu add command -font $font -label "Help" -command "menu_help Tray"
$menu add command -font $mfont -label "Properties" -command do_props
$menu add command -font $mfont -label "Help" -command "menu_help Tray"
$menu add separator
$menu add command -font $font -label "New Client" -command do_new_client
$menu add command -font $font -label "Disconnect All" -command do_disconnect_all
$menu add command -font $mfont -label "New Client" -command do_new_client
$menu add command -font $mfont -label "Disconnect All" -command do_disconnect_all
$menu add separator
set wv "$menu.casc1"
@ -3789,9 +3807,9 @@ proc make_icon {} {
-command "do_var WindowView" \
-variable menu_var(WindowView)
}
$menu add cascade -font $font -label "Window View" -menu $wv
$menu add cascade -font $mfont -label "Window View" -menu $wv
$menu add command -font $font -label "Stop x11vnc" -command clean_icon_exit
$menu add command -font $mfont -label "Stop x11vnc" -command clean_icon_exit
bind $icon_win <ButtonPress-1> "pmenu $menu %X %Y"
bind $icon_win <ButtonPress-3> "pmenu $menu %X %Y"
@ -4698,7 +4716,7 @@ global helpall helptext helpremote helplabel hostname osname
global all_settings reply_xdisplay always_update
global max_text_height max_text_width
global menu_var unset_str menus_disabled
global bfont ffont old_labels have_labelframes
global bfont ffont sfont snfont old_labels have_labelframes
global connected_to_x11vnc
global delay_sleep extra_sleep extra_sleep_split
global cache_all_query_vars

@ -409,7 +409,7 @@
"you will be presented with a dialog that shows the information\n"
"about the VNC client.\n"
"\n"
"You can chose to disconnect the client by clicking on the \n"
"You can choose to disconnect the client by clicking on the \n"
"\\\"Disconnect\\\" checkbox and pressing \\\"OK\\\". There will be a\n"
"confirmation dialog to doublecheck.\n"
"\n"
@ -506,8 +506,8 @@
" remote-control commands.\n"
" \n"
" - \\\"Ask for Confirmation\\\" toggles whether a popup menu will be presented\n"
" at the X display when a new VNC viewer attempts to connects. The person\n"
" sitting at the X display can chose to accept or reject the connection\n"
" at the X display when a new VNC viewer attempts to connect. The person\n"
" sitting at the X display can choose to accept or reject the connection\n"
" or accept the connection in View-Only mode. It corresponds to the \n"
" \\\"-R accept:popup\\\" and \\\"-R accept:\\\" remote-control commands.\n"
" \n"
@ -546,7 +546,7 @@
"\n"
" set helptext(Misc-Tuning:) \"\n"
"x11vnc has what seems like hundreds of tuning parameters. In this\n"
"sub-menu we place some lesser used ones. Mostly likely you'll want to\n"
"sub-menu we place some lesser used ones. Most likely you'll want to\n"
"leave them at their default values, but you can try them out quickly\n"
"with the gui to see if they improve things.\n"
"\"\n"
@ -631,7 +631,7 @@
" mappings and so provide less variation in kinds of colors.\n"
"\n"
" A visual's \\\"depth\\\" is how many of the pixels are used in the\n"
" actual recipe. This may sound wasteful (i.t. not using some of the\n"
" actual recipe. This may sound wasteful (i.e. not using some of the\n"
" bits), but for 32bpp (4 billion colors) that is too much and nearly\n"
" always only 24 for them are used. The most common Visual seems to\n"
" be depth 24 TrueColor at 32bpp. This provides 16 million colors\n"
@ -651,7 +651,7 @@
"visual does not destroy the image data in the 24bit visual. Evidently\n"
"popup menus can be done very quickly this way: they use the 8bit visual\n"
"and when the popup goes away the graphics data in the 24bit visual is\n"
"immediately reexposed without having the application redrawing it.\n"
"immediately reexposed without having the application redraw it.\n"
"\n"
"Also, some legacy applications can only use 8bpp visuals. But in these\n"
"days of high color graphics and web browsers one would like the rest\n"
@ -687,7 +687,7 @@
"Note if the application pops up multiple windows they are not tracked\n"
"and shared. So this is not application sharing. The application has to\n"
"be very simple (e.g. a simple terminal or the image window on a webcam)\n"
"for this mode to be useable.\n"
"for this mode to be usable.\n"
"\"\n"
" set helptext(ResizeRotate:) \"\n"
"This sub-menu has some options regarding screens that support the X\n"
@ -728,7 +728,7 @@
"This sub-menu has some options for the x11vnc Scroll detection and\n"
"CopyRect speedup scheme.\n"
"\n"
"For this mode, x11vnc \\\"spies\\\" on communication be the X server and\n"
"For this mode, x11vnc \\\"spies\\\" on communication between the X server and\n"
"applications using the RECORD extension. It looks for various patterns\n"
"to detect a scrolled window. This only works for some applications,\n"
"fortunately some important ones.\n"
@ -2043,9 +2043,11 @@
" }\n"
"\n"
" foreach piece $query_result_list {\n"
"#puts stderr \"UMV: $piece\"\n"
" if {[regexp {^([^:][^:]*):(.*)$} $piece m0 item val]} {\n"
" if {[info exists menu_var($item)]} {\n"
" set old $menu_var($item)\n"
"#puts stderr \" $old\"\n"
" if {$val == \"N/A\"} {\n"
" continue\n"
" }\n"
@ -2891,6 +2893,11 @@
" global bfont ffont beginner_mode simple_gui_created\n"
" global helptext helpremote helplabel\n"
"\n"
" # some tweaks...\n"
" if {![info exists menu_var(deny)]} {\n"
" set menu_var(deny) 0\n"
" }\n"
"\n"
" set case \"\";\n"
" set L_casc \"\"\n"
" set L_casc_count 0\n"
@ -3240,7 +3247,14 @@
" global have_labelframes ffont bfont\n"
" global props_buttons icon_noadvanced\n"
"\n"
" if ![info exists props_accept] {\n"
" if [info exists menu_var(deny)] {\n"
" if {$menu_var(deny) == $unset_str || $menu_var(deny) == 0} {\n"
" set props_accept 1\n"
" } else {\n"
" set props_accept 0\n"
" }\n"
" } else {\n"
" set menu_var(deny) 0\n"
" set props_accept 1\n"
" }\n"
" set prop0_accept $props_accept\n"
@ -3735,15 +3749,18 @@
" global tray_embed tray_running env\n"
" global x11vnc_client_file client_tail client_str saved_clients_str\n"
" global client_balloon_id\n"
" global bfont sfont ffont\n"
" global bfont sfont snfont ffont\n"
" global icon_minimal gui_start_mode\n"
" global window_view_posted menu_var x11vnc_gui_geom\n"
" set min_x 24\n"
" set min_y 24\n"
" \n"
" set font $bfont\n"
" set mfont $font\n"
"\n"
" if {$tray_embed} {\n"
" set font $sfont\n"
" set mfont $snfont\n"
" }\n"
" if {[info exists env(X11VNC_ICON_FONT)]} {\n"
" set font $env(X11VNC_ICON_FONT)\n"
@ -3774,15 +3791,16 @@
" label $l -text $lab -borderwidth $bw -font $font\n"
" icon_win_cfg 0\n"
"\n"
"\n"
" set window_view_posted 0\n"
" pack $l -fill both -expand 1\n"
" set menu \"$l.menu\"\n"
" menu $menu -tearoff 0 -postcommand {set window_view_posted 0}\n"
" $menu add command -font $font -label \"Properties\" -command do_props\n"
" $menu add command -font $font -label \"Help\" -command \"menu_help Tray\"\n"
" $menu add command -font $mfont -label \"Properties\" -command do_props\n"
" $menu add command -font $mfont -label \"Help\" -command \"menu_help Tray\"\n"
" $menu add separator\n"
" $menu add command -font $font -label \"New Client\" -command do_new_client\n"
" $menu add command -font $font -label \"Disconnect All\" -command do_disconnect_all\n"
" $menu add command -font $mfont -label \"New Client\" -command do_new_client\n"
" $menu add command -font $mfont -label \"Disconnect All\" -command do_disconnect_all\n"
" $menu add separator\n"
"\n"
" set wv \"$menu.casc1\"\n"
@ -3795,9 +3813,9 @@
" -command \"do_var WindowView\" \\\n"
" -variable menu_var(WindowView)\n"
" }\n"
" $menu add cascade -font $font -label \"Window View\" -menu $wv\n"
" $menu add cascade -font $mfont -label \"Window View\" -menu $wv\n"
"\n"
" $menu add command -font $font -label \"Stop x11vnc\" -command clean_icon_exit\n"
" $menu add command -font $mfont -label \"Stop x11vnc\" -command clean_icon_exit\n"
"\n"
" bind $icon_win <ButtonPress-1> \"pmenu $menu %X %Y\"\n"
" bind $icon_win <ButtonPress-3> \"pmenu $menu %X %Y\"\n"
@ -4704,7 +4722,7 @@
"global all_settings reply_xdisplay always_update\n"
"global max_text_height max_text_width\n"
"global menu_var unset_str menus_disabled\n"
"global bfont ffont old_labels have_labelframes\n"
"global bfont ffont sfont snfont old_labels have_labelframes\n"
"global connected_to_x11vnc\n"
"global delay_sleep extra_sleep extra_sleep_split\n"
"global cache_all_query_vars\n"

@ -2,7 +2,7 @@
.TH X11VNC "1" "July 2005" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
version: 0.7.2, lastmod: 2005-07-06
version: 0.7.2, lastmod: 2005-07-09
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@ -1378,6 +1378,23 @@ Disable any use of the RECORD extension. This is
currently used by the \fB-scrollcopyrect\fR scheme and to
monitor X server grabs.
.PP
\fB-grab_buster,\fR \fB-nograb_buster\fR
.IP
Some of the use of the RECORD extension can leave a
tiny window for XGrabServer deadlock. This is only if
the whole-server grabbing application expects mouse
or keyboard input before releasing the grab. It is
usually a window manager that does this. x11vnc takes
care to avoid the the problem, but if caught x11vnc
will freeze. Without \fB-grab_buster,\fR the only solution
is to go the physical display and give it some input
to satisfy the grabbing app. Or manually kill and
restart the window manager. With \fB-grab_buster,\fR x11vnc
will fork a helper thread and if x11vnc appears to be
stuck in a grab after a period of time (20-30 sec)
then it will inject some user input: button clicks,
Escape, mouse motion, etc to try to break the grab.
.PP
\fB-debug_grabs\fR
.IP
Turn on debugging info printout with respect to

@ -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) {

Loading…
Cancel
Save