Commit ae59284a authored by runge's avatar runge

x11vnc: scrolling: grabserver, autorepeat throttling, mouse wheel, fix onetile

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