summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--prepare_x11vnc_dist.sh1
-rw-r--r--x11vnc/ChangeLog5
-rw-r--r--x11vnc/README76
-rwxr-xr-xx11vnc/tkx11vnc2
-rw-r--r--x11vnc/tkx11vnc.h2
-rw-r--r--x11vnc/x11vnc.157
-rw-r--r--x11vnc/x11vnc.c1069
8 files changed, 983 insertions, 233 deletions
diff --git a/ChangeLog b/ChangeLog
index 7bc75cd..0e0f0a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-05-24 Karl Runge <runge@karlrunge.com>
+ * x11vnc: scrollcopyrect: GrabServer detection, autorepeat throttling..
+ * prepare_x11vnc_dist.sh: grep out new libvncserver-config line.
+
2005-05-23 Karl Runge <runge@karlrunge.com>
* configure.ac: malloc(0) is never used, so we don't need the check
diff --git a/prepare_x11vnc_dist.sh b/prepare_x11vnc_dist.sh
index ca78be6..9af70cf 100644
--- a/prepare_x11vnc_dist.sh
+++ b/prepare_x11vnc_dist.sh
@@ -7,6 +7,7 @@ cd "$(dirname "$0")"
mv configure.ac configure.ac.LibVNCServer
cat configure.ac.LibVNCServer | \
+egrep -v 'AC_CONFIG_COMMANDS.*libvncserver-config' | \
sed -e "s/LibVNCServer, [^,)]*\([(,]\)*/x11vnc, $VERSION\1/g" \
-e "s/\(contrib\|examples\|vncterm\|libvncclient\|test\|client_examples\)\/Makefile//g" \
-e "s/LibVNCServer.spec/x11vnc.spec/g" \
diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog
index ef2312e..964f754 100644
--- a/x11vnc/ChangeLog
+++ b/x11vnc/ChangeLog
@@ -1,3 +1,8 @@
+2005-05-24 Karl Runge <runge@karlrunge.com>
+ * more -scrollcopyrect: GrabServer detection, autorepeat throttling,
+ hack to clean screen 3,4,5 Alt_L in a row, mouse wheel detect.
+ * fix bug wrt switching to single_copytile, add Darwin to shm limit.
+
2005-05-17 Karl Runge <runge@karlrunge.com>
* more -scrollcopyrect, -scr_term hacks for terminals.
* -wait_ui, -nowait_bog tunables. push cursor sooner.
diff --git a/x11vnc/README b/x11vnc/README
index 822c343..8b9f1c1 100644
--- a/x11vnc/README
+++ b/x11vnc/README
@@ -1,5 +1,5 @@
-x11vnc README file Date: Tue May 17 14:39:38 EDT 2005
+x11vnc README file Date: Tue May 24 23:49:07 EDT 2005
The following information is taken from these URLs:
@@ -4238,7 +4238,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-05-17
+x11vnc: allow VNC connections to real X11 displays. 0.7.2 lastmod: 2005-05-24
x11vnc options:
-display disp -auth file
@@ -4289,7 +4289,8 @@ x11vnc options:
-noscrollcopyrect -scr_area n
-scr_skip list -scr_inc list
-scr_keys list -scr_term list
- -scr_parms string -debug_scroll
+ -scr_keyrepeat lo-hi -scr_parms string
+ -debug_scroll -noxrecord
-pointer_mode n -input_skip n
-speeds rd,bw,lat -debug_pointer
-debug_keyboard -defer time
@@ -4335,7 +4336,7 @@ libvncserver options:
% x11vnc -help
-x11vnc: allow VNC connections to real X11 displays. 0.7.2 lastmod: 2005-05-17
+x11vnc: allow VNC connections to real X11 displays. 0.7.2 lastmod: 2005-05-24
Typical usage is:
@@ -4357,8 +4358,12 @@ the name of the machine running x11vnc and N is XXXX - 5900, i.e. usually
By default x11vnc will not allow the screen to be shared and it will exit
as soon as the client disconnects. See -shared and -forever below to override
-these protections. See the FAQ on how to tunnel the VNC connection through
-an encrypted channel such as ssh(1).
+these protections. See the FAQ for details how to tunnel the VNC connection
+through an encrypted channel such as ssh(1). In brief:
+
+ ssh -L 5900:localhost:5900 far-host 'x11vnc -localhost -display :0'
+
+ vncviewer -encodings 'copyrect tight zrle hextile' localhost:0
For additional info see: http://www.karlrunge.com/x11vnc/
and http://www.karlrunge.com/x11vnc/#faq
@@ -5215,7 +5220,7 @@ Options:
to Keystroke generated scrolls (e.g. Up arrow). If it
is prefixed with "MOUSE:" it only applies to Mouse
induced scrolls (e.g. dragging on a scrollbar).
- Default: ##Soffice.bin
+ Default: ##Soffice.bin,##StarOffice
-scr_inc list Opposite of -scr_skip: this list is consulted first
and if there is a match the window will be monitored
@@ -5246,14 +5251,14 @@ Options:
never induce scrolling by themselves.
-scr_term list Yet another cosmetic kludge. Apply shell/terminal
- heuristics to applications matching comma separated list
- (same as -scr_skip/-scr_inc). For example an annoying
- transient under scroll detection is if you hit Enter in
- a terminal shell with full text window, the solid text
- cursor block will be scrolled up. So for a short time
- there are two (or more) block cursors on the screen.
- There are similar scenarios, (e.g. an output line is
- duplicated).
+ heuristics to applications matching comma separated
+ list (same as for -scr_skip/-scr_inc). For example an
+ annoying transient under scroll detection is if you
+ hit Enter in a terminal shell with full text window,
+ the solid text cursor block will be scrolled up.
+ So for a short time there are two (or more) block
+ cursors on the screen. There are similar scenarios,
+ (e.g. an output line is duplicated).
These transients are induced by the approximation of
scroll detection (e.g. it detects the scroll, but not
@@ -5268,6 +5273,19 @@ Options:
the annoying artifacts. Use "none" to disable.
Default: "term"
+-scr_keyrepeat lo-hi If a key is held down (or otherwise repeats rapidly) and
+ this induces a rapid sequence of scrolls (e.g. holding
+ down an Arrow key) the "scrollcopyrect" detection
+ and overhead may not be able to keep up. A time per
+ single scroll estimate is performed and if that estimate
+ predicts a sustainable scrollrate of keys per second
+ between "lo" and "hi" then repeated keys will be
+ DISCARDED to maintain the scrollrate. For example your
+ key autorepeat may be 25 keys/sec, but for a large
+ window or slow link only 8 scrolls per second can be
+ sustained, then roughly 2 out of every 3 repeated keys
+ will be discarded during this period. Default: "4-20"
+
-scr_parms string Set various parameters for the scrollcopyrect mode.
The format is similar to that for -wireframe and packed
with lots of parameters:
@@ -5314,6 +5332,10 @@ Options:
heuristics. "-ds" is an alias. Specify it multiple
times for more output.
+-noxrecord Disable any use of the RECORD extension. This is
+ currently used by the -scrollcopyrect scheme and to
+ monitor X server grabs.
+
-pointer_mode n Various pointer motion update schemes. "-pm" is
an alias. The problem is pointer motion can cause
rapid changes on the screen: consider the rapid changes
@@ -5529,8 +5551,8 @@ Options:
usage should be very rare, i.e. doing something strange
with /dev/fb0.
--pipeinput cmd Another experimental option: it lets you supply
- an extern command in "cmd" that x11vnc will pipe
+-pipeinput cmd Another experimental option: it lets you supply an
+ external command in "cmd" that x11vnc will pipe
all of the user input events to in a simple format.
In -pipeinput mode by default x11vnc will not process
any of the user input events. If you prefix "cmd"
@@ -5789,7 +5811,10 @@ Options:
scr_inc:list set -scr_inc to "list"
scr_keys:list set -scr_keys to "list"
scr_term:list set -scr_term to "list"
+ scr_keyrepeat:str set -scr_keyrepeat to "str"
scr_parms:str set -scr_parms parameters.
+ noxrecord disable all use of RECORD extension.
+ xrecord enable use of RECORD extension.
pointer_mode:n set -pointer_mode to n. same as "pm"
input_skip:n set -input_skip to n.
speeds:str set -speeds to str.
@@ -5905,14 +5930,15 @@ Options:
noclear_mods clear_keys noclear_keys remap repeat
norepeat fb nofb bell nobell sel nosel primary noprimary
cursorshape nocursorshape cursorpos nocursorpos cursor
- show_cursor noshow_cursor nocursor arrow xfixes noxfixes
- xdamage noxdamage xd_area xd_mem alphacut alphafrac
- alpharemove noalpharemove alphablend noalphablend
- xwarppointer xwarp noxwarppointer noxwarp buttonmap
- dragging nodragging wireframe_mode wireframe wf
- nowireframe nowf wirecopyrect wcr nowirecopyrect nowcr
- scr_area scr_skip scr_inc scr_keys scr_term scr_parms
- scrollcopyrect scr noscrollcopyrect noscr pointer_mode
+ show_cursor noshow_cursor nocursor arrow xfixes
+ noxfixes xdamage noxdamage xd_area xd_mem alphacut
+ alphafrac alpharemove noalpharemove alphablend
+ noalphablend xwarppointer xwarp noxwarppointer
+ noxwarp buttonmap dragging nodragging wireframe_mode
+ wireframe wf nowireframe nowf wirecopyrect wcr
+ nowirecopyrect nowcr scr_area scr_skip scr_inc scr_keys
+ scr_term scr_keyrepeat scr_parms scrollcopyrect scr
+ noscrollcopyrect noscr noxrecord xrecord pointer_mode
pm input_skip input client_input speeds debug_pointer dp
nodebug_pointer nodp debug_keyboard dk nodebug_keyboard
nodk deferupdate defer wait_ui wait_bog nowait_bog wait
diff --git a/x11vnc/tkx11vnc b/x11vnc/tkx11vnc
index 5ef148b..d1e27c1 100755
--- a/x11vnc/tkx11vnc
+++ b/x11vnc/tkx11vnc
@@ -172,6 +172,7 @@ Misc
nolookup
--
xtrap
+ xrecord
--
bg
=-C:ignore,exit sigpipe:
@@ -266,6 +267,7 @@ Tuning
scr_inc:
scr_keys:
scr_term:
+ scr_keyrepeat:
scr_parms:
-- D
speeds:
diff --git a/x11vnc/tkx11vnc.h b/x11vnc/tkx11vnc.h
index 7864574..1e0d9d5 100644
--- a/x11vnc/tkx11vnc.h
+++ b/x11vnc/tkx11vnc.h
@@ -178,6 +178,7 @@
" nolookup\n"
" --\n"
" xtrap\n"
+" xrecord\n"
" --\n"
" bg\n"
" =-C:ignore,exit sigpipe:\n"
@@ -272,6 +273,7 @@
" scr_inc:\n"
" scr_keys:\n"
" scr_term:\n"
+" scr_keyrepeat:\n"
" scr_parms:\n"
" -- D\n"
" speeds:\n"
diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1
index c7757ac..acf8a70 100644
--- a/x11vnc/x11vnc.1
+++ b/x11vnc/x11vnc.1
@@ -2,7 +2,7 @@
.TH X11VNC "1" "May 2005" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
- version: 0.7.2, lastmod: 2005-05-17
+ version: 0.7.2, lastmod: 2005-05-24
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@@ -28,9 +28,14 @@ the name of the machine running x11vnc and N is XXXX - 5900, i.e. usually
.PP
By default x11vnc will not allow the screen to be shared and it will exit
as soon as the client disconnects. See \fB-shared\fR and \fB-forever\fR below to override
-these protections. See the FAQ on how to tunnel the VNC connection through
-an encrypted channel such as
+these protections. See the FAQ for details how to tunnel the VNC connection
+through an encrypted channel such as
.IR ssh (1).
+In brief:
+.IP
+ssh -L 5900:localhost:5900 far-host 'x11vnc -localhost -display :0'
+.IP
+vncviewer -encodings 'copyrect tight zrle hextile' localhost:0
.PP
For additional info see: http://www.karlrunge.com/x11vnc/
and http://www.karlrunge.com/x11vnc/#faq
@@ -1152,7 +1157,7 @@ If a pattern is prefixed with "KEY:" it only applies
to Keystroke generated scrolls (e.g. Up arrow). If it
is prefixed with "MOUSE:" it only applies to Mouse
induced scrolls (e.g. dragging on a scrollbar).
-Default: ##Soffice.bin
+Default: ##Soffice.bin,##StarOffice
.PP
\fB-scr_inc\fR \fIlist\fR
.IP
@@ -1212,6 +1217,21 @@ from the actual X framebuffer. This usually reduces
the annoying artifacts. Use "none" to disable.
Default: "term"
.PP
+\fB-scr_keyrepeat\fR \fIlo-hi\fR
+.IP
+If a key is held down (or otherwise repeats rapidly) and
+this induces a rapid sequence of scrolls (e.g. holding
+down an Arrow key) the "scrollcopyrect" detection
+and overhead may not be able to keep up. A time per
+single scroll estimate is performed and if that estimate
+predicts a sustainable scrollrate of keys per second
+between "lo" and "hi" then repeated keys will be
+DISCARDED to maintain the scrollrate. For example your
+key autorepeat may be 25 keys/sec, but for a large
+window or slow link only 8 scrolls per second can be
+sustained, then roughly 2 out of every 3 repeated keys
+will be discarded during this period. Default: "4-20"
+.PP
\fB-scr_parms\fR \fIstring\fR
.IP
Set various parameters for the scrollcopyrect mode.
@@ -1262,6 +1282,12 @@ Turn on debugging info printout for the scroll
heuristics. "\fB-ds\fR" is an alias. Specify it multiple
times for more output.
.PP
+\fB-noxrecord\fR
+.IP
+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-pointer_mode\fR \fIn\fR
.IP
Various pointer motion update schemes. "\fB-pm\fR" is
@@ -1942,8 +1968,14 @@ scr_keys:list set \fB-scr_keys\fR to "list"
.IP
scr_term:list set \fB-scr_term\fR to "list"
.IP
+scr_keyrepeat:str set \fB-scr_keyrepeat\fR to "str"
+.IP
scr_parms:str set \fB-scr_parms\fR parameters.
.IP
+noxrecord disable all use of RECORD extension.
+.IP
+xrecord enable use of RECORD extension.
+.IP
pointer_mode:n set \fB-pointer_mode\fR to n. same as "pm"
.IP
input_skip:n set \fB-input_skip\fR to n.
@@ -2128,14 +2160,15 @@ noskip_dups add_keysyms noadd_keysyms clear_mods
noclear_mods clear_keys noclear_keys remap repeat
norepeat fb nofb bell nobell sel nosel primary noprimary
cursorshape nocursorshape cursorpos nocursorpos cursor
-show_cursor noshow_cursor nocursor arrow xfixes noxfixes
-xdamage noxdamage xd_area xd_mem alphacut alphafrac
-alpharemove noalpharemove alphablend noalphablend
-xwarppointer xwarp noxwarppointer noxwarp buttonmap
-dragging nodragging wireframe_mode wireframe wf
-nowireframe nowf wirecopyrect wcr nowirecopyrect nowcr
-scr_area scr_skip scr_inc scr_keys scr_term scr_parms
-scrollcopyrect scr noscrollcopyrect noscr pointer_mode
+show_cursor noshow_cursor nocursor arrow xfixes
+noxfixes xdamage noxdamage xd_area xd_mem alphacut
+alphafrac alpharemove noalpharemove alphablend
+noalphablend xwarppointer xwarp noxwarppointer
+noxwarp buttonmap dragging nodragging wireframe_mode
+wireframe wf nowireframe nowf wirecopyrect wcr
+nowirecopyrect nowcr scr_area scr_skip scr_inc scr_keys
+scr_term scr_keyrepeat scr_parms scrollcopyrect scr
+noscrollcopyrect noscr noxrecord xrecord pointer_mode
pm input_skip input client_input speeds debug_pointer dp
nodebug_pointer nodp debug_keyboard dk nodebug_keyboard
nodk deferupdate defer wait_ui wait_bog nowait_bog wait
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index a05b911..be428f8 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -372,12 +372,12 @@ double xdamage_scheduled_mark = 0.0;
sraRegionPtr xdamage_scheduled_mark_region = NULL;
/* date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.7.2 lastmod: 2005-05-17";
+char lastmod[] = "0.7.2 lastmod: 2005-05-24";
int hack_val = 0;
/* X display info */
-Display *dpy = 0; /* the single display screen we connect to */
+Display *dpy = NULL; /* the single display screen we connect to */
int scr;
Window window, rootwin; /* polled window, root window (usu. same) */
Visual *default_visual; /* the default visual (unless -visual) */
@@ -494,6 +494,10 @@ unsigned char *tile_has_xdamage_diff, *tile_row_has_xdamage_diff;
time_t last_event, last_input = 0, last_client = 0;
time_t last_keyboard_input = 0, last_pointer_input = 0;
double last_keyboard_time = 0.0;
+double last_pointer_time = 0.0;
+double last_pointer_click_time = 0.0;
+double last_pointer_motion_time = 0.0;
+double last_key_to_button_remap_time = 0.0;
double servertime_diff = 0.0;
double x11vnc_start = 0.0;
@@ -512,7 +516,10 @@ int got_pointer_input = 0;
int got_keyboard_input = 0;
int urgent_update = 0;
int last_keyboard_keycode = 0;
-rfbKeySym last_keysym = 0;
+rfbBool last_rfb_down = FALSE;
+rfbBool last_rfb_key_accepted = FALSE;
+rfbKeySym last_rfb_keysym = 0;
+double last_rfb_keytime = 0.0;
int fb_copy_in_progress = 0;
int drag_in_progress = 0;
int shut_down = 0;
@@ -593,10 +600,12 @@ void initialize_xinerama(void);
void initialize_xfixes(void);
void initialize_xdamage(void);
int valid_window(Window, XWindowAttributes *, int);
+int xtranslate(Window, Window, int, int, int*, int*, Window*, int);
void create_xdamage_if_needed(void);
void destroy_xdamage_if_needed(void);
void mark_for_xdamage(int, int, int, int);
void mark_region_for_xdamage(sraRegionPtr);
+void set_xdamage_mark(int, int, int, int);
void initialize_xrandr(void);
XImage *initialize_xdisplay_fb(void);
@@ -638,6 +647,7 @@ void set_wirecopyrect_mode(char *);
void set_scrollcopyrect_mode(char *);
void initialize_scroll_matches(void);
void initialize_scroll_term(void);
+void initialize_max_keyrepeat(void);
void initialize_scroll_keys(void);
int try_copyrect(Window, int, int, int, int, int, int, int *, sraRegionPtr,
double);
@@ -721,7 +731,7 @@ int scale_round(int, double);
void zero_fb(int, int, int, int);
void push_black_screen(int);
void push_sleep(int);
-void refresh_screen(void);
+void refresh_screen(int);
/* -- options.h -- */
@@ -842,9 +852,14 @@ char *pad_geometry = NULL;
time_t pad_geometry_time;
int use_snapfb = 0;
-Display *rdpy_data = 0; /* Data connection for RECORD */
-Display *rdpy_ctrl = 0; /* Control connection for RECORD */
+Display *rdpy_data = NULL; /* Data connection for RECORD */
+Display *rdpy_ctrl = NULL; /* Control connection for RECORD */
int use_xrecord = 0;
+int noxrecord = 0;
+
+Display *gdpy_data = NULL; /* Ditto for GrabServer watcher */
+Display *gdpy_ctrl = NULL;
+int xserver_grabbed = 0;
char *client_connect = NULL; /* strings for -connect option */
char *client_connect_file = NULL;
@@ -924,6 +939,10 @@ int debug_scroll = 0;
double pointer_flush_delay = 0.0;
double last_scroll_event = 0.0;
int max_scroll_keyrate = 0;
+double max_keyrepeat_time = 0.0;
+char *max_keyrepeat_str = NULL;
+char *max_keyrepeat_str0 = "4-20";
+int max_keyrepeat_lo = 1, max_keyrepeat_hi = 40;
enum scroll_types {
SCR_NONE = 0,
SCR_MOUSE,
@@ -950,7 +969,8 @@ char **scroll_skip_mouse = NULL;
char *scroll_skip_str = NULL;
char *scroll_skip_str0 =
/* "##Konsole," * no problems, known heuristics do not work */
- "##Soffice.bin" /* big problems, no clips, scrolls outside area */
+ "##Soffice.bin," /* big problems, no clips, scrolls outside area */
+ "##StarOffice"
;
char **scroll_term = NULL;
@@ -1924,7 +1944,7 @@ int try_user_and_display(uid_t uid, char *dpystr) {
return 0;
} else {
/* child */
- Display *dpy2 = 0;
+ Display *dpy2 = NULL;
int rc;
rc = switch_user_env(uid, name, home, 0);
@@ -2811,13 +2831,15 @@ int XTRAP_GrabControl_wr(Display *dpy, Bool impervious) {
return 0;
}
-void disable_grabserver(Display *in_dpy) {
+void disable_grabserver(Display *in_dpy, int change) {
int ok = 0;
static int didmsg = 0;
if (! xtrap_input) {
if (XTestGrabControl_wr(in_dpy, True)) {
- XTRAP_GrabControl_wr(in_dpy, False);
+ if (change) {
+ XTRAP_GrabControl_wr(in_dpy, False);
+ }
if (! didmsg) {
rfbLog("GrabServer control via XTEST.\n");
didmsg = 1;
@@ -2835,7 +2857,9 @@ void disable_grabserver(Display *in_dpy) {
}
} else {
if (XTRAP_GrabControl_wr(in_dpy, True)) {
- XTestGrabControl_wr(in_dpy, False);
+ if (change) {
+ XTestGrabControl_wr(in_dpy, False);
+ }
if (! didmsg) {
rfbLog("GrabServer control via DEC-XTRAP.\n");
didmsg = 1;
@@ -2868,11 +2892,17 @@ Bool XRecordQueryVersion_wr(Display *dpy, int *maj, int *min) {
}
#if LIBVNCSERVER_HAVE_RECORD
-XRecordRange *rr_CA;
-XRecordRange *rr_CW;
+XRecordRange *rr_CA = NULL;
+XRecordRange *rr_CW = NULL;
+XRecordRange *rr_GS = NULL;
XRecordRange *rr_scroll[10];
XRecordContext rc_scroll;
XRecordClientSpec rcs_scroll;
+XRecordRange *rr_grab[10];
+XRecordContext rc_grab;
+XRecordClientSpec rcs_grab;
+
+void record_grab(XPointer, XRecordInterceptData *);
#endif
int xrecording = 0;
@@ -2885,6 +2915,63 @@ KeySym xrecord_keysym = NoSymbol;
#define NAMEINFO 2048
char xrecord_name_info[NAMEINFO];
+char *xerror_string(XErrorEvent *error);
+int trap_record_xerror(Display *, XErrorEvent *);
+int trapped_record_xerror;
+XErrorEvent *trapped_record_xerror_event;
+
+void xrecord_grabserver(int start) {
+ XErrorHandler old_handler = NULL;
+ int rc;
+
+ 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(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(gdpy_ctrl);
+ XCloseDisplay(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(gdpy_ctrl);
+ XCloseDisplay(gdpy_data);
+ gdpy_ctrl = NULL;
+ gdpy_data = NULL;
+ XSetErrorHandler(old_handler);
+ return;
+ }
+ XSetErrorHandler(old_handler);
+ XFlush(gdpy_data);
+#endif
+}
+
void initialize_xrecord(void) {
use_xrecord = 0;
if (! xrecord_present) {
@@ -2893,10 +2980,19 @@ void initialize_xrecord(void) {
if (nofb) {
return;
}
+ if (noxrecord) {
+ return;
+ }
#if LIBVNCSERVER_HAVE_RECORD
+
+ if (rr_CA) XFree(rr_CA);
+ if (rr_CW) XFree(rr_CW);
+ if (rr_GS) XFree(rr_GS);
+
rr_CA = XRecordAllocRange();
rr_CW = XRecordAllocRange();
- if (! rr_CA || ! rr_CW) {
+ rr_GS = XRecordAllocRange();
+ if (!rr_CA || !rr_CW || !rr_GS) {
return;
}
/* protocol request ranges: */
@@ -2906,19 +3002,107 @@ void initialize_xrecord(void) {
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(rdpy_data);
+ rdpy_data = NULL;
+ }
+ if (rdpy_ctrl) {
+ XCloseDisplay(rdpy_ctrl);
+ rdpy_ctrl = NULL;
+ }
rdpy_ctrl = XOpenDisplay(DisplayString(dpy));
XSync(dpy, True);
XSync(rdpy_ctrl, True);
/* open datalink connection to DISPLAY: */
rdpy_data = XOpenDisplay(DisplayString(dpy));
if (!rdpy_ctrl || ! rdpy_data) {
+ X_UNLOCK;
return;
}
- disable_grabserver(rdpy_ctrl);
- disable_grabserver(rdpy_data);
+ 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(gdpy_data);
+ gdpy_data = NULL;
+ }
+ if (gdpy_ctrl) {
+ XCloseDisplay(gdpy_ctrl);
+ gdpy_ctrl = NULL;
+ }
+ xserver_grabbed = 0;
+
+ gdpy_ctrl = XOpenDisplay(DisplayString(dpy));
+ XSync(dpy, True);
+ XSync(gdpy_ctrl, True);
+ gdpy_data = XOpenDisplay(DisplayString(dpy));
+ 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 (rr_CA) XFree(rr_CA);
+ if (rr_CW) XFree(rr_CW);
+ if (rr_GS) XFree(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(rdpy_data);
+ rdpy_data = NULL;
+ }
+ if (rdpy_ctrl) {
+ XCloseDisplay(rdpy_ctrl);
+ rdpy_ctrl = NULL;
+ }
+ if (gdpy_data) {
+ XCloseDisplay(gdpy_data);
+ gdpy_data = NULL;
+ }
+ if (gdpy_ctrl) {
+ XCloseDisplay(gdpy_ctrl);
+ gdpy_ctrl = NULL;
+ }
+ xserver_grabbed = 0;
+ X_UNLOCK;
#endif
+ use_xrecord = 0;
}
int xrecord_skip_keysym(rfbKeySym keysym) {
@@ -3047,7 +3231,7 @@ winattr_t scr_attr_cache[SCR_ATTR_CACHE];
double attr_cache_max_age = 1.5;
int lookup_attr_cache(Window win, int *cache_index, int *next_index) {
- double dnow, t, oldest;
+ double now, t, oldest;
int i, old_index = -1, count = 0;
Window cwin;
@@ -3061,13 +3245,13 @@ int lookup_attr_cache(Window win, int *cache_index, int *next_index) {
return 0;
}
- dtime0(&dnow);
+ dtime0(&now);
for (i=0; i < SCR_ATTR_CACHE; i++) {
cwin = scr_attr_cache[i].win;
t = scr_attr_cache[i].time;
- if (dnow > t + attr_cache_max_age) {
+ 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;
@@ -3110,6 +3294,7 @@ if (0) fprintf(stderr, "lookup_attr_cache count: %d\n", count);
}
}
+
typedef struct scroll_event {
Window win, frame;
int dx, dy;
@@ -3253,8 +3438,9 @@ if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
valid = valid_window(src, &attr, 1);
if (valid) {
- XTranslateCoordinates(dpy, src, rootwin, 0, 0,
- &rx, &ry, &c);
+ if (!xtranslate(src, rootwin, 0, 0, &rx, &ry, &c, 1)) {
+ valid = 0;
+ }
}
if (next_index >= 0) {
i = next_index;
@@ -3289,7 +3475,7 @@ if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
}
-if (dba || db) {
+if (0 || dba || db) {
double st, dt;
st = (double) rec_data->server_time/1000.0;
dt = (dnow() - servertime_diff) - st;
@@ -3744,8 +3930,9 @@ if (0) fprintf(stderr, "lookup_attr_cache MISS: %2d %2d 0x%lx %d\n",
cache_index, next_index, win, valid);
if (valid) {
- XTranslateCoordinates(dpy, win, rootwin, 0, 0,
- &rx, &ry, &c);
+ if (!xtranslate(win, rootwin, 0, 0, &rx, &ry, &c, 1)) {
+ valid = 0;
+ }
}
if (next_index >= 0) {
i = next_index;
@@ -3780,7 +3967,7 @@ if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
}
if (db > 1) fprintf(stderr, "record_CW-%d\n", k++);
-if (dba || db) {
+if (0 || dba || db) {
double st, dt;
st = (double) rec_data->server_time/1000.0;
dt = (dnow() - servertime_diff) - st;
@@ -3885,18 +4072,101 @@ void record_switch(XPointer ptr, XRecordInterceptData *rec_data) {
}
XRecordFreeData(rec_data);
}
+
+void record_grab(XPointer ptr, XRecordInterceptData *rec_data) {
+ xReq *req;
+
+ /* 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 = dnow() - x11vnc_start;
+ xserver_grabbed++;
+ if (0) 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 = dnow() - x11vnc_start;
+ xserver_grabbed--;
+ if (xserver_grabbed < 0) {
+ xserver_grabbed = 0;
+ }
+ if (0) rfbLog("X server Un-Grabbed: %d %.5f\n", xserver_grabbed, now);
+ } else {
+ ;
+ }
+ XRecordFreeData(rec_data);
+}
+#endif
+
+void check_xrecord_grabserver(void) {
+ int last_val, cnt = 0, i, max = 10;
+ double d;
+#if LIBVNCSERVER_HAVE_RECORD
+ if (!gdpy_ctrl || !gdpy_data) {
+ return;
+ }
+
+if (0) dtime0(&d);
+ XFlush(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(gdpy_ctrl);
+ }
+if (0) {
+ d = dtime(&d);
+fprintf(stderr, "check_xrecord_grabserver: cnt=%d i=%d %.4f\n", cnt, i, d);
+}
#endif
+}
#if LIBVNCSERVER_HAVE_RECORD
void shutdown_record_context(XRecordContext rc, int bequiet, int reopen) {
int ret1, ret2;
+ int verb = (!bequiet && !quiet);
+
+ 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 && !bequiet && !quiet) {
+ if (!ret1 && verb) {
rfbLog("XRecordDisableContext(0x%lx) failed.\n", rc);
}
- ret2 = XRecordFreeContext(rdpy_ctrl, rc_scroll);
- if (!ret2 && !bequiet && !quiet) {
+ ret2 = XRecordFreeContext(rdpy_ctrl, rc);
+ if (!ret2 && verb) {
rfbLog("XRecordFreeContext(0x%lx) failed.\n", rc);
}
XFlush(rdpy_ctrl);
@@ -3904,44 +4174,139 @@ void shutdown_record_context(XRecordContext rc, int bequiet, int reopen) {
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(rdpy_data);
- rdpy_data = XOpenDisplay(dpystr);
+ rdpy_data = NULL;
- if (! rdpy_data) {
- rfbLog("Failed to reopen RECORD data connection:"
+ if (debug_scroll) {
+ rfbLog("closing RECORD control connection.\n");
+ }
+ XCloseDisplay(rdpy_ctrl);
+ rdpy_ctrl = NULL;
+
+ rdpy_ctrl = XOpenDisplay(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);
- XCloseDisplay(rdpy_ctrl);
- rdpy_ctrl = XOpenDisplay(dpystr);
+ disable_grabserver(rdpy_ctrl, 0);
+ XSync(rdpy_ctrl, True);
- if (! rdpy_ctrl) {
- rfbLog("Failed to reopen RECORD control connection:"
+ rdpy_data = XOpenDisplay(dpystr);
+
+ if (! rdpy_data) {
+ rfbLog("Failed to reopen RECORD data connection:"
"%s\n", dpystr);
rfbLog(" disabling RECORD scroll detection.\n");
+ XCloseDisplay(rdpy_ctrl);
+ rdpy_ctrl = NULL;
use_xrecord = 0;
return;
}
- if (! bequiet && reopen == 2) {
+ disable_grabserver(rdpy_data, 0);
+
+ if (debug_scroll || (! bequiet && reopen == 2)) {
rfbLog("reopened RECORD data and control display"
" connections: %s\n", dpystr);
}
- disable_grabserver(rdpy_ctrl);
- disable_grabserver(rdpy_data);
}
}
#endif
-char *xerror_string(XErrorEvent *error);
-int trap_record_xerror(Display *, XErrorEvent *);
-int trapped_record_xerror;
-XErrorEvent *trapped_record_xerror_event;
+void check_xrecord_reset(void) {
+ static double last_reset = 0.0;
+ int reset_time = 120, reset_idle = 15;
+ int reset_time2 = 600, reset_idle2 = 40;
+ double now;
+ 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;
+ reset_idle = reset_idle2;
+ }
+
+ if (!use_xrecord) {
+ return;
+ }
+ if (xrecording) {
+ return;
+ }
+ if (button_mask) {
+ return;
+ }
+ if (xserver_grabbed) {
+ 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 (now < last_reset + reset_time) {
+ return;
+ }
+ if (now < last_pointer_click_time + reset_idle) {
+ return;
+ }
+ if (now < last_keyboard_time + reset_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;
+#endif
+}
#define RECORD_ERROR_MSG \
if (! quiet) { \
@@ -3956,7 +4321,7 @@ XErrorEvent *trapped_record_xerror_event;
void xrecord_watch(int start, int setby) {
Window focus, wm, c, clast;
static double create_time = 0.0;
- double dnow;
+ double now;
static double last_error = 0.0;
int rc, db = debug_scroll;
int do_shutdown = 0;
@@ -3964,6 +4329,8 @@ void xrecord_watch(int start, int setby) {
XErrorHandler old_handler = NULL;
static Window last_win = None, last_result = None;
+if (0) db = 1;
+
if (nofb) {
xrecording = 0;
return;
@@ -3975,15 +4342,25 @@ void xrecord_watch(int start, int setby) {
return;
}
- dtime0(&dnow);
- if (dnow < last_error + 0.5) {
+ dtime0(&now);
+ if (now < last_error + 0.5) {
return;
}
+ if (gdpy_ctrl) {
+ X_LOCK;
+ check_xrecord_grabserver();
+ X_UNLOCK;
+ if (xserver_grabbed) {
+if (db) 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) fprintf(stderr, "XRECORD OFF: %d/%d %.4f\n", xrecording, setby, dnow - x11vnc_start);
+if (db) fprintf(stderr, "XRECORD OFF: %d/%d %.4f\n", xrecording, setby, now - x11vnc_start);
xrecording = 0;
if (! rc_scroll) {
xrecord_focus_window = None;
@@ -3994,10 +4371,9 @@ if (db) fprintf(stderr, "XRECORD OFF: %d/%d %.4f\n", xrecording, setby, dnow -
return;
}
- if (! do_shutdown && dnow > create_time + shut_time) {
+ if (! do_shutdown && now > create_time + shut_time) {
/* XXX unstable if we keep a RECORD going forever */
do_shutdown = 1;
- shut_reopen = 1;
}
SCR_LOCK;
@@ -4009,18 +4385,36 @@ if (db > 1) fprintf(stderr, "=== shutdown-scroll 0x%lx\n", rc_scroll);
old_handler = XSetErrorHandler(trap_record_xerror);
shutdown_record_context(rc_scroll, 0, shut_reopen);
- if (! use_xrecord) return;
+ 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;
- last_error = dnow;
+ last_error = now;
}
+
XSetErrorHandler(old_handler);
X_UNLOCK;
-
- rc_scroll = 0;
+ SCR_UNLOCK;
} else {
if (rcs_scroll) {
@@ -4042,11 +4436,16 @@ if (db > 1) fprintf(stderr, "=== disab-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scr
shutdown_record_context(rc_scroll,
0, reopen_dpys);
-
- last_error = dnow;
rc_scroll = 0;
- if (! use_xrecord) return;
+ last_error = now;
+
+ if (! use_xrecord) {
+ XSetErrorHandler(old_handler);
+ X_UNLOCK;
+ SCR_UNLOCK;
+ return;
+ }
}
XSetErrorHandler(old_handler);
X_UNLOCK;
@@ -4076,7 +4475,7 @@ if (db > 1) fprintf(stderr, "=== disab-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scr
rcs_scroll = 0;
return;
}
-if (db) fprintf(stderr, "XRECORD ON: %d/%d %.4f\n", xrecording, setby, dnow - x11vnc_start);
+if (db) fprintf(stderr, "XRECORD ON: %d/%d %.4f\n", xrecording, setby, now - x11vnc_start);
if (xrecording) {
return;
@@ -4085,7 +4484,7 @@ if (db) fprintf(stderr, "XRECORD ON: %d/%d %.4f\n", xrecording, setby, dnow -
if (do_shutdown && rc_scroll) {
static int didmsg = 0;
/* should not happen... */
- if (1 || !didmsg) {
+ if (0 || !didmsg) {
rfbLog("warning: do_shutdown && rc_scroll\n");
didmsg = 1;
}
@@ -4192,13 +4591,31 @@ if (db) fprintf(stderr, "--- xrecord_watch: SKIP.\n");
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 {
@@ -4224,11 +4641,11 @@ if (db > 1) fprintf(stderr, "=-= reg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scr
if (!XRecordRegisterClients(rdpy_ctrl, rc_scroll, 0,
&rcs_scroll, 1, rr_scroll, 2)) {
- if (1 || dnow > last_error + 60) {
+ if (1 || now > last_error + 60) {
rfbLog("failed to register client 0x%lx with"
" X RECORD context rc_scroll.\n", clast);
}
- last_error = dnow;
+ last_error = now;
rcs_scroll = 0;
/* continue on for now... */
}
@@ -4252,14 +4669,12 @@ if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll);
} else if (! rcs_scroll || trapped_record_xerror) {
/* try again later */
shutdown_record_context(rc_scroll, 0, reopen_dpys);
- if (! use_xrecord) return;
rc_scroll = 0;
- last_error = dnow;
+ last_error = now;
XSetErrorHandler(old_handler);
X_UNLOCK;
SCR_UNLOCK;
-
return;
}
@@ -4285,24 +4700,25 @@ if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll);
(XPointer) xrecord_seq);
if (!rc || trapped_record_xerror) {
- if (1 || dnow > last_error + 60) {
+ if (1 || now > last_error + 60) {
rfbLog("failed to enable RECORD context "
- "rc_scroll: 0x%lx\n", rc_scroll);
+ "rc_scroll: 0x%lx rc: %d\n", rc_scroll, rc);
if (trapped_record_xerror) {
RECORD_ERROR_MSG;
}
}
shutdown_record_context(rc_scroll, 0, reopen_dpys);
- if (! use_xrecord) return;
rc_scroll = 0;
- last_error = dnow;
+ last_error = now;
xrecording = 0;
/* continue on for now... */
}
XSetErrorHandler(old_handler);
/* XXX this may cause more problems than it solves... */
- XFlush(rdpy_data);
+ if (use_xrecord) {
+ XFlush(rdpy_data);
+ }
X_UNLOCK;
SCR_UNLOCK;
@@ -4398,14 +4814,7 @@ void clean_up_exit (int ret) {
XEFreeTC(trap_ctx);
}
#endif
-#if LIBVNCSERVER_HAVE_RECORD
- /* XXX currently blocks: */
-#if 0
- if (rdpy_ctrl && rc_scroll) XRecordDisableContext(rdpy_ctrl, rc_scroll);
- if (rdpy_data) XCloseDisplay(rdpy_data);
- if (rdpy_ctrl) XCloseDisplay(rdpy_ctrl);
-#endif
-#endif
+ /* XXX rdpy_ctrl, etc. cannot close w/o blocking */
XCloseDisplay(dpy);
X_UNLOCK;
@@ -4673,6 +5082,30 @@ int valid_window(Window win, XWindowAttributes *attr_ret, int bequiet) {
return ok;
}
+Bool xtranslate(Window src, Window dst, int src_x, int src_y, int *dst_x,
+ int *dst_y, Window *child, int bequiet) {
+ XErrorHandler old_handler;
+ Bool ok = False;
+
+ trapped_xerror = 0;
+ old_handler = XSetErrorHandler(trap_xerror);
+ if (XTranslateCoordinates(dpy, src, dst, src_x, src_y, dst_x,
+ dst_y, child)) {
+ ok = True;
+ }
+ if (trapped_xerror && trapped_xerror_event) {
+ if (! quiet && ! bequiet) {
+ rfbLog("xtranslate: trapped XError: %s (0x%lx)\n",
+ xerror_string(trapped_xerror_event), src);
+ }
+ ok = False;
+ }
+ XSetErrorHandler(old_handler);
+ trapped_xerror = 0;
+
+ return ok;
+}
+
int wait_until_mapped(Window win) {
int ms = 50, waittime = 30;
time_t start = time(0);
@@ -8470,7 +8903,7 @@ keyevent_t key_history[KEY_HIST];
double typing_rate(double time_window, int *repeating) {
double dt = 1.0, now = dnow();
KeySym key = NoSymbol;
- int i, idx, cnt = 0, diff_keys = 0;
+ int i, idx, cnt = 0, repeat_keys = 0;
if (key_history_idx == -1) {
if (repeating) {
@@ -8493,15 +8926,17 @@ double typing_rate(double time_window, int *repeating) {
break;
}
cnt++;
- if (key != NoSymbol && key != key_history[idx].sym) {
- diff_keys++;
+ if (key == NoSymbol) {
+ key = key_history[idx].sym;
+ repeat_keys = 1;
+ } else if (key == key_history[idx].sym) {
+ repeat_keys++;
}
- key = key_history[idx].sym;
}
if (repeating) {
- if (! diff_keys && cnt > 4) {
- *repeating = 1;
+ if (repeat_keys >= 2) {
+ *repeating = repeat_keys;
} else {
*repeating = 0;
}
@@ -8525,18 +8960,21 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
int idx, isbutton = 0;
allowed_input_t input;
time_t now = time(0);
- double dnow;
+ double tnow;
+ static int skipped_last_down;
static rfbBool last_down;
- static rfbKeySym last_keysym;
+ static rfbKeySym last_keysym = NoSymbol;
+ static rfbKeySym max_keyrepeat_last_keysym = NoSymbol;
+ static double max_keyrepeat_last_time = 0.0;
- dtime0(&dnow);
+ dtime0(&tnow);
if (debug_keyboard) {
char *str;
X_LOCK;
str = XKeysymToString(keysym);
rfbLog("keyboard(%s, 0x%x \"%s\") %.4f\n", down ? "down":"up",
- (int) keysym, str ? str : "null", dnow - x11vnc_start);
+ (int) keysym, str ? str : "null", tnow - x11vnc_start);
X_UNLOCK;
}
@@ -8552,7 +8990,12 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
last_down = down;
last_keysym = keysym;
- last_keyboard_time = dnow;
+ last_keyboard_time = tnow;
+
+ last_rfb_down = down;
+ last_rfb_keysym = keysym;
+ last_rfb_keytime = tnow;
+ last_rfb_key_accepted = FALSE;
if (key_history_idx == -1) {
for (idx=0; idx<KEY_HIST; idx++) {
@@ -8568,73 +9011,80 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
}
key_history[idx].sym = keysym;
key_history[idx].down = down;
- key_history[idx].time = dnow;
-
- if (0 && max_scroll_keyrate) {
- /* XXX not working... */
- static int hlen = 256, hidx = 0;
- static keyevent_t history[256];
- static rfbKeySym last_down_skip_keysym = None;
- double key_dt, keytimes[256];
- int idx, i, nrep = 0, skip = 0;
-
- if (!down) {
- if (last_down_skip_keysym != None) {
- if (keysym == last_down_skip_keysym) {
- skip = 1;
- }
+ key_history[idx].time = tnow;
+
+ if (use_xdamage && down && skip_duplicate_key_events &&
+ (keysym == XK_Alt_L || keysym == XK_Super_L)) {
+ int i, k, run = 0;
+ double delay = 1.0;
+ for (i=0; i<16; i++) {
+ k = idx - i;
+ if (k < 0) k += KEY_HIST;
+ if (!key_history[k].down) {
+ continue;
}
- } else {
- if (last_scroll_type == SCR_KEY &&
- dnow < last_scroll_event + 1.0) {
- key_dt = 1.0/max_scroll_keyrate;
-if (0) fprintf(stderr, "key_dt: %.4f\n", key_dt);
- for (i=0; i<hlen; i++) {
- idx = hidx - i - 1;
- if (idx < 0) idx += hlen;
-
- if (history[idx].sym != keysym) {
- break;
- }
- if (dnow > history[idx].time + 1.5) {
- break;
- }
- if (history[idx].down == down) {
+ if (key_history[k].time < tnow - delay) {
+ break;
+ } else if (key_history[k].sym == XK_Alt_L) {
+ run++;
+ } else if (key_history[k].sym == XK_Super_L) {
+ run++;
+ } else {
+ break;
+ }
+ }
+ if (run == 3) {
+ rfbLog("3*Alt_L, calling: set_xdamage_mark()\n");
+ set_xdamage_mark(0, 0, dpy_x, dpy_y);
+ } else if (run == 4) {
+ rfbLog("4*Alt_L, calling: refresh_screen(0)\n");
+ refresh_screen(0);
+ } else if (run == 5) {
+ rfbLog("5*Alt_L, setting: do_copy_screen\n");
+ do_copy_screen = 1;
+ }
+ }
-if (0) fprintf(stderr, "key_dt: %.4f %d %d %.4f\n", key_dt, history[idx].sym,
- history[idx].down, history[idx].time - x11vnc_start);
+ if (!down && skipped_last_down) {
+ int db = debug_scroll;
+ if (keysym == max_keyrepeat_last_keysym) {
+ skipped_last_down = 0;
+ if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s "
+ "%.4f %.4f\n", keysym, down ? "down":"up ",
+ tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
+ return;
+ }
+ }
+ if (down && max_keyrepeat_time > 0.0) {
+ int skip = 0;
+ int db = debug_scroll;
- keytimes[nrep++] =
- history[idx].time;
- }
- }
- if (nrep > 0) {
- idx = hidx - 1;
- if (idx < 0) idx += hlen;
- if (dnow < keytimes[0] + key_dt) {
- skip = 1;
- }
- }
+ if (max_keyrepeat_last_keysym != NoSymbol &&
+ max_keyrepeat_last_keysym != keysym) {
+ ;
+ } else {
+ if (tnow < max_keyrepeat_last_time+max_keyrepeat_time) {
+ skip = 1;
}
}
+ max_keyrepeat_time = 0.0;
if (skip) {
- rfbLog("--- scroll keyrate skipping 0x%lx %s rep:%d "
- "%.4f\n", keysym, down ? "down":"up", nrep,
- down ? dnow - keytimes[0] : dnow - x11vnc_start);
- if (down) {
- last_down_skip_keysym = keysym;
- }
+ if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s "
+ "%.4f %.4f\n", keysym, down ? "down":"up ",
+ tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
+ max_keyrepeat_last_keysym = keysym;
+ skipped_last_down = 1;
return;
- }
- last_down_skip_keysym = None;
-
- history[hidx].sym = keysym;
- history[hidx].time = dnow;
- history[hidx].down = down;
- if (++hidx >= hlen) {
- hidx = 0;
+ } else {
+ if (db) rfbLog("--- scroll keyrate KEEPING 0x%lx %s "
+ "%.4f %.4f\n", keysym, down ? "down":"up ",
+ tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
}
}
+ max_keyrepeat_last_keysym = keysym;
+ max_keyrepeat_last_time = tnow;
+ skipped_last_down = 0;
+ last_rfb_key_accepted = TRUE;
if (pipeinput_fh != NULL) {
pipe_keyboard(down, keysym, client);
@@ -8645,6 +9095,11 @@ if (0) fprintf(stderr, "key_dt: %.4f %d %d %.4f\n", key_dt, history[idx].sym,
last_keyboard_input = now;
last_keysym = keysym;
+
+ last_rfb_down = down;
+ last_rfb_keysym = keysym;
+ last_rfb_keytime = tnow;
+
got_user_input++;
got_keyboard_input++;
}
@@ -8665,6 +9120,11 @@ if (0) fprintf(stderr, "key_dt: %.4f %d %d %.4f\n", key_dt, history[idx].sym,
last_keyboard_input = now;
last_keysym = keysym;
+
+ last_rfb_down = down;
+ last_rfb_keysym = keysym;
+ last_rfb_keytime = tnow;
+
got_user_input++;
got_keyboard_input++;
@@ -8723,6 +9183,7 @@ if (0) fprintf(stderr, "key_dt: %.4f %d %d %.4f\n", key_dt, history[idx].sym,
rfbLog("keyboard(): remapping keystroke to button %d"
" click\n", button);
}
+ dtime0(&last_key_to_button_remap_time);
X_LOCK;
/*
@@ -9145,6 +9606,10 @@ static void update_x11_pointer_position(int x, int y) {
}
X_UNLOCK;
+ if (cursor_x != x || cursor_y != y) {
+ last_pointer_motion_time = dnow();
+ }
+
cursor_x = x;
cursor_y = y;
@@ -9230,6 +9695,10 @@ static void update_x11_pointer_mask(int mask) {
if (raw_fb && ! dpy) return; /* raw_fb hack */
+ if (mask != button_mask) {
+ last_pointer_click_time = dnow();
+ }
+
if (scaling && ! got_scrollcopyrect) {
xr_mouse = 0;
} else if (nofb) {
@@ -9268,10 +9737,18 @@ if (debug_scroll > 1) fprintf(stderr, "wm_win: 0x%lx\n", mwin);
skip = 1;
} else {
int ok = 0;
+ int btn4 = (1<<3);
+ int btn5 = (1<<4);
+
if (near_scrollbar_edge(x, y, w, h, px, py)) {
ok = 1;
}
- if (! ok && mwin != None) {
+ if (mask & (btn4|btn5)) {
+ /* scroll wheel mouse */
+ ok = 1;
+ }
+ if (mwin != None) {
+ /* skinny internal window */
int w = attr.width;
int h = attr.height;
if (h > 10 * w || w > 10 * h) {
@@ -9401,6 +9878,7 @@ void pipe_pointer(int mask, int x, int y, rfbClientPtr client) {
void pointer(int mask, int x, int y, rfbClientPtr client) {
allowed_input_t input;
int sent = 0, buffer_it = 0;
+ double now;
if (debug_pointer && mask >= 0) {
static int show_motion = -1;
@@ -9455,6 +9933,9 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
if (view_only) {
return;
}
+
+ now = dnow();
+
if (mask >= 0) {
/*
* mask = -1 is a special case call from scan_for_updates()
@@ -9468,6 +9949,8 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
got_user_input++;
got_pointer_input++;
last_pointer_client = client;
+
+ last_pointer_time = now;
}
/*
@@ -10863,8 +11346,9 @@ void check_xevents(void) {
if (now > last_sync + 1200) {
/* kludge for any remaining event leaks */
int bugout = use_xdamage ? 500 : 50;
+ int qlen, i;
if (last_sync != 0) {
- int qlen = XEventsQueued(dpy, QueuedAlready);
+ qlen = XEventsQueued(dpy, QueuedAlready);
if (qlen >= bugout) {
rfbLog("event leak: %d queued, "
" calling XSync(dpy, True)\n", qlen);
@@ -10874,6 +11358,20 @@ void check_xevents(void) {
}
}
last_sync = now;
+
+ /* clear these, we don't want any events on them */
+ if (rdpy_ctrl) {
+ qlen = XEventsQueued(rdpy_ctrl, QueuedAlready);
+ for (i=0; i<qlen; i++) {
+ XNextEvent(rdpy_ctrl, &xev);
+ }
+ }
+ if (gdpy_ctrl) {
+ qlen = XEventsQueued(gdpy_ctrl, QueuedAlready);
+ for (i=0; i<qlen; i++) {
+ XNextEvent(gdpy_ctrl, &xev);
+ }
+ }
}
X_UNLOCK;
@@ -11574,7 +12072,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
push_black_screen(4);
} else if (!strcmp(p, "refresh")) {
NOTAPP
- refresh_screen();
+ refresh_screen(1);
} else if (!strcmp(p, "reset")) {
NOTAPP
do_new_fb(1);
@@ -12459,7 +12957,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
"(if applicable).\n");
if (! xtrap_input) {
xtrap_input = 1;
- disable_grabserver(dpy);
+ disable_grabserver(dpy, 1);
}
} else if (!strcmp(p, "noxtrap")) {
@@ -12471,7 +12969,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
"(if applicable).\n");
if (xtrap_input) {
xtrap_input = 0;
- disable_grabserver(dpy);
+ disable_grabserver(dpy, 1);
}
} else if (!strcmp(p, "xrandr")) {
@@ -13401,6 +13899,24 @@ char *process_remote_cmd(char *cmd, int stringonly) {
scroll_term_str);
initialize_scroll_term();
+ } else if (strstr(p, "scr_keyrepeat") == p) {
+ char *s = max_keyrepeat_str;
+ if (!s || *s == '\0') s = max_keyrepeat_str0;
+ COLON_CHECK("scr_keyrepeat:")
+ if (query) {
+ snprintf(buf, bufn, "ans=%s%s%s", p, co, NONUL(s));
+ goto qry;
+ }
+ p += strlen("scr_keyrepeat:");
+ if (max_keyrepeat_str) {
+ free(max_keyrepeat_str);
+ }
+
+ max_keyrepeat_str = strdup(p);
+ rfbLog("remote_cmd: changed -scr_keyrepeat to: %s\n",
+ max_keyrepeat_str);
+ initialize_max_keyrepeat();
+
} else if (strstr(p, "scr_parms") == p) {
COLON_CHECK("scr_parms:")
if (query) {
@@ -13460,6 +13976,29 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("remote_cmd: changed -scrollcopyrect mode "
"to: %s\n", NONUL(scroll_copyrect));
+ } else if (!strcmp(p, "noxrecord")) {
+ int orig = noxrecord;
+ if (query) {
+ snprintf(buf, bufn, "ans=%s:%d", p, noxrecord);
+ goto qry;
+ }
+ noxrecord = 1;
+ rfbLog("set noxrecord to: %d\n", noxrecord);
+ if (orig != noxrecord) {
+ shutdown_xrecord();
+ }
+ } else if (!strcmp(p, "xrecord")) {
+ int orig = noxrecord;
+ if (query) {
+ snprintf(buf, bufn, "ans=%s:%d", p, !noxrecord);
+ goto qry;
+ }
+ noxrecord = 0;
+ rfbLog("set noxrecord to: %d\n", noxrecord);
+ if (orig != noxrecord) {
+ initialize_xrecord();
+ }
+
} else if (strstr(p, "pointer_mode") == p) {
int pm;
COLON_CHECK("pointer_mode:")
@@ -14476,6 +15015,7 @@ void add_region_xdamage(sraRegionPtr new_region) {
reg = xdamage_regions[prev_tick];
if (reg != NULL) {
+if (0) fprintf(stderr, "add_region_xdamage: prev_tick: %d reg %p\n", prev_tick, reg);
sraRgnOr(reg, new_region);
}
}
@@ -17161,7 +17701,7 @@ XImage *initialize_raw_fb(void) {
DisplayString(dpy));
XCloseDisplay(dpy); /* yow! */
}
- dpy = 0;
+ dpy = NULL;
}
#endif
@@ -17580,8 +18120,11 @@ XImage *initialize_xdisplay_fb(void) {
int disp_y = DisplayHeight(dpy, scr);
Window twin;
/* subwins can be a dicey if they are changing size... */
+ trapped_xerror = 0;
+ old_handler = XSetErrorHandler(trap_xerror);
XTranslateCoordinates(dpy, window, rootwin, 0, 0, &subwin_x,
&subwin_y, &twin);
+
if (subwin_x + wdpy_x > disp_x) {
shift = 1;
subwin_x = disp_x - wdpy_x - 3;
@@ -17599,8 +18142,6 @@ XImage *initialize_xdisplay_fb(void) {
subwin_y = 1;
}
- trapped_xerror = 0;
- old_handler = XSetErrorHandler(trap_xerror);
if (shift) {
XMoveWindow(dpy, window, subwin_x, subwin_y);
}
@@ -18982,10 +19523,9 @@ void blackout_tiles(void) {
}
/*
- * to simplify things drop down to single copy mode, no vcr, etc...
+ * to simplify things drop down to single copy mode, etc...
*/
single_copytile = 1;
-
/* loop over all tiles. */
for (ty=0; ty < ntiles_y; ty++) {
for (tx=0; tx < ntiles_x; tx++) {
@@ -19237,12 +19777,15 @@ void push_black_screen(int n) {
push_sleep(n);
}
-void refresh_screen(void) {
+void refresh_screen(int push) {
+ int i;
if (!screen) {
return;
}
mark_rect_as_modified(0, 0, dpy_x, dpy_y, 1);
- rfbPE(-1);
+ for (i=0; i<push; i++) {
+ rfbPE(-1);
+ }
}
/*
@@ -19635,6 +20178,7 @@ void initialize_polling_images(void) {
" to manually\n");
rfbLog("shm: delete unattached shm segments.\n");
single_copytile_count = i;
+ single_copytile = 1;
}
tile_shm_count++;
if (single_copytile && i >= 1) {
@@ -19757,7 +20301,6 @@ static void hint_updates(void) {
}
}
-
for (i=0; i < hint_count; i++) {
/* pass update info to vnc: */
mark_hint(hint_list[i]);
@@ -21432,7 +21975,7 @@ void set_offset(void) {
return;
}
X_LOCK;
- XTranslateCoordinates(dpy, window, rootwin, 0, 0, &off_x, &off_y, &w);
+ xtranslate(window, rootwin, 0, 0, &off_x, &off_y, &w, 0);
X_UNLOCK;
}
@@ -21880,6 +22423,7 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui,
}
if (dpy) {
XCloseDisplay(dpy);
+ dpy = NULL;
}
if (old_xauth) {
if (*old_xauth == '\0') {
@@ -22792,6 +23336,30 @@ void initialize_scroll_term(void) {
}
}
+void initialize_max_keyrepeat(void) {
+ char *str;
+ int lo, hi;
+
+ if (max_keyrepeat_str != NULL && *max_keyrepeat_str != '\0') {
+ str = max_keyrepeat_str;
+ } else {
+ str = max_keyrepeat_str0;
+ }
+
+ if (sscanf(str, "%d-%d", &lo, &hi) != 2) {
+ rfbLog("skipping invalid -scr_keyrepeat string: %s\n", str);
+ sscanf(max_keyrepeat_str0, "%d-%d", &lo, &hi);
+ }
+ max_keyrepeat_lo = lo;
+ max_keyrepeat_hi = hi;
+ if (max_keyrepeat_lo < 1) {
+ max_keyrepeat_lo = 1;
+ }
+ if (max_keyrepeat_hi > 40) {
+ max_keyrepeat_hi = 40;
+ }
+}
+
typedef struct saveline {
int x0, y0, x1, y1;
int shift;
@@ -23382,7 +23950,7 @@ if (n) { \
fprintf(stderr, "---PUSH\n"); \
}
-int push_scr_ev(double max_age, int type, int bdpush, int bdx, int bdy,
+int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy,
int bdskinny) {
Window frame, win, win0;
int x, y, w, h, wx, wy, ww, wh, dx, dy;
@@ -23390,12 +23958,16 @@ int push_scr_ev(double max_age, int type, int bdpush, int bdx, int bdy,
int nx, ny, nw, nh;
int dret = 1, do_fb_push = 0, obscured;
int ev, ev_tot = scr_ev_cnt;
- double tm, dt, st, dnow, waittime = 0.125;
+ double tm, dt, st, waittime = 0.125;
+ double max_age = *age;
int db = debug_scroll, rrate = get_read_rate();
sraRegionPtr backfill, whole, tmpregion, tmpregion2;
int link, latency, netrate;
int ypad = 0;
+ /* we return the oldest one. */
+ *age = 0.0;
+
if (ev_tot == 0) {
return dret;
}
@@ -23410,8 +23982,6 @@ int push_scr_ev(double max_age, int type, int bdpush, int bdx, int bdy,
waittime *= 3;
}
- dtime0(&dnow);
-
backfill = sraRgnCreate();
whole = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
@@ -23426,6 +23996,7 @@ int push_scr_ev(double max_age, int type, int bdpush, int bdx, int bdy,
if (db) fprintf(stderr, "ypad: %d dy[0]: %d\n", ypad, scr_ev[0].dy);
for (ev=0; ev < ev_tot; ev++) {
+ double ag;
x = scr_ev[ev].x;
y = scr_ev[ev].y;
@@ -23444,12 +24015,18 @@ if (db) fprintf(stderr, "ypad: %d dy[0]: %d\n", ypad, scr_ev[0].dy);
nh = scr_ev[ev].new_h;
st = scr_ev[ev].t;
- if (dabs((dnow - servertime_diff) - st) > max_age) {
-if (db) fprintf(stderr, "push_scr_ev: TOO OLD: %.4f :: (%.4f - %.4f) - %.4f \n", (dnow - servertime_diff) - st, dnow, servertime_diff, st);
+ ag = (dnow() - servertime_diff) - st;
+ if (ag > *age) {
+ *age = ag;
+ }
+
+ if (dabs(ag) > max_age) {
+if (db) fprintf(stderr, "push_scr_ev: TOO OLD: %.4f :: (%.4f - %.4f) "
+ "- %.4f \n", ag, dnow(), servertime_diff, st);
dret = 0;
break;
} else {
-if (db) fprintf(stderr, "push_scr_ev: AGE: %.4f\n", (dnow - servertime_diff) - st);
+if (db) fprintf(stderr, "push_scr_ev: AGE: %.4f\n", ag);
}
if (win != win0) {
if (db) fprintf(stderr, "push_scr_ev: DIFF WIN: 0x%lx != 0x%lx\n", win, win0);
@@ -23659,7 +24236,7 @@ PUSH_TEST(0);
}
sraRgnReleaseIterator(iter);
dt = dtime(&tm);
-if (0) fprintf(stderr, " dfc---- dt: %.4f", dt);
+if (db) fprintf(stderr, " dfc---- dt: %.4f", dt);
}
if (db && dret) fprintf(stderr, " **** dret=%d", dret);
@@ -23992,6 +24569,9 @@ void mark_region_for_xdamage(sraRegionPtr region) {
void set_xdamage_mark(int x, int y, int w, int h) {
sraRegionPtr region;
+ if (! use_xdamage) {
+ return;
+ }
mark_for_xdamage(x, y, w, h);
if (xdamage_scheduled_mark == 0.0) {
@@ -24021,8 +24601,12 @@ int check_xrecord_keys(void) {
static int persist_count = 0;
double last_scroll, scroll_persist = scr_key_persist;
double spin_fac = 1.0, scroll_fac = 2.0;
- double max_spin;
- double max_long_spin = 0.3;
+ double max_spin, max_long_spin = 0.3;
+ double set_repeat_in;
+ static double set_repeat = 0.0;
+
+ set_repeat_in = set_repeat;
+ set_repeat = 0.0;
get_out = 1;
if (got_keyboard_input) {
@@ -24034,6 +24618,10 @@ int check_xrecord_keys(void) {
get_out = 0;
}
+ if (set_repeat_in > 0.0 && tnow < last_key_scroll + set_repeat_in) {
+ get_out = 0;
+ }
+
if (get_out) {
persist_start = 0.0;
persist_count = 0;
@@ -24048,9 +24636,14 @@ int check_xrecord_keys(void) {
max_spin = scr_key_time;
- if (tnow < last_key_scroll + scroll_persist) {
+ if (set_repeat_in > 0.0 && tnow < last_key_scroll + 2*set_repeat_in) {
+ max_spin = 2 * set_repeat_in;
+ } else if (tnow < last_key_scroll + scroll_persist) {
max_spin = 1.25*(tnow - last_key_scroll);
- } else if (xrecord_scroll_keysym(last_keysym)) {
+ } else if (tnow < last_key_to_button_remap_time + scroll_persist) {
+ /* mostly a hack I use for testing -remap key -> btn4/btn5 */
+ max_spin = scroll_persist;
+ } else if (xrecord_scroll_keysym(last_rfb_keysym)) {
spin_fac = scroll_fac;
}
if (max_spin > max_long_spin) {
@@ -24058,13 +24651,13 @@ int check_xrecord_keys(void) {
}
/* XXX use this somehow */
- link = link_rate(&latency, &netrate);
+if (0) link = link_rate(&latency, &netrate);
gk = gk0 = got_keyboard_input;
dtime0(&tm);
-if (db) fprintf(stderr, "check_xrecord_keys: BEGIN LOOP: scr_ev_cnt: %d max: %.3f\n",
- scr_ev_cnt, max_spin);
+if (db) fprintf(stderr, "check_xrecord_keys: BEGIN LOOP: scr_ev_cnt: "
+ "%d max: %.3f %.4f\n", scr_ev_cnt, max_spin, tm - x11vnc_start);
while (1) {
@@ -24085,6 +24678,10 @@ if (db) fprintf(stderr, "check_xrecord_keys: BEGIN LOOP: scr_ev_cnt: %d max: %.3
XFlush(dpy);
X_UNLOCK;
+ if (set_repeat_in > 0.0) {
+ max_keyrepeat_time = set_repeat_in;
+ }
+
if (use_threads) {
usleep(1000);
} else {
@@ -24096,10 +24693,14 @@ if (db) fprintf(stderr, "check_xrecord_keys: BEGIN LOOP: scr_ev_cnt: %d max: %.3
if (got_keyboard_input > gk) {
gk = got_keyboard_input;
input++;
- if (xrecord_scroll_keysym(last_keysym)) {
+ if (set_repeat_in) {
+ ;
+ } else if (xrecord_scroll_keysym(last_rfb_keysym)) {
spin_fac = scroll_fac;
}
-if (db) fprintf(stderr, "check_xrecord: more keys: %.3f\n", spin);
+if (0 || db) fprintf(stderr, "check_xrecord: more keys: %.3f 0x%x "
+ " %.4f %s %s\n", spin, last_rfb_keysym, last_rfb_keytime - x11vnc_start,
+ last_rfb_down ? "down":"up ", last_rfb_key_accepted ? "accept":"skip");
flush2 = 1;
XFlush(dpy);
}
@@ -24109,16 +24710,20 @@ if (db) fprintf(stderr, "check_xrecord: more keys: %.3f\n", spin);
X_UNLOCK;
if (spin >= max_spin * spin_fac) {
-if (db) fprintf(stderr, "check_xrecord: SPIN-OUT: %.3f/%.3f\n", spin,
+if (0 || db) fprintf(stderr, "check_xrecord: SPIN-OUT: %.3f/%.3f\n", spin,
max_spin * spin_fac);
fail = 1;
break;
}
}
+ max_keyrepeat_time = 0.0;
+
if (scr_ev_cnt) {
int dret, ev = scr_ev_cnt - 1;
int bdx, bdy, bdskinny, bdpush = 0;
+ double max_age = 0.25, age, tm, dt;
+ static double last_scr_ev = 0.0;
last_wx = scr_ev[ev].win_x;
last_wy = scr_ev[ev].win_y;
@@ -24136,10 +24741,34 @@ if (db) fprintf(stderr, "check_xrecord: SPIN-OUT: %.3f/%.3f\n", spin,
set_bdpush(SCR_KEY, &last_bdpush, &bdpush);
}
- dret = push_scr_ev(0.25, SCR_KEY, bdpush, bdx, bdy, bdskinny);
+ dtime0(&tm);
+ age = max_age;
+ dret = push_scr_ev(&age, SCR_KEY, bdpush, bdx, bdy, bdskinny);
+ dt = dtime(&tm);
ret = 1 + dret;
scr_ev_cnt = 0;
+
+ if (ret == 2 && xrecord_scroll_keysym(last_rfb_keysym)) {
+ int repeating;
+ double time_lo = 1.0/max_keyrepeat_lo;
+ double time_hi = 1.0/max_keyrepeat_hi;
+ double rate = typing_rate(0.0, &repeating);
+if (0 || db) fprintf(stderr, "Typing: dt: %.4f rate: %.1f\n", dt, rate);
+ if (repeating) {
+ /* n.b. the "quantum" is about 1/30 sec. */
+ max_keyrepeat_time = 1.0*dt;
+ if (max_keyrepeat_time > time_lo ||
+ max_keyrepeat_time < time_hi) {
+ max_keyrepeat_time = 0.0;
+ } else {
+ set_repeat = max_keyrepeat_time;
+if (0 || db) fprintf(stderr, "set max_keyrepeat_time: %.2f\n", max_keyrepeat_time);
+ }
+ }
+ }
+
+ last_scr_ev = dnow();
}
if ((got_one && ret < 2) || persist_count) {
@@ -24197,6 +24826,10 @@ int check_xrecord_mouse(void) {
static int want_back_in = 0;
int came_back_in;
+ int scroll_wheel = 0;
+ int btn4 = (1<<3);
+ int btn5 = (1<<4);
+
get_out = 1;
if (button_mask) {
get_out = 0;
@@ -24226,6 +24859,10 @@ if (0) fprintf(stderr, "check_xrecord_mouse: IN xrecording: %d\n", xrecording);
}
want_back_in = 0;
+ if (button_mask & (btn4|btn5)) {
+ scroll_wheel = 1;
+ }
+
/*
* set up times for the various "reputations"
*
@@ -24278,15 +24915,15 @@ if (0) fprintf(stderr, "check_xrecord_mouse: IN xrecording: %d\n", xrecording);
last_x = start_x = cursor_x;
last_y = start_y = cursor_y;
-if (db) fprintf(stderr, "check_xrecord_mouse: BEGIN LOOP: scr_ev_cnt: %d max: %.3f\n",
- scr_ev_cnt, max_spin[scroll_rep]);
+if (db) fprintf(stderr, "check_xrecord_mouse: BEGIN LOOP: scr_ev_cnt: "
+ "%d max: %.3f %.4f\n", scr_ev_cnt, max_spin[scroll_rep], tm - x11vnc_start);
while (1) {
double spin_check;
if (scr_ev_cnt) {
int dret, ev = scr_ev_cnt - 1;
int bdpush = 0, bdx, bdy, bdskinny;
- double tm, dt;
+ double tm, dt, age = 0.35;
got_one = 1;
scrollability(xrecord_ptr_window, SCR_SUCCESS);
@@ -24309,7 +24946,7 @@ if (db) fprintf(stderr, "check_xrecord_mouse: BEGIN LOOP: scr_ev_cnt: %d max: %.
dtime0(&tm);
- dret = push_scr_ev(0.35, SCR_MOUSE, bdpush, bdx,
+ dret = push_scr_ev(&age, SCR_MOUSE, bdpush, bdx,
bdy, bdskinny);
ret = 1 + dret;
@@ -24406,6 +25043,10 @@ if (db) fprintf(stderr, "check_xrecord: SPIN-OUT-3: %.3f/%.3f\n", spin, max_long
} else if (came_back_in) {
dtime0(&button_up_time);
doflush = 1;
+ } else if (scroll_wheel) {
+if (db) fprintf(stderr, "check_xrecord: SCROLL-WHEEL-BUTTON-UP-KEEP-GOING: %.3f/%.3f %d/%d %d/%d\n", spin, max_long[scroll_rep], last_x, last_y, cursor_x, cursor_y);
+ doflush = 1;
+ dtime0(&button_up_time);
} else if (last_x == cursor_x && last_y == cursor_y) {
if (db) fprintf(stderr, "check_xrecord: BUTTON-UP: %.3f/%.3f %d/%d %d/%d\n", spin, max_long[scroll_rep], last_x, last_y, cursor_x, cursor_y);
break;
@@ -26701,6 +27342,7 @@ if (0 && dt > 0.0) fprintf(stderr, "dt: %.5f %.4f\n", dt, dnow() - x11vnc_start)
msec = (int) (1000 * 1.75 * bave);
if (dts[ndt - nave - 1] > 0.75 * bave) {
msec = 1.5 * msec;
+ set_xdamage_mark(0, 0, dpy_x, dpy_y);
}
if (msec > 1500) {
msec = 1500;
@@ -26828,6 +27470,7 @@ if (debug_scroll) fprintf(stderr, "watch_loop: LOOP-BACK: %d\n", ret);
check_connect_inputs();
check_padded_fb();
check_xdamage_state();
+ check_xrecord_reset();
check_add_keysyms();
if (started_as_root) {
check_switched_user();
@@ -26952,8 +27595,12 @@ static void print_help(int mode) {
"\n"
"By default x11vnc will not allow the screen to be shared and it will exit\n"
"as soon as the client disconnects. See -shared and -forever below to override\n"
-"these protections. See the FAQ on how to tunnel the VNC connection through\n"
-"an encrypted channel such as ssh(1).\n"
+"these protections. See the FAQ for details how to tunnel the VNC connection\n"
+"through an encrypted channel such as ssh(1). In brief:\n"
+"\n"
+" ssh -L 5900:localhost:5900 far-host 'x11vnc -localhost -display :0'\n"
+"\n"
+" vncviewer -encodings 'copyrect tight zrle hextile' localhost:0\n"
"\n"
"For additional info see: http://www.karlrunge.com/x11vnc/\n"
" and http://www.karlrunge.com/x11vnc/#faq\n"
@@ -27875,6 +28522,19 @@ static void print_help(int mode) {
" the annoying artifacts. Use \"none\" to disable.\n"
" Default: \"%s\"\n"
"\n"
+"-scr_keyrepeat lo-hi If a key is held down (or otherwise repeats rapidly) and\n"
+" this induces a rapid sequence of scrolls (e.g. holding\n"
+" down an Arrow key) the \"scrollcopyrect\" detection\n"
+" and overhead may not be able to keep up. A time per\n"
+" single scroll estimate is performed and if that estimate\n"
+" predicts a sustainable scrollrate of keys per second\n"
+" between \"lo\" and \"hi\" then repeated keys will be\n"
+" DISCARDED to maintain the scrollrate. For example your\n"
+" key autorepeat may be 25 keys/sec, but for a large\n"
+" window or slow link only 8 scrolls per second can be\n"
+" sustained, then roughly 2 out of every 3 repeated keys\n"
+" will be discarded during this period. Default: \"%s\"\n"
+"\n"
"-scr_parms string Set various parameters for the scrollcopyrect mode.\n"
" The format is similar to that for -wireframe and packed\n"
" with lots of parameters:\n"
@@ -27921,6 +28581,10 @@ static void print_help(int mode) {
" heuristics. \"-ds\" is an alias. Specify it multiple\n"
" times for more output.\n"
"\n"
+"-noxrecord Disable any use of the RECORD extension. This is\n"
+" currently used by the -scrollcopyrect scheme and to\n"
+" monitor X server grabs.\n"
+"\n"
"-pointer_mode n Various pointer motion update schemes. \"-pm\" is\n"
" an alias. The problem is pointer motion can cause\n"
" rapid changes on the screen: consider the rapid changes\n"
@@ -28403,7 +29067,10 @@ static void print_help(int mode) {
" scr_inc:list set -scr_inc to \"list\"\n"
" scr_keys:list set -scr_keys to \"list\"\n"
" scr_term:list set -scr_term to \"list\"\n"
+" scr_keyrepeat:str set -scr_keyrepeat to \"str\"\n"
" scr_parms:str set -scr_parms parameters.\n"
+" noxrecord disable all use of RECORD extension.\n"
+" xrecord enable use of RECORD extension.\n"
" pointer_mode:n set -pointer_mode to n. same as \"pm\"\n"
" input_skip:n set -input_skip to n.\n"
" speeds:str set -speeds to str.\n"
@@ -28519,14 +29186,15 @@ static void print_help(int mode) {
" noclear_mods clear_keys noclear_keys remap repeat\n"
" norepeat fb nofb bell nobell sel nosel primary noprimary\n"
" cursorshape nocursorshape cursorpos nocursorpos cursor\n"
-" show_cursor noshow_cursor nocursor arrow xfixes noxfixes\n"
-" xdamage noxdamage xd_area xd_mem alphacut alphafrac\n"
-" alpharemove noalpharemove alphablend noalphablend\n"
-" xwarppointer xwarp noxwarppointer noxwarp buttonmap\n"
-" dragging nodragging wireframe_mode wireframe wf\n"
-" nowireframe nowf wirecopyrect wcr nowirecopyrect nowcr\n"
-" scr_area scr_skip scr_inc scr_keys scr_term scr_parms\n"
-" scrollcopyrect scr noscrollcopyrect noscr pointer_mode\n"
+" show_cursor noshow_cursor nocursor arrow xfixes\n"
+" noxfixes xdamage noxdamage xd_area xd_mem alphacut\n"
+" alphafrac alpharemove noalpharemove alphablend\n"
+" noalphablend xwarppointer xwarp noxwarppointer\n"
+" noxwarp buttonmap dragging nodragging wireframe_mode\n"
+" wireframe wf nowireframe nowf wirecopyrect wcr\n"
+" nowirecopyrect nowcr scr_area scr_skip scr_inc scr_keys\n"
+" scr_term scr_keyrepeat scr_parms scrollcopyrect scr\n"
+" noscrollcopyrect noscr noxrecord xrecord pointer_mode\n"
" pm input_skip input client_input speeds debug_pointer dp\n"
" nodebug_pointer nodp debug_keyboard dk nodebug_keyboard\n"
" nodk deferupdate defer wait_ui wait_bog nowait_bog wait\n"
@@ -28667,6 +29335,7 @@ static void print_help(int mode) {
scrollcopyrect_min_area,
scroll_skip_str0 ? scroll_skip_str0 : "(empty)",
scroll_term_str0,
+ max_keyrepeat_str0,
SCROLL_COPYRECT_PARMS,
pointer_mode_max, pointer_mode,
ui_skip,
@@ -28825,6 +29494,8 @@ static int limit_shm(void) {
limit = 1;
}
}
+ } else if (!strcmp(UT.sysname, "Darwin")) {
+ limit = 1;
}
if (limit && ! quiet) {
fprintf(stderr, "reducing shm usage on %s %s (adding "
@@ -29455,12 +30126,20 @@ int main(int argc, char* argv[]) {
} else if (!strcmp(arg, "-scr_keys")) {
CHECK_ARGC
scroll_key_list_str = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-scr_term")) {
+ CHECK_ARGC
+ scroll_term_str = strdup(argv[++i]);
+ } else if (!strcmp(arg, "-scr_keyrepeat")) {
+ CHECK_ARGC
+ max_keyrepeat_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-scr_parms")) {
CHECK_ARGC
scroll_copyrect_str = strdup(argv[++i]);
} else if (!strcmp(arg, "-debug_scroll")
|| !strcmp(arg, "-ds")) {
debug_scroll++;
+ } else if (!strcmp(arg, "-noxrecord")) {
+ noxrecord = 1;
} else if (!strcmp(arg, "-pointer_mode")
|| !strcmp(arg, "-pm")) {
char *p, *s;
@@ -29868,6 +30547,7 @@ int main(int argc, char* argv[]) {
}
initialize_scroll_matches();
initialize_scroll_term();
+ initialize_max_keyrepeat();
/* increase rfbwait if threaded */
if (use_threads && ! got_rfbwait) {
@@ -30384,7 +31064,7 @@ int main(int argc, char* argv[]) {
* input is not processed) we tell the server to process our
* requests during all grabs:
*/
- disable_grabserver(dpy);
+ disable_grabserver(dpy, 0);
/* check for RECORD */
if (! XRecordQueryVersion_wr(dpy, &maj, &min)) {
@@ -30508,7 +31188,6 @@ int main(int argc, char* argv[]) {
initialize_signals();
-
initialize_speeds();
initialize_keyboard_and_pointer();
@@ -30562,5 +31241,3 @@ int main(int argc, char* argv[]) {
#undef argc
#undef argv
}
-
-