Commit 52ba8bfb authored by runge's avatar runge

x11vnc: -cursor change shape handling, configure.ac: add more macros for X extensions

parent 3a4f41f6
2004-08-29 Karl Runge <runge@karlrunge.com>
* x11vnc: changes in cursor shape handling: use rfbSetCursor()
* cursor shape options: -cursor, -cursor (X|some|most)
* -vncconnect the default.
* configure.ac: add more macros for X extensions.
2004-08-15 Karl Runge <runge@karlrunge.com> 2004-08-15 Karl Runge <runge@karlrunge.com>
* x11vnc: -overlay to fix colors with Sun 8+24 overlay visuals. * x11vnc: -overlay to fix colors with Sun 8+24 overlay visuals.
* -sid option. * -sid option.
......
...@@ -39,29 +39,62 @@ AM_CONDITIONAL(WITH_FFMPEG, test ! -z "$with_ffmpeg") ...@@ -39,29 +39,62 @@ AM_CONDITIONAL(WITH_FFMPEG, test ! -z "$with_ffmpeg")
# Checks for X libraries # Checks for X libraries
HAVE_X="false" HAVE_X="false"
AC_PATH_XTRA AC_PATH_XTRA
AH_TEMPLATE(HAVE_XSHM, [MIT-SHM extension build environment present])
AH_TEMPLATE(HAVE_XTEST, [XTEST extension build environment present])
AH_TEMPLATE(HAVE_XKEYBOARD, [XKEYBOARD extension build environment present]) AH_TEMPLATE(HAVE_XKEYBOARD, [XKEYBOARD extension build environment present])
AH_TEMPLATE(HAVE_LIBXINERAMA, [XINERAMA extension build environment present]) AH_TEMPLATE(HAVE_LIBXINERAMA, [XINERAMA extension build environment present])
AH_TEMPLATE(HAVE_LIBXRANDR, [XRANDR extension build environment present])
AH_TEMPLATE(HAVE_LIBXFIXES, [XFIXES extension build environment present])
AH_TEMPLATE(HAVE_LIBXDAMAGE, [XDAMAGE extension build environment present])
if test "$X_CFLAGS" != "-DX_DISPLAY_MISSING"; then if test "$X_CFLAGS" != "-DX_DISPLAY_MISSING"; then
saved_CPPFLAGS="$CPPFLAGS" AC_CHECK_LIB(X11, XGetImage, HAVE_X="true",
CPPFLAGS="$CPPFLAGS $X_CFLAGS" HAVE_X="false",
AC_CHECK_HEADER(X11/XKBlib.h, HAVE_XKBLIB_H="true", $X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS)
HAVE_XKBLIB_H="false", [#include <X11/Xlib.h>])
CPPFLAGS="$saved_CPPFLAGS" if test $HAVE_X = "true"; then
if test $HAVE_XKBLIB_H = "true"; then X_PRELIBS="$X_PRELIBS -lXext"
AC_CHECK_LIB(X11, XkbSelectEvents,
[AC_DEFINE(HAVE_XKEYBOARD)], , AC_CHECK_LIB(Xext, XShmGetImage,
[AC_DEFINE(HAVE_XSHM)], ,
$X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS) $X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS)
fi
AC_CHECK_LIB(Xinerama, XineramaQueryScreens, AC_CHECK_LIB(Xtst, XTestFakeKeyEvent,
X_PRELIBS="$X_PRELIBS -lXinerama" X_PRELIBS="$X_PRELIBS -lXtst"
[AC_DEFINE(HAVE_LIBXINERAMA)], , [AC_DEFINE(HAVE_XTEST)], ,
$X_LIBS $X_PRELIBS -lX11 -lXext $X_EXTRA_LIBS) $X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS)
AC_CHECK_LIB(Xtst, XTestFakeKeyEvent, HAVE_XTEST="true",
HAVE_XTEST="false", saved_CPPFLAGS="$CPPFLAGS"
$X_LIBS $X_PRELIBS -lX11 -lXext $X_EXTRA_LIBS) CPPFLAGS="$CPPFLAGS $X_CFLAGS"
if test $HAVE_XTEST = "true"; then AC_CHECK_HEADER(X11/XKBlib.h, HAVE_XKBLIB_H="true",
X_LIBS="$X_LIBS $X_PRELIBS -lXtst -lXext -lX11 $X_EXTRA_LIBS" HAVE_XKBLIB_H="false", [#include <X11/Xlib.h>])
HAVE_X="true" CPPFLAGS="$saved_CPPFLAGS"
if test $HAVE_XKBLIB_H = "true"; then
AC_CHECK_LIB(X11, XkbSelectEvents,
[AC_DEFINE(HAVE_XKEYBOARD)], ,
$X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS)
fi
AC_CHECK_LIB(Xinerama, XineramaQueryScreens,
X_PRELIBS="$X_PRELIBS -lXinerama"
[AC_DEFINE(HAVE_LIBXINERAMA)], ,
$X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS)
AC_CHECK_LIB(Xrandr, XRRSelectInput,
X_PRELIBS="$X_PRELIBS -lXrandr"
[AC_DEFINE(HAVE_LIBXRANDR)], ,
$X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS)
AC_CHECK_LIB(Xfixes, XFixesGetCursorImage,
X_PRELIBS="$X_PRELIBS -lXfixes"
[AC_DEFINE(HAVE_LIBXFIXES)], ,
$X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS)
AC_CHECK_LIB(Xdamage, XDamageQueryExtension,
X_PRELIBS="$X_PRELIBS -lXdamage"
[AC_DEFINE(HAVE_LIBXDAMAGE)], ,
$X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS)
X_LIBS="$X_LIBS $X_PRELIBS -lX11 $X_EXTRA_LIBS"
fi fi
fi fi
AC_SUBST(X_LIBS) AC_SUBST(X_LIBS)
......
2004-08-29 Karl Runge <runge@karlrunge.com>
* remove old mouse patch code, now use rfbSetCursor (+ workarounds)
* changed cursor shape options (no more -mouse, ...) to '-cursor mode'
where 'mode' can be empty "X", "some", or "most". "some" adds
heuristics for two more cursors.
* -nocursorshape added.
* ifdef checks for XSHM and XTEST. Add *_wr wrappers as well.
* -vncconnect is now the default.
2004-08-15 Karl Runge <runge@karlrunge.com> 2004-08-15 Karl Runge <runge@karlrunge.com>
* -overlay option to fix color problems on Sun machines with 8+24 * -overlay option to fix color problems on Sun machines with 8+24
and 24+8 overlay visuals, uses Solaris XReadScreen(). and 24+8 overlay visuals, uses Solaris XReadScreen().
......
x11vnc README file Date: Sun Aug 15 16:30:33 EDT 2004 x11vnc README file Date: Sun Aug 29 15:33:42 EDT 2004
The following information is taken from these URLs: The following information is taken from these URLs:
...@@ -345,6 +345,9 @@ LDFLAGS="-L $JPEG/lib -R $JPEG/lib -L $ZLIB/lib -R $ZLIB/lib" ...@@ -345,6 +345,9 @@ LDFLAGS="-L $JPEG/lib -R $JPEG/lib -L $ZLIB/lib -R $ZLIB/lib"
CPPFLAGS="$CPPFLAGS -I /usr/openwin/include" CPPFLAGS="$CPPFLAGS -I /usr/openwin/include"
LDFLAGS="$LDFLAGS -L /usr/openwin/lib -R /usr/openwin/lib" LDFLAGS="$LDFLAGS -L /usr/openwin/lib -R /usr/openwin/lib"
# Everything needs to built with _REENTRANT for thread safe errno:
CPPFLAGS="$CPPFLAGS -D_REENTRANT"
export PATH CPPFLAGS LDFLAGS export PATH CPPFLAGS LDFLAGS
./configure ./configure
...@@ -488,14 +491,16 @@ ls -l ./x11vnc/x11vnc ...@@ -488,14 +491,16 @@ ls -l ./x11vnc/x11vnc
acceleration at the physical display and so likely defeats the acceleration at the physical display and so likely defeats the
purpose. Nevertheless this could be handy in some circumstances, purpose. Nevertheless this could be handy in some circumstances,
e.g. if the speed at the physical display was tolerable. e.g. if the speed at the physical display was tolerable.
Unfortunately it does not seem shadowfb can't be turned on and off Unfortunately it does not seem shadowfb can be turned on and off
dynamically... dynamically...
* Somewhat surprisingly, the X11 mouse (cursor) shape is write-only * Somewhat surprisingly, the X11 mouse (cursor) shape is write-only
and cannot be queried from the X server. So in x11vnc the cursor and cannot be queried from the X server. So in x11vnc the cursor
shape stays fixed at an arrow. (see the -mouseX option, however, shape stays fixed at an arrow. (see the "-cursor X" and other
for a partial hack for the root window). Also, on Solaris using options, however, for a partial hack for the root window, etc.).
the SUN_OVL overlay extension, x11vnc can show the correct mouse Also, on Solaris using the SUN_OVL overlay extension, x11vnc can
cursor when the -overlay is also supplied. show the correct mouse cursor when the -overlay option is also
supplied. For XFree86/Xorg, the XFIXES extension should help this
as well.
* Audio from applications is of course not redirected (separate * Audio from applications is of course not redirected (separate
redirectors do exist, e.g. esd). The XBell() "beeps" will work if redirectors do exist, e.g. esd). The XBell() "beeps" will work if
the X server supports the XKEYBOARD extension. (Note that on the X server supports the XKEYBOARD extension. (Note that on
...@@ -546,10 +551,10 @@ ls -l ./x11vnc/x11vnc ...@@ -546,10 +551,10 @@ ls -l ./x11vnc/x11vnc
start out OK, but after a while the colors are incorrect in certain start out OK, but after a while the colors are incorrect in certain
windows. windows.
[36]Q-10: Color problems: Why are the colors for some of the windows [36]Q-10: Color problems: Why are the colors for some windows messed
messed up in x11vnc? BTW, I have an X display that has nice overlay up in x11vnc? BTW, I have an X display that has nice
visuals of multiple color depths. E.g. there are both depth 8 and 24 overlay/multi-depth visuals of different color depths: e.g. there are
visuals available at the same time. both depth 8 and 24 visuals available at the same time.
[37]Q-11: How do I figure out the window id to supply to the -id [37]Q-11: How do I figure out the window id to supply to the -id
windowid option? windowid option?
...@@ -909,8 +914,8 @@ display :0 ...@@ -909,8 +914,8 @@ display :0
If so, there are a couple options. 1) Can you set the default visual If so, there are a couple options. 1) Can you set the default visual
on your display to be depth 24 TrueColor? Sun machines often have 8+24 on your display to be depth 24 TrueColor? Sun machines often have 8+24
overlay visuals, and you can make the default visual depth 24 overlay/multi-depth visuals, and you can make the default visual depth
TrueColor (see fbconfig(1) and Xsun(1)). 2) As of Feb/2004, in the 24 TrueColor (see fbconfig(1) and Xsun(1)). 2) As of Feb/2004, in the
libvncserver CVS, x11vnc has the -visual option to allow you to force libvncserver CVS, x11vnc has the -visual option to allow you to force
the framebuffer visual to whatever you want (this usually messes up the framebuffer visual to whatever you want (this usually messes up
the colors unless you are very careful). In this case, the option the colors unless you are very careful). In this case, the option
...@@ -940,16 +945,17 @@ display :0 ...@@ -940,16 +945,17 @@ display :0
non-zero in 8bpp PseudoColor on an obscure setup, and this option non-zero in 8bpp PseudoColor on an obscure setup, and this option
corrected the problems. corrected the problems.
Q-10: Color problems: Why are the colors for some of the windows Q-10: Color problems: Why are the colors for some windows messed up in
messed up in x11vnc? BTW, I have an X display that has nice overlay x11vnc? BTW, I have an X display that has nice overlay/multi-depth
visuals of multiple color depths. E.g. there are both depth 8 and 24 visuals of different color depths: e.g. there are both depth 8 and 24
visuals available at the same time. visuals available at the same time.
You may want to review the [97]previous question regarding 8 bpp You may want to review the [97]previous question regarding 8 bpp
PseudoColor. PseudoColor.
If that isn't the problem, run xdpyinfo to see what the default visual If that isn't the problem, run xdpyinfo(1) to see what the default
is. Does it have a depth of 8? If it does, can you possibly visual is and what the depths of the other visuals are. Does the
default visual have a depth of 8? If it does, can you possibly
re-configure your X server to make the depth 24 visual the default? If re-configure your X server to make the depth 24 visual the default? If
you can do it, this will save you a lot of grief WRT colors and x11vnc you can do it, this will save you a lot of grief WRT colors and x11vnc
(and for general usage too!). Here is how I do this on an old (and for general usage too!). Here is how I do this on an old
...@@ -958,12 +964,23 @@ display :0 ...@@ -958,12 +964,23 @@ display :0
and it works nicely (note: to log into console from the dtlogin and it works nicely (note: to log into console from the dtlogin
window, select "Options -> Command Line Login", then login and enter window, select "Options -> Command Line Login", then login and enter
the above command). If you have root permission, a more permanent and the above command). See the -dev section of the Xsun(1) manpage for a
convenient option is to put a line like: description of the above arguments. If you have root permission, a
more permanent and convenient thing to do is to record the arguments
in a line like:
:0 Local local_uid@console root /usr/openwin/bin/Xsun -dev /dev/fb defclass :0 Local local_uid@console root /usr/openwin/bin/Xsun -dev /dev/fb defclass
TrueColor defdepth 24 TrueColor defdepth 24
in /etc/dt/config/Xservers (see /usr/dt/config/Xservers). in /etc/dt/config/Xservers (see /usr/dt/config/Xservers). Also look at
the fbconfig(1) and related manpages (e.g. ffbconfig, m64config,
pgxconfig, SUNWjfb_config, etc ...) for hardware framebuffer settings
that may achieve the same effect. In general for non-Sun machines,
look at the "-cc class" and related options in your X server manpage
(perhaps Xserver(1)), it may allow modifying the default visual (e.g.
"-cc 4", see <X11/X.h> for the visual class numbers). On XFree86 some
video card drivers (e.g. Matrox mga) have settings like Option
"Overlay" "24,8" to support multi-depth overlays. For these, use the
"-cc 4" X server command line option to get a depth 24 default visual.
Another option is if the system with overlay visuals is a Sun system Another option is if the system with overlay visuals is a Sun system
running Solaris you can use the -overlay x11vnc option (Aug/2004) to running Solaris you can use the -overlay x11vnc option (Aug/2004) to
...@@ -973,16 +990,15 @@ TrueColor defdepth 24 ...@@ -973,16 +990,15 @@ TrueColor defdepth 24
mentioned by x11vnc users) that require the default depth be 8bpp, or mentioned by x11vnc users) that require the default depth be 8bpp, or
will use a 8bpp visual even if depth 24 visuals are available, and so will use a 8bpp visual even if depth 24 visuals are available, and so
the default depth workaround described in the previous paragraph is the default depth workaround described in the previous paragraph is
not sufficient. not sufficient for these apps.
Misc. notes on -overlay mode: An amusing by-product of -overlay mode Misc. notes on -overlay mode: An amusing by-product of -overlay mode
is that mouse cursor shape (e.g. use -X or -mouse options) is correct. is that mouse cursor shape is correct. The -overlay mode may be
The -overlay mode may be somewhat slower than normal mode due to the somewhat slower than normal mode due to the extra framebuffer
extra framebuffer manipulations that must be performed. Also, there is manipulations that must be performed. Also, there is a bug in that for
a bug in that for some popup menus, the windows they overlap will have some popup menus, the windows they overlap will have painting problems
painting problems while the popup is up (a workaround is to disable while the popup is up (a workaround is to disable SaveUnders by
SaveUnders by passing -su to Xsun, e.g. in your passing -su to Xsun, e.g. in your /etc/dt/config/Xservers file).
/etc/dt/config/Xservers file).
Still not working? Run xwininfo on the application with the messed up Still not working? Run xwininfo on the application with the messed up
colors to verify that the depth of its visual is different from the colors to verify that the depth of its visual is different from the
...@@ -1537,7 +1553,7 @@ mp/x11vnc_sh.log ...@@ -1537,7 +1553,7 @@ mp/x11vnc_sh.log
On Solaris you cannot have the bare number 5900 in /etc/inetd.conf, On Solaris you cannot have the bare number 5900 in /etc/inetd.conf,
you'll need to replace it with a word like x11vnc an then put you'll need to replace it with a word like x11vnc an then put
something like x11vnc 5900/tcp in /etc/services. something like "x11vnc 5900/tcp" in /etc/services.
Be sure to look at your /etc/hosts.allow and /etc/hosts.deny settings Be sure to look at your /etc/hosts.allow and /etc/hosts.deny settings
to limit the machines that can connect to this service (your to limit the machines that can connect to this service (your
...@@ -1589,11 +1605,11 @@ mp/x11vnc_sh.log ...@@ -1589,11 +1605,11 @@ mp/x11vnc_sh.log
believe this is because the cursor shape is often downloaded to the believe this is because the cursor shape is often downloaded to the
graphics hardware (video card), but I could be mistaken. graphics hardware (video card), but I could be mistaken.
A simple kludge is provided by the -mouseX option that changes the A simple kludge is provided by the "-cursor X" option that changes the
cursor when the mouse is on the root background (or any window has the cursor when the mouse is on the root background (or any window has the
same cursor as the root background). Note that desktops like GNOME or same cursor as the root background). Note that desktops like GNOME or
KDE often cover up the root background, so this won't work for those KDE often cover up the root background, so this won't work for those
cases. cases. Also see the "-cursor some" option for additional kludges.
It should be possible to apply some heuristics where x11vnc tries to It should be possible to apply some heuristics where x11vnc tries to
build up a table of cursors for the windows it sees, perhaps using a build up a table of cursors for the windows it sees, perhaps using a
...@@ -1602,7 +1618,8 @@ mp/x11vnc_sh.log ...@@ -1602,7 +1618,8 @@ mp/x11vnc_sh.log
Also note that as of Aug/2004 in the libvncserver CVS, on Solaris Also note that as of Aug/2004 in the libvncserver CVS, on Solaris
using the SUN_OVL overlay extension, x11vnc can show the correct mouse using the SUN_OVL overlay extension, x11vnc can show the correct mouse
cursor when the -overlay is also supplied. (-overlay has some other cursor when the -overlay is also supplied. (-overlay has some other
problems however, and can be slower). problems however, and can be slower). Plans are in the works to use
XFIXES for this on XFree86, Xorg, and Xsun.
Q-31: Why does the mouse arrow just stay in one corner in my Q-31: Why does the mouse arrow just stay in one corner in my
vncviewer, whereas my cursor (that does move) is just a dot? vncviewer, whereas my cursor (that does move) is just a dot?
...@@ -1612,6 +1629,10 @@ mp/x11vnc_sh.log ...@@ -1612,6 +1629,10 @@ mp/x11vnc_sh.log
with the -nocursor option to x11vnc if your viewer does not have this with the -nocursor option to x11vnc if your viewer does not have this
extension. extension.
Note: as of Aug/2004 in the libvncserver CVS this should be fixed: the
default for non-tightvnc viewers will be to draw the moving cursor
into the framebuffer. This can also be disabled via -nocursor.
Q-32: Can I take advantage of the TightVNC extension to the VNC Q-32: Can I take advantage of the TightVNC extension to the VNC
protocol where Cursor Positions Updates are sent back to all connected protocol where Cursor Positions Updates are sent back to all connected
clients (i.e. passive viewers can see the mouse cursor being moved clients (i.e. passive viewers can see the mouse cursor being moved
...@@ -1619,7 +1640,9 @@ mp/x11vnc_sh.log ...@@ -1619,7 +1640,9 @@ mp/x11vnc_sh.log
Use the -cursorpos option when starting x11vnc. A VNC viewer must Use the -cursorpos option when starting x11vnc. A VNC viewer must
support the Cursor Positions Updates for the user to see the mouse support the Cursor Positions Updates for the user to see the mouse
motions (the TightVNC viewers support this). motions (the TightVNC viewers support this). As of Aug/2004 in the
libvncserver CVS -cursorpos is the default. See -nocursorpos and
-nocursorshape.
Q-33: Is it possible to swap the mouse buttons (e.g. left-handed Q-33: Is it possible to swap the mouse buttons (e.g. left-handed
operation), or arbitrarily remap them? How about mapping button clicks operation), or arbitrarily remap them? How about mapping button clicks
...@@ -1823,8 +1846,8 @@ ied) ...@@ -1823,8 +1846,8 @@ ied)
* If you just want to watch one (simple) window use -id (cuts down * If you just want to watch one (simple) window use -id (cuts down
extraneous polling and updates, but can be buggy or insufficient) extraneous polling and updates, but can be buggy or insufficient)
* Set -nosel (disables all clipboard selection exchange) * Set -nosel (disables all clipboard selection exchange)
* Do not use -mouse or -mouseX (repainting the remote mouse takes * Use -nocursor (repainting the remote cursor position and shape
resources and round trips) takes resources and round trips)
Q-39: How can I get my AltGr and Shift modifiers to work between Q-39: How can I get my AltGr and Shift modifiers to work between
keyboards for different languages? keyboards for different languages?
...@@ -2403,8 +2426,8 @@ x11vnc: a VNC server for real X displays ...@@ -2403,8 +2426,8 @@ 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 -help % x11vnc -help
x11vnc: allow VNC connections to real X11 displays. 0.6.3pre lastmod: 2004-08-1 x11vnc: allow VNC connections to real X11 displays. 0.6.3pre lastmod: 2004-08-2
5 9
Typical usage is: Typical usage is:
...@@ -2450,11 +2473,15 @@ Options: ...@@ -2450,11 +2473,15 @@ Options:
setting the XAUTHORITY environment varirable to "file" setting the XAUTHORITY environment varirable to "file"
before startup. See Xsecurity(7), xauth(1) man pages. before startup. See Xsecurity(7), xauth(1) man pages.
-id windowid Show the window corresponding to "windowid" not the -id windowid Show the window corresponding to "windowid" not
entire display. Warning: bugs! new toplevels missed!... the entire display. New windows like popup menus,
etc may not be seen, or will be clipped. x11vnc may
crash if the window changes size, is iconified, etc.
Use xwininfo(1) to get the window id. Primarily useful
for exporting very simple applications.
-sid windowid As -id, but instead of using the window directly it -sid windowid As -id, but instead of using the window directly it
shifts a root view to it: shows saveUnders menus, etc, shifts a root view to it: this shows saveUnders menus,
although they will be clipped if they extend beyond etc, although they will be clipped if they extend beyond
the window. the window.
-flashcmap In 8bpp indexed color, let the installed colormap flash -flashcmap In 8bpp indexed color, let the installed colormap flash
as the pointer moves from window to window (slow). as the pointer moves from window to window (slow).
...@@ -2465,11 +2492,12 @@ Options: ...@@ -2465,11 +2492,12 @@ Options:
packed with 8 for PseudoColor and 24 for TrueColor). packed with 8 for PseudoColor and 24 for TrueColor).
Currently -overlay only works on Solaris (it uses Currently -overlay only works on Solaris (it uses
XReadScreen(3X11)). There are still some problems with XReadScreen(3X11)). There is a problem with image
surrounding-region painting for popup menus (but not "bleeding" around transient popup menus (but not
for the popup menu itself); a workaround is to disable for the menu itself): a workaround is to disable
SaveUnders (pass -su to Xsun). Amusingly, if -overlay SaveUnders by passing the "-su" argument to Xsun
is used with -mouse, the mouse cursor shape is correct. (in /etc/dt/config/Xservers, say). Also note that,
the mouse cursor shape is exactly correct in this mode.
Use -overlay as a workaround for situations like these: Use -overlay as a workaround for situations like these:
Some legacy applications require the default visual Some legacy applications require the default visual
...@@ -2482,7 +2510,10 @@ Options: ...@@ -2482,7 +2510,10 @@ Options:
due to the extra image transformations required. due to the extra image transformations required.
For optimal performance do not use -overlay, but rather For optimal performance do not use -overlay, but rather
configure the X server so that the default visual is configure the X server so that the default visual is
depth 24 TrueColor and have all apps use that visual. depth 24 TrueColor and try to have all apps use that
visual (some apps have -use24 or -visual options).
-overlay_nocursor Sets -overlay, but does not try to draw the exact mouse
cursor shape using the overlay mechanism.
-visual n Experimental option: probably does not do what you -visual n Experimental option: probably does not do what you
think. It simply *forces* the visual used for the think. It simply *forces* the visual used for the
framebuffer; this may be a bad thing... It is useful for framebuffer; this may be a bad thing... It is useful for
...@@ -2492,9 +2523,10 @@ Options: ...@@ -2492,9 +2523,10 @@ Options:
for a list. If the string ends in ":m" for better for a list. If the string ends in ":m" for better
or for worse the visual depth is forced to be m. or for worse the visual depth is forced to be m.
-scale fraction Scale the framebuffer by factor "fraction". Values -scale fraction Scale the framebuffer by factor "fraction".
less than 1 shrink the fb. Note: image may not be sharp Values less than 1 shrink the fb. Note: image may not
and response may be slower. If "fraction" contains be sharp and response may be slower. Currently the
cursor shape is not scaled. If "fraction" contains
a decimal point "." it is taken as a floating point a decimal point "." it is taken as a floating point
number, alternatively the notation "m/n" may be used number, alternatively the notation "m/n" may be used
to denote fractions exactly, e.g. -scale 2/3. to denote fractions exactly, e.g. -scale 2/3.
...@@ -2504,7 +2536,7 @@ Options: ...@@ -2504,7 +2536,7 @@ Options:
If you just want a quick, rough scaling without If you just want a quick, rough scaling without
blending, append ":nb" to "fraction" (e.g. -scale blending, append ":nb" to "fraction" (e.g. -scale
1/3:nb). For compatibility with vncviewers the scaled 1/3:nb). For compatibility with vncviewers the scaled
width is adjusted to be a multiple of 4, to disable width is adjusted to be a multiple of 4: to disable
this use ":n4". More esoteric options: ":in" use this use ":n4". More esoteric options: ":in" use
interpolation scheme even when shrinking, ":pad", interpolation scheme even when shrinking, ":pad",
pad scaled width and height to be multiples of scaling pad scaled width and height to be multiples of scaling
...@@ -2524,9 +2556,10 @@ Options: ...@@ -2524,9 +2556,10 @@ Options:
periodically check for new hosts. The first line is periodically check for new hosts. The first line is
read and then the file is truncated. read and then the file is truncated.
-vncconnect Monitor the VNC_CONNECT X property set by the standard -vncconnect Monitor the VNC_CONNECT X property set by the standard
VNC program vncconnect(1). When the property is set -novncconnect VNC program vncconnect(1). When the property is
to host or host:port establish a reverse connection. set to "host" or "host:port" establish a reverse
Using xprop(1) instead of vncconnect may work, see FAQ. connection. Using xprop(1) instead of vncconnect may
work, see the FAQ. Default: -vncconnect
-inetd Launched by inetd(1): stdio instead of listening socket. -inetd Launched by inetd(1): stdio instead of listening socket.
Note: if you are not redirecting stderr to a log file Note: if you are not redirecting stderr to a log file
(via shell 2> or -o option) you must also specify the (via shell 2> or -o option) you must also specify the
...@@ -2617,16 +2650,18 @@ Options: ...@@ -2617,16 +2650,18 @@ Options:
-flipbyteorder Sometimes needed if remotely polled host has different -flipbyteorder Sometimes needed if remotely polled host has different
endianness. Ignored unless -noshm is set. endianness. Ignored unless -noshm is set.
-onetile Do not use the new copy_tiles() framebuffer mechanism, -onetile Do not use the new copy_tiles() framebuffer mechanism,
just use 1 shm tile for polling. Same as -old_copytile. just use 1 shm tile for polling. Limits shm segments
Limits shm segments used to 3. used to 3.
-blackout string Black out rectangles on the screen. "string" is a -blackout string Black out rectangles on the screen. "string" is a
comma separated list of WxH+X+Y type geometries for comma separated list of WxH+X+Y type geometries for
each rectangle. each rectangle.
-xinerama If your screen is composed of multiple monitors -xinerama If your screen is composed of multiple monitors
glued together via XINERAMA, and that screen is glued together via XINERAMA, and that screen is
non-rectangular this option will try to guess the areas non-rectangular this option will try to guess the
to black out (if your system has libXinerama). areas to black out (if your system has libXinerama).
In general on XINERAMA displays you may need to use the
-xwarppointer option if the mouse pointer misbehaves.
-o logfile Write stderr messages to file "logfile" instead of -o logfile Write stderr messages to file "logfile" instead of
to the terminal. Same as -logfile "file". to the terminal. Same as -logfile "file".
...@@ -2654,7 +2689,9 @@ Options: ...@@ -2654,7 +2689,9 @@ Options:
where a Keysym is bound to multiple keys (e.g. "<" + ">" where a Keysym is bound to multiple keys (e.g. "<" + ">"
and "," + "<" keys). Default: -modtweak and "," + "<" keys). Default: -modtweak
-xkb When in modtweak mode, use the XKEYBOARD extension -xkb When in modtweak mode, use the XKEYBOARD extension
(if it exists) to do the modifier tweaking. (if it exists) to do the modifier tweaking. This is
powerful and should be tried if there are still
keymapping problems when using the simpler -modtweak.
-skip_keycodes string Skip keycodes not on your keyboard but your X server -skip_keycodes string Skip keycodes not on your keyboard but your X server
thinks exist. Currently only applies to -xkb mode. thinks exist. Currently only applies to -xkb mode.
"string" is a comma separated list of decimal "string" is a comma separated list of decimal
...@@ -2701,17 +2738,70 @@ Options: ...@@ -2701,17 +2738,70 @@ Options:
back to clients. (PRIMARY is still set on received back to clients. (PRIMARY is still set on received
changes, however). changes, however).
-nocursor Do not have the VNC viewer show a local cursor. -cursor [mode] Sets how the pointer cursor shape (little icon at the
-mouse Draw a 2nd cursor at the current X pointer position. -nocursor mouse pointer) should be handled. The "mode" string
-mouseX As -mouse, but also draw an "X" when pointer is on is optional and is described below. The default
root background. is to show some sort of cursor shape(s). How this
-X Shorthand for -mouseX -nocursor. is done depends on the VNC viewer and the X server.
-xwarppointer Move the pointer with XWarpPointer() instead of XTEST Use -nocursor to disable cursor shapes completely.
(try as a workaround if pointer behaves poorly, e.g.
on touchscreens or other non-standard setups). Some VNC viewers support the TightVNC CursorPosUpdates
and CursorShapeUpdates extensions (cuts down on
network traffic by not having to send the cursor image
every time the pointer is moved), in which case these
extensions are used (see -nocursorshape and -nocursorpos
below). For other viewers the cursor shape is written
directly to the framebuffer every time the pointer is
moved or changed and gets sent along with the other
framebuffer updates. In this case, there will be
some lag between the vnc viewer pointer and the remote
cursor position.
If the X display supports retrieving the cursor shape
information from the X server, then the default
is to use that mode. On Solaris this requires
the SUN_OVL extension and the -overlay option to be
supplied. (see also the -overlay_nomouse option). (Soon)
on XFree86/Xorg the XFIXES extension is required.
Either can be disabled with -nocursor, and also some
values of the "mode" option below.
The "mode" string can be used to fine-tune the
displaying of cursor shapes. It can be used the
following ways:
"-cursor X" - when the cursor appears to be on the
root window, draw the familiar X shape. Some desktops
such as GNOME cover up the root window completely,
and so this will not work, try "X1", etc, to try to
shift the tree depth. On high latency links or slow
machines there will be a time lag between expected and
the actual cursor shape.
"-cursor some" - like "X" but use additional
heuristics to try to guess if the window should have
a windowmanager-like resizer cursor or a text input
I-beam cursor. This is a complete hack, but may be
useful in some situations because it provides a little
more feedback about the cursor shape.
"-cursor most" - try to show as many cursors as
possible. Often this will only be the same as "some".
On Solaris if XFIXES is not available, -overlay mode
will be used.
-nocursorshape Do not use the TightVNC CursorShapeUpdates extension
even if clients support it. See -cursor above.
-cursorpos Option -cursorpos enables sending the X cursor position -cursorpos Option -cursorpos enables sending the X cursor position
-nocursorpos back to all vnc clients that support the TightVNC -nocursorpos back to all vnc clients that support the TightVNC
CursorPosUpdates extension. Default: -cursorpos CursorPosUpdates extension. Other clients will be able
to see the pointer motions. Default: -cursorpos
-xwarppointer Move the pointer with XWarpPointer(3X) instead of XTEST
extension. Use this as a workaround if the pointer
motion behaves incorrectly, e.g. on touchscreens or
other non-standard setups. Also sometimes needed on
XINERAMA displays.
-buttonmap string String to remap mouse buttons. Format: IJK-LMN, this -buttonmap string String to remap mouse buttons. Format: IJK-LMN, this
maps buttons I -> L, etc., e.g. -buttonmap 13-31 maps buttons I -> L, etc., e.g. -buttonmap 13-31
...@@ -2800,7 +2890,8 @@ These options are passed to libvncserver: ...@@ -2800,7 +2890,8 @@ These options are passed to libvncserver:
Pretty wild huh? [1]Contact me if you have any questions or problems. Pretty wild huh? [1]Contact me if you have any questions or problems.
Personally, I use: Personally, I use:
x11vnc -rfbauth $HOME/.vnc/passwd -nap -flashcmap -cursorpos -norepeat x11vnc -rfbauth $HOME/.vnc/passwd -nap -flashcmap -cursor X -norepeat -add_keys
yms
(the -flashcmap only matters on old 8-bit X displays) (the -flashcmap only matters on old 8-bit X displays)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.TH X11VNC "1" "August 2004" "x11vnc " "User Commands" .TH X11VNC "1" "August 2004" "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.6.3pre, lastmod: 2004-08-15 version: 0.6.3pre, lastmod: 2004-08-29
.SH SYNOPSIS .SH SYNOPSIS
.B x11vnc .B x11vnc
[OPTION]... [OPTION]...
...@@ -63,14 +63,20 @@ man pages. ...@@ -63,14 +63,20 @@ man pages.
.PP .PP
\fB-id\fR \fIwindowid\fR \fB-id\fR \fIwindowid\fR
.IP .IP
Show the window corresponding to \fIwindowid\fR not the Show the window corresponding to \fIwindowid\fR not
entire display. Warning: bugs! new toplevels missed!... the entire display. New windows like popup menus,
etc may not be seen, or will be clipped. x11vnc may
crash if the window changes size, is iconified, etc.
Use
.IR xwininfo (1)
to get the window id. Primarily useful
for exporting very simple applications.
.PP .PP
\fB-sid\fR \fIwindowid\fR \fB-sid\fR \fIwindowid\fR
.IP .IP
As \fB-id,\fR but instead of using the window directly it As \fB-id,\fR but instead of using the window directly it
shifts a root view to it: shows saveUnders menus, etc, shifts a root view to it: this shows saveUnders menus,
although they will be clipped if they extend beyond etc, although they will be clipped if they extend beyond
the window. the window.
.PP .PP
\fB-flashcmap\fR \fB-flashcmap\fR
...@@ -90,11 +96,12 @@ and 24+8 overlay visuals (the 32 bits per pixel are ...@@ -90,11 +96,12 @@ and 24+8 overlay visuals (the 32 bits per pixel are
packed with 8 for PseudoColor and 24 for TrueColor). packed with 8 for PseudoColor and 24 for TrueColor).
.IP .IP
Currently \fB-overlay\fR only works on Solaris (it uses Currently \fB-overlay\fR only works on Solaris (it uses
XReadScreen(3X11)). There are still some problems with XReadScreen(3X11)). There is a problem with image
surrounding-region painting for popup menus (but not "bleeding" around transient popup menus (but not
for the popup menu itself); a workaround is to disable for the menu itself): a workaround is to disable
SaveUnders (pass \fB-su\fR to Xsun). Amusingly, if \fB-overlay\fR SaveUnders by passing the "-su" argument to Xsun
is used with \fB-mouse,\fR the mouse cursor shape is correct. (in /etc/dt/config/Xservers, say). Also note that,
the mouse cursor shape is exactly correct in this mode.
.IP .IP
Use \fB-overlay\fR as a workaround for situations like these: Use \fB-overlay\fR as a workaround for situations like these:
Some legacy applications require the default visual Some legacy applications require the default visual
...@@ -107,7 +114,13 @@ Under \fB-overlay,\fR performance will be somewhat degraded ...@@ -107,7 +114,13 @@ Under \fB-overlay,\fR performance will be somewhat degraded
due to the extra image transformations required. due to the extra image transformations required.
For optimal performance do not use \fB-overlay,\fR but rather For optimal performance do not use \fB-overlay,\fR but rather
configure the X server so that the default visual is configure the X server so that the default visual is
depth 24 TrueColor and have all apps use that visual. depth 24 TrueColor and try to have all apps use that
visual (some apps have \fB-use24\fR or \fB-visual\fR options).
.PP
\fB-overlay_nocursor\fR
.IP
Sets \fB-overlay,\fR but does not try to draw the exact mouse
cursor shape using the overlay mechanism.
.PP .PP
\fB-visual\fR \fIn\fR \fB-visual\fR \fIn\fR
.IP .IP
...@@ -124,9 +137,10 @@ or for worse the visual depth is forced to be m. ...@@ -124,9 +137,10 @@ or for worse the visual depth is forced to be m.
.PP .PP
\fB-scale\fR \fIfraction\fR \fB-scale\fR \fIfraction\fR
.IP .IP
Scale the framebuffer by factor \fIfraction\fR. Values Scale the framebuffer by factor \fIfraction\fR.
less than 1 shrink the fb. Note: image may not be sharp Values less than 1 shrink the fb. Note: image may not
and response may be slower. If \fIfraction\fR contains be sharp and response may be slower. Currently the
cursor shape is not scaled. If \fIfraction\fR contains
a decimal point "." it is taken as a floating point a decimal point "." it is taken as a floating point
number, alternatively the notation "m/n" may be used number, alternatively the notation "m/n" may be used
to denote fractions exactly, e.g. \fB-scale\fR 2/3. to denote fractions exactly, e.g. \fB-scale\fR 2/3.
...@@ -136,7 +150,7 @@ Scaling Options: can be added after \fIfraction\fR via ...@@ -136,7 +150,7 @@ Scaling Options: can be added after \fIfraction\fR via
If you just want a quick, rough scaling without If you just want a quick, rough scaling without
blending, append ":nb" to \fIfraction\fR (e.g. \fB-scale\fR blending, append ":nb" to \fIfraction\fR (e.g. \fB-scale\fR
1/3:nb). For compatibility with vncviewers the scaled 1/3:nb). For compatibility with vncviewers the scaled
width is adjusted to be a multiple of 4, to disable width is adjusted to be a multiple of 4: to disable
this use ":n4". More esoteric options: ":in" use this use ":n4". More esoteric options: ":in" use
interpolation scheme even when shrinking, ":pad", interpolation scheme even when shrinking, ":pad",
pad scaled width and height to be multiples of scaling pad scaled width and height to be multiples of scaling
...@@ -173,13 +187,17 @@ read and then the file is truncated. ...@@ -173,13 +187,17 @@ read and then the file is truncated.
\fB-vncconnect\fR \fB-vncconnect\fR
.IP .IP
Monitor the VNC_CONNECT X property set by the standard Monitor the VNC_CONNECT X property set by the standard
.PP
\fB-novncconnect\fR
.IP
VNC program VNC program
.IR vncconnect (1) .IR vncconnect (1)
. When the property is set . When the property is
to host or host:port establish a reverse connection. set to "host" or "host:port" establish a reverse
Using connection. Using
.IR xprop (1) .IR xprop (1)
instead of vncconnect may work, see FAQ. instead of vncconnect may
work, see the FAQ. Default: \fB-vncconnect\fR
.PP .PP
\fB-inetd\fR \fB-inetd\fR
.IP .IP
...@@ -306,8 +324,8 @@ endianness. Ignored unless \fB-noshm\fR is set. ...@@ -306,8 +324,8 @@ endianness. Ignored unless \fB-noshm\fR is set.
\fB-onetile\fR \fB-onetile\fR
.IP .IP
Do not use the new copy_tiles() framebuffer mechanism, Do not use the new copy_tiles() framebuffer mechanism,
just use 1 shm tile for polling. Same as \fB-old_copytile.\fR just use 1 shm tile for polling. Limits shm segments
Limits shm segments used to 3. used to 3.
.PP .PP
\fB-blackout\fR \fIstring\fR \fB-blackout\fR \fIstring\fR
.IP .IP
...@@ -319,8 +337,10 @@ each rectangle. ...@@ -319,8 +337,10 @@ each rectangle.
.IP .IP
If your screen is composed of multiple monitors If your screen is composed of multiple monitors
glued together via XINERAMA, and that screen is glued together via XINERAMA, and that screen is
non-rectangular this option will try to guess the areas non-rectangular this option will try to guess the
to black out (if your system has libXinerama). areas to black out (if your system has libXinerama).
In general on XINERAMA displays you may need to use the
\fB-xwarppointer\fR option if the mouse pointer misbehaves.
.PP .PP
\fB-o\fR \fIlogfile\fR \fB-o\fR \fIlogfile\fR
.IP .IP
...@@ -376,7 +396,9 @@ and "," + "<" keys). Default: \fB-modtweak\fR ...@@ -376,7 +396,9 @@ and "," + "<" keys). Default: \fB-modtweak\fR
\fB-xkb\fR \fB-xkb\fR
.IP .IP
When in modtweak mode, use the XKEYBOARD extension When in modtweak mode, use the XKEYBOARD extension
(if it exists) to do the modifier tweaking. (if it exists) to do the modifier tweaking. This is
powerful and should be tried if there are still
keymapping problems when using the simpler \fB-modtweak.\fR
.PP .PP
\fB-skip_keycodes\fR \fIstring\fR \fB-skip_keycodes\fR \fIstring\fR
.IP .IP
...@@ -453,34 +475,79 @@ Do not poll the PRIMARY selection for changes to send ...@@ -453,34 +475,79 @@ Do not poll the PRIMARY selection for changes to send
back to clients. (PRIMARY is still set on received back to clients. (PRIMARY is still set on received
changes, however). changes, however).
.PP .PP
\fB-nocursor\fR \fB-cursor\fR \fI[mode],\fR \fB-nocursor\fR
.IP .IP
Do not have the VNC viewer show a local cursor. Sets how the pointer cursor shape (little icon at the
.PP mouse pointer) should be handled. The "mode" string
\fB-mouse\fR is optional and is described below. The default
.IP is to show some sort of cursor shape(s). How this
Draw a 2nd cursor at the current X pointer position. is done depends on the VNC viewer and the X server.
.PP Use \fB-nocursor\fR to disable cursor shapes completely.
\fB-mouseX\fR .IP
.IP Some VNC viewers support the TightVNC CursorPosUpdates
As \fB-mouse,\fR but also draw an "X" when pointer is on and CursorShapeUpdates extensions (cuts down on
root background. network traffic by not having to send the cursor image
.PP every time the pointer is moved), in which case these
\fB-X\fR extensions are used (see \fB-nocursorshape\fR and \fB-nocursorpos\fR
.IP below). For other viewers the cursor shape is written
Shorthand for \fB-mouseX\fR \fB-nocursor.\fR directly to the framebuffer every time the pointer is
.PP moved or changed and gets sent along with the other
\fB-xwarppointer\fR framebuffer updates. In this case, there will be
.IP some lag between the vnc viewer pointer and the remote
Move the pointer with XWarpPointer() instead of XTEST cursor position.
(try as a workaround if pointer behaves poorly, e.g. .IP
on touchscreens or other non-standard setups). If the X display supports retrieving the cursor shape
information from the X server, then the default
is to use that mode. On Solaris this requires
the SUN_OVL extension and the \fB-overlay\fR option to be
supplied. (see also the \fB-overlay_nomouse\fR option). (Soon)
on XFree86/Xorg the XFIXES extension is required.
Either can be disabled with \fB-nocursor,\fR and also some
values of the "mode" option below.
.IP
The "mode" string can be used to fine-tune the
displaying of cursor shapes. It can be used the
following ways:
.IP
"-cursor X" - when the cursor appears to be on the
root window, draw the familiar X shape. Some desktops
such as GNOME cover up the root window completely,
and so this will not work, try "X1", etc, to try to
shift the tree depth. On high latency links or slow
machines there will be a time lag between expected and
the actual cursor shape.
.IP
"-cursor some" - like "X" but use additional
heuristics to try to guess if the window should have
a windowmanager-like resizer cursor or a text input
I-beam cursor. This is a complete hack, but may be
useful in some situations because it provides a little
more feedback about the cursor shape.
.IP
"-cursor most" - try to show as many cursors as
possible. Often this will only be the same as "some".
On Solaris if XFIXES is not available, \fB-overlay\fR mode
will be used.
.PP
\fB-nocursorshape\fR
.IP
Do not use the TightVNC CursorShapeUpdates extension
even if clients support it. See \fB-cursor\fR above.
.PP .PP
\fB-cursorpos,\fR \fB-nocursorpos\fR \fB-cursorpos,\fR \fB-nocursorpos\fR
.IP .IP
Option \fB-cursorpos\fR enables sending the X cursor position Option \fB-cursorpos\fR enables sending the X cursor position
back to all vnc clients that support the TightVNC back to all vnc clients that support the TightVNC
CursorPosUpdates extension. Default: \fB-cursorpos\fR CursorPosUpdates extension. Other clients will be able
to see the pointer motions. Default: \fB-cursorpos\fR
.PP
\fB-xwarppointer\fR
.IP
Move the pointer with XWarpPointer(3X) instead of XTEST
extension. Use this as a workaround if the pointer
motion behaves incorrectly, e.g. on touchscreens or
other non-standard setups. Also sometimes needed on
XINERAMA displays.
.PP .PP
\fB-buttonmap\fR \fIstring\fR \fB-buttonmap\fR \fIstring\fR
.IP .IP
......
...@@ -65,14 +65,10 @@ ...@@ -65,14 +65,10 @@
* cursor, but we cannot extract what the cursor is... * cursor, but we cannot extract what the cursor is...
* *
* Nevertheless, the current *position* of the remote X mouse pointer * Nevertheless, the current *position* of the remote X mouse pointer
* is shown with the -mouse option. Further, if -mouseX or -X is used, a * is shown with the -cursor option. Further, if -cursorX or -X is used, a
* trick is done to at least show the root window cursor vs non-root cursor. * trick is done to at least show the root window cursor vs non-root cursor.
* (perhaps some heuristic can be done to further distinguish cases...) * (perhaps some heuristic can be done to further distinguish cases...)
* *
* With -mouse there are occasionally some repainting errors involving
* big areas near the cursor. The mouse painting is in general a bit
* ragged and not very pleasant.
*
* Windows using visuals other than the default X visual may have * Windows using visuals other than the default X visual may have
* their colors messed up. When using 8bpp indexed color, the colormap * their colors messed up. When using 8bpp indexed color, the colormap
* is attempted to be followed, but may become out of date. Use the * is attempted to be followed, but may become out of date. Use the
...@@ -82,7 +78,7 @@ ...@@ -82,7 +78,7 @@
* On Sun hardware we try to work around this with -overlay. * On Sun hardware we try to work around this with -overlay.
* *
* Feature -id <windowid> can be picky: it can crash for things like the * Feature -id <windowid> can be picky: it can crash for things like the
* window not sufficiently mapped into server memory, use of -mouse, etc. * window not sufficiently mapped into server memory, use of -cursor, etc.
* SaveUnders menus, popups, etc will not be seen. * SaveUnders menus, popups, etc will not be seen.
* *
* Occasionally, a few tile updates can be missed leaving a patch of * Occasionally, a few tile updates can be missed leaving a patch of
...@@ -90,7 +86,8 @@ ...@@ -90,7 +86,8 @@
* which is no longer the default. * which is no longer the default.
* *
* There seems to be a serious bug with simultaneous clients when * There seems to be a serious bug with simultaneous clients when
* threaded, currently the only workaround in this case is -nothreads. * threaded, currently the only workaround in this case is -nothreads
* (which is now the default).
* *
*/ */
...@@ -108,17 +105,46 @@ ...@@ -108,17 +105,46 @@
/* -- x11vnc.h -- */ /* -- x11vnc.h -- */
/*
* At some point beyond 0.7pre remove these two definitions since we
* have them set in configure (for all users of this x11vnc.c file).
* Then move them to the comment below.
*/
#define LIBVNCSERVER_HAVE_XSHM
#define LIBVNCSERVER_HAVE_XTEST
/*
* If you are building in an older libvncserver tree with this newer
* x11vnc.c file you may need to uncomment some of these lines since
* your older libvncserver configure is not setting them.
*
* For LIBVNCSERVER_HAVE_LIBXINERAMA you may also need to add to the
* linking -lXinerama (by setting LDFLAGS=-lXinerama before configure).
*
#define LIBVNCSERVER_HAVE_LIBXINERAMA
#define LIBVNCSERVER_HAVE_XFIXES
#define LIBVNCSERVER_HAVE_XDAMAGE
*
*/
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#ifdef LIBVNCSERVER_HAVE_XSHM
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h> #include <X11/extensions/XShm.h>
#endif
#ifdef LIBVNCSERVER_HAVE_XTEST
#include <X11/extensions/XTest.h> #include <X11/extensions/XTest.h>
#endif
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
...@@ -147,22 +173,12 @@ ...@@ -147,22 +173,12 @@
#include <X11/extensions/transovl.h> #include <X11/extensions/transovl.h>
#endif #endif
/*
* Temporary kludge: to run with -xinerama define the following
* macro (uncomment) and be sure to link with -lXinerama
* (e.g. LDFLAGS=-lXinerama before configure). Support for this is
* being added to libvncserver 'configure.ac' so it will all be done
* automatically, but it won't be in users' build trees for a while,
* so one can do it manually here.
#define LIBVNCSERVER_HAVE_LIBXINERAMA
*/
#ifdef LIBVNCSERVER_HAVE_LIBXINERAMA #ifdef LIBVNCSERVER_HAVE_LIBXINERAMA
#include <X11/extensions/Xinerama.h> #include <X11/extensions/Xinerama.h>
#endif #endif
/* date +'lastmod: %Y-%m-%d' */ /* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.6.3pre lastmod: 2004-08-15"; char lastmod[] = "0.6.3pre lastmod: 2004-08-29";
/* X display info */ /* X display info */
...@@ -182,31 +198,41 @@ XImage *scanline; ...@@ -182,31 +198,41 @@ XImage *scanline;
XImage *fullscreen; XImage *fullscreen;
XImage **tile_row; /* for all possible row runs */ XImage **tile_row; /* for all possible row runs */
#ifndef LIBVNCSERVER_HAVE_XSHM
/*
* for simplicity, define these since we'll never use them
* under using_shm = 0.
*/
typedef struct {
int shmid; char *shmaddr; Bool readOnly;
} XShmSegmentInfo;
#endif
/* corresponding shm structures */ /* corresponding shm structures */
XShmSegmentInfo scanline_shm; XShmSegmentInfo scanline_shm;
XShmSegmentInfo fullscreen_shm; XShmSegmentInfo fullscreen_shm;
XShmSegmentInfo *tile_row_shm; /* for all possible row runs */ XShmSegmentInfo *tile_row_shm; /* for all possible row runs */
/* rfb info */ /* rfb screen info */
rfbScreenInfoPtr screen; rfbScreenInfoPtr screen;
rfbCursorPtr cursor;
char *main_fb; /* our copy of the X11 fb */ char *main_fb; /* our copy of the X11 fb */
char *rfb_fb; /* same as main_fb unless transformation */ char *rfb_fb; /* same as main_fb unless transformation */
int rfb_bytes_per_line;
int main_bytes_per_line; int main_bytes_per_line;
unsigned long main_red_mask, main_green_mask, main_blue_mask; unsigned long main_red_mask, main_green_mask, main_blue_mask;
unsigned short main_red_max, main_green_max, main_blue_max; unsigned short main_red_max, main_green_max, main_blue_max;
unsigned short main_red_shift, main_green_shift, main_blue_shift; unsigned short main_red_shift, main_green_shift, main_blue_shift;
int rfb_bytes_per_line;
/* scaling info */ /* scaling parameters */
int scaling = 0;
int scaling_noblend = 0;
int scaling_nomult4 = 0;
int scaling_pad = 0;
int scaling_interpolate = 0;
double scale_fac = 1.0; double scale_fac = 1.0;
int scaled_x = 0, scaled_y = 0; int scaling = 0;
int scale_numer = 0, scale_denom = 0; int scaling_noblend = 0; /* no blending option (very course) */
int scaling_nomult4 = 0; /* do not require width = n * 4 */
int scaling_pad = 0; /* pad out scaled sizes to fit denominator */
int scaling_interpolate = 0; /* use interpolation scheme when shrinking */
int scaled_x = 0, scaled_y = 0; /* dimensions of scaled display */
int scale_numer = 0, scale_denom = 0; /* n/m */
/* size of the basic tile unit that is polled for changes: */ /* size of the basic tile unit that is polled for changes: */
int tile_x = 32; int tile_x = 32;
...@@ -216,25 +242,6 @@ int ntiles, ntiles_x, ntiles_y; ...@@ -216,25 +242,6 @@ int ntiles, ntiles_x, ntiles_y;
/* arrays that indicate changed or checked tiles. */ /* arrays that indicate changed or checked tiles. */
unsigned char *tile_has_diff, *tile_tried; unsigned char *tile_has_diff, *tile_tried;
/* blacked-out region (-blackout, -xinerama) */
typedef struct bout {
int x1, y1, x2, y2;
} blackout_t;
#define BO_MAX 16
typedef struct tbout {
blackout_t bo[BO_MAX]; /* hardwired max rectangles. */
int cover;
int count;
} tile_blackout_t;
#define BLACKR_MAX 100
blackout_t blackr[BLACKR_MAX]; /* hardwired max blackouts */
int blackouts = 0;
tile_blackout_t *tile_blackout;
/* saved cursor */
int cur_save_x, cur_save_y, cur_save_w, cur_save_h, cur_saved = 0;
/* times of recent events */ /* times of recent events */
time_t last_event, last_input, last_client = 0; time_t last_event, last_input, last_client = 0;
...@@ -254,7 +261,6 @@ int shut_down = 0; ...@@ -254,7 +261,6 @@ int shut_down = 0;
char vnc_connect_str[VNC_CONNECT_MAX+1]; char vnc_connect_str[VNC_CONNECT_MAX+1];
Atom vnc_connect_prop = None; Atom vnc_connect_prop = None;
/* function prototypes (see filename comment above) */ /* function prototypes (see filename comment above) */
int all_clients_initialized(void); int all_clients_initialized(void);
...@@ -286,7 +292,14 @@ void initialize_xinerama(void); ...@@ -286,7 +292,14 @@ void initialize_xinerama(void);
void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client); void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
void myXTestFakeKeyEvent(Display*, KeyCode, Bool, time_t); void XTestFakeKeyEvent_wr(Display*, KeyCode, Bool, unsigned long);
void XTestFakeButtonEvent_wr(Display*, unsigned int, Bool, unsigned long);
void XTestFakeMotionEvent_wr(Display*, int, int, int, unsigned long);
int XTestGrabControl_wr(Display*, Bool);
Bool XTestCompareCurrentCursorWithWindow_wr(Display*, Window);
Bool XTestCompareCursorWithWindow_wr(Display*, Window, Cursor);
Bool XTestQueryExtension_wr(Display*, int*, int*, int*, int*);
void XTestDiscard_wr(Display*);
typedef struct hint { typedef struct hint {
/* location x, y, height, and width of a change-rectangle */ /* location x, y, height, and width of a change-rectangle */
...@@ -299,22 +312,24 @@ void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force); ...@@ -299,22 +312,24 @@ void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force);
enum rfbNewClientAction new_client(rfbClientPtr client); enum rfbNewClientAction new_client(rfbClientPtr client);
void nofb_hook(rfbClientPtr client); void nofb_hook(rfbClientPtr client);
void pointer(int mask, int x, int y, rfbClientPtr client); void pointer(int mask, int x, int y, rfbClientPtr client);
void cursor_position(int, int);
void read_vnc_connect_prop(void); void read_vnc_connect_prop(void);
void redraw_mouse(void);
void restore_mouse_patch(void);
void rfbPE(rfbScreenInfoPtr, long); void rfbPE(rfbScreenInfoPtr, long);
void rfbCFD(rfbScreenInfoPtr, long);
void scan_for_updates(void); void scan_for_updates(void);
void set_colormap(void); void set_colormap(void);
void set_offset(void); void set_offset(void);
void set_visual(char *vstring); void set_visual(char *vstring);
void set_cursor(int, int, int);
int get_which_cursor(void);
void shm_clean(XShmSegmentInfo *, XImage *); void shm_clean(XShmSegmentInfo *, XImage *);
void shm_delete(XShmSegmentInfo *); void shm_delete(XShmSegmentInfo *);
void update_mouse(void); void check_x11_pointer(void);
void watch_bell_event(void); void check_bell_event(void);
void watch_xevents(void); void check_xevents(void);
void xcut_receive(char *text, int len, rfbClientPtr client); void xcut_receive(char *text, int len, rfbClientPtr client);
...@@ -347,13 +362,14 @@ int xinerama = 0; /* -xinerama */ ...@@ -347,13 +362,14 @@ int xinerama = 0; /* -xinerama */
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;
int vnc_connect = 0; /* -vncconnect option */ int vnc_connect = 1; /* -vncconnect option */
int local_cursor = 1; /* whether the viewer draws a local cursor */ int show_cursor = 1; /* show cursor shapes */
int cursor_pos = 1; /* cursor position updates -cursorpos */ int show_multiple_cursors = 0; /* show X when on root background, etc */
int show_mouse = 0; /* display a cursor for the real mouse */ char *multiple_cursors_mode = "default";
int cursor_pos_updates = 1; /* cursor position updates -cursorpos */
int cursor_shape_updates = 1; /* cursor shape updates -nocursorshape */
int use_xwarppointer = 0; /* use XWarpPointer instead of XTestFake... */ int use_xwarppointer = 0; /* use XWarpPointer instead of XTestFake... */
int show_root_cursor = 0; /* show X when on root background */
int show_dragging = 1; /* process mouse movement events */ int show_dragging = 1; /* process mouse movement events */
int no_autorepeat = 0; /* turn off autorepeat with clients */ int no_autorepeat = 0; /* turn off autorepeat with clients */
int watch_bell = 1; /* watch for the bell using XKEYBOARD */ int watch_bell = 1; /* watch for the bell using XKEYBOARD */
...@@ -391,8 +407,16 @@ int sigpipe = 1; /* 0=skip, 1=ignore, 2=exit */ ...@@ -391,8 +407,16 @@ int sigpipe = 1; /* 0=skip, 1=ignore, 2=exit */
/* visual stuff for -visual override or -overlay */ /* visual stuff for -visual override or -overlay */
VisualID visual_id = (VisualID) 0; VisualID visual_id = (VisualID) 0;
int visual_depth = 0; int visual_depth = 0;
/* for -overlay mode on Solaris. X server draws cursor correctly. */
int overlay = 0; int overlay = 0;
int overlay_mouse = 0; int overlay_cursor = 1;
#ifdef LIBVNCSERVER_HAVE_XTEST
int xtest_present = 1;
#else
int xtest_present = 0;
#endif
/* tile heuristics: */ /* tile heuristics: */
double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */ double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */
...@@ -467,6 +491,18 @@ int nfix(int i, int n) { ...@@ -467,6 +491,18 @@ int nfix(int i, int n) {
return i; return i;
} }
void lowercase(char *str) {
char *p;
if (str == NULL) {
return;
}
p = str;
while (*p != '\0') {
*p = tolower(*p);
p++;
}
}
/* /*
* Kludge to interpose image gets and limit to a subset rectangle of * Kludge to interpose image gets and limit to a subset rectangle of
* the rootwin. This is the -sid option trying to work around invisible * the rootwin. This is the -sid option trying to work around invisible
...@@ -481,7 +517,9 @@ int rootshift = 0; ...@@ -481,7 +517,9 @@ int rootshift = 0;
y += off_y; \ y += off_y; \
} }
/* Wrappers for Image related X calls */ /*
* Wrappers for Image related X calls
*/
Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y, Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y,
unsigned long mask) { unsigned long mask) {
...@@ -489,7 +527,47 @@ Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y, ...@@ -489,7 +527,47 @@ Status XShmGetImage_wr(Display *disp, Drawable d, XImage *image, int x, int y,
/* The Solaris overlay stuff is all non-shm (using_shm = 0) */ /* The Solaris overlay stuff is all non-shm (using_shm = 0) */
#ifdef LIBVNCSERVER_HAVE_XSHM
return XShmGetImage(disp, d, image, x, y, mask); return XShmGetImage(disp, d, image, x, y, mask);
#else
return (Status) 0;
#endif
}
XImage *XShmCreateImage_wr(Display* disp, Visual* vis, unsigned int depth,
int format, char* data, XShmSegmentInfo* shminfo, unsigned int width,
unsigned int height) {
#ifdef LIBVNCSERVER_HAVE_XSHM
return XShmCreateImage(disp, vis, depth, format, data, shminfo,
width, height);
#else
return (XImage *) 0;
#endif
}
Status XShmAttach_wr(Display *disp, XShmSegmentInfo *shminfo) {
#ifdef LIBVNCSERVER_HAVE_XSHM
return XShmAttach(disp, shminfo);
#else
return (Status) 0;
#endif
}
Status XShmDetach_wr(Display *disp, XShmSegmentInfo *shminfo) {
#ifdef LIBVNCSERVER_HAVE_XSHM
return XShmDetach(disp, shminfo);
#else
return (Status) 0;
#endif
}
Bool XShmQueryExtension_wr(Display *disp) {
#ifdef LIBVNCSERVER_HAVE_XSHM
return XShmQueryExtension(disp);
#else
return False;
#endif
} }
XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y, XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y,
...@@ -502,7 +580,7 @@ XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y, ...@@ -502,7 +580,7 @@ XImage *XGetSubImage_wr(Display *disp, Drawable d, int x, int y,
if (overlay && dest_x == 0 && dest_y == 0) { if (overlay && dest_x == 0 && dest_y == 0) {
size_t size = dest_image->height * dest_image->bytes_per_line; size_t size = dest_image->height * dest_image->bytes_per_line;
XImage *xi = XReadScreen(disp, d, x, y, width, height, XImage *xi = XReadScreen(disp, d, x, y, width, height,
(Bool) overlay_mouse); (Bool) overlay_cursor);
/* /*
* There is extra overhead from memcpy and free... * There is extra overhead from memcpy and free...
...@@ -529,7 +607,7 @@ XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y, ...@@ -529,7 +607,7 @@ XImage *XGetImage_wr(Display *disp, Drawable d, int x, int y,
#ifdef SOLARIS #ifdef SOLARIS
if (overlay) { if (overlay) {
return XReadScreen(disp, d, x, y, width, height, return XReadScreen(disp, d, x, y, width, height,
(Bool) overlay_mouse); (Bool) overlay_cursor);
} }
#endif #endif
return XGetImage(disp, d, x, y, width, height, plane_mask, format); return XGetImage(disp, d, x, y, width, height, plane_mask, format);
...@@ -563,6 +641,100 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth, ...@@ -563,6 +641,100 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth,
width, height, bitmap_pad, bytes_per_line); width, height, bitmap_pad, bytes_per_line);
} }
/*
* wrappers for XTestFakeKeyEvent, etc..
*/
void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
unsigned long delay) {
if (debug_keyboard) {
rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n",
key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)),
down ? "down":"up");
}
if (! xtest_present) {
return;
}
if (down) {
last_keyboard_input = -key;
} else {
last_keyboard_input = key;
}
#ifdef LIBVNCSERVER_HAVE_XTEST
XTestFakeKeyEvent(dpy, key, down, delay);
#endif
}
void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press,
unsigned long delay) {
if (! xtest_present) {
return;
}
#ifdef LIBVNCSERVER_HAVE_XTEST
XTestFakeButtonEvent(dpy, button, is_press, delay);
#endif
}
void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y,
unsigned long delay) {
if (! xtest_present) {
return;
}
#ifdef LIBVNCSERVER_HAVE_XTEST
XTestFakeMotionEvent(dpy, screen, x, y, delay);
#endif
}
Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w) {
if (! xtest_present) {
return False;
}
#ifdef LIBVNCSERVER_HAVE_XTEST
return XTestCompareCurrentCursorWithWindow(dpy, w);
#else
return False;
#endif
}
Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor) {
if (! xtest_present) {
return False;
}
#ifdef LIBVNCSERVER_HAVE_XTEST
return XTestCompareCursorWithWindow(dpy, w, cursor);
#else
return False;
#endif
}
int XTestGrabControl_wr(Display* dpy, Bool impervious) {
if (! xtest_present) {
return 0;
}
#ifdef LIBVNCSERVER_HAVE_XTEST
return XTestGrabControl(dpy, impervious);
#else
return 0;
#endif
}
Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj,
int *min) {
#ifdef LIBVNCSERVER_HAVE_XTEST
return XTestQueryExtension(dpy, ev, er, maj, min);
#else
return False;
#endif
}
void XTestDiscard_wr(Display *dpy) {
if (! xtest_present) {
return;
}
#ifdef LIBVNCSERVER_HAVE_XTEST
XTestDiscard(dpy);
#endif
}
/* -- cleanup.c -- */ /* -- cleanup.c -- */
/* /*
...@@ -603,7 +775,7 @@ void clean_up_exit (int ret) { ...@@ -603,7 +775,7 @@ void clean_up_exit (int ret) {
autorepeat(1); autorepeat(1);
} }
X_LOCK; X_LOCK;
XTestDiscard(dpy); XTestDiscard_wr(dpy);
XCloseDisplay(dpy); XCloseDisplay(dpy);
X_UNLOCK; X_UNLOCK;
...@@ -847,54 +1019,6 @@ static int run_user_command(char *cmd, rfbClientPtr client) { ...@@ -847,54 +1019,6 @@ static int run_user_command(char *cmd, rfbClientPtr client) {
return rc; return rc;
} }
/*
* Kludge for -norepeat option: we turn off keystroke autorepeat in
* the X server when clients are connected. This may annoy people at
* the physical display. We do this because 'key down' and 'key up'
* user input events may be separated by 100s of ms due to screen fb
* processing or link latency, thereby inducing the X server to apply
* autorepeat when it should not. Since the *client* is likely doing
* keystroke autorepeating as well, it kind of makes sense to shut it
* off if no one is at the physical display...
*/
void autorepeat(int restore) {
XKeyboardState kstate;
XKeyboardControl kctrl;
static int save_auto_repeat = -1;
if (restore) {
if (save_auto_repeat < 0) {
return; /* nothing to restore */
}
X_LOCK;
/* read state and skip restore if equal (e.g. no clients) */
XGetKeyboardControl(dpy, &kstate);
if (kstate.global_auto_repeat == save_auto_repeat) {
X_UNLOCK;
return;
}
kctrl.auto_repeat_mode = save_auto_repeat;
XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl);
XFlush(dpy);
X_UNLOCK;
rfbLog("Restored X server key autorepeat to: %d\n",
save_auto_repeat);
} else {
X_LOCK;
XGetKeyboardControl(dpy, &kstate);
save_auto_repeat = kstate.global_auto_repeat;
kctrl.auto_repeat_mode = AutoRepeatModeOff;
XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl);
XFlush(dpy);
X_UNLOCK;
rfbLog("Disabled X server key autorepeat. (you can run the\n");
rfbLog("command: 'xset r on' to force it back on)\n");
}
}
/* /*
* callback for when a client disconnects * callback for when a client disconnects
...@@ -1907,7 +2031,7 @@ void clear_modifiers(int init) { ...@@ -1907,7 +2031,7 @@ void clear_modifiers(int init) {
rfbLog("clear_modifiers: up: %-10s (0x%x) " rfbLog("clear_modifiers: up: %-10s (0x%x) "
"keycode=0x%x\n", keystrs[i], keysym, keycode); "keycode=0x%x\n", keystrs[i], keysym, keycode);
} }
myXTestFakeKeyEvent(dpy, keycode, False, CurrentTime); XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime);
} }
XFlush(dpy); XFlush(dpy);
} }
...@@ -1925,12 +2049,61 @@ void clear_keys(void) { ...@@ -1925,12 +2049,61 @@ void clear_keys(void) {
if (keystate[k]) { if (keystate[k]) {
KeyCode keycode = (KeyCode) k; KeyCode keycode = (KeyCode) k;
rfbLog("clear_keys: keycode=%d\n", keycode); rfbLog("clear_keys: keycode=%d\n", keycode);
myXTestFakeKeyEvent(dpy, keycode, False, CurrentTime); XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime);
} }
} }
XFlush(dpy); XFlush(dpy);
} }
/*
* Kludge for -norepeat option: we turn off keystroke autorepeat in
* the X server when clients are connected. This may annoy people at
* the physical display. We do this because 'key down' and 'key up'
* user input events may be separated by 100s of ms due to screen fb
* processing or link latency, thereby inducing the X server to apply
* autorepeat when it should not. Since the *client* is likely doing
* keystroke autorepeating as well, it kind of makes sense to shut it
* off if no one is at the physical display...
*/
void autorepeat(int restore) {
XKeyboardState kstate;
XKeyboardControl kctrl;
static int save_auto_repeat = -1;
if (restore) {
if (save_auto_repeat < 0) {
return; /* nothing to restore */
}
X_LOCK;
/* read state and skip restore if equal (e.g. no clients) */
XGetKeyboardControl(dpy, &kstate);
if (kstate.global_auto_repeat == save_auto_repeat) {
X_UNLOCK;
return;
}
kctrl.auto_repeat_mode = save_auto_repeat;
XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl);
XFlush(dpy);
X_UNLOCK;
rfbLog("Restored X server key autorepeat to: %d\n",
save_auto_repeat);
} else {
X_LOCK;
XGetKeyboardControl(dpy, &kstate);
save_auto_repeat = kstate.global_auto_repeat;
kctrl.auto_repeat_mode = AutoRepeatModeOff;
XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl);
XFlush(dpy);
X_UNLOCK;
rfbLog("Disabled X server key autorepeat. (you can run the\n");
rfbLog("command: 'xset r on' to force it back on)\n");
}
}
static KeySym added_keysyms[0x100]; static KeySym added_keysyms[0x100];
int add_keysym(KeySym keysym) { int add_keysym(KeySym keysym) {
...@@ -2147,25 +2320,6 @@ void initialize_remap(char *infile) { ...@@ -2147,25 +2320,6 @@ void initialize_remap(char *infile) {
fclose(in); fclose(in);
} }
/*
* debugging wrapper for XTestFakeKeyEvent()
*/
void myXTestFakeKeyEvent(Display* dpy, KeyCode key, Bool down,
time_t cur_time) {
if (debug_keyboard) {
rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n",
key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)),
down ? "down":"up");
}
if (down) {
last_keyboard_input = -key;
} else {
last_keyboard_input = key;
}
XTestFakeKeyEvent(dpy, key, down, cur_time);
}
/* /*
* preliminary support for using the Xkb (XKEYBOARD) extension for handling * preliminary support for using the Xkb (XKEYBOARD) extension for handling
* user input. inelegant, slow, and incomplete currently... but initial * user input. inelegant, slow, and incomplete currently... but initial
...@@ -2847,7 +3001,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, ...@@ -2847,7 +3001,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
"inadvertent Multi_key from Shift " "inadvertent Multi_key from Shift "
"(doing %03d up now)\n", shift_is_down); "(doing %03d up now)\n", shift_is_down);
} }
myXTestFakeKeyEvent(dpy, shift_is_down, False, XTestFakeKeyEvent_wr(dpy, shift_is_down, False,
CurrentTime); CurrentTime);
} else { } else {
involves_multi_key = 0; involves_multi_key = 0;
...@@ -2859,7 +3013,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, ...@@ -2859,7 +3013,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
if (sentmods[i] == 0) continue; if (sentmods[i] == 0) continue;
dn = (Bool) needmods[i]; dn = (Bool) needmods[i];
if (dn) continue; if (dn) continue;
myXTestFakeKeyEvent(dpy, sentmods[i], dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime);
} }
for (j=0; j<8; j++) { for (j=0; j<8; j++) {
/* next, do the Mod downs */ /* next, do the Mod downs */
...@@ -2867,7 +3021,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, ...@@ -2867,7 +3021,7 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
if (sentmods[i] == 0) continue; if (sentmods[i] == 0) continue;
dn = (Bool) needmods[i]; dn = (Bool) needmods[i];
if (!dn) continue; if (!dn) continue;
myXTestFakeKeyEvent(dpy, sentmods[i], dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime);
} }
if (involves_multi_key) { if (involves_multi_key) {
...@@ -2879,14 +3033,14 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, ...@@ -2879,14 +3033,14 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
"inadvertent Multi_key from Shift " "inadvertent Multi_key from Shift "
"(doing %03d down now)\n", shift_is_down); "(doing %03d down now)\n", shift_is_down);
} }
myXTestFakeKeyEvent(dpy, shift_is_down, True, XTestFakeKeyEvent_wr(dpy, shift_is_down, True,
CurrentTime); CurrentTime);
} }
/* /*
* With the above modifier work done, send the actual keycode: * With the above modifier work done, send the actual keycode:
*/ */
myXTestFakeKeyEvent(dpy, Kc_f, (Bool) down, CurrentTime); XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime);
/* /*
* Now undo the modifier work: * Now undo the modifier work:
...@@ -2897,7 +3051,8 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, ...@@ -2897,7 +3051,8 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
if (sentmods[i] == 0) continue; if (sentmods[i] == 0) continue;
dn = (Bool) needmods[i]; dn = (Bool) needmods[i];
if (!dn) continue; if (!dn) continue;
myXTestFakeKeyEvent(dpy, sentmods[i], !dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn,
CurrentTime);
} }
for (j=7; j>=0; j--) { for (j=7; j>=0; j--) {
/* finally reverse the Mod ups we did */ /* finally reverse the Mod ups we did */
...@@ -2905,12 +3060,13 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym, ...@@ -2905,12 +3060,13 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
if (sentmods[i] == 0) continue; if (sentmods[i] == 0) continue;
dn = (Bool) needmods[i]; dn = (Bool) needmods[i];
if (dn) continue; if (dn) continue;
myXTestFakeKeyEvent(dpy, sentmods[i], !dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn,
CurrentTime);
} }
} else { /* for up case, hopefully just need to pop it up: */ } else { /* for up case, hopefully just need to pop it up: */
myXTestFakeKeyEvent(dpy, Kc_f, (Bool) down, CurrentTime); XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime);
} }
X_UNLOCK; X_UNLOCK;
} }
...@@ -3059,20 +3215,20 @@ static void tweak_mod(signed char mod, rfbBool down) { ...@@ -3059,20 +3215,20 @@ static void tweak_mod(signed char mod, rfbBool down) {
X_LOCK; X_LOCK;
if (is_shift && mod != 1) { if (is_shift && mod != 1) {
if (mod_state & LEFTSHIFT) { if (mod_state & LEFTSHIFT) {
myXTestFakeKeyEvent(dpy, left_shift_code, !dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, left_shift_code, !dn, CurrentTime);
} }
if (mod_state & RIGHTSHIFT) { if (mod_state & RIGHTSHIFT) {
myXTestFakeKeyEvent(dpy, right_shift_code, !dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, right_shift_code, !dn, CurrentTime);
} }
} }
if ( ! is_shift && mod == 1 ) { if ( ! is_shift && mod == 1 ) {
myXTestFakeKeyEvent(dpy, left_shift_code, dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, left_shift_code, dn, CurrentTime);
} }
if ( altgr && (mod_state & ALTGR) && mod != 2 ) { if ( altgr && (mod_state & ALTGR) && mod != 2 ) {
myXTestFakeKeyEvent(dpy, altgr, !dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, altgr, !dn, CurrentTime);
} }
if ( altgr && ! (mod_state & ALTGR) && mod == 2 ) { if ( altgr && ! (mod_state & ALTGR) && mod == 2 ) {
myXTestFakeKeyEvent(dpy, altgr, dn, CurrentTime); XTestFakeKeyEvent_wr(dpy, altgr, dn, CurrentTime);
} }
X_UNLOCK; X_UNLOCK;
if (debug_keyboard) { if (debug_keyboard) {
...@@ -3141,7 +3297,7 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, ...@@ -3141,7 +3297,7 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
} }
if ( k != NoSymbol ) { if ( k != NoSymbol ) {
X_LOCK; X_LOCK;
myXTestFakeKeyEvent(dpy, k, (Bool) down, CurrentTime); XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime);
X_UNLOCK; X_UNLOCK;
} }
...@@ -3219,8 +3375,8 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { ...@@ -3219,8 +3375,8 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
return; return;
} }
X_LOCK; X_LOCK;
XTestFakeButtonEvent(dpy, button, True, CurrentTime); XTestFakeButtonEvent_wr(dpy, button, True, CurrentTime);
XTestFakeButtonEvent(dpy, button, False, CurrentTime); XTestFakeButtonEvent_wr(dpy, button, False, CurrentTime);
XFlush(dpy); XFlush(dpy);
X_UNLOCK; X_UNLOCK;
return; return;
...@@ -3252,7 +3408,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { ...@@ -3252,7 +3408,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
} }
if ( k != NoSymbol ) { if ( k != NoSymbol ) {
myXTestFakeKeyEvent(dpy, k, (Bool) down, CurrentTime); XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime);
XFlush(dpy); XFlush(dpy);
} }
...@@ -3261,7 +3417,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { ...@@ -3261,7 +3417,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
/* -- pointer.c -- */ /* -- pointer.c -- */
/* /*
* pointer event handling routines. * pointer event (motion and button click) handling routines.
*/ */
typedef struct ptrremap { typedef struct ptrremap {
KeySym keysym; KeySym keysym;
...@@ -3325,7 +3481,9 @@ static void buttonparse(int from, char **s) { ...@@ -3325,7 +3481,9 @@ static void buttonparse(int from, char **s) {
if (sscanf(t, "0x%x", &i) == 1) { if (sscanf(t, "0x%x", &i) == 1) {
ksym = (KeySym) i; /* hex value */ ksym = (KeySym) i; /* hex value */
} else { } else {
X_LOCK;
ksym = XStringToKeysym(t); /* string value */ ksym = XStringToKeysym(t); /* string value */
X_UNLOCK;
} }
if (ksym == NoSymbol) { if (ksym == NoSymbol) {
/* see if Button<N> "keysym" was used: */ /* see if Button<N> "keysym" was used: */
...@@ -3348,6 +3506,7 @@ static void buttonparse(int from, char **s) { ...@@ -3348,6 +3506,7 @@ static void buttonparse(int from, char **s) {
/* /*
* XXX may not work with -modtweak or -xkb * XXX may not work with -modtweak or -xkb
*/ */
X_LOCK;
kcode = XKeysymToKeycode(dpy, ksym); kcode = XKeysymToKeycode(dpy, ksym);
pointer_map[from][n].keysym = ksym; pointer_map[from][n].keysym = ksym;
...@@ -3374,6 +3533,7 @@ static void buttonparse(int from, char **s) { ...@@ -3374,6 +3533,7 @@ static void buttonparse(int from, char **s) {
XKeysymToString(ksym), ksym, kcode, XKeysymToString(ksym), ksym, kcode,
pointer_map[from][n].down, pointer_map[from][n].down,
pointer_map[from][n].up); pointer_map[from][n].up);
X_UNLOCK;
} }
t = strtok(NULL, "+"); t = strtok(NULL, "+");
n++; n++;
...@@ -3442,6 +3602,7 @@ void initialize_pointer_map(char *pointer_remap) { ...@@ -3442,6 +3602,7 @@ void initialize_pointer_map(char *pointer_remap) {
X_LOCK; X_LOCK;
num_buttons = XGetPointerMapping(dpy, map, MAX_BUTTONS); num_buttons = XGetPointerMapping(dpy, map, MAX_BUTTONS);
X_UNLOCK;
if (num_buttons < 0) { if (num_buttons < 0) {
num_buttons = 0; num_buttons = 0;
...@@ -3500,30 +3661,37 @@ void initialize_pointer_map(char *pointer_remap) { ...@@ -3500,30 +3661,37 @@ void initialize_pointer_map(char *pointer_remap) {
} }
} }
} }
X_UNLOCK;
} }
/* /*
* Send a pointer event to the X server. * Send a pointer event to the X server.
*/ */
static void update_pointer(int mask, int x, int y) { static void update_x11_pointer(int mask, int x, int y) {
int i, mb; int i, mb;
X_LOCK; X_LOCK;
if (use_xwarppointer) {
if (! use_xwarppointer) { XWarpPointer(dpy, None, window, 0, 0, 0, 0, x+off_x, y+off_y);
XTestFakeMotionEvent(dpy, scr, x+off_x, y+off_y, CurrentTime);
} else { } else {
XWarpPointer(dpy, None, window, 0, 0, 0, 0, x+off_x, y+off_y); XTestFakeMotionEvent_wr(dpy, scr, x+off_x, y+off_y,
CurrentTime);
} }
X_UNLOCK;
cursor_x = x; cursor_x = x;
cursor_y = y; cursor_y = y;
/* record the x, y position for the rfb screen as well. */
cursor_position(x, y);
/* change the cursor shape if necessary */
set_cursor(x, y, get_which_cursor());
last_event = last_input = time(0); last_event = last_input = time(0);
X_LOCK;
/* look for buttons that have be clicked or released: */
for (i=0; i < MAX_BUTTONS; i++) { for (i=0; i < MAX_BUTTONS; i++) {
/* look for buttons that have be clicked or released: */
if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) { if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) {
int k; int k;
if (debug_pointer) { if (debug_pointer) {
...@@ -3552,7 +3720,7 @@ static void update_pointer(int mask, int x, int y) { ...@@ -3552,7 +3720,7 @@ static void update_pointer(int mask, int x, int y) {
" %s (event %d)\n", mb, bmask " %s (event %d)\n", mb, bmask
? "down" : "up", k+1); ? "down" : "up", k+1);
} }
XTestFakeButtonEvent(dpy, mb, (mask & (1<<i)) XTestFakeButtonEvent_wr(dpy, mb, (mask & (1<<i))
? True : False, CurrentTime); ? True : False, CurrentTime);
} else { } else {
/* sent keysym up or down */ /* sent keysym up or down */
...@@ -3574,11 +3742,11 @@ static void update_pointer(int mask, int x, int y) { ...@@ -3574,11 +3742,11 @@ static void update_pointer(int mask, int x, int y) {
dpy, key, 0))); dpy, key, 0)));
} }
if (down) { if (down) {
myXTestFakeKeyEvent(dpy, key, True, XTestFakeKeyEvent_wr(dpy, key, True,
CurrentTime); CurrentTime);
} }
if (up) { if (up) {
myXTestFakeKeyEvent(dpy, key, False, XTestFakeKeyEvent_wr(dpy, key, False,
CurrentTime); CurrentTime);
} }
} }
...@@ -3605,24 +3773,38 @@ static void update_pointer(int mask, int x, int y) { ...@@ -3605,24 +3773,38 @@ static void update_pointer(int mask, int x, int y) {
/* /*
* Actual callback from libvncserver when it gets a pointer event. * Actual callback from libvncserver when it gets a pointer event.
* This may queue pointer events rather than sending them immediately
* to the X server. (see update_x11_pointer())
*/ */
void pointer(int mask, int x, int y, rfbClientPtr client) { void pointer(int mask, int x, int y, rfbClientPtr client) {
if (debug_pointer && mask >= 0) { if (debug_pointer && mask >= 0) {
rfbLog("pointer(mask: 0x%x, x:%4d, y:%4d)\n", mask, x, y); static int show_motion = -1;
if (show_motion == -1) {
if (getenv("X11VNC_DB_NOMOTION")) {
show_motion = 0;
} else {
show_motion = 1;
}
}
if (show_motion) {
rfbLog("pointer(mask: 0x%x, x:%4d, y:%4d)\n",
mask, x, y);
}
} }
if (view_only) { if (view_only) {
return; return;
} }
if (client->viewOnly) { if (client && client->viewOnly) {
return; return;
} }
if (scaling) { if (scaling) {
/* map from rfb size to X11 size: */
x = ((double) x / scaled_x) * dpy_x; x = ((double) x / scaled_x) * dpy_x;
if (x >= dpy_x) x = dpy_x - 1; x = nfix(x, dpy_x);
y = ((double) y / scaled_y) * dpy_y; y = ((double) y / scaled_y) * dpy_y;
if (y >= dpy_y) y = dpy_y - 1; y = nfix(y, dpy_y);
} }
if (mask >= 0) { if (mask >= 0) {
...@@ -3698,7 +3880,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) { ...@@ -3698,7 +3880,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
if (debug_pointer) { if (debug_pointer) {
rfbLog("pointer(): sending event %d\n", i+1); rfbLog("pointer(): sending event %d\n", i+1);
} }
update_pointer(ev[i][0], ev[i][1], ev[i][2]); update_x11_pointer(ev[i][0], ev[i][1], ev[i][2]);
} }
if (nevents && dt > maxwait) { if (nevents && dt > maxwait) {
X_LOCK; X_LOCK;
...@@ -3720,7 +3902,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) { ...@@ -3720,7 +3902,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
} }
/* update the X display with the event: */ /* update the X display with the event: */
update_pointer(mask, x, y); update_x11_pointer(mask, x, y);
} }
/* -- xkb_bell.c -- */ /* -- xkb_bell.c -- */
...@@ -3782,7 +3964,7 @@ void initialize_watch_bell(void) { ...@@ -3782,7 +3964,7 @@ void initialize_watch_bell(void) {
* We call this periodically to process any bell events that have * We call this periodically to process any bell events that have
* taken place. * taken place.
*/ */
void watch_bell_event(void) { void check_bell_event(void) {
XEvent xev; XEvent xev;
XkbAnyEvent *xkb_ev; XkbAnyEvent *xkb_ev;
int got_bell = 0; int got_bell = 0;
...@@ -3804,7 +3986,7 @@ void watch_bell_event(void) { ...@@ -3804,7 +3986,7 @@ void watch_bell_event(void) {
if (got_bell) { if (got_bell) {
if (! all_clients_initialized()) { if (! all_clients_initialized()) {
rfbLog("watch_bell_event: not sending bell: " rfbLog("check_bell_event: not sending bell: "
"uninitialized clients\n"); "uninitialized clients\n");
} else { } else {
rfbSendBell(screen); rfbSendBell(screen);
...@@ -3812,7 +3994,7 @@ void watch_bell_event(void) { ...@@ -3812,7 +3994,7 @@ void watch_bell_event(void) {
} }
} }
#else #else
void watch_bell_event(void) {} void check_bell_event(void) {}
#endif #endif
/* -- selection.c -- */ /* -- selection.c -- */
...@@ -4060,7 +4242,7 @@ static void selection_send(XEvent *ev) { ...@@ -4060,7 +4242,7 @@ static void selection_send(XEvent *ev) {
* This routine is periodically called to check for selection related * This routine is periodically called to check for selection related
* and other X11 events and respond to them as needed. * and other X11 events and respond to them as needed.
*/ */
void watch_xevents(void) { void check_xevents(void) {
XEvent xev; XEvent xev;
static int first = 1, sent_some_sel = 0; static int first = 1, sent_some_sel = 0;
static time_t last_request = 0; static time_t last_request = 0;
...@@ -4245,10 +4427,11 @@ typedef struct cursor_info { ...@@ -4245,10 +4427,11 @@ typedef struct cursor_info {
int wx, wy; /* size of cursor */ int wx, wy; /* size of cursor */
int sx, sy; /* shift to its centering point */ int sx, sy; /* shift to its centering point */
int reverse; /* swap black and white */ int reverse; /* swap black and white */
rfbCursorPtr rfb;
} cursor_info_t; } cursor_info_t;
/* main cursor */ /* main cursor */
static char* cur_data = static char* curs_arrow_data =
" " " "
" x " " x "
" xx " " xx "
...@@ -4268,7 +4451,7 @@ static char* cur_data = ...@@ -4268,7 +4451,7 @@ static char* cur_data =
" " " "
" "; " ";
static char* cur_mask = static char* curs_arrow_mask =
"xx " "xx "
"xxx " "xxx "
"xxxx " "xxxx "
...@@ -4287,16 +4470,13 @@ static char* cur_mask = ...@@ -4287,16 +4470,13 @@ static char* cur_mask =
" xx " " xx "
" " " "
" "; " ";
#define CUR_SIZE 18 static cursor_info_t cur_arrow = {NULL, NULL, 18, 18, 0, 0, 0, NULL};
#define CUR_DATA cur_data
#define CUR_MASK cur_mask
static cursor_info_t cur0 = {NULL, NULL, CUR_SIZE, CUR_SIZE, 0, 0, 0};
/* /*
* It turns out we can at least detect mouse is on the root window so * It turns out we can at least detect mouse is on the root window so
* show it (under -mouseX or -X) with this familiar cursor... * show it (under -cursorX or -X) with this familiar cursor...
*/ */
static char* root_data = static char* curs_root_data =
" " " "
" " " "
" xxx xxx " " xxx xxx "
...@@ -4316,7 +4496,7 @@ static char* root_data = ...@@ -4316,7 +4496,7 @@ static char* root_data =
" " " "
" "; " ";
static char* root_mask = static char* curs_root_mask =
" " " "
" xxxx xxxx " " xxxx xxxx "
" xxxxx xxxxx " " xxxxx xxxxx "
...@@ -4335,172 +4515,487 @@ static char* root_mask = ...@@ -4335,172 +4515,487 @@ static char* root_mask =
" xxxxx xxxxx " " xxxxx xxxxx "
" xxxx xxxx " " xxxx xxxx "
" "; " ";
static cursor_info_t cur1 = {NULL, NULL, 18, 18, 8, 8, 1}; static cursor_info_t cur_root = {NULL, NULL, 18, 18, 8, 8, 1, NULL};
static char* curs_fleur_data =
" "
" xx "
" xxxx "
" xxxxxx "
" xx "
" x xx x "
" xx xx xx "
" xxxxxxxxxxxxxx "
" xxxxxxxxxxxxxx "
" xx xx xx "
" x xx x "
" xx "
" xxxxxx "
" xxxx "
" xx "
" ";
static char* curs_fleur_mask =
" xxxx "
" xxxxx "
" xxxxxx "
" xxxxxxxx "
" x xxxxxx x "
" xxx xxxx xxx "
"xxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxx"
" xxx xxxx xxx "
" x xxxxxx x "
" xxxxxxxx "
" xxxxxx "
" xxxx "
" xxxx ";
static cursor_info_t cur_fleur = {NULL, NULL, 16, 16, 8, 8, 1, NULL};
static char* curs_plus_data =
" "
" xx "
" xx "
" xx "
" xx "
" xxxxxxxxxx "
" xxxxxxxxxx "
" xx "
" xx "
" xx "
" xx "
" ";
static char* curs_plus_mask =
" xxxx "
" xxxx "
" xxxx "
" xxxx "
"xxxxxxxxxxxx"
"xxxxxxxxxxxx"
"xxxxxxxxxxxx"
"xxxxxxxxxxxx"
" xxxx "
" xxxx "
" xxxx "
" xxxx ";
static cursor_info_t cur_plus = {NULL, NULL, 12, 12, 5, 6, 1, NULL};
static char* curs_xterm_data =
" "
" xxx xxx "
" xxx "
" x "
" x "
" x "
" x "
" x "
" x "
" x "
" x "
" x "
" x "
" xxx "
" xxx xxx "
" ";
static char* curs_xterm_mask =
" xxxx xxxx "
" xxxxxxxxx "
" xxxxxxxxx "
" xxxxx "
" xxx "
" xxx "
" xxx "
" xxx "
" xxx "
" xxx "
" xxx "
" xxx "
" xxxxx "
" xxxxxxxxx "
" xxxxxxxxx "
" xxxx xxxx ";
static cursor_info_t cur_xterm = {NULL, NULL, 16, 16, 8, 8, 1, NULL};
enum cursor_names {
CURS_ARROW = 0,
CURS_ROOT,
CURS_WM,
CURS_TERM
};
static cursor_info_t *cursors[2]; static cursor_info_t *cursors[10];
static void setup_cursors(void) { static void setup_cursors(void) {
/* TODO clean this up if we ever do more cursors... */ /* TODO clean this up if we ever do more cursors... */
rfbCursorPtr rfb_curs;
int i, n = 0;
cur_arrow.data = curs_arrow_data;
cur_arrow.mask = curs_arrow_mask;
cur_root.data = curs_root_data;
cur_root.mask = curs_root_mask;
cur_plus.data = curs_plus_data;
cur_plus.mask = curs_plus_mask;
cur_fleur.data = curs_fleur_data;
cur_fleur.mask = curs_fleur_mask;
cur_xterm.data = curs_xterm_data;
cur_xterm.mask = curs_xterm_mask;
cur0.data = cur_data; cursors[CURS_ARROW] = &cur_arrow; n++;
cur0.mask = cur_mask; cursors[CURS_ROOT] = &cur_root; n++;
cursors[CURS_WM] = &cur_fleur; n++;
cursors[CURS_TERM] = &cur_xterm; n++;
cur1.data = root_data; for (i=0; i<n; i++) {
cur1.mask = root_mask; cursor_info_t *ci = cursors[i];
ci->data = strdup(ci->data);
ci->mask = strdup(ci->mask);
rfb_curs = rfbMakeXCursor(ci->wx, ci->wy, ci->data, ci->mask);
if (ci->reverse) {
rfb_curs->foreRed = 0x0000;
rfb_curs->foreGreen = 0x0000;
rfb_curs->foreBlue = 0x0000;
rfb_curs->backRed = 0xffff;
rfb_curs->backGreen = 0xffff;
rfb_curs->backBlue = 0xffff;
}
rfb_curs->xhot = ci->sx;
rfb_curs->yhot = ci->sy;
rfb_curs->cleanup = FALSE;
rfb_curs->cleanupSource = FALSE;
rfb_curs->cleanupMask = FALSE;
rfb_curs->cleanupRichSource = FALSE;
cursors[0] = &cur0; ci->rfb = rfb_curs;
cursors[1] = &cur1; }
} }
typedef struct win_str_info {
char *wm_name;
char *res_name;
char *res_class;
} win_str_info_t;
/* /*
* data and functions for -mouse real pointer position updates * Descends window tree at pointer until the window cursor matches the current
* cursor. So far only used to detect if mouse is on root background or not.
* (returns 0 in that case, 1 otherwise).
*
* It seems impossible to do, but if the actual cursor could ever be
* determined we might want to hash that info on window ID or something...
*/ */
static char cur_save[(4 * CUR_SIZE * CUR_SIZE)]; void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) {
static int cur_save_cx, cur_save_cy, cur_save_which; Window r, c;
int i, rx, ry, wx, wy;
unsigned int mask;
Window wins[10];
int descend, maxtries = 10;
char *name, a;
static XClassHint *classhint = NULL;
int nm_info = 1;
XErrorHandler old_handler;
X_LOCK;
a = multiple_cursors_mode[0];
if (a == 'd' || a == 'X') {
nm_info = 0;
}
*(winfo->wm_name) = '\0';
*(winfo->res_name) = '\0';
*(winfo->res_class) = '\0';
/* some times a window can go away before we get to it */
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
c = window;
descend = -1;
while (c) {
wins[++descend] = c;
if (descend >= maxtries - 1) {
break;
}
if ( XTestCompareCurrentCursorWithWindow_wr(dpy, c) ) {
break;
}
XQueryPointer(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &mask);
}
if (nm_info) {
int got_wm_name = 0, got_res_name = 0, got_res_class = 0;
if (! classhint) {
classhint = XAllocClassHint();
}
for (i = descend; i >=0; i--) {
c = wins[i];
if (! c) {
continue;
}
if (! got_wm_name && XFetchName(dpy, c, &name)) {
if (name) {
if (*name != '\0') {
strcpy(winfo->wm_name, name);
got_wm_name = 1;
}
XFree(name);
}
}
if (classhint && (! got_res_name || ! got_res_class)) {
if (XGetClassHint(dpy, c, classhint)) {
char *p;
p = classhint->res_name;
if (p) {
if (*p != '\0' && ! got_res_name) {
strcpy(winfo->res_name, p);
got_res_name = 1;
}
XFree(p);
classhint->res_name = NULL;
}
p = classhint->res_class;
if (p) {
if (*p != '\0' && ! got_res_class) {
strcpy(winfo->res_class, p);
got_res_class = 1;
}
XFree(p);
classhint->res_class = NULL;
}
}
}
}
}
XSetErrorHandler(old_handler);
trapped_xerror = 0;
X_UNLOCK;
*depth = descend;
*w = wins[descend];
}
int get_which_cursor(void) {
int which = CURS_ARROW;
if (show_multiple_cursors) {
int depth;
static win_str_info_t winfo;
static int first = 1, depth_cutoff = -1;
Window win;
XErrorHandler old_handler;
int mode = 0;
char a = multiple_cursors_mode[0];
if (a == 'd') {
mode = 0;
} else if (a == 'X') {
mode = 1;
} else {
mode = 2;
}
if (depth_cutoff < 0) {
int din;
if (sscanf(multiple_cursors_mode, "X%d", &din) == 1) {
depth_cutoff = din;
} else {
depth_cutoff = 0;
}
}
if (first) {
winfo.wm_name = (char *) malloc(1024);
winfo.res_name = (char *) malloc(1024);
winfo.res_class = (char *) malloc(1024);
}
first = 0;
tree_descend_cursor(&depth, &win, &winfo);
if (depth <= depth_cutoff) {
which = CURS_ROOT;
} else if (mode >= 2) {
int which0 = which;
if (win) {
int ratio = 10, x, y;
unsigned int w, h, bw, d;
Window r;
trapped_xerror = 0;
old_handler = XSetErrorHandler(trap_xerror);
if (XGetGeometry(dpy, win, &r, &x, &y, &w, &h,
&bw, &d)) {
if (w > ratio * h || h > ratio * w) {
which = CURS_WM;
}
}
XSetErrorHandler(old_handler);
trapped_xerror = 0;
}
if (which == which0) {
lowercase(winfo.res_name);
lowercase(winfo.res_class);
if (strstr(winfo.res_name, "term")) {
which = CURS_TERM;
} else if (strstr(winfo.res_class, "term")) {
which = CURS_TERM;
}
}
}
}
return which;
}
/* /*
* save current cursor info and the patch of non-cursor data it covers * Some utilities for marking the little cursor patch region as
* modified, etc.
*/ */
static void save_mouse_patch(int x, int y, int w, int h, int cx, int cy, void mark_cursor_patch_modified(rfbScreenInfoPtr s, int old) {
int which) { int curx, cury, xhot, yhot, w, h;
int pixelsize = bpp >> 3; int x1, x2, y1, y2;
char *fbp = main_fb;
int ly, i = 0;
for (ly = y; ly < y + h; ly++) { if (! s->cursor) {
memcpy(cur_save+i, fbp + ly * main_bytes_per_line return;
+ x * pixelsize, w * pixelsize); }
i += w * pixelsize; if (old) {
/* use oldCursor pos */
curx = s->oldCursorX;
cury = s->oldCursorY;
} else {
curx = s->cursorX;
cury = s->cursorY;
} }
cur_save_x = x; /* patch geometry */
cur_save_y = y; xhot = s->cursor->xhot;
cur_save_w = w; yhot = s->cursor->yhot;
cur_save_h = h; w = s->cursor->width;
h = s->cursor->height;
x1 = curx - xhot;
x2 = x1 + w;
x1 = nfix(x1, s->width);
x2 = nfix(x2, s->width);
y1 = cury - yhot;
y2 = y1 + h;
y1 = nfix(y1, s->height);
y2 = nfix(y2, s->height);
rfbMarkRectAsModified(s, x1, y1, x1+x2, y1+y2);
}
cur_save_which = which; /* which cursor and its position */ void set_cursor_was_changed(rfbScreenInfoPtr s) {
cur_save_cx = cx; rfbClientIteratorPtr iter;
cur_save_cy = cy; rfbClientPtr cl;
cur_saved = 1; iter = rfbGetClientIterator(s);
while( (cl = rfbClientIteratorNext(iter)) ) {
cl->cursorWasChanged = TRUE;
}
rfbReleaseClientIterator(iter);
} }
/* void set_cursor_was_moved(rfbScreenInfoPtr s) {
* put the non-cursor patch back in the rfb fb rfbClientIteratorPtr iter;
*/ rfbClientPtr cl;
void restore_mouse_patch(void) {
int pixelsize = bpp >> 3;
char *fbp = main_fb;
int ly, i = 0;
if (! cur_saved) { iter = rfbGetClientIterator(s);
return; /* not yet saved */ while( (cl = rfbClientIteratorNext(iter)) ) {
cl->cursorWasMoved = TRUE;
} }
rfbReleaseClientIterator(iter);
}
for (ly = cur_save_y; ly < cur_save_y + cur_save_h; ly++) { void unset_cursor_shape_updates(rfbScreenInfoPtr s) {
memcpy(fbp + ly * main_bytes_per_line + cur_save_x * pixelsize, rfbClientIteratorPtr iter;
cur_save+i, cur_save_w * pixelsize); rfbClientPtr cl;
i += cur_save_w * pixelsize;
iter = rfbGetClientIterator(s);
while( (cl = rfbClientIteratorNext(iter)) ) {
cl->enableCursorShapeUpdates = FALSE;
cl->enableCursorPosUpdates = FALSE;
cl->cursorWasChanged = FALSE;
} }
rfbReleaseClientIterator(iter);
} }
/* int cursor_pos_updates_clients(rfbScreenInfoPtr s) {
* Descends window tree at pointer until the window cursor matches the current rfbClientIteratorPtr iter;
* cursor. So far only used to detect if mouse is on root background or not. rfbClientPtr cl;
* (returns 0 in that case, 1 otherwise). int count = 0;
*
* It seems impossible to do, but if the actual cursor could ever be
* determined we might want to hash that info on window ID or something...
*/
static int tree_descend_cursor(void) {
Window r, c;
int rx, ry, wx, wy;
unsigned int mask;
int descend = 0, tries = 0, maxtries = 1;
X_LOCK; iter = rfbGetClientIterator(s);
c = window; while( (cl = rfbClientIteratorNext(iter)) ) {
while (c) { if (cl->enableCursorPosUpdates) {
if (++tries > maxtries) { count++;
descend = maxtries;
break;
}
if ( XTestCompareCurrentCursorWithWindow(dpy, c) ) {
break;
} }
XQueryPointer(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &mask);
descend++;
} }
X_UNLOCK; rfbReleaseClientIterator(iter);
return descend; return count;
} }
/* int cursor_shape_updates_clients(rfbScreenInfoPtr s) {
* This is for mouse patch drawing under -xinerama or -blackout rfbClientIteratorPtr iter;
*/ rfbClientPtr cl;
static void blackout_nearby_tiles(int x, int y, int dt) { int count = 0;
int sx, sy, n, b;
int tx = x/tile_x;
int ty = y/tile_y;
if (! blackouts) {
return;
}
if (dt < 1) {
dt = 1;
}
/* loop over a range of tiles, blacking out as needed */
for (sx = tx - dt; sx <= tx + dt; sx++) { iter = rfbGetClientIterator(s);
if (sx < 0 || sx >= tile_x) { while( (cl = rfbClientIteratorNext(iter)) ) {
continue; if (cl->enableCursorShapeUpdates) {
} count++;
for (sy = ty - dt; sy <= ty + dt; sy++) {
if (sy < 0 || sy >= tile_y) {
continue;
}
n = sx + sy * ntiles_x;
if (tile_blackout[n].cover == 0) {
continue;
}
for (b=0; b <= tile_blackout[n].count; b++) {
int x1, y1, x2, y2;
x1 = tile_blackout[n].bo[b].x1;
y1 = tile_blackout[n].bo[b].y1;
x2 = tile_blackout[n].bo[b].x2;
y2 = tile_blackout[n].bo[b].y2;
zero_fb(x1, y1, x2, y2);
}
} }
} }
rfbReleaseClientIterator(iter);
return count;
} }
/* /*
* Send rfbCursorPosUpdates back to clients that understand them. This * Record rfb cursor position screen->cursorX, etc (a la defaultPtrAddEvent())
* seems to be TightVNC specific. * Then set up for sending rfbCursorPosUpdates back
* to clients that understand them. This seems to be TightVNC specific.
*/ */
static void cursor_pos_updates(int x, int y) { void cursor_position(int x, int y) {
rfbClientIteratorPtr iter; rfbClientIteratorPtr iter;
rfbClientPtr cl; rfbClientPtr cl;
int cnt = 0; int cnt = 0, nonCursorPosUpdates_clients = 0;
int x_in = x, y_in = y; int x_old, y_old, x_in = x, y_in = y;
if (! cursor_pos) {
return;
}
/* x and y are current positions of X11 pointer on the X11 display */ /* x and y are current positions of X11 pointer on the X11 display */
if (scaling) { if (scaling) {
x = ((double) x / dpy_x) * scaled_x; x = ((double) x / dpy_x) * scaled_x;
if (x >= scaled_x) x = scaled_x - 1; x = nfix(x, scaled_x);
y = ((double) y / dpy_y) * scaled_y; y = ((double) y / dpy_y) * scaled_y;
if (y >= scaled_y) y = scaled_y - 1; y = nfix(y, scaled_y);
} }
if (x == screen->cursorX && y == screen->cursorY) { if (x == screen->cursorX && y == screen->cursorY) {
return; return;
} }
x_old = screen->oldCursorX;
y_old = screen->oldCursorY;
if (screen->cursorIsDrawn) { if (screen->cursorIsDrawn) {
rfbUndrawCursor(screen); rfbUndrawCursor(screen);
...@@ -4516,6 +5011,10 @@ static void cursor_pos_updates(int x, int y) { ...@@ -4516,6 +5011,10 @@ static void cursor_pos_updates(int x, int y) {
iter = rfbGetClientIterator(screen); iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) { while( (cl = rfbClientIteratorNext(iter)) ) {
if (! cl->enableCursorPosUpdates) { if (! cl->enableCursorPosUpdates) {
nonCursorPosUpdates_clients++;
continue;
}
if (! cursor_pos_updates) {
continue; continue;
} }
if (cl == last_pointer_client) { if (cl == last_pointer_client) {
...@@ -4528,7 +5027,7 @@ static void cursor_pos_updates(int x, int y) { ...@@ -4528,7 +5027,7 @@ static void cursor_pos_updates(int x, int y) {
} else { } else {
/* an X11 app evidently warped the pointer */ /* an X11 app evidently warped the pointer */
if (debug_pointer) { if (debug_pointer) {
rfbLog("cursor_pos_updates: warp " rfbLog("cursor_position: warp "
"detected dx=%3d dy=%3d\n", "detected dx=%3d dy=%3d\n",
cursor_x - x, cursor_y - y); cursor_x - x, cursor_y - y);
} }
...@@ -4542,190 +5041,76 @@ static void cursor_pos_updates(int x, int y) { ...@@ -4542,190 +5041,76 @@ static void cursor_pos_updates(int x, int y) {
} }
rfbReleaseClientIterator(iter); rfbReleaseClientIterator(iter);
if (nonCursorPosUpdates_clients && show_cursor) {
if (x_old != x || y_old != y) {
mark_cursor_patch_modified(screen, 0);
}
}
if (debug_pointer && cnt) { if (debug_pointer && cnt) {
rfbLog("cursor_pos_updates: sent position x=%3d y=%3d to %d" rfbLog("cursor_position: sent position x=%3d y=%3d to %d"
" clients\n", x, y, cnt); " clients\n", x, y, cnt);
} }
} }
/* void set_rfb_cursor(int which) {
* draw one of the mouse cursors into the rfb fb int workaround = 1; /* if rfbSetCursor does not mark modified */
*/
static void draw_mouse(int x, int y, int which, int update) {
int px, py, i, offset;
int pixelsize = bpp >> 3;
char *fbp = main_fb;
char cdata, cmask;
char *data, *mask;
int white = 255, black = 0, shade;
int x0, x1, x2, y0, y1, y2;
int cur_x, cur_y, cur_sx, cur_sy, reverse;
static int first = 1;
if (! show_mouse) { if (! show_cursor) {
return; return;
} }
if (first) {
first = 0; if (workaround && screen->cursor) {
setup_cursors(); int all_are_cursor_pos = 1;
} rfbClientIteratorPtr iter;
rfbClientPtr cl;
data = cursors[which]->data; /* pattern data */
mask = cursors[which]->mask;
cur_x = cursors[which]->wx; /* widths */
cur_y = cursors[which]->wy;
cur_sx = cursors[which]->sx; /* shifts */
cur_sy = cursors[which]->sy;
reverse = cursors[which]->reverse; /* reverse video */
if (indexed_colour) {
black = BlackPixel(dpy, scr) % 256;
white = WhitePixel(dpy, scr) % 256;
}
if (reverse) {
int tmp = black;
black = white;
white = tmp;
}
/*
* notation:
* x0, y0: position after cursor shift (no edge corrections)
* x1, y1: corrected for lower boundary < 0
* x2, y2: position + cursor width and corrected for upper boundary
*/
x0 = x1 = x - cur_sx; /* apply shift */
if (x1 < 0) x1 = 0;
y0 = y1 = y - cur_sy;
if (y1 < 0) y1 = 0;
x2 = x0 + cur_x; /* apply width for upper endpoints */
if (x2 >= dpy_x) x2 = dpy_x - 1;
y2 = y0 + cur_y;
if (y2 >= dpy_y) y2 = dpy_y - 1;
/* save the patch and info about which cursor will overwrite it */
save_mouse_patch(x1, y1, x2 - x1, y2 - y1, x, y, which);
for (py = 0; py < cur_y; py++) {
if (y0 + py < 0 || y0 + py >= dpy_y) {
continue; /* off screen */
}
for (px = 0; px < cur_x; px++) {
if (x0 + px < 0 || x0 + px >= dpy_x){
continue; /* off screen */
}
cdata = data[px + py * cur_x];
cmask = mask[px + py * cur_x];
if (cmask != 'x') {
continue; /* transparent */
}
shade = white; iter = rfbGetClientIterator(screen);
if (cdata != cmask) { while( (cl = rfbClientIteratorNext(iter)) ) {
shade = black; if (! cl->enableCursorPosUpdates) {
all_are_cursor_pos = 0;
} }
if (! cl->enableCursorShapeUpdates) {
offset = (y0 + py)*main_bytes_per_line + (x0 + px)*pixelsize; all_are_cursor_pos = 0;
/* fill in each color byte in the fb */
for (i=0; i < pixelsize; i++) {
fbp[offset+i] = (char) shade;
} }
} }
} rfbReleaseClientIterator(iter);
if (blackouts) {
/*
* loop over a range of tiles, blacking out as needed
* note we currently disable mouse drawing under blackouts.
*/
static int mx = -1, my = -1;
int skip = 0;
if (mx < 0) {
mx = x;
my = y;
} else if (mx == x && my == y) {
skip = 1;
}
mx = x;
my = y;
if (! skip) { if (! all_are_cursor_pos) {
blackout_nearby_tiles(x, y, 2); mark_cursor_patch_modified(screen, 1);
} }
} }
if (update) { rfbSetCursor(screen, cursors[which]->rfb, FALSE);
/* x and y of the real (X server) mouse */
static int mouse_x = -1;
static int mouse_y = -1;
if (x != mouse_x || y != mouse_y) {
hint_t hint;
hint.x = x1;
hint.y = y2;
hint.w = x2 - x1;
hint.h = y2 - y1;
mark_hint(hint);
if (mouse_x < 0) {
mouse_x = 0;
}
if (mouse_y < 0) {
mouse_y = 0;
}
/* XXX this ignores change of shift... */
x1 = mouse_x - cur_sx;
if (x1 < 0) x1 = 0;
y1 = mouse_y - cur_sy;
if (y1 < 0) y1 = 0;
x2 = mouse_x - cur_sx + cur_x;
if (x2 >= dpy_x) x2 = dpy_x - 1;
y2 = mouse_y - cur_sy + cur_y; /* this is a 2nd workaround for rfbSetCursor() */
if (y2 >= dpy_y) y2 = dpy_y - 1; if (screen->underCursorBuffer == NULL &&
screen->underCursorBufferLen != 0) {
hint.x = x1; screen->underCursorBufferLen = 0;
hint.y = y2; }
hint.w = x2 - x1;
hint.h = y2 - y1;
mark_hint(hint);
mouse_x = x; if (workaround) {
mouse_y = y; set_cursor_was_changed(screen);
}
} }
} }
/* void set_cursor(int x, int y, int which) {
* wrapper to redraw the mouse patch static int last = -1;
*/ if (last < 0 || which != last) {
void redraw_mouse(void) { set_rfb_cursor(which);
if (cur_saved) {
/* redraw saved mouse from info (save_mouse_patch) */
draw_mouse(cur_save_cx, cur_save_cy, cur_save_which, 0);
} }
last = which;
} }
/* /*
* routine called periodically to update the mouse aspects (drawn & * routine called periodically to update cursor aspects, this catches
* cursorpos updates) * warps and cursor shape changes.
*/ */
void update_mouse(void) { void check_x11_pointer(void) {
Window root_w, child_w; Window root_w, child_w;
rfbBool ret; rfbBool ret;
int root_x, root_y, win_x, win_y, which = 0; int root_x, root_y, win_x, win_y;
int x, y;
unsigned int mask; unsigned int mask;
X_LOCK; X_LOCK;
...@@ -4736,18 +5121,25 @@ void update_mouse(void) { ...@@ -4736,18 +5121,25 @@ void update_mouse(void) {
if (! ret) { if (! ret) {
return; return;
} }
if (debug_pointer) {
if (show_root_cursor) { static int last_x = -1, last_y = -1;
int descend; if (root_x != last_x || root_y != last_y) {
if ( (descend = tree_descend_cursor()) ) { rfbLog("XQueryPointer: x:%4d, y:%4d)\n",
which = 0; root_x, root_y);
} else {
which = 1;
} }
last_x = root_x;
last_y = root_y;
} }
cursor_pos_updates(root_x - off_x, root_y - off_y); /* offset subtracted since XQueryPointer relative to rootwin */
draw_mouse(root_x - off_x, root_y - off_y, which, 1); x = root_x - off_x;
y = root_y - off_y;
/* record the cursor position in the rfb screen */
cursor_position(x, y);
/* change the cursor shape if necessary */
set_cursor(x, y, get_which_cursor());
} }
/* -- screen.c -- */ /* -- screen.c -- */
...@@ -4945,7 +5337,7 @@ void set_visual(char *str) { ...@@ -4945,7 +5337,7 @@ void set_visual(char *str) {
/* /*
* Presumably under -nofb the clients will never request the framebuffer. * Presumably under -nofb the clients will never request the framebuffer.
* But we have gotten such a request... so let's just give them * However, we have gotten such a request... so let's just give them
* the current view on the display. n.b. x2vnc and perhaps win2vnc * the current view on the display. n.b. x2vnc and perhaps win2vnc
* requests a 1x1 pixel for some workaround so sadly this evidently * requests a 1x1 pixel for some workaround so sadly this evidently
* nearly always happens. * nearly always happens.
...@@ -5065,7 +5457,20 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { ...@@ -5065,7 +5457,20 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
for (i=1; i< *argc; i++) { for (i=1; i< *argc; i++) {
rfbLog("\t[%d] %s\n", i, argv[i]); rfbLog("\t[%d] %s\n", i, argv[i]);
} }
rfbLog("for a list of options run: x11vnc -help\n"); rfbLog("For a list of options run: x11vnc -help\n");
rfbLog("\n");
rfbLog("Here is a list of removed or obsolete"
" options:\n");
rfbLog("\n");
rfbLog("removed: -hints, -nohints\n");
rfbLog("removed: -cursorposall\n");
rfbLog("\n");
rfbLog("renamed: -old_copytile, use -onetile\n");
rfbLog("renamed: -mouse, use -cursor\n");
rfbLog("renamed: -mouseX, use -cursor X\n");
rfbLog("renamed: -X, use -cursor X\n");
rfbLog("renamed: -nomouse, use -nocursor\n");
clean_up_exit(1); clean_up_exit(1);
} }
} }
...@@ -5083,14 +5488,28 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { ...@@ -5083,14 +5488,28 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
if ( ! have_masks && screen->rfbServerFormat.bitsPerPixel == 8 if ( ! have_masks && screen->rfbServerFormat.bitsPerPixel == 8
&& CellsOfScreen(ScreenOfDisplay(dpy,scr)) ) { && CellsOfScreen(ScreenOfDisplay(dpy,scr)) ) {
/* indexed colour */ /* indexed colour */
if (!quiet) rfbLog("Using X display with 8bpp indexed color\n"); if (!quiet) {
rfbLog("X display %s is 8bpp indexed color\n",
DisplayString(dpy));
if (! flash_cmap && ! overlay) {
rfbLog("\n");
rfbLog("In 8bpp PseudoColor mode if you "
"experience color\n");
rfbLog("problems you may want to enable "
"following the\n");
rfbLog("changing colormap by using the "
"-flashcmap option.\n");
rfbLog("\n");
}
}
indexed_colour = 1; indexed_colour = 1;
set_colormap(); set_colormap();
} else { } else {
/* general case ... */ /* general case ... */
if (! quiet) { if (! quiet) {
rfbLog("Using X display with %dbpp depth=%d true " rfbLog("X display %s is %dbpp depth=%d true "
"color\n", fb->bits_per_pixel, fb->depth); "color\n", DisplayString(dpy), fb->bits_per_pixel,
fb->depth);
} }
/* convert masks to bit shifts and max # colors */ /* convert masks to bit shifts and max # colors */
...@@ -5130,6 +5549,15 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { ...@@ -5130,6 +5549,15 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
main_green_shift = screen->rfbServerFormat.greenShift; main_green_shift = screen->rfbServerFormat.greenShift;
main_blue_shift = screen->rfbServerFormat.blueShift; main_blue_shift = screen->rfbServerFormat.blueShift;
} }
if (overlay && ! quiet) {
rfbLog("\n");
rfbLog("Overlay mode enabled: If you experience color\n");
rfbLog("problems when popup menus are on the screen, try\n");
rfbLog("disabling SaveUnders in your X server, one way is\n");
rfbLog("to start the X server with the '-su' option, e.g.:\n");
rfbLog("Xsun -su ... see Xserver(1), xinit(1) for more info.\n");
rfbLog("\n");
}
/* nofb is for pointer/keyboard only handling. */ /* nofb is for pointer/keyboard only handling. */
if (nofb) { if (nofb) {
...@@ -5187,11 +5615,11 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { ...@@ -5187,11 +5615,11 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
screen->setXCutText = xcut_receive; screen->setXCutText = xcut_receive;
} }
if (local_cursor) { setup_cursors();
cursor = rfbMakeXCursor(CUR_SIZE, CUR_SIZE, CUR_DATA, CUR_MASK); if (! show_cursor) {
screen->cursor = cursor;
} else {
screen->cursor = NULL; screen->cursor = NULL;
} else {
screen->cursor = cursors[0]->rfb;
} }
rfbInitServer(screen); rfbInitServer(screen);
...@@ -5220,6 +5648,22 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { ...@@ -5220,6 +5648,22 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
* routines related to xinerama and blacking out rectangles * routines related to xinerama and blacking out rectangles
*/ */
/* blacked-out region (-blackout, -xinerama) */
typedef struct bout {
int x1, y1, x2, y2;
} blackout_t;
#define BO_MAX 16
typedef struct tbout {
blackout_t bo[BO_MAX]; /* hardwired max rectangles. */
int cover;
int count;
} tile_blackout_t;
#define BLACKR_MAX 100
blackout_t blackr[BLACKR_MAX]; /* hardwired max blackouts */
tile_blackout_t *tile_blackout;
int blackouts = 0;
/* /*
* Take a comma separated list of geometries: WxH+X+Y and register them as * Take a comma separated list of geometries: WxH+X+Y and register them as
* rectangles to black out from the screen. * rectangles to black out from the screen.
...@@ -5292,10 +5736,6 @@ void blackout_tiles(void) { ...@@ -5292,10 +5736,6 @@ 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, no vcr, etc...
*/ */
single_copytile = 1; single_copytile = 1;
if (show_mouse) {
rfbLog("disabling remote mouse drawing due to blackouts\n");
show_mouse = 0;
}
/* loop over all tiles. */ /* loop over all tiles. */
for (ty=0; ty < ntiles_y; ty++) { for (ty=0; ty < ntiles_y; ty++) {
...@@ -5604,6 +6044,20 @@ static void set_fs_factor(int max) { ...@@ -5604,6 +6044,20 @@ static void set_fs_factor(int max) {
} }
} }
char *flip_ximage_byte_order(XImage *xim) {
char *order;
if (xim->byte_order == LSBFirst) {
order = "MSBFirst";
xim->byte_order = MSBFirst;
xim->bitmap_bit_order = MSBFirst;
} else {
order = "LSBFirst";
xim->byte_order = LSBFirst;
xim->bitmap_bit_order = LSBFirst;
}
return order;
}
/* /*
* set up an XShm image, or if not using shm just create the XImage. * set up an XShm image, or if not using shm just create the XImage.
*/ */
...@@ -5611,6 +6065,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, ...@@ -5611,6 +6065,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
char *name) { char *name) {
XImage *xim; XImage *xim;
static int reported_flip = 0;
shm->shmid = -1; shm->shmid = -1;
shm->shmaddr = (char *) -1; shm->shmaddr = (char *) -1;
...@@ -5639,21 +6094,11 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, ...@@ -5639,21 +6094,11 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
return 0; return 0;
} }
if (flip_byte_order) { if (flip_byte_order) {
static int reported = 0; char *order = flip_ximage_byte_order(xim);
char *bo; if (! reported_flip && ! quiet) {
if (xim->byte_order == LSBFirst) { rfbLog("Changing XImage byte order"
bo = "MSBFirst"; " to %s\n", order);
xim->byte_order = MSBFirst; reported_flip = 1;
xim->bitmap_bit_order = MSBFirst;
} else {
bo = "LSBFirst";
xim->byte_order = LSBFirst;
xim->bitmap_bit_order = LSBFirst;
}
if (! reported && ! quiet) {
rfbLog("changing XImage byte order"
" to %s\n", bo);
reported = 1;
} }
} }
...@@ -5661,7 +6106,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, ...@@ -5661,7 +6106,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
return 1; return 1;
} }
xim = XShmCreateImage(dpy, default_visual, depth, ZPixmap, NULL, xim = XShmCreateImage_wr(dpy, default_visual, depth, ZPixmap, NULL,
shm, w, h); shm, w, h);
if (xim == NULL) { if (xim == NULL) {
...@@ -5672,6 +6117,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, ...@@ -5672,6 +6117,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
*ximg_ptr = xim; *ximg_ptr = xim;
#ifdef LIBVNCSERVER_HAVE_XSHM
shm->shmid = shmget(IPC_PRIVATE, shm->shmid = shmget(IPC_PRIVATE,
xim->bytes_per_line * xim->height, IPC_CREAT | 0777); xim->bytes_per_line * xim->height, IPC_CREAT | 0777);
...@@ -5704,7 +6150,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, ...@@ -5704,7 +6150,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
shm->readOnly = False; shm->readOnly = False;
if (! XShmAttach(dpy, shm)) { if (! XShmAttach_wr(dpy, shm)) {
rfbErr("XShmAttach(%s) failed.\n", name); rfbErr("XShmAttach(%s) failed.\n", name);
XDestroyImage(xim); XDestroyImage(xim);
*ximg_ptr = NULL; *ximg_ptr = NULL;
...@@ -5718,6 +6164,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, ...@@ -5718,6 +6164,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
X_UNLOCK; X_UNLOCK;
return 0; return 0;
} }
#endif
X_UNLOCK; X_UNLOCK;
return 1; return 1;
...@@ -5727,21 +6174,24 @@ void shm_delete(XShmSegmentInfo *shm) { ...@@ -5727,21 +6174,24 @@ void shm_delete(XShmSegmentInfo *shm) {
if (! using_shm) { if (! using_shm) {
return; return;
} }
#ifdef LIBVNCSERVER_HAVE_XSHM
if (shm->shmaddr != (char *) -1) { if (shm->shmaddr != (char *) -1) {
shmdt(shm->shmaddr); shmdt(shm->shmaddr);
} }
if (shm->shmid != -1) { if (shm->shmid != -1) {
shmctl(shm->shmid, IPC_RMID, 0); shmctl(shm->shmid, IPC_RMID, 0);
} }
#endif
} }
void shm_clean(XShmSegmentInfo *shm, XImage *xim) { void shm_clean(XShmSegmentInfo *shm, XImage *xim) {
if (! using_shm || nofb) { if (! using_shm) {
return; return;
} }
#ifdef LIBVNCSERVER_HAVE_XSHM
X_LOCK; X_LOCK;
if (shm->shmid != -1) { if (shm->shmid != -1) {
XShmDetach(dpy, shm); XShmDetach_wr(dpy, shm);
} }
if (xim != NULL) { if (xim != NULL) {
XDestroyImage(xim); XDestroyImage(xim);
...@@ -5749,6 +6199,7 @@ void shm_clean(XShmSegmentInfo *shm, XImage *xim) { ...@@ -5749,6 +6199,7 @@ void shm_clean(XShmSegmentInfo *shm, XImage *xim) {
X_UNLOCK; X_UNLOCK;
shm_delete(shm); shm_delete(shm);
#endif
} }
void initialize_shm(void) { void initialize_shm(void) {
...@@ -6423,7 +6874,7 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) { ...@@ -6423,7 +6874,7 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
} }
void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) { void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) {
if (rfb_fb == main_fb || force) { if (rfb_fb == main_fb || force) {
rfbMarkRectAsModified(screen, x1, y1, x2, y2); rfbMarkRectAsModified(screen, x1, y1, x2, y2);
} else if (scaling) { } else if (scaling) {
...@@ -6446,12 +6897,11 @@ void mark_hint(hint_t hint) { ...@@ -6446,12 +6897,11 @@ void mark_hint(hint_t hint) {
/* /*
* copy_tiles() gives a slight improvement over copy_tile() since * copy_tiles() gives a slight improvement over copy_tile() since
* adjacent runs of tiles are done all at once there is some savings * adjacent runs of tiles are done all at once there is some savings
* due to contiguous memory access. Not a great speedup, but in * due to contiguous memory access. Not a great speedup, but in some
* some cases it can be up to 2X. Even more on a SunRay where no * cases it can be up to 2X. Even more on a SunRay or ShadowFB where
* graphics hardware is involved in the read. Generally, graphics * no graphics hardware is involved in the read. Generally, graphics
* devices are optimized for write, not read, so we are limited by * devices are optimized for write, not read, so we are limited by the
* the read bandwidth, sometimes only 5 MB/sec on otherwise fast * read bandwidth, sometimes only 5 MB/sec on otherwise fast hardware.
* hardware.
*/ */
static int *first_line = NULL, *last_line; static int *first_line = NULL, *last_line;
static unsigned short *left_diff, *right_diff; static unsigned short *left_diff, *right_diff;
...@@ -6464,8 +6914,6 @@ static void copy_tiles(int tx, int ty, int nt) { ...@@ -6464,8 +6914,6 @@ static void copy_tiles(int tx, int ty, int nt) {
int pixelsize = bpp >> 3; int pixelsize = bpp >> 3;
int first_min, last_max; int first_min, last_max;
int restored_patch = 0; /* for show_mouse */
char *src, *dst, *s_src, *s_dst, *m_src, *m_dst; char *src, *dst, *s_src, *s_dst, *m_src, *m_dst;
char *h_src, *h_dst; char *h_src, *h_dst;
if (! first_line) { if (! first_line) {
...@@ -6554,24 +7002,6 @@ static void copy_tiles(int tx, int ty, int nt) { ...@@ -6554,24 +7002,6 @@ static void copy_tiles(int tx, int ty, int nt) {
} }
} }
/*
* Some awkwardness wrt the little remote mouse patch we display.
* When threaded we want to have as small a window of time
* as possible when the mouse image is not in the fb, otherwise
* a libvncserver thread may send the uncorrected patch to the
* clients.
*/
if (show_mouse && use_threads && cur_saved) {
/* check for overlap */
if (cur_save_x + cur_save_w > x && x + size_x > cur_save_x &&
cur_save_y + cur_save_h > y && y + size_y > cur_save_y) {
/* restore the real data to the rfb fb */
restore_mouse_patch();
restored_patch = 1;
}
}
src = tile_row[nt]->data; src = tile_row[nt]->data;
dst = main_fb + y * main_bytes_per_line + x * pixelsize; dst = main_fb + y * main_bytes_per_line + x * pixelsize;
...@@ -6624,9 +7054,6 @@ static void copy_tiles(int tx, int ty, int nt) { ...@@ -6624,9 +7054,6 @@ static void copy_tiles(int tx, int ty, int nt) {
for (t=1; t <= nt; t++) { for (t=1; t <= nt; t++) {
tile_has_diff[n+(t-1)] = 0; tile_has_diff[n+(t-1)] = 0;
} }
if (restored_patch) {
redraw_mouse();
}
return; return;
} else { } else {
/* /*
...@@ -6753,10 +7180,6 @@ static void copy_tiles(int tx, int ty, int nt) { ...@@ -6753,10 +7180,6 @@ static void copy_tiles(int tx, int ty, int nt) {
s_dst += main_bytes_per_line; s_dst += main_bytes_per_line;
} }
if (restored_patch) {
redraw_mouse();
}
/* record all the info in the region array for this tile: */ /* record all the info in the region array for this tile: */
for (t=1; t <= nt; t++) { for (t=1; t <= nt; t++) {
int s = t - 1; int s = t - 1;
...@@ -7150,7 +7573,7 @@ static void nap_set(int tile_cnt) { ...@@ -7150,7 +7573,7 @@ static void nap_set(int tile_cnt) {
nap_diff_count = 0; nap_diff_count = 0;
} }
if (show_mouse) { if (show_cursor) {
/* kludge for the up to 4 tiles the mouse patch could occupy */ /* kludge for the up to 4 tiles the mouse patch could occupy */
if ( tile_cnt > 4) { if ( tile_cnt > 4) {
last_event = time(0); last_event = time(0);
...@@ -7169,7 +7592,7 @@ static void nap_sleep(int ms, int split) { ...@@ -7169,7 +7592,7 @@ static void nap_sleep(int ms, int split) {
for (i=0; i<split; i++) { for (i=0; i<split; i++) {
usleep(ms * 1000 / split); usleep(ms * 1000 / split);
if (! use_threads && i != split - 1) { if (! use_threads && i != split - 1) {
rfbProcessEvents(screen, -1); rfbPE(screen, -1);
} }
if (input != got_user_input) { if (input != got_user_input) {
break; break;
...@@ -7482,11 +7905,6 @@ void scan_for_updates(void) { ...@@ -7482,11 +7905,6 @@ void scan_for_updates(void) {
} }
} }
if (show_mouse && ! use_threads) {
/* single-thread is safe to do it here for all scanning */
restore_mouse_patch();
}
/* scan with the initial y to the jitter value from scanlines: */ /* scan with the initial y to the jitter value from scanlines: */
scan_in_progress = 1; scan_in_progress = 1;
tile_count = scan_display(scanlines[scan_count], 0); tile_count = scan_display(scanlines[scan_count], 0);
...@@ -7538,12 +7956,6 @@ void scan_for_updates(void) { ...@@ -7538,12 +7956,6 @@ void scan_for_updates(void) {
if (fs_factor && tile_count > fs_frac * ntiles) { if (fs_factor && tile_count > fs_frac * ntiles) {
fb_copy_in_progress = 1; fb_copy_in_progress = 1;
copy_screen(); copy_screen();
if (show_mouse || cursor_pos) {
if (show_mouse && ! use_threads) {
redraw_mouse();
}
update_mouse();
}
fb_copy_in_progress = 0; fb_copy_in_progress = 0;
if (use_threads && ! old_pointer) { if (use_threads && ! old_pointer) {
pointer(-1, 0, 0, NULL); pointer(-1, 0, 0, NULL);
...@@ -7616,13 +8028,6 @@ void scan_for_updates(void) { ...@@ -7616,13 +8028,6 @@ void scan_for_updates(void) {
ping_clients(tile_diffs); ping_clients(tile_diffs);
} }
/* Handle the remote mouse pointer */
if (show_mouse || cursor_pos) {
if (show_mouse && ! use_threads) {
redraw_mouse();
}
update_mouse();
}
nap_check(tile_diffs); nap_check(tile_diffs);
} }
...@@ -7698,7 +8103,11 @@ static int check_user_input(double dt, int *cnt) { ...@@ -7698,7 +8103,11 @@ static int check_user_input(double dt, int *cnt) {
* likely they have all be sent already. * likely they have all be sent already.
*/ */
while (1) { while (1) {
rfbCheckFds(screen, 1000); if (show_multiple_cursors) {
rfbPE(screen, 1000);
} else {
rfbCFD(screen, 1000);
}
XFlush(dpy); XFlush(dpy);
spin += dtime(&tm); spin += dtime(&tm);
...@@ -7757,7 +8166,11 @@ static int check_user_input(double dt, int *cnt) { ...@@ -7757,7 +8166,11 @@ static int check_user_input(double dt, int *cnt) {
miss = 0; miss = 0;
for (i=0; i<split; i++) { for (i=0; i<split; i++) {
usleep(ms * 1000); usleep(ms * 1000);
rfbCheckFds(screen, 1000); if (show_multiple_cursors) {
rfbPE(screen, 1000);
} else {
rfbCFD(screen, 1000);
}
spin += dtime(&tm); spin += dtime(&tm);
if (got_pointer_input > g) { if (got_pointer_input > g) {
XFlush(dpy); XFlush(dpy);
...@@ -7803,10 +8216,17 @@ double dtime(double *t_old) { ...@@ -7803,10 +8216,17 @@ double dtime(double *t_old) {
/* /*
* utility wrapper to call rfbProcessEvents * utility wrapper to call rfbProcessEvents
* checks that we are not in threaded mode.
*/ */
void rfbPE(rfbScreenInfoPtr scr, long us) { void rfbPE(rfbScreenInfoPtr scr, long usec) {
if (! use_threads) {
rfbProcessEvents(scr, usec);
}
}
void rfbCFD(rfbScreenInfoPtr scr, long usec) {
if (! use_threads) { if (! use_threads) {
rfbProcessEvents(scr, us); rfbCheckFds(scr, usec);
} }
} }
...@@ -7828,7 +8248,10 @@ static void watch_loop(void) { ...@@ -7828,7 +8248,10 @@ static void watch_loop(void) {
got_keyboard_input = 0; got_keyboard_input = 0;
if (! use_threads) { if (! use_threads) {
rfbProcessEvents(screen, -1); rfbPE(screen, -1);
if (! cursor_shape_updates) {
unset_cursor_shape_updates(screen);
}
if (check_user_input(dt, &cnt)) { if (check_user_input(dt, &cnt)) {
/* true means loop back for more input */ /* true means loop back for more input */
continue; continue;
...@@ -7839,7 +8262,7 @@ static void watch_loop(void) { ...@@ -7839,7 +8262,7 @@ static void watch_loop(void) {
clean_up_exit(0); clean_up_exit(0);
} }
watch_xevents(); check_xevents();
check_connect_inputs(); check_connect_inputs();
if (! screen->rfbClientHead) { /* waiting for a client */ if (! screen->rfbClientHead) { /* waiting for a client */
...@@ -7847,9 +8270,11 @@ static void watch_loop(void) { ...@@ -7847,9 +8270,11 @@ static void watch_loop(void) {
continue; continue;
} }
if (nofb) { /* no framebuffer polling needed */ if (nofb) {
if (cursor_pos) { /* no framebuffer polling needed */
update_mouse(); if (cursor_pos_updates) {
/* -nofb -cursorpos usage is rare */
check_x11_pointer();
} }
continue; continue;
} }
...@@ -7859,7 +8284,7 @@ static void watch_loop(void) { ...@@ -7859,7 +8284,7 @@ static void watch_loop(void) {
* check for any bell events. * check for any bell events.
* n.b. assumes -nofb folks do not want bell... * n.b. assumes -nofb folks do not want bell...
*/ */
watch_bell_event(); check_bell_event();
} }
if (! show_dragging && button_mask) { if (! show_dragging && button_mask) {
/* if any button is pressed do not update screen */ /* if any button is pressed do not update screen */
...@@ -7874,6 +8299,7 @@ static void watch_loop(void) { ...@@ -7874,6 +8299,7 @@ static void watch_loop(void) {
rfbUndrawCursor(screen); rfbUndrawCursor(screen);
scan_for_updates(); scan_for_updates();
check_x11_pointer();
dt = dtime(&tm); dt = dtime(&tm);
} }
...@@ -7936,11 +8362,15 @@ static void print_help(void) { ...@@ -7936,11 +8362,15 @@ static void print_help(void) {
" setting the XAUTHORITY environment varirable to \"file\"\n" " setting the XAUTHORITY environment varirable to \"file\"\n"
" before startup. See Xsecurity(7), xauth(1) man pages.\n" " before startup. See Xsecurity(7), xauth(1) man pages.\n"
"\n" "\n"
"-id windowid Show the window corresponding to \"windowid\" not the\n" "-id windowid Show the window corresponding to \"windowid\" not\n"
" entire display. Warning: bugs! new toplevels missed!...\n" " the entire display. New windows like popup menus,\n"
" etc may not be seen, or will be clipped. x11vnc may\n"
" crash if the window changes size, is iconified, etc.\n"
" Use xwininfo(1) to get the window id. Primarily useful\n"
" for exporting very simple applications.\n"
"-sid windowid As -id, but instead of using the window directly it\n" "-sid windowid As -id, but instead of using the window directly it\n"
" shifts a root view to it: shows saveUnders menus, etc,\n" " shifts a root view to it: this shows saveUnders menus,\n"
" although they will be clipped if they extend beyond\n" " etc, although they will be clipped if they extend beyond\n"
" the window.\n" " the window.\n"
"-flashcmap In 8bpp indexed color, let the installed colormap flash\n" "-flashcmap In 8bpp indexed color, let the installed colormap flash\n"
" as the pointer moves from window to window (slow).\n" " as the pointer moves from window to window (slow).\n"
...@@ -7951,11 +8381,12 @@ static void print_help(void) { ...@@ -7951,11 +8381,12 @@ static void print_help(void) {
" packed with 8 for PseudoColor and 24 for TrueColor).\n" " packed with 8 for PseudoColor and 24 for TrueColor).\n"
"\n" "\n"
" Currently -overlay only works on Solaris (it uses\n" " Currently -overlay only works on Solaris (it uses\n"
" XReadScreen(3X11)). There are still some problems with\n" " XReadScreen(3X11)). There is a problem with image\n"
" surrounding-region painting for popup menus (but not\n" " \"bleeding\" around transient popup menus (but not\n"
" for the popup menu itself); a workaround is to disable\n" " for the menu itself): a workaround is to disable\n"
" SaveUnders (pass -su to Xsun). Amusingly, if -overlay\n" " SaveUnders by passing the \"-su\" argument to Xsun\n"
" is used with -mouse, the mouse cursor shape is correct.\n" " (in /etc/dt/config/Xservers, say). Also note that,\n"
" the mouse cursor shape is exactly correct in this mode.\n"
"\n" "\n"
" Use -overlay as a workaround for situations like these:\n" " Use -overlay as a workaround for situations like these:\n"
" Some legacy applications require the default visual\n" " Some legacy applications require the default visual\n"
...@@ -7968,7 +8399,10 @@ static void print_help(void) { ...@@ -7968,7 +8399,10 @@ static void print_help(void) {
" due to the extra image transformations required.\n" " due to the extra image transformations required.\n"
" For optimal performance do not use -overlay, but rather\n" " For optimal performance do not use -overlay, but rather\n"
" configure the X server so that the default visual is\n" " configure the X server so that the default visual is\n"
" depth 24 TrueColor and have all apps use that visual.\n" " depth 24 TrueColor and try to have all apps use that\n"
" visual (some apps have -use24 or -visual options).\n"
"-overlay_nocursor Sets -overlay, but does not try to draw the exact mouse\n"
" cursor shape using the overlay mechanism.\n"
"-visual n Experimental option: probably does not do what you\n" "-visual n Experimental option: probably does not do what you\n"
" think. It simply *forces* the visual used for the\n" " think. It simply *forces* the visual used for the\n"
" framebuffer; this may be a bad thing... It is useful for\n" " framebuffer; this may be a bad thing... It is useful for\n"
...@@ -7978,9 +8412,10 @@ static void print_help(void) { ...@@ -7978,9 +8412,10 @@ static void print_help(void) {
" for a list. If the string ends in \":m\" for better\n" " for a list. If the string ends in \":m\" for better\n"
" or for worse the visual depth is forced to be m.\n" " or for worse the visual depth is forced to be m.\n"
"\n" "\n"
"-scale fraction Scale the framebuffer by factor \"fraction\". Values\n" "-scale fraction Scale the framebuffer by factor \"fraction\".\n"
" less than 1 shrink the fb. Note: image may not be sharp\n" " Values less than 1 shrink the fb. Note: image may not\n"
" and response may be slower. If \"fraction\" contains\n" " be sharp and response may be slower. Currently the\n"
" cursor shape is not scaled. If \"fraction\" contains\n"
" a decimal point \".\" it is taken as a floating point\n" " a decimal point \".\" it is taken as a floating point\n"
" number, alternatively the notation \"m/n\" may be used\n" " number, alternatively the notation \"m/n\" may be used\n"
" to denote fractions exactly, e.g. -scale 2/3.\n" " to denote fractions exactly, e.g. -scale 2/3.\n"
...@@ -7990,7 +8425,7 @@ static void print_help(void) { ...@@ -7990,7 +8425,7 @@ static void print_help(void) {
" If you just want a quick, rough scaling without\n" " If you just want a quick, rough scaling without\n"
" blending, append \":nb\" to \"fraction\" (e.g. -scale\n" " blending, append \":nb\" to \"fraction\" (e.g. -scale\n"
" 1/3:nb). For compatibility with vncviewers the scaled\n" " 1/3:nb). For compatibility with vncviewers the scaled\n"
" width is adjusted to be a multiple of 4, to disable\n" " width is adjusted to be a multiple of 4: to disable\n"
" this use \":n4\". More esoteric options: \":in\" use\n" " this use \":n4\". More esoteric options: \":in\" use\n"
" interpolation scheme even when shrinking, \":pad\",\n" " interpolation scheme even when shrinking, \":pad\",\n"
" pad scaled width and height to be multiples of scaling\n" " pad scaled width and height to be multiples of scaling\n"
...@@ -8010,9 +8445,10 @@ static void print_help(void) { ...@@ -8010,9 +8445,10 @@ static void print_help(void) {
" periodically check for new hosts. The first line is\n" " periodically check for new hosts. The first line is\n"
" read and then the file is truncated.\n" " read and then the file is truncated.\n"
"-vncconnect Monitor the VNC_CONNECT X property set by the standard\n" "-vncconnect Monitor the VNC_CONNECT X property set by the standard\n"
" VNC program vncconnect(1). When the property is set\n" "-novncconnect VNC program vncconnect(1). When the property is\n"
" to host or host:port establish a reverse connection.\n" " set to \"host\" or \"host:port\" establish a reverse\n"
" Using xprop(1) instead of vncconnect may work, see FAQ.\n" " connection. Using xprop(1) instead of vncconnect may\n"
" work, see the FAQ. Default: %s\n"
"-inetd Launched by inetd(1): stdio instead of listening socket.\n" "-inetd Launched by inetd(1): stdio instead of listening socket.\n"
" Note: if you are not redirecting stderr to a log file\n" " Note: if you are not redirecting stderr to a log file\n"
" (via shell 2> or -o option) you must also specify the\n" " (via shell 2> or -o option) you must also specify the\n"
...@@ -8103,16 +8539,18 @@ static void print_help(void) { ...@@ -8103,16 +8539,18 @@ static void print_help(void) {
"-flipbyteorder Sometimes needed if remotely polled host has different\n" "-flipbyteorder Sometimes needed if remotely polled host has different\n"
" endianness. Ignored unless -noshm is set.\n" " endianness. Ignored unless -noshm is set.\n"
"-onetile Do not use the new copy_tiles() framebuffer mechanism,\n" "-onetile Do not use the new copy_tiles() framebuffer mechanism,\n"
" just use 1 shm tile for polling. Same as -old_copytile.\n" " just use 1 shm tile for polling. Limits shm segments\n"
" Limits shm segments used to 3.\n" " used to 3.\n"
"\n" "\n"
"-blackout string Black out rectangles on the screen. \"string\" is a\n" "-blackout string Black out rectangles on the screen. \"string\" is a\n"
" comma separated list of WxH+X+Y type geometries for\n" " comma separated list of WxH+X+Y type geometries for\n"
" each rectangle.\n" " each rectangle.\n"
"-xinerama If your screen is composed of multiple monitors\n" "-xinerama If your screen is composed of multiple monitors\n"
" glued together via XINERAMA, and that screen is\n" " glued together via XINERAMA, and that screen is\n"
" non-rectangular this option will try to guess the areas\n" " non-rectangular this option will try to guess the\n"
" to black out (if your system has libXinerama).\n" " areas to black out (if your system has libXinerama).\n"
" In general on XINERAMA displays you may need to use the\n"
" -xwarppointer option if the mouse pointer misbehaves.\n"
"\n" "\n"
"-o logfile Write stderr messages to file \"logfile\" instead of\n" "-o logfile Write stderr messages to file \"logfile\" instead of\n"
" to the terminal. Same as -logfile \"file\".\n" " to the terminal. Same as -logfile \"file\".\n"
...@@ -8144,7 +8582,9 @@ static void print_help(void) { ...@@ -8144,7 +8582,9 @@ static void print_help(void) {
" the X server instead of Mode_switch (AltGr).\n" " the X server instead of Mode_switch (AltGr).\n"
#endif #endif
"-xkb When in modtweak mode, use the XKEYBOARD extension\n" "-xkb When in modtweak mode, use the XKEYBOARD extension\n"
" (if it exists) to do the modifier tweaking.\n" " (if it exists) to do the modifier tweaking. This is\n"
" powerful and should be tried if there are still\n"
" keymapping problems when using the simpler -modtweak.\n"
"-skip_keycodes string Skip keycodes not on your keyboard but your X server\n" "-skip_keycodes string Skip keycodes not on your keyboard but your X server\n"
" thinks exist. Currently only applies to -xkb mode.\n" " thinks exist. Currently only applies to -xkb mode.\n"
" \"string\" is a comma separated list of decimal\n" " \"string\" is a comma separated list of decimal\n"
...@@ -8199,17 +8639,70 @@ static void print_help(void) { ...@@ -8199,17 +8639,70 @@ static void print_help(void) {
" back to clients. (PRIMARY is still set on received\n" " back to clients. (PRIMARY is still set on received\n"
" changes, however).\n" " changes, however).\n"
"\n" "\n"
"-nocursor Do not have the VNC viewer show a local cursor.\n" "-cursor [mode] Sets how the pointer cursor shape (little icon at the\n"
"-mouse Draw a 2nd cursor at the current X pointer position.\n" "-nocursor mouse pointer) should be handled. The \"mode\" string\n"
"-mouseX As -mouse, but also draw an \"X\" when pointer is on\n" " is optional and is described below. The default\n"
" root background.\n" " is to show some sort of cursor shape(s). How this\n"
"-X Shorthand for -mouseX -nocursor.\n" " is done depends on the VNC viewer and the X server.\n"
"-xwarppointer Move the pointer with XWarpPointer() instead of XTEST\n" " Use -nocursor to disable cursor shapes completely.\n"
" (try as a workaround if pointer behaves poorly, e.g.\n" "\n"
" on touchscreens or other non-standard setups).\n" " Some VNC viewers support the TightVNC CursorPosUpdates\n"
" and CursorShapeUpdates extensions (cuts down on\n"
" network traffic by not having to send the cursor image\n"
" every time the pointer is moved), in which case these\n"
" extensions are used (see -nocursorshape and -nocursorpos\n"
" below). For other viewers the cursor shape is written\n"
" directly to the framebuffer every time the pointer is\n"
" moved or changed and gets sent along with the other\n"
" framebuffer updates. In this case, there will be\n"
" some lag between the vnc viewer pointer and the remote\n"
" cursor position.\n"
"\n"
" If the X display supports retrieving the cursor shape\n"
" information from the X server, then the default\n"
" is to use that mode. On Solaris this requires\n"
" the SUN_OVL extension and the -overlay option to be\n"
" supplied. (see also the -overlay_nomouse option). (Soon)\n"
" on XFree86/Xorg the XFIXES extension is required.\n"
" Either can be disabled with -nocursor, and also some\n"
" values of the \"mode\" option below.\n"
"\n"
" The \"mode\" string can be used to fine-tune the\n"
" displaying of cursor shapes. It can be used the\n"
" following ways:\n"
"\n"
" \"-cursor X\" - when the cursor appears to be on the\n"
" root window, draw the familiar X shape. Some desktops\n"
" such as GNOME cover up the root window completely,\n"
" and so this will not work, try \"X1\", etc, to try to\n"
" shift the tree depth. On high latency links or slow\n"
" machines there will be a time lag between expected and\n"
" the actual cursor shape.\n"
"\n"
" \"-cursor some\" - like \"X\" but use additional\n"
" heuristics to try to guess if the window should have\n"
" a windowmanager-like resizer cursor or a text input\n"
" I-beam cursor. This is a complete hack, but may be\n"
" useful in some situations because it provides a little\n"
" more feedback about the cursor shape.\n"
"\n"
" \"-cursor most\" - try to show as many cursors as\n"
" possible. Often this will only be the same as \"some\".\n"
" On Solaris if XFIXES is not available, -overlay mode\n"
" will be used.\n"
"\n"
"-nocursorshape Do not use the TightVNC CursorShapeUpdates extension\n"
" even if clients support it. See -cursor above.\n"
"-cursorpos Option -cursorpos enables sending the X cursor position\n" "-cursorpos Option -cursorpos enables sending the X cursor position\n"
"-nocursorpos back to all vnc clients that support the TightVNC\n" "-nocursorpos back to all vnc clients that support the TightVNC\n"
" CursorPosUpdates extension. Default: %s\n" " CursorPosUpdates extension. Other clients will be able\n"
" to see the pointer motions. Default: %s\n"
"-xwarppointer Move the pointer with XWarpPointer(3X) instead of XTEST\n"
" extension. Use this as a workaround if the pointer\n"
" motion behaves incorrectly, e.g. on touchscreens or\n"
" other non-standard setups. Also sometimes needed on\n"
" XINERAMA displays.\n"
"\n"
"-buttonmap string String to remap mouse buttons. Format: IJK-LMN, this\n" "-buttonmap string String to remap mouse buttons. Format: IJK-LMN, this\n"
" maps buttons I -> L, etc., e.g. -buttonmap 13-31\n" " maps buttons I -> L, etc., e.g. -buttonmap 13-31\n"
"\n" "\n"
...@@ -8284,9 +8777,10 @@ static void print_help(void) { ...@@ -8284,9 +8777,10 @@ static void print_help(void) {
fprintf(stderr, help, lastmod, fprintf(stderr, help, lastmod,
view_only ? "on":"off", view_only ? "on":"off",
shared ? "on":"off", shared ? "on":"off",
vnc_connect ? "-vncconnect":"-novncconnect",
use_modifier_tweak ? "-modtweak":"-nomodtweak", use_modifier_tweak ? "-modtweak":"-nomodtweak",
no_autorepeat ? "-norepeat":"-repeat", no_autorepeat ? "-norepeat":"-repeat",
cursor_pos ? "-cursorpos":"-nocursorpos", cursor_pos_updates ? "-cursorpos":"-nocursorpos",
defer_update, defer_update,
waitms, waitms,
take_naps ? "on":"off", take_naps ? "on":"off",
...@@ -8536,7 +9030,8 @@ static void check_rcfile(int argc, char **argv) { ...@@ -8536,7 +9030,8 @@ static void check_rcfile(int argc, char **argv) {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
XImage *fb; XImage *fb;
int i, ev, er, maj, min; int i;
int ev, er, maj, min;
char *use_dpy = NULL; char *use_dpy = NULL;
char *auth_file = NULL; char *auth_file = NULL;
char *arg, *visual_str = NULL; char *arg, *visual_str = NULL;
...@@ -8652,8 +9147,10 @@ int main(int argc, char* argv[]) { ...@@ -8652,8 +9147,10 @@ int main(int argc, char* argv[]) {
scale_denom = n; scale_denom = n;
} }
if (scale_fac == 1.0) { if (scale_fac == 1.0) {
fprintf(stderr, "scaling disabled for factor " if (! quiet) {
"%f\n", scale_fac); rfbLog("scaling disabled for factor "
" %f\n", scale_fac);
}
} else { } else {
scaling = 1; scaling = 1;
} }
...@@ -8662,6 +9159,9 @@ int main(int argc, char* argv[]) { ...@@ -8662,6 +9159,9 @@ int main(int argc, char* argv[]) {
visual_str = argv[++i]; visual_str = argv[++i];
} else if (!strcmp(arg, "-overlay")) { } else if (!strcmp(arg, "-overlay")) {
overlay = 1; overlay = 1;
} else if (!strcmp(arg, "-overlay_nocursor")) {
overlay = 1;
overlay_cursor = 0;
} else if (!strcmp(arg, "-flashcmap")) { } else if (!strcmp(arg, "-flashcmap")) {
flash_cmap = 1; flash_cmap = 1;
} else if (!strcmp(arg, "-notruecolor")) { } else if (!strcmp(arg, "-notruecolor")) {
...@@ -8715,6 +9215,8 @@ int main(int argc, char* argv[]) { ...@@ -8715,6 +9215,8 @@ int main(int argc, char* argv[]) {
} }
} else if (!strcmp(arg, "-vncconnect")) { } else if (!strcmp(arg, "-vncconnect")) {
vnc_connect = 1; vnc_connect = 1;
} else if (!strcmp(arg, "-novncconnect")) {
vnc_connect = 0;
} else if (!strcmp(arg, "-inetd")) { } else if (!strcmp(arg, "-inetd")) {
inetd = 1; inetd = 1;
} else if (!strcmp(arg, "-noshm")) { } else if (!strcmp(arg, "-noshm")) {
...@@ -8760,23 +9262,28 @@ int main(int argc, char* argv[]) { ...@@ -8760,23 +9262,28 @@ int main(int argc, char* argv[]) {
watch_selection = 0; watch_selection = 0;
} else if (!strcmp(arg, "-noprimary")) { } else if (!strcmp(arg, "-noprimary")) {
watch_primary = 0; watch_primary = 0;
} else if (!strcmp(arg, "-nocursor")) { } else if (!strcmp(arg, "-cursor")) {
local_cursor = 0; show_cursor = 1;
} else if (!strcmp(arg, "-mouse")) { if (i >= argc-1) {
show_mouse = 1; ;
} else if (!strcmp(arg, "-mouseX")) { } else {
show_mouse = 1; char *s = argv[i+1];
show_root_cursor = 1; if (*s == 'X' || !strcmp(s, "default") ||
} else if (!strcmp(arg, "-X")) { !strcmp(s, "some") || !strcmp(s, "most")) {
show_mouse = 1; multiple_cursors_mode = strdup(s);
show_root_cursor = 1; i++;
local_cursor = 0; }
} else if (!strcmp(arg, "-xwarppointer")) { }
use_xwarppointer = 1; } else if (!strcmp(arg, "-nocursor")) {
show_cursor = 0;
} else if (!strcmp(arg, "-cursorpos")) { } else if (!strcmp(arg, "-cursorpos")) {
cursor_pos = 1; cursor_pos_updates = 1;
} else if (!strcmp(arg, "-nocursorpos")) { } else if (!strcmp(arg, "-nocursorpos")) {
cursor_pos = 0; cursor_pos_updates = 0;
} else if (!strcmp(arg, "-nocursorshape")) {
cursor_shape_updates = 0;
} else if (!strcmp(arg, "-xwarppointer")) {
use_xwarppointer = 1;
} else if (!strcmp(arg, "-buttonmap")) { } else if (!strcmp(arg, "-buttonmap")) {
CHECK_ARGC CHECK_ARGC
pointer_remap = argv[++i]; pointer_remap = argv[++i];
...@@ -8792,10 +9299,8 @@ int main(int argc, char* argv[]) { ...@@ -8792,10 +9299,8 @@ int main(int argc, char* argv[]) {
no_autorepeat = 1; no_autorepeat = 1;
} else if (!strcmp(arg, "-repeat")) { } else if (!strcmp(arg, "-repeat")) {
no_autorepeat = 0; no_autorepeat = 0;
} else if (!strcmp(arg, "-onetile") } else if (!strcmp(arg, "-onetile")) {
|| !strcmp(arg, "-old_copytile")) {
single_copytile = 1; single_copytile = 1;
} else if (!strcmp(arg, "-debug_pointer")) {
} else if (!strcmp(arg, "-debug_pointer") } else if (!strcmp(arg, "-debug_pointer")
|| !strcmp(arg, "-dp")) { || !strcmp(arg, "-dp")) {
debug_pointer++; debug_pointer++;
...@@ -8842,9 +9347,6 @@ int main(int argc, char* argv[]) { ...@@ -8842,9 +9347,6 @@ int main(int argc, char* argv[]) {
} else if (!strcmp(arg, "-fuzz")) { } else if (!strcmp(arg, "-fuzz")) {
CHECK_ARGC CHECK_ARGC
tile_fuzz = atoi(argv[++i]); tile_fuzz = atoi(argv[++i]);
} else if (!strcmp(arg, "-hints") || !strcmp(arg, "-nohints")) {
fprintf(stderr, "warning: -hints/-nohints option "
"has been removed.\n");
} else if (!strcmp(arg, "-h") || !strcmp(arg, "-help") } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")
|| !strcmp(arg, "-?")) { || !strcmp(arg, "-?")) {
print_help(); print_help();
...@@ -8907,8 +9409,7 @@ int main(int argc, char* argv[]) { ...@@ -8907,8 +9409,7 @@ int main(int argc, char* argv[]) {
if (! quiet && ! inetd) { if (! quiet && ! inetd) {
int i; int i;
for (i=1; i < argc_vnc; i++) { for (i=1; i < argc_vnc; i++) {
fprintf(stderr, "passing arg to libvncserver: %s\n", rfbLog("passing arg to libvncserver: %s\n", argv_vnc[i]);
argv_vnc[i]);
if (!strcmp(argv_vnc[i], "-passwd")) { if (!strcmp(argv_vnc[i], "-passwd")) {
i++; i++;
} }
...@@ -8937,9 +9438,8 @@ int main(int argc, char* argv[]) { ...@@ -8937,9 +9438,8 @@ int main(int argc, char* argv[]) {
FILE *in; FILE *in;
in = fopen(passwdfile, "r"); in = fopen(passwdfile, "r");
if (in == NULL) { if (in == NULL) {
fprintf(stderr, "cannot open passwdfile: %s\n", rfbLog("cannot open passwdfile: %s\n", passwdfile);
passwdfile); rfbLog("fopen");
perror("fopen");
exit(1); exit(1);
} }
if (fgets(line, 1024, in) != NULL) { if (fgets(line, 1024, in) != NULL) {
...@@ -8970,15 +9470,15 @@ int main(int argc, char* argv[]) { ...@@ -8970,15 +9470,15 @@ int main(int argc, char* argv[]) {
if (ok) { if (ok) {
viewonly_passwd = strdup(line); viewonly_passwd = strdup(line);
} else { } else {
fprintf(stderr, "*** not setting" rfbLog("*** not setting"
" viewonly password to the 2nd" " viewonly password to the 2nd"
" line of %s. (blank or other" " line of %s. (blank or other"
" problem)\n", passwdfile); " problem)\n", passwdfile);
} }
} }
} else { } else {
fprintf(stderr, "cannot read a line from " rfbLog("cannot read a line from passwdfile: %s\n",
"passwdfile: %s\n", passwdfile); passwdfile);
exit(1); exit(1);
} }
fclose(in); fclose(in);
...@@ -8996,17 +9496,15 @@ int main(int argc, char* argv[]) { ...@@ -8996,17 +9496,15 @@ int main(int argc, char* argv[]) {
} }
} }
if (viewonly_passwd && pw_loc < 0) { if (viewonly_passwd && pw_loc < 0) {
fprintf(stderr, "-passwd must be supplied when using " rfbLog("-passwd must be supplied when using -viewpasswd\n");
"-viewpasswd\n");
exit(1); exit(1);
} }
/* fixup settings that do not make sense */ /* fixup settings that do not make sense */
if (use_threads && nofb && cursor_pos) { if (use_threads && nofb && cursor_pos_updates) {
if (! quiet) { if (! quiet) {
fprintf(stderr, "disabling -threads under -nofb " rfbLog("disabling -threads under -nofb -cursorpos\n");
"-cursorpos\n");
} }
use_threads = 0; use_threads = 0;
} }
...@@ -9022,34 +9520,94 @@ int main(int argc, char* argv[]) { ...@@ -9022,34 +9520,94 @@ int main(int argc, char* argv[]) {
bg = 0; bg = 0;
} }
if (flip_byte_order && using_shm && ! quiet) {
rfbLog("warning: -flipbyte order only works with -noshm\n");
}
/* increase rfbwait if threaded */ /* increase rfbwait if threaded */
if (use_threads && ! got_rfbwait) { if (use_threads && ! got_rfbwait) {
argv_vnc[argc_vnc++] = "-rfbwait"; argv_vnc[argc_vnc++] = "-rfbwait";
argv_vnc[argc_vnc++] = "604800000"; /* one week... */ argv_vnc[argc_vnc++] = "604800000"; /* one week... */
} }
/* cursor shapes setup */
#ifdef SOLARIS
if (show_cursor && ! overlay && overlay_cursor &&
!strcmp(multiple_cursors_mode, "most")) {
overlay = 1;
if (! quiet) {
rfbLog("enabling -overlay mode to achieve "
"'-cursor most'\n");
rfbLog("disable with: -overlay_nocursor.\n");
}
}
#endif
if (overlay) { if (overlay) {
#ifdef SOLARIS #ifdef SOLARIS
using_shm = 0; using_shm = 0;
if (flash_cmap && ! quiet) { if (flash_cmap && ! quiet) {
fprintf(stderr, "warning: -flashcmap may be " rfbLog("warning: -flashcmap may be incompatible "
"incompatible with -overlay\n"); "with -overlay\n");
} }
if (show_mouse) { if (show_cursor && overlay_cursor) {
show_mouse = 0; char *s = multiple_cursors_mode;
overlay_mouse = 1; if (*s == 'X' || !strcmp(s, "some")) {
/*
* user wants these modes, so disable fb cursor
*/
overlay_cursor = 0;
} else {
/*
* "default" and "most", we turn off
* show_cursor since it will automatically
* be in the framebuffer.
*/
show_cursor = 0;
}
} }
#else #else
if (! quiet) { if (! quiet) {
fprintf(stderr, "disabling -overlay: currently only " rfbLog("disabling -overlay: only available on "
"available on Solaris Xsun.\n"); "Solaris Xsun.\n");
} }
overlay = 0; overlay = 0;
#endif #endif
} }
if (show_cursor) {
char *s = multiple_cursors_mode;
if (*s == 'X' || !strcmp(s, "some")) {
show_multiple_cursors = 1;
} else if (!strcmp(s, "most")) {
/* later check for XFIXES, for now "some" */
show_multiple_cursors = 1;
}
}
/* no framebuffer (Win2VNC) mode */
if (nofb) {
/* disable things that do not make sense */
using_shm = 0;
flash_cmap = 0;
show_cursor = 0;
show_multiple_cursors = 0;
overlay = 0;
if (! quiet) {
rfbLog("disabling -cursor, fb, shm, etc. in "
"-nofb mode.\n");
}
if (! got_deferupdate && ! got_defer) {
/* reduce defer time under -nofb */
defer_update = defer_update_nofb;
}
}
/* check for OS with small shm limits */ /* check for OS with small shm limits */
if (using_shm && ! single_copytile) { if (using_shm && ! single_copytile) {
if (limit_shm()) { if (limit_shm()) {
...@@ -9057,10 +9615,6 @@ int main(int argc, char* argv[]) { ...@@ -9057,10 +9615,6 @@ int main(int argc, char* argv[]) {
} }
} }
if (nofb && ! got_deferupdate && ! got_defer) {
/* reduce defer time under -nofb */
defer_update = defer_update_nofb;
}
if (! got_deferupdate) { if (! got_deferupdate) {
char tmp[40]; char tmp[40];
/* XXX not working yet in libvncserver */ /* XXX not working yet in libvncserver */
...@@ -9068,9 +9622,10 @@ int main(int argc, char* argv[]) { ...@@ -9068,9 +9622,10 @@ int main(int argc, char* argv[]) {
argv_vnc[argc_vnc++] = "-deferupdate"; argv_vnc[argc_vnc++] = "-deferupdate";
argv_vnc[argc_vnc++] = strdup(tmp); argv_vnc[argc_vnc++] = strdup(tmp);
} }
if (debug_pointer || debug_keyboard) { if (debug_pointer || debug_keyboard) {
if (bg || quiet) { if (bg || quiet) {
fprintf(stderr, "disabling -bg/-q under -debug_pointer" rfbLog("disabling -bg/-q under -debug_pointer"
"/-debug_keyboard\n"); "/-debug_keyboard\n");
bg = 0; bg = 0;
quiet = 0; quiet = 0;
...@@ -9079,81 +9634,85 @@ int main(int argc, char* argv[]) { ...@@ -9079,81 +9634,85 @@ int main(int argc, char* argv[]) {
if (! quiet) { if (! quiet) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "display: %s\n", use_dpy ? use_dpy fprintf(stderr, "Settings:\n");
fprintf(stderr, " display: %s\n", use_dpy ? use_dpy
: "null"); : "null");
fprintf(stderr, "subwin: 0x%x\n", subwin); fprintf(stderr, " subwin: 0x%x\n", subwin);
fprintf(stderr, "flashcmap: %d\n", flash_cmap); fprintf(stderr, " flashcmap: %d\n", flash_cmap);
fprintf(stderr, "force_idx: %d\n", force_indexed_color); fprintf(stderr, " force_idx: %d\n", force_indexed_color);
fprintf(stderr, "scaling: %d %.5f\n", scaling, scale_fac); fprintf(stderr, " scaling: %d %.5f\n", scaling, scale_fac);
fprintf(stderr, "visual: %s\n", visual_str ? visual_str fprintf(stderr, " visual: %s\n", visual_str ? visual_str
: "null"); : "null");
fprintf(stderr, "overlay: %d\n", overlay); fprintf(stderr, " overlay: %d\n", overlay);
fprintf(stderr, "ovl_mouse: %d\n", overlay_mouse); fprintf(stderr, " ovl_cursor: %d\n", overlay_cursor);
fprintf(stderr, "viewonly: %d\n", view_only); fprintf(stderr, " viewonly: %d\n", view_only);
fprintf(stderr, "shared: %d\n", shared); fprintf(stderr, " shared: %d\n", shared);
fprintf(stderr, "conn_once: %d\n", connect_once); fprintf(stderr, " conn_once: %d\n", connect_once);
fprintf(stderr, "connect: %s\n", client_connect fprintf(stderr, " connect: %s\n", client_connect
? client_connect : "null"); ? client_connect : "null");
fprintf(stderr, "connectfile %s\n", client_connect_file fprintf(stderr, " connectfile %s\n", client_connect_file
? client_connect_file : "null"); ? client_connect_file : "null");
fprintf(stderr, "vnc_conn: %d\n", vnc_connect); fprintf(stderr, " vnc_conn: %d\n", vnc_connect);
fprintf(stderr, "authfile: %s\n", auth_file ? auth_file fprintf(stderr, " authfile: %s\n", auth_file ? auth_file
: "null"); : "null");
fprintf(stderr, "allow: %s\n", allow_list ? allow_list fprintf(stderr, " allow: %s\n", allow_list ? allow_list
: "null"); : "null");
fprintf(stderr, "passfile: %s\n", passwdfile ? passwdfile fprintf(stderr, " passfile: %s\n", passwdfile ? passwdfile
: "null"); : "null");
fprintf(stderr, "accept: %s\n", accept_cmd ? accept_cmd fprintf(stderr, " accept: %s\n", accept_cmd ? accept_cmd
: "null"); : "null");
fprintf(stderr, "gone: %s\n", gone_cmd ? gone_cmd fprintf(stderr, " gone: %s\n", gone_cmd ? gone_cmd
: "null"); : "null");
fprintf(stderr, "inetd: %d\n", inetd); fprintf(stderr, " inetd: %d\n", inetd);
fprintf(stderr, "using_shm: %d\n", using_shm); fprintf(stderr, " using_shm: %d\n", using_shm);
fprintf(stderr, "flipbytes: %d\n", flip_byte_order); fprintf(stderr, " flipbytes: %d\n", flip_byte_order);
fprintf(stderr, "blackout: %s\n", blackout_string fprintf(stderr, " blackout: %s\n", blackout_string
? blackout_string : "null"); ? blackout_string : "null");
fprintf(stderr, "xinerama: %d\n", xinerama); fprintf(stderr, " xinerama: %d\n", xinerama);
fprintf(stderr, "logfile: %s\n", logfile ? logfile fprintf(stderr, " logfile: %s\n", logfile ? logfile
: "null");
fprintf(stderr, "bg: %d\n", bg);
fprintf(stderr, "mod_tweak: %d\n", use_modifier_tweak);
fprintf(stderr, "isolevel3: %d\n", use_iso_level3);
fprintf(stderr, "xkb: %d\n", use_xkb_modtweak);
fprintf(stderr, "skipkeys: %s\n", skip_keycodes ? skip_keycodes
: "null"); : "null");
fprintf(stderr, "addkeysyms: %d\n", add_keysyms); fprintf(stderr, " bg: %d\n", bg);
fprintf(stderr, "xkbcompat: %d\n", xkbcompat); fprintf(stderr, " mod_tweak: %d\n", use_modifier_tweak);
fprintf(stderr, "clearmods: %d\n", clear_mods); fprintf(stderr, " isolevel3: %d\n", use_iso_level3);
fprintf(stderr, "remap: %s\n", remap_file ? remap_file fprintf(stderr, " xkb: %d\n", use_xkb_modtweak);
fprintf(stderr, " skipkeys: %s\n",
skip_keycodes ? skip_keycodes : "null");
fprintf(stderr, " addkeysyms: %d\n", add_keysyms);
fprintf(stderr, " xkbcompat: %d\n", xkbcompat);
fprintf(stderr, " clearmods: %d\n", clear_mods);
fprintf(stderr, " remap: %s\n", remap_file ? remap_file
: "null"); : "null");
fprintf(stderr, "nofb: %d\n", nofb); fprintf(stderr, " nofb: %d\n", nofb);
fprintf(stderr, "watchbell: %d\n", watch_bell); fprintf(stderr, " watchbell: %d\n", watch_bell);
fprintf(stderr, "watchsel: %d\n", watch_selection); fprintf(stderr, " watchsel: %d\n", watch_selection);
fprintf(stderr, "watchprim: %d\n", watch_primary); fprintf(stderr, " watchprim: %d\n", watch_primary);
fprintf(stderr, "loc_curs: %d\n", local_cursor); fprintf(stderr, " cursor: %d\n", show_cursor);
fprintf(stderr, "mouse: %d\n", show_mouse); fprintf(stderr, " root_curs: %d\n", show_multiple_cursors);
fprintf(stderr, "root_curs: %d\n", show_root_cursor); fprintf(stderr, " curs_mode: %s\n", multiple_cursors_mode
fprintf(stderr, "xwarpptr: %d\n", use_xwarppointer); ? multiple_cursors_mode : "null");
fprintf(stderr, "cursorpos: %d\n", cursor_pos); fprintf(stderr, " xwarpptr: %d\n", use_xwarppointer);
fprintf(stderr, "buttonmap: %s\n", pointer_remap fprintf(stderr, " cursorpos: %d\n", cursor_pos_updates);
fprintf(stderr, " cursorshp: %d\n", cursor_shape_updates);
fprintf(stderr, " buttonmap: %s\n", pointer_remap
? pointer_remap : "null"); ? pointer_remap : "null");
fprintf(stderr, "dragging: %d\n", show_dragging); fprintf(stderr, " dragging: %d\n", show_dragging);
fprintf(stderr, "old_ptr: %d\n", old_pointer); fprintf(stderr, " old_ptr: %d\n", old_pointer);
fprintf(stderr, "inputskip: %d\n", ui_skip); fprintf(stderr, " inputskip: %d\n", ui_skip);
fprintf(stderr, "norepeat: %d\n", no_autorepeat); fprintf(stderr, " norepeat: %d\n", no_autorepeat);
fprintf(stderr, "debug_ptr: %d\n", debug_pointer); fprintf(stderr, " debug_ptr: %d\n", debug_pointer);
fprintf(stderr, "debug_key: %d\n", debug_keyboard); fprintf(stderr, " debug_key: %d\n", debug_keyboard);
fprintf(stderr, "defer: %d\n", defer_update); fprintf(stderr, " defer: %d\n", defer_update);
fprintf(stderr, "waitms: %d\n", waitms); fprintf(stderr, " waitms: %d\n", waitms);
fprintf(stderr, "take_naps: %d\n", take_naps); fprintf(stderr, " take_naps: %d\n", take_naps);
fprintf(stderr, "sigpipe: %d\n", sigpipe); fprintf(stderr, " sigpipe: %d\n", sigpipe);
fprintf(stderr, "threads: %d\n", use_threads); fprintf(stderr, " threads: %d\n", use_threads);
fprintf(stderr, "fs_frac: %.2f\n", fs_frac); fprintf(stderr, " fs_frac: %.2f\n", fs_frac);
fprintf(stderr, "onetile: %d\n", single_copytile); fprintf(stderr, " onetile: %d\n", single_copytile);
fprintf(stderr, "gaps_fill: %d\n", gaps_fill); fprintf(stderr, " gaps_fill: %d\n", gaps_fill);
fprintf(stderr, "grow_fill: %d\n", grow_fill); fprintf(stderr, " grow_fill: %d\n", grow_fill);
fprintf(stderr, "tile_fuzz: %d\n", tile_fuzz); fprintf(stderr, " tile_fuzz: %d\n", tile_fuzz);
fprintf(stderr, "version: %s\n", lastmod); fprintf(stderr, "\n");
rfbLog("x11vnc version: %s\n", lastmod);
} else { } else {
rfbLogEnable(0); rfbLogEnable(0);
} }
...@@ -9182,11 +9741,11 @@ int main(int argc, char* argv[]) { ...@@ -9182,11 +9741,11 @@ int main(int argc, char* argv[]) {
if (xkbcompat) { if (xkbcompat) {
Bool rc = XkbIgnoreExtension(True); Bool rc = XkbIgnoreExtension(True);
if (! quiet) { if (! quiet) {
fprintf(stderr, "disabling xkb extension. rc=%d\n", rc); rfbLog("disabling xkb extension. rc=%d\n", rc);
if (watch_bell) { }
watch_bell = 0; if (watch_bell) {
fprintf(stderr, "disabling bell.\n"); watch_bell = 0;
} if (! quiet) rfbLog("disabling bell.\n");
} }
} }
#else #else
...@@ -9194,6 +9753,7 @@ int main(int argc, char* argv[]) { ...@@ -9194,6 +9753,7 @@ int main(int argc, char* argv[]) {
watch_bell = 0; watch_bell = 0;
use_xkb_modtweak = 0; use_xkb_modtweak = 0;
#endif #endif
if (use_dpy) { if (use_dpy) {
dpy = XOpenDisplay(use_dpy); dpy = XOpenDisplay(use_dpy);
} else if ( (use_dpy = getenv("DISPLAY")) ) { } else if ( (use_dpy = getenv("DISPLAY")) ) {
...@@ -9203,13 +9763,12 @@ int main(int argc, char* argv[]) { ...@@ -9203,13 +9763,12 @@ int main(int argc, char* argv[]) {
} }
if (! dpy) { if (! dpy) {
fprintf(stderr, "XOpenDisplay failed (%s)\n", rfbLog("XOpenDisplay failed (%s)\n", use_dpy ? use_dpy:"null");
use_dpy ? use_dpy:"null");
exit(1); exit(1);
} else if (use_dpy) { } else if (use_dpy) {
if (! quiet) fprintf(stderr, "Using X display %s\n", use_dpy); if (! quiet) rfbLog("Using X display %s\n", use_dpy);
} else { } else {
if (! quiet) fprintf(stderr, "Using default X display.\n"); if (! quiet) rfbLog("Using default X display.\n");
} }
scr = DefaultScreen(dpy); scr = DefaultScreen(dpy);
...@@ -9222,28 +9781,43 @@ int main(int argc, char* argv[]) { ...@@ -9222,28 +9781,43 @@ int main(int argc, char* argv[]) {
} }
/* check for XTEST */ /* check for XTEST */
if (! XTestQueryExtension(dpy, &ev, &er, &maj, &min)) { if (! XTestQueryExtension_wr(dpy, &ev, &er, &maj, &min)) {
fprintf(stderr, "Display does not support XTest extension.\n"); rfbLog("warning: XTest extension not available, most user"
exit(1); " input\n");
rfbLog("(pointer and keyboard) will be discarded.\n");
xtest_present = 0;
rfbLog("no XTest extension, switching to -xwarppointer mode\n");
rfbLog("for pointer motion input.\n");
use_xwarppointer = 1;
} }
/* /*
* Window managers will often grab the display during resize, etc. * Window managers will often grab the display during resize, etc.
* To avoid deadlock (our user resize input is not processed) * To avoid deadlock (our user resize input is not processed)
* we tell the server to process our requests during all grabs: * we tell the server to process our requests during all grabs:
*/ */
XTestGrabControl(dpy, True); XTestGrabControl_wr(dpy, True);
/* check for MIT-SHM */ /* check for MIT-SHM */
if (! nofb && ! XShmQueryExtension(dpy)) { if (! nofb && ! XShmQueryExtension_wr(dpy)) {
if (! using_shm) { if (! using_shm) {
if (! quiet) { if (! quiet) {
fprintf(stderr, "info: display does not " rfbLog("info: display does not support"
"support XShm.\n"); " XShm.\n");
} }
} else { } else {
fprintf(stderr, "Display does not support XShm " rfbLog("warning: XShm extension is not available.\n");
"extension (must be local).\n"); rfbLog("For best performance the X Display should be"
" local. (i.e.\n");
rfbLog("the x11vnc and X server processes should be"
" running on\n");
rfbLog("the same machine.)\n");
#ifdef LIBVNCSERVER_HAVE_XSHM
rfbLog("Restart with -noshm to override this.\n");
exit(1); exit(1);
#else
rfbLog("Switching to -noshm mode.\n");
using_shm = 0;
#endif
} }
} }
...@@ -9286,8 +9860,10 @@ int main(int argc, char* argv[]) { ...@@ -9286,8 +9860,10 @@ int main(int argc, char* argv[]) {
} }
initialize_watch_bell(); initialize_watch_bell();
if (!use_xkb && use_xkb_modtweak) { if (!use_xkb && use_xkb_modtweak) {
fprintf(stderr, "warning: disabling xkb modtweak." if (! quiet) {
" XKEYBOARD ext. not present.\n"); fprintf(stderr, "warning: disabling xkb modtweak."
" XKEYBOARD ext. not present.\n");
}
use_xkb_modtweak = 0; use_xkb_modtweak = 0;
} }
#endif #endif
...@@ -9316,9 +9892,8 @@ int main(int argc, char* argv[]) { ...@@ -9316,9 +9892,8 @@ int main(int argc, char* argv[]) {
/* this may be overridden via visual_id below */ /* this may be overridden via visual_id below */
default_visual = attr.visual; default_visual = attr.visual;
/* show_mouse has some segv crashes as well */ if (show_multiple_cursors) {
if (show_root_cursor) { show_multiple_cursors = 0;
show_root_cursor = 0;
if (! quiet) { if (! quiet) {
fprintf(stderr, "disabling root cursor drawing" fprintf(stderr, "disabling root cursor drawing"
" for subwindow\n"); " for subwindow\n");
...@@ -9368,6 +9943,10 @@ int main(int argc, char* argv[]) { ...@@ -9368,6 +9943,10 @@ int main(int argc, char* argv[]) {
XFree(vinfo); XFree(vinfo);
} }
if (! quiet) {
rfbLog("default visual ID: 0x%x\n",
(int) XVisualIDFromVisual(default_visual));
}
if (nofb) { if (nofb) {
/* /*
...@@ -9388,7 +9967,7 @@ int main(int argc, char* argv[]) { ...@@ -9388,7 +9967,7 @@ int main(int argc, char* argv[]) {
fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes,
ZPixmap); ZPixmap);
if (! quiet) { if (! quiet) {
fprintf(stderr, "Read initial data from X display into" rfbLog("Read initial data from X display into"
" framebuffer.\n"); " framebuffer.\n");
} }
} }
...@@ -9432,6 +10011,7 @@ int main(int argc, char* argv[]) { ...@@ -9432,6 +10011,7 @@ int main(int argc, char* argv[]) {
if (remap_file != NULL) { if (remap_file != NULL) {
initialize_remap(remap_file); initialize_remap(remap_file);
} }
initialize_pointer_map(pointer_remap); initialize_pointer_map(pointer_remap);
clear_modifiers(1); clear_modifiers(1);
...@@ -9454,7 +10034,7 @@ int main(int argc, char* argv[]) { ...@@ -9454,7 +10034,7 @@ int main(int argc, char* argv[]) {
if (host != NULL) { if (host != NULL) {
/* note that vncviewer special cases 5900-5999 */ /* note that vncviewer special cases 5900-5999 */
if (inetd) { if (inetd) {
; /* should not occur */ ; /* should not occur (rfbPort) */
} else if (quiet) { } else if (quiet) {
if (port >= 5900) { if (port >= 5900) {
fprintf(stderr, "The VNC desktop is " fprintf(stderr, "The VNC desktop is "
...@@ -9478,7 +10058,11 @@ int main(int argc, char* argv[]) { ...@@ -9478,7 +10058,11 @@ int main(int argc, char* argv[]) {
} }
} }
fflush(stderr); fflush(stderr);
fprintf(stdout, "PORT=%d\n", screen->rfbPort); if (inetd) {
; /* should not occur (rfbPort) */
} else {
fprintf(stdout, "PORT=%d\n", screen->rfbPort);
}
fflush(stdout); fflush(stdout);
} }
......
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