diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | prepare_x11vnc_dist.sh | 2 | ||||
-rw-r--r-- | x11vnc/ChangeLog | 10 | ||||
-rw-r--r-- | x11vnc/Makefile.am | 3 | ||||
-rw-r--r-- | x11vnc/README | 136 | ||||
-rw-r--r-- | x11vnc/misc/Makefile.am | 1 | ||||
-rw-r--r-- | x11vnc/misc/README | 32 | ||||
-rw-r--r-- | x11vnc/misc/blockdpy.c | 352 | ||||
-rw-r--r-- | x11vnc/misc/dtVncPopup | 109 | ||||
-rwxr-xr-x | x11vnc/misc/rx11vnc | 133 | ||||
-rwxr-xr-x | x11vnc/misc/rx11vnc.pl | 199 | ||||
-rwxr-xr-x | x11vnc/misc/shm_clear | 97 | ||||
-rwxr-xr-x | x11vnc/misc/slide.pl | 112 | ||||
-rwxr-xr-x | x11vnc/misc/vcinject.pl | 113 | ||||
-rwxr-xr-x | x11vnc/misc/x11vnc_loop | 89 | ||||
-rwxr-xr-x | x11vnc/tkx11vnc | 39 | ||||
-rw-r--r-- | x11vnc/tkx11vnc.h | 39 | ||||
-rw-r--r-- | x11vnc/x11vnc.1 | 149 | ||||
-rw-r--r-- | x11vnc/x11vnc.c | 1530 |
20 files changed, 2862 insertions, 290 deletions
@@ -1,3 +1,7 @@ +2005-04-10 Karl Runge <runge@karlrunge.com> + * configure.ac: add mmap + * x11vnc: -rawfb, -pipeinput, -xtrap, -flag, ... + 2005-04-03 Karl Runge <runge@karlrunge.com> * configure.ac: add conditional libXTrap checking * x11vnc: use DEC-XTRAP on old X11R5 for grab control. diff --git a/configure.ac b/configure.ac index 5274259..cd31883 100644 --- a/configure.ac +++ b/configure.ac @@ -266,7 +266,7 @@ AC_FUNC_VPRINTF AC_FUNC_FORK AC_CHECK_LIB(nsl,gethostbyname) AC_CHECK_LIB(socket,socket) -AC_CHECK_FUNCS([ftime gethostbyname gethostname gettimeofday inet_ntoa memmove memset mkfifo select socket strchr strcspn strdup strerror strstr setsid getpwuid getpwnam getuid geteuid setuid waitpid setutxent]) +AC_CHECK_FUNCS([ftime gethostbyname gethostname gettimeofday inet_ntoa memmove memset mmap mkfifo select socket strchr strcspn strdup strerror strstr setsid getpwuid getpwnam getuid geteuid setuid waitpid setutxent]) # check, if shmget is in cygipc.a AC_CHECK_LIB(cygipc,shmget) @@ -295,6 +295,7 @@ AC_CONFIG_FILES([Makefile libvncserver/Makefile contrib/Makefile x11vnc/Makefile + x11vnc/misc/Makefile examples/Makefile vncterm/Makefile classes/Makefile diff --git a/prepare_x11vnc_dist.sh b/prepare_x11vnc_dist.sh index c2e9735..ca78be6 100644 --- a/prepare_x11vnc_dist.sh +++ b/prepare_x11vnc_dist.sh @@ -1,6 +1,6 @@ #!/bin/bash -VERSION="0.7.1pre" +VERSION="0.7.2" cd "$(dirname "$0")" diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog index 20448ab..f56ad71 100644 --- a/x11vnc/ChangeLog +++ b/x11vnc/ChangeLog @@ -1,3 +1,13 @@ +2005-04-10 Karl Runge <runge@karlrunge.com> + * -rawfb non X-polling (i.e. shm, mmap, lseek). + * -pipeinput enable external user input processing command. + * -xtrap use XESimulateXEventRequest to inject user input. + * scaling blend for StaticGray, add :fb scaling option. + * default password macros. + * improve -norepeat use under -viewonly. + * -flag flagfile to aid wrapper scripts. + * add utility scripts, etc. dir ./misc + 2005-04-03 Karl Runge <runge@karlrunge.com> * try DEC-XTRAP on X11R5 if XTestGrabControl is missing. * -shiftcmap n, for 8bpp displays using < 256 color cells diff --git a/x11vnc/Makefile.am b/x11vnc/Makefile.am index bca1150..b601725 100644 --- a/x11vnc/Makefile.am +++ b/x11vnc/Makefile.am @@ -1,6 +1,9 @@ DEFINES = -I .. LDADD = ../libvncserver/libvncserver.a @WSOCKLIB@ +SUBDIRS = misc +DIST_SUBDIRS = misc + man_MANS=x11vnc.1 EXTRA_DIST=ChangeLog README tkx11vnc $(man_MANS) diff --git a/x11vnc/README b/x11vnc/README index f079d56..391bdda 100644 --- a/x11vnc/README +++ b/x11vnc/README @@ -1,5 +1,5 @@ -x11vnc README file Date: Sun Apr 3 16:28:59 EDT 2005 +x11vnc README file Date: Sun Apr 10 00:24:10 EDT 2005 The following information is taken from these URLs: @@ -97,15 +97,22 @@ x11vnc: a VNC server for real X displays You could have also set the environment variable DISPLAY=:0 instead of using -display. This step attaches x11vnc to the far-away.east:0 X - display (no viewer clients yet). + display (i.e. no viewer clients yet). To get X11 permissions right, you may also need to set the XAUTHORITY environment variable (or use the [12]-auth option) to point to the correct MIT-MAGIC-COOKIE file (e.g. /home/joe/.Xauthority). More on this [13]below. - There will then be much chatter printed out from x11vnc, until it - finally says something like: + If you suspect an X11 permissions problem do this simple test: while + sitting at the physical X display open a terminal window + (gnome-terminal, xterm, etc). You should be able to start x11vnc + without any need for command line options in that terminal. If that + works OK then you know X11 permissions are the only thing preventing + it from working when you try to start x11vnc via a remote shell. + + When x11vnc starts up there will then be much chatter printed out, + until it finally says something like: . . 13/05/2004 14:59:54 Autoprobing selected port 5900 @@ -1021,14 +1028,24 @@ make specify it. Nearly always the correct value will be ":0" For the latter error, you need to set up the X11 permissions - correctly. See the xauth(1), Xsecurity(7), and xhost(1) man pages for - much info. For example, you may need to set your XAUTHORITY - environment variable or use the [142]-auth option to point to the - correct cookie file (e.g. /home/joe/.Xauthority or /var/gdm/:0.Xauth), - or simply be sure you run x11vnc as the correct user (i.e. the user - who owns the X session you wish to view). Running x11vnc as root is - not enough: you need to know where the XAUTHORITY file for the desired - X display is. Example: + correctly. + + To make sure X11 permissions are the problem do this simple test: + while sitting at the physical X display open a terminal window + (gnome-terminal, xterm, etc). You should be able to start x11vnc + without any need for special steps or command line options in that + terminal. If that works OK then you know X11 permissions are the only + thing preventing it from working when you try to start x11vnc via, + say, a remote shell. + + How to Solve: See the xauth(1), Xsecurity(7), and xhost(1) man pages + for much info on X11 permissions. For example, you may need to set + your XAUTHORITY environment variable or use the [142]-auth option to + point to the correct cookie file (e.g. /home/joe/.Xauthority or + /var/gdm/:0.Xauth), or simply be sure you run x11vnc as the correct + user (i.e. the user who owns the X session you wish to view). Running + x11vnc as root is not enough: you need to know where the XAUTHORITY + file for the desired X display is. Example: x11vnc -display :0 -auth /var/gdm/:0.Xauth Less safe, but to avoid figuring out where the XAUTHORITY file is, if @@ -1036,24 +1053,26 @@ make should be able to attach x11vnc to the session (from the same machine). The person could then type "xhost -localhost" after x11vnc has connected to go back to the default permissions. Also, for some - situations the -users lurk= option may be of use (please read the + situations the "-users lurk=" option may be of use (please read the documentation on the [143]-users option). - To test out your X11 permissions, set DISPLAY and possibly XAUTHORITY - (see your shell's man page, bash(1), tcsh(1), on how to set - environment variables) and type xdpyinfo in the same place you will be - typing (or otherwise running) x11vnc. If information is printed out - about the X display (screen sizes, supported extensions, color visuals - info) that means the X11 permissions are set up properly: xdpyinfo - successfully connected to DISPLAY. You could also type xclock and make - sure no errors are reported (a clock should appear on the X display, - type Ctrl-C to quit it) + To test out your X11 permissions from a remote shell, set DISPLAY and + possibly XAUTHORITY (see your shell's man page, bash(1), tcsh(1), on + how to set environment variables) and type xdpyinfo in the same place + you will be typing (or otherwise running) x11vnc. If information is + printed out about the X display (screen sizes, supported extensions, + color visuals info) that means the X11 permissions are set up + properly: xdpyinfo successfully connected to DISPLAY! You could also + type xclock and make sure no errors are reported (a clock should + appear on the X display, press Ctrl-C to stop it). If these work, then + typing "x11vnc" should also work. Important: if you cannot get your X11 permissions so that the xdpyinfo or xclock tests work, x11vnc also will not work (all of these X clients must be allowed to connect to the X server to function properly). + Q-2: I can't get x11vnc and/or libvncserver to compile. Make sure you have all of the required -devel packages installed. @@ -1092,6 +1111,7 @@ make XFree86-devel zlib-devel + Q-3: I just built x11vnc successfully, but when I use it my keystrokes and mouse button clicks are ignored (I am able to move the mouse though). @@ -1131,6 +1151,7 @@ h 20/03/2005 22:33:09 No XTEST extension, switching to -xwarppointer mode for 20/03/2005 22:33:09 pointer motion input. + Q-4: Help, I need to run x11vnc on Solaris 2.5.1 (or other old Unix/Linux) and it doesn't compile! @@ -1177,6 +1198,7 @@ typedef unsigned int in_addr_t; it worked or not). If there is enough demand we will try to push clean compilations back to earlier Solaris, Linux, etc, releases. + Q-5: Where can I get a precompiled x11vnc binary for my Operating System? @@ -1225,6 +1247,7 @@ typedef unsigned int in_addr_t; resulting data.tar.gz tar file. Also, rpm2cpio(1) is useful in extracting files from rpm packages. + Q-6: Where can I get a VNC Viewer binary (or source code) for the Operating System I will be viewing from? @@ -1234,6 +1257,7 @@ typedef unsigned int in_addr_t; * [156]http://www.realvnc.com/download-free.html * [157]http://sourceforge.net/projects/cotvnc/ + Q-7: How can I see all of x11vnc's command line options and documentation on how to use them? @@ -1241,6 +1265,7 @@ typedef unsigned int in_addr_t; -help for long descriptions about each option. The output is listed [158]here as well. + Q-8: I don't like typing arcane command line options every time I start x11vnc. What can I do? Is there a config file? Or a GUI? @@ -1275,6 +1300,7 @@ display :0 "x11vnc ... -gui other:0" in the latter case the gui is displayed on other:0, not the X display x11vnc is polling. + Q-9: Can I make x11vnc more quiet and also go into the background after starting up? @@ -1284,6 +1310,7 @@ display :0 Note that under -bg the stderr messages will be lost unless you use the "[162]-o logfile" option. + Q-10: Sometimes when a VNC viewer dies abruptly, x11vnc also dies with the error message like: "Broken pipe". I'm using the -forever mode and I want x11vnc to keep running. @@ -1297,6 +1324,7 @@ display :0 [163]x11vnc.c file. It also has an [164]option -sigpipe exit to have x11vnc clean up and exit upon receiving SIGPIPE. + Q-11: Are there any build-time customizations possible, e.g. change defaults, create a smaller binary, etc? @@ -1318,6 +1346,14 @@ display :0 If other things (e.g. "-I ...") are needed in CPPFLAGS add them as well. + Be careful the the following two variables: HARDWIRE_PASSWD and + HARDWIRE_VIEWPASSWD. If set (remember to include the double quotes + around the string), they will be used as default values for the + -passwd and -viewpasswd options. Of course the strings will exist + unobscured in the x11vnc: the binary better not be readable by + unintendeds. Perhaps this is of use in remote access for an embedded + application, etc... + Let us know if more build-time customizations would be useful. If the system does not have the XTEST XTestGrabControl interface (some @@ -1357,6 +1393,7 @@ display :0 All of them will work with x11vnc (except x2x where it is not needed). + Q-13: I am running Win2VNC on my Windows machine and "x11vnc -nofb" on Unix to pass keyboard and mouse to the Unix monitor. Whenever I start Win2VNC it quickly disconnects and x11vnc says: @@ -1401,6 +1438,7 @@ display :0 non-zero in 8bpp PseudoColor on an obscure setup, and this option corrected the problems. + Q-15: Color problems: Why are the colors for some windows messed up in x11vnc? BTW, my X display has nice overlay/multi-depth visuals of different color depths: e.g. there are both depth 8 and 24 visuals @@ -1480,6 +1518,7 @@ TrueColor defdepth 24 [182]-overlay option works for Solaris machines with overlay visuals where most of this problem occurs. + Q-16: How do I figure out the window id to supply to the -id windowid option? @@ -1498,6 +1537,7 @@ TrueColor defdepth 24 extracts the windowid. Besides "pick" there is also "id:root" to allow you to go back to root window when doing remote-control. + Q-17: Why don't menus or other transient windows come up when I am using the -id windowid option to view a single application window? @@ -1515,6 +1555,7 @@ TrueColor defdepth 24 x11vnc is known to crash under both -id and -sid, so both modes are still experimental. Please report any reproducible bugs. + Q-18: My X display is depth 24 at 24bpp (instead of the normal depth 24 at 32bpp). I'm having lots of color and visual problems with x11vnc and/or vncviewer. What's up? @@ -1673,6 +1714,7 @@ TrueColor defdepth 24 Alt. Alternatively, the [196]-clear_mods option and [197]-clear_keys option can be used to release pressed keys at startup and exit. + Q-22: Can I change settings in x11vnc without having to restart it? Can I remote control it? @@ -1718,6 +1760,7 @@ TrueColor defdepth 24 text (i.e. not obscured like the -rfbauth VNC passwords) password options. + Q-24: Can I have two passwords for VNC viewers, one for full access and the other for view-only access to the display? @@ -1745,6 +1788,7 @@ TrueColor defdepth 24 plain text passwords from $HOME/.vnc/passwd since it is very straight-forward to work out what to do from the VNC source code. + Q-25: Can I fine tune what types of user input are allowed? E.g. have some users just be able to move the mouse, but not click or type anything? @@ -1758,6 +1802,7 @@ TrueColor defdepth 24 These settings can also be applied on a per-viewer basis via the remote control mechanism or the GUI. E.g. x11vnc -R input:hostname:M + Q-26: Why does x11vnc exit as soon as the VNC viewer disconnects? And why doesn't it allow more than one VNC viewer to connect at the same time? @@ -1776,6 +1821,7 @@ TrueColor defdepth 24 apply these security measures, they will not be done for you automatically. + Q-27: Can I limit which machines incoming VNC clients can connect from? @@ -1794,6 +1840,7 @@ TrueColor defdepth 24 [216](tcp_wrappers) and then use /etc/hosts.allow See hosts_access(5) for complete details. + Q-28: How do I build x11vnc/libvncserver with libwrap (tcp_wrappers) support? @@ -1814,6 +1861,7 @@ TrueColor defdepth 24 x11vnc with libwrap support because the /usr/sbin/tcpd reference in /etc/inetd.conf handles the tcp_wrappers stuff. + Q-29: Can I have x11vnc only listen on one network interface (e.g. internal LAN) rather than having it listen on all network interfaces and relying on -allow to filter unwanted connections out? @@ -1830,6 +1878,7 @@ TrueColor defdepth 24 option [220]-localhost now implies "-listen localhost" since that is what most people expect it to do. + Q-30: Now that -localhost implies listening only on the loopback interface, how I can occasionally allow in a non-localhost via the allowonce remote control command? @@ -1847,6 +1896,7 @@ TrueColor defdepth 24 in on the listening interface. If you just toggle [225]-localhost on and off x11vnc should see to it that you never get into such a state. + Q-31: How can I tunnel my connection to x11vnc via an encrypted SSH channel between two Unix machines? @@ -1857,6 +1907,7 @@ TrueColor defdepth 24 Other secure encrypted methods exists, e.g. stunnel, IPSEC, various VPNs, etc. + Q-32: How can I tunnel my connection to x11vnc via an encrypted SSH channel from Windows using an SSH client like Putty? @@ -1900,6 +1951,7 @@ TrueColor defdepth 24 5500 instead of 5900 (i.e. 'Source port: 5500' and 'Destination: localhost:5500' for a Remote connection). + Q-33: Can I prompt the user at the local X display whether the incoming VNC client should be accepted or not? Can I decide to make some clients view-only? How about running an arbitrary program to make @@ -1994,6 +2046,7 @@ exit 1 variables are set as in "-accept command" (except that RFB_MODE will be "gone"). + Q-34: Does x11vnc support Unix usernames and passwords? Can I further limit the set of Unix usernames who can connect to the VNC desktop? @@ -2045,6 +2098,7 @@ exit 1 # reject it For this to work with ssh port redirection, the ssh option UsePrivilegeSeparation must be enabled. + Q-35: I start x11vnc as root because it is launched via inetd(1) or a display manager like gdm(1). Can I have x11vnc later switch to a different user? @@ -2056,6 +2110,7 @@ exit 1 # reject it +nobody" that switches to the Unix user nobody right after connections to the X display are established. + Q-36: I use a screen-lock when I leave my workstation (e.g. xscreensaver or xlock). When I remotely access my workstation desktop via x11vnc I can unlock the desktop fine, but I am worried people will @@ -2090,6 +2145,7 @@ exit 1 # reject it obviously re-lock the screen before disconnecting!). Instructions can be found in the source code for the utility at the above link. + Q-37: Can I have x11vnc automatically lock the screen when I disconnect the VNC viewer? @@ -2138,6 +2194,7 @@ x11vnc -logfile $HOME/.x11vnc.log -rfbauth $HOME/.vnc/passwd -forever -bg plus any other options you desire. + Q-39: How can I use x11vnc to connect to an X login screen like xdm, GNOME gdm, KDE kdm, or CDE dtlogin? (i.e. nobody is logged into an X session yet). @@ -2279,6 +2336,7 @@ rever -bg If the machine is a traditional Xterminal you may want to read [253]this FAQ. + Q-40: Can I run x11vnc out of inetd(1)? How about xinetd(1)? Yes, perhaps a line something like this in /etc/inetd.conf will do it @@ -2347,6 +2405,7 @@ service x11vncservice With the contents of /usr/local/bin/x11vnc_sh similar to the example given above. + Q-41: How do I make x11vnc work with the Java VNC viewer applet in a web browser? @@ -2374,6 +2433,7 @@ service x11vncservice entirely from the viewer-side by having the jar file there and using either the java or appletviewer commands to run the program. + Q-42: Are reverse connections (i.e. the VNC server connecting to the VNC viewer) using "vncviewer -listen" and vncconnect(1) supported? @@ -2401,6 +2461,7 @@ service x11vncservice # xprop -root -f VNC_CONNECT 8s -set VNC_CONNECT "$1" + Q-43: Can I use x11vnc as a replacement for Xvnc? (i.e. not for a real display, but for a virtual one I keep around). @@ -2443,6 +2504,7 @@ xmodmap -e "add Control = Control_L Control_R" One can use this sort of scheme to export other virtual X sessions, say Xnest or even Xvnc itself (useful for testing x11vnc). + Q-44: How can I use x11vnc on "headless" machines? Why might I want to? @@ -2539,6 +2601,7 @@ ied) done over local machine sockets it should be acceptable (see an [265]earlier question discussing -noshm). + Q-46: How can I make x11vnc use less system resources? The [266]-nap and "[267]-wait n" (where n is the sleep between polls @@ -2548,6 +2611,7 @@ ied) [268]-onetile option will use less memory and use fewer shared memory slots (add [269]-fs 1.0 for one less slot). + Q-47: How can I make x11vnc use MORE system resources? You can try [270]-threads and dial down the wait time (e.g. -wait 1) @@ -2561,6 +2625,7 @@ ied) the x11vnc [272]-id option) can be streamed over a LAN or wireless at a reasonable frame rate. + Q-48: I use x11vnc over a slow link with high latency (e.g. dialup modem), is there anything I can do to speed things up? @@ -2622,6 +2687,7 @@ ied) * Use [282]-nocursor and [283]-nocursorpos (repainting the remote cursor position and shape takes resources and round trips) + Q-49: When I drag windows around with the mouse or scroll up and down things really bog down (unless I do the drag in a single, quick motion). Is there anything to do to improve things? @@ -2648,6 +2714,7 @@ ied) (try to get the viewers to use different VNC encodings, e.g. tight and ZRLE). + Q-50: Does x11vnc support the X DAMAGE Xserver extension to find modified regions of the screen quickly and efficiently? @@ -2733,6 +2800,7 @@ ied) apply a patch to your VNC Viewer to extract hidden alpha channel data under 32bpp. [296]Details can be found here. + Q-52: When using XFIXES cursorshape mode, some of the cursors look really bad with extra black borders around the cursor and other cruft. How can I improve their appearance? @@ -2780,6 +2848,7 @@ ied) -alpharemove to brighten them by having x11vnc divide out the alpha value. + Q-53: In XFIXES mode, are there any hacks to handle cursor transparency ("alpha channel") exactly? @@ -2830,6 +2899,7 @@ ied) CursorShapeUpdates) will be to draw the moving cursor into the x11vnc framebuffer. This can also be disabled via -nocursor. + Q-55: Can I take advantage of the TightVNC extension to the VNC protocol where Cursor Positions Updates are sent back to all connected clients (i.e. passive viewers can see the mouse cursor being moved @@ -2839,8 +2909,9 @@ ied) support the Cursor Positions Updates for the user to see the mouse motions (the TightVNC viewers support this). As of Aug/2004 in the libvncserver CVS -cursorpos is the default. See also [305]-nocursorpos - and [306]-nocursorshape. - + and [306]-nocursorshape. + + Q-56: Is it possible to swap the mouse buttons (e.g. left-handed operation), or arbitrarily remap them? How about mapping button clicks to keystrokes, e.g. to partially emulate Mouse wheel scrolling? @@ -2918,6 +2989,7 @@ ied) [313]-debug_keyboard option prints out much info for every keystroke and so can be useful debugging things. + Q-58: When I try to type a "<" (i.e. less than) instead I get ">" (i.e. greater than)! Strangely, typing ">" works OK!! @@ -2978,6 +3050,7 @@ ied) Note that the [317]-debug_keyboard option prints out much info for every keystroke to aid debugging keyboard problems. + Q-59: I'm using an "international" keyboard (e.g. German "de", or Danish "dk") and the -modtweak mode works well if the VNC viewer is run on a Unix/Linux machine with a similar keyboard. But if I run @@ -3067,6 +3140,7 @@ ied) when the Keysym is received from a VNC viewer, and only after that would -add_keysyms, or anything else, come into play. + Q-60: When typing I sometimes get double, triple, or more of my keystrokes repeated. I'm sure I only typed them once, what can I do? @@ -3103,6 +3177,7 @@ ied) autorepeating so there is no big loss here, unless someone is also working at the physical display and misses his autorepeating. + Q-61: The x11vnc -norepeat mode is in effect, but I still get repeated keystrokes!! @@ -3126,6 +3201,7 @@ ied) something in your desktop is automatically turning it back on you should figure out how to disable that somehow. + Q-62: The machine where I run x11vnc has an AltGr key, but the local machine where I run the VNC viewer does not. Is there a way I can map a local unused key to send an AltGr? How about a Compose key as well? @@ -3140,6 +3216,7 @@ ied) Super_R-Mode_switch,Menu-Multi_key" or use "-remap filename" to specify remappings from a file. + Q-63: I have a Sun machine I run x11vnc on. Its Sun keyboard has just one Alt key labelled "Alt" and two Meta keys labelled with little diamonds. The machine where I run the VNC viewer only has Alt keys. @@ -3157,6 +3234,7 @@ ied) cannot send Alt_L in this case, maybe -remap Super_L-Meta_L would be a better choice if the Super_L key is typically unused. + Q-64: Can I map a keystroke to a mouse button click on the remote machine? @@ -3202,6 +3280,7 @@ ied) local display. Especially for hand-held devices. See also [332]this FAQ on x11vnc scaling. + Q-66: Does x11vnc support server-side framebuffer scaling? (E.g. to make the desktop smaller). @@ -3262,6 +3341,7 @@ ied) scaling to a different factor (e.g. use "-scale_cursor 1" to keep the cursor at its natural unscaled size). + Q-67: Does x11vnc work with Xinerama? (i.e. multiple monitors joined together to form one big, single screen). @@ -3289,6 +3369,7 @@ ied) function. (This may be due to a bug in the X server for XTEST when Xinerama is enabled). + Q-68: Can I use x11vnc on a multi-headed display that is not Xinerama (i.e. separate screens :0.0, :0.1, ... for each monitor)? @@ -3312,6 +3393,7 @@ ied) this case (to limit each x11vnc to 3 shm segments), or even [342]-noshm to use no shm segments. + Q-69: Can x11vnc show only a portion of the display? (E.g. for a special purpose rfb application). @@ -3324,6 +3406,7 @@ ied) the [344]-id or [345]-sid options are used. The offset is measured from the upper left corner of the selected window. + Q-70: Does x11vnc support the XRANDR (X Resize, Rotate and Reflection) extension? Whenever I rotate or resize the screen x11vnc just seems to crash. @@ -3346,11 +3429,13 @@ ied) specify "-xrandr exit" then all will be disconnected and x11vnc will terminate. + Q-71: Why is the view in my VNC viewer completely black? Or why is everything flashing around randomly? See the next FAQ for a possible explanation. + Q-72: I use Linux Virtual Consoles (VC's) to implement 'Fast User Switching' between users' sessions (e.g. Betty is on Ctrl-Alt-F7, Bobby is on Ctrl-Alt-F8, and Sid is on Ctrl-Alt-F1: they use those @@ -3378,6 +3463,7 @@ ied) x11vnc can poll it correctly), one can use the chvt(1) command, e.g. "chvt 7" for VC #7. + Q-73: Can I use x11vnc to view my VMWare session remotely? Yes, since VMWare is an X application you can view it via x11vnc in @@ -3421,6 +3507,7 @@ ied) to have a video card, (but need not have a monitor, Keyboard or mouse)). + Q-74: I am using x11vnc where my local machine has "popup/hidden taskbars" (e.g. GNOME or MacOS X) and the remote display where x11vnc runs also has "popup/hidden taskbars" (e.g. GNOME). When I move the @@ -3449,6 +3536,7 @@ ied) "Klipper" that do odd things with the selection, clipboard, and cutbuffers. + Q-76: Why don't I hear the "Beeps" in my X session (e.g. when typing tput bel in an xterm)? diff --git a/x11vnc/misc/Makefile.am b/x11vnc/misc/Makefile.am new file mode 100644 index 0000000..5cd4d0a --- /dev/null +++ b/x11vnc/misc/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST=README blockdpy.c dtVncPopup rx11vnc rx11vnc.pl shm_clear slide.pl vcinject.pl x11vnc_loop diff --git a/x11vnc/misc/README b/x11vnc/misc/README new file mode 100644 index 0000000..be7063f --- /dev/null +++ b/x11vnc/misc/README @@ -0,0 +1,32 @@ + +In this directory you'll find a hodgepodge of wrapper scripts and +utility programs that have found some use with x11vnc. + +Some are on the rough side and will need some customization for your +use. Many of them are described on the webpage: + + http://www.karlrunge.com/x11vnc + +(use your browser's Find action to find them!). Some of them also have +documentation near the top of the file. + +x11vnc -accept scripts: + + blockdpy.c try to lock screen if local person knocks monitor out of DPMS + dtVncPopup CDE/dtksh by Stefan Radman to accept connections, lock screen + +x11vnc launch wrappers: + + rx11vnc simple ssh/rsh x11vnc launcher. -S option needs work... + rx11vnc.pl perl script tries to do rx11vnc -S tunnelling better. + +x11vnc -pipeinput/-rawfb utilities: + + vcinject.pl perl script like LinuxVNC.c, for x11vnc viewing of linux console + slide.pl amusing example using x11vnc -rawfb for jpeg slideshow. + +Misc. scripts: + + shm_clear list or remove orphaned shm slots from hard x11vnc crashes. + x11vnc_loop kludge to run in bg attaching x11vnc to X login. Better to + use Xsetup mechanism. diff --git a/x11vnc/misc/blockdpy.c b/x11vnc/misc/blockdpy.c new file mode 100644 index 0000000..f3b428e --- /dev/null +++ b/x11vnc/misc/blockdpy.c @@ -0,0 +1,352 @@ +/* + * blockdpy.c + * + * Copyright (c) 2004 Karl J. Runge <runge@karlrunge.com> + * All rights reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + *----------------------------------------------------------------------- + * + * This tool is intended for use with x11vnc. It is a kludge to try to + * "block" access via the physical display while x11vnc is running. + * + * The expected application is that of a user who screen-locks his + * workstation before leaving and then later unlocks it remotely via + * x11vnc. The user is concerned people with physical access to the + * machine will be watching, etc. + * + * Of course if people have physical access to the machine there are + * much larger potential security problems, but the idea here is to put + * up a larger barrier than simply turning on the monitor and tapping + * the mouse (i.e. to wake up the monitor from DPMS and then observe + * the x11vnc activity). + * + * This program requires DPMS support in the video card and monitor, + * and the DPMS extension in the X server and the corresponding + * library with the DPMS API (libXext). + * + * It starts off by forcing the state to be DPMSModeOff (lowest power). + * Then it periodically (a few times a second) checks if the system is + * still in that state. If it discovers it to be in another state, it + * immediately runs, as a separate command, a screen-lock program, "xlock" + * by default. The environment variable XLOCK_CMD or -lock option can + * override this default. "xscreensaver-command" might be another choice. + * + * It is up to the user to make sure the screen-lock command works + * and PATH is set up correctly, etc. The command can do anything, + * it doesn't have to lock the screen. It could make the sound of a + * dog barking, for example :-) + * + * The option '-grab' causes the program to additionally call + * XGrabServer() to try to prevent physical mouse or keyboard input to get + * to any applications on the screen. NOTE: do NOT use, not working yet! + * Freezes everything. + * + * The options: -display and -auth can be used to set the DISPLAY and + * XAUTHORITY environment variables via the command line. + * + * The options -standby and -suspend change the desired DPMS level + * to be DPMSModeStandby and DPMSModeSuspend, respectively. + * + * The option '-f flagfile' indicates a flag file to watch for to cause + * the program to clean up and exit once it exists. No screen locking is + * done when the file appears: it is an 'all clear' flag. Presumably the + * x11vnc user has relocked the screen before the flagfile is created. + * See below for coupling this behavior with the -gone command. + * + * The option '-bg' causes the program to fork into the background and + * return 0 if everything looks ok. If there was an error up to that + * point the return value would be 1. + * + * Option '-v' prints more info out, useful for testing and debugging. + * + * + * These options allow this sort of x11vnc usage: + * + * x11vnc ... -accept "blockdpy -bg -f $HOME/.bdpy" -gone "touch $HOME/.bdpy" + * + * (this may also work for gone: -gone "killall blockdpy") + * + * In the above, once a client connects this program starts up in the + * background and monitors the DPMS level. When the client disconnects + * (he relocked the screen before doing so) the flag file is created and + * so this program exits normally. On the other hand, if the physical + * mouse or keyboard was used during the session, this program would + * have locked the screen as soon as it noticed the DPMS change. + * + * One could create shell scripts for -accept and -gone that do much + * more sophisticated things. This would be needed if more than one + * client connects at a time. + * + * It is important to remember once this program locks the screen + * it *exits*, so nothing will be watching the screen at that point. + * Don't immediately unlock the screen from in x11vnc!! Best to think + * about what might have happened, disconnect the VNC viewer, and then + * restart x11vnc (thereby having this monitoring program started again). + * + * + * To compile on Linux or Solaris: + + cc -o blockdpy blockdpy.c -L /usr/X11R6/lib -L /usr/openwin/lib -lX11 -lXext + + * (may also need -I /usr/.../include on older machines). + * + */ + +#include <stdio.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <signal.h> + +#include <X11/Xlib.h> +#include <X11/Xproto.h> +#include <X11/extensions/dpms.h> + +Display *dpy = NULL; +CARD16 standby, suspend, off; +int grab = 0; +int verbose = 0; +int bg = 0; + +/* for sleeping some number of millisecs */ +struct timeval _mysleep; +#define msleep(x) \ + _mysleep.tv_sec = ((x)*1000) / 1000000; \ + _mysleep.tv_usec = ((x)*1000) % 1000000; \ + select(0, NULL, NULL, NULL, &_mysleep); + +/* called on signal or if DPMS changed, or other problem */ +void reset(int sig) { + if (grab) { + if (verbose) { + fprintf(stderr, "calling XUngrabServer()\n"); + } + XUngrabServer(dpy); + } + if (verbose) { + fprintf(stderr, "resetting original DPMS values.\n"); + } + fprintf(stderr, "blockdpy: reset sig=%d called\n", sig); + DPMSEnable(dpy); + DPMSSetTimeouts(dpy, standby, suspend, off); + XFlush(dpy); + if (sig) { + XCloseDisplay(dpy); + exit(0); + } +} + +int main(int argc, char** argv) { + + int verbose = 0, bg = 0; + int i, ev, er; + char *lock_cmd = "xlock"; + char *flag_file = NULL; + char estr[100], cmd[500]; + struct stat sbuf; + CARD16 power; + CARD16 desired = DPMSModeOff; + BOOL state; + + + /* setup the lock command. it may be reset by -lock below. */ + if (getenv("XLOCK_CMD")) { + lock_cmd = (char *) getenv("XLOCK_CMD"); + } + + /* process cmd line: */ + for (i=1; i<argc; i++) { + if (!strcmp(argv[i], "-display")) { + sprintf(estr, "DISPLAY=%s", argv[++i]); + putenv(strdup(estr)); + } else if (!strcmp(argv[i], "-auth")) { + sprintf(estr, "XAUTHORITY=%s", argv[++i]); + putenv(strdup(estr)); + } else if (!strcmp(argv[i], "-lock")) { + lock_cmd = argv[++i]; + } else if (!strcmp(argv[i], "-f")) { + flag_file = argv[++i]; + unlink(flag_file); + } else if (!strcmp(argv[i], "-grab")) { + grab = 1; + } else if (!strcmp(argv[i], "-bg")) { + bg = 1; + } else if (!strcmp(argv[i], "-v")) { + verbose = 1; + } else if (!strcmp(argv[i], "-standby")) { + desired = DPMSModeStandby; + } else if (!strcmp(argv[i], "-suspend")) { + desired = DPMSModeSuspend; + } else if (!strcmp(argv[i], "-off")) { + desired = DPMSModeOff; + } + } + + /* we want it to go into background to avoid blocking, so add '&'. */ + strcpy(cmd, lock_cmd); + strcat(cmd, " &"); + lock_cmd = cmd; + + /* close any file descriptors we may have inherited (e.g. port 5900) */ + for (i=3; i<=100; i++) { + close(i); + } + + /* open DISPLAY */ + dpy = XOpenDisplay(NULL); + if (! dpy) { + fprintf(stderr, "XOpenDisplay failed.\n"); + exit(1); + } + + /* check for DPMS extension */ + if (! DPMSQueryExtension(dpy, &ev, &er)) { + fprintf(stderr, "DPMSQueryExtension failed.\n"); + exit(1); + } + if (! DPMSCapable(dpy)) { + fprintf(stderr, "DPMSCapable failed.\n"); + exit(1); + } + /* make sure DPMS is enabled */ + if (! DPMSEnable(dpy)) { + fprintf(stderr, "DPMSEnable failed.\n"); + exit(1); + } + + /* retrieve the timeouts for later resetting */ + if (! DPMSGetTimeouts(dpy, &standby, &suspend, &off)) { + fprintf(stderr, "DPMSGetTimeouts failed.\n"); + exit(1); + } + if (! standby || ! suspend || ! off) { + /* if none, set to some reasonable values */ + standby = 900; + suspend = 1200; + off = 1800; + } + if (verbose) { + fprintf(stderr, "DPMS timeouts: %d %d %d\n", standby, + suspend, off); + } + + /* now set them to very small values */ + if (desired == DPMSModeOff) { + if (! DPMSSetTimeouts(dpy, 1, 1, 1)) { + fprintf(stderr, "DPMSSetTimeouts failed.\n"); + exit(1); + } + } else if (desired == DPMSModeSuspend) { + if (! DPMSSetTimeouts(dpy, 1, 1, 0)) { + fprintf(stderr, "DPMSSetTimeouts failed.\n"); + exit(1); + } + } else if (desired == DPMSModeStandby) { + if (! DPMSSetTimeouts(dpy, 1, 0, 0)) { + fprintf(stderr, "DPMSSetTimeouts failed.\n"); + exit(1); + } + } + XFlush(dpy); + + /* set handlers for clean up in case we terminate via signal */ + signal(SIGHUP, reset); + signal(SIGINT, reset); + signal(SIGQUIT, reset); + signal(SIGABRT, reset); + signal(SIGTERM, reset); + + /* force state into DPMS Off (lowest power) mode */ + if (! DPMSForceLevel(dpy, desired)) { + fprintf(stderr, "DPMSForceLevel failed.\n"); + exit(1); + } + XFlush(dpy); + + /* read state */ + msleep(500); + if (! DPMSInfo(dpy, &power, &state)) { + fprintf(stderr, "DPMSInfo failed.\n"); + exit(1); + } + fprintf(stderr, "power: %d state: %d\n", power, state); + + /* grab display if desired. NOT WORKING */ + if (grab) { + if (verbose) { + fprintf(stderr, "calling XGrabServer()\n"); + } + XGrabServer(dpy); + } + + /* go into background if desired. */ + if (bg) { + pid_t p; + if ((p = fork()) != 0) { + if (p < 0) { + fprintf(stderr, "problem forking.\n"); + exit(1); + } else { + /* XXX no fd closing */ + exit(0); + } + } + } + + /* main loop: */ + while (1) { + /* reassert DPMSModeOff (desired) */ + if (verbose) fprintf(stderr, "reasserting desired DPMSMode\n"); + DPMSForceLevel(dpy, desired); + XFlush(dpy); + + /* wait a bit */ + msleep(200); + + /* check for flag file appearence */ + if (flag_file && stat(flag_file, &sbuf) == 0) { + if (verbose) { + fprintf(stderr, "flag found: %s\n", flag_file); + } + unlink(flag_file); + reset(0); + exit(0); + } + + /* check state and power level */ + if (! DPMSInfo(dpy, &power, &state)) { + fprintf(stderr, "DPMSInfo failed.\n"); + reset(0); + exit(1); + } + if (verbose) { + fprintf(stderr, "power: %d state: %d\n", power, state); + } + if (!state || power != desired) { + /* Someone (or maybe a cat) is evidently watching... */ + fprintf(stderr, "DPMS CHANGE: power: %d state: %d\n", + power, state); + break; + } + } + reset(0); + fprintf(stderr, "locking screen with command: \"%s\"\n", lock_cmd); + system(lock_cmd); + exit(0); +} diff --git a/x11vnc/misc/dtVncPopup b/x11vnc/misc/dtVncPopup new file mode 100644 index 0000000..e90cc8b --- /dev/null +++ b/x11vnc/misc/dtVncPopup @@ -0,0 +1,109 @@ +#!/usr/dt/bin/dtksh +# +# accept dialog script for x11vnc +# 2004-07-13 stefan.radman@ctbto.org +# should work in any CDE environment (Sun,HP,IBM,...) +# +# when called without parameters shows a CDE question dialog: +# Do you want to accept a VNC connection +# from IP address $RFB_CLIENT_IP to your desktop? +# Note: +# After 30 seconds the screen will +# be locked and the connection will be +# accepted automatically." +# [Yes} {__No__] [View/Only] +# and counts down a timer in the dialog title bar +# when the timer is down to 0, it locks the display and returns 0 +# (if the screenlock was successful or if the login prompt was active) +# +# buttons=retcode: +# Yes = 0 +# No = 1 (same as closing the dialog windows) +# View/Only = 3 +# +# usage: x11vnc -forever -shared -accept "yes:0,no:*,view:3 dtVncPopup" -gone "dtVncPopup lock" +# +# security considerations: when you return to your console and unlock the display +# you can never know if enyone else is connected to your display +# + +# timeout until accept +timeout=30 + +# dialog message +test -z "${RFB_CLIENT_IP}" && unknown="an unknown " || ip="$RFB_CLIENT_IP " +message="\ +Do you want to accept a VNC connection +from ${unknown}IP address ${ip}to your desktop? +Note: +After $timeout seconds the screen will +be locked and the connection will be +accepted automatically." + +# action functions +accept () { + exit 0 +} +reject () { + exit 1 +} +view () { + exit 3 +} +lock () { + # lock only if dtsession active + xrdb -query | grep -c '^dtsession*' || accept + # accept only if lock succeeds + /usr/dt/bin/dtaction LockDisplay && accept || reject +} + +# main + +# actions can be called directly +test $# -gt 0 && $@ + +# initialize the display +XtInitialize TOPLEVEL vncPopup VncPopup "$0" "$@" + +# create a message dialog containing the contents of the specified file +XmCreateQuestionDialog DIALOG $TOPLEVEL dialog \ + dialogTitle:"$DTKSH_APPNAME" \ + messageString:"$message" \ + unmapCallback:reject \ +# symbolPixmap:/usr/dt/appconfig/icons/C/DtFlag.m.pm + +# change the OK button to "Yes" +XmMessageBoxGetChild OK_BUTTON $DIALOG DIALOG_OK_BUTTON +XtSetValues $OK_BUTTON \ + labelString:"Yes" \ + activateCallback:accept + +# change the Cancel Button to "No" +XmMessageBoxGetChild CANCEL_BUTTON $DIALOG DIALOG_CANCEL_BUTTON +XtSetValues $CANCEL_BUTTON \ + labelString:"No" \ + activateCallback:reject + +# change Help button to View-Only, set focus and make it the default +XmMessageBoxGetChild HELP_BUTTON $DIALOG DIALOG_HELP_BUTTON +XtSetValues $HELP_BUTTON \ + labelString:"View\nOnly" \ + activateCallback:view + +# make "No" the default (for unmap as well) +XtSetValues $DIALOG \ + defaultButton:$CANCEL_BUTTON initialFocus:$CANCEL_BUTTON \ + +# create the ticker +ticker () { + test $timeout -eq 0 && lock + XtSetValues $DIALOG dialogTitle:"accepting in $timeout seconds" + XtAddTimeOut TICKER 1000 ticker + timeout=`expr $timeout - 1` +} + +# display dialog and activate ticker +XtAddTimeOut TICKER 1000 ticker +XtManageChild $DIALOG +XtMainLoop + diff --git a/x11vnc/misc/rx11vnc b/x11vnc/misc/rx11vnc new file mode 100755 index 0000000..27e6d06 --- /dev/null +++ b/x11vnc/misc/rx11vnc @@ -0,0 +1,133 @@ +#!/bin/sh +# +# usage: rx11vnc [-s] <host>:<xdisplay> +# rx11vnc [-s] <host> (assumes xdisplay is 0) +# +# -s means use ssh instead of rsh. +# -S tries to tunnel the vnc traffic thru ssh. (experimental...) +# +#set -xv + +# +# Place your x11vnc cmd + options here (must have -bg and -display +# with -display as the last one) +# +cmd="x11vnc -nap -q -bg -display" +viewer="vncviewer" +rsh=rsh + +# +# The following two settings are only used under -S (ssh tunnel) +# +# Unfortunately, we have to set up the ssh port redirection *before* +# x11vnc has started and selected its listening port. +# tunnel_ports is a list of ports we expect/hope to be free on both +# the local and remote machines: +# +tunnel_ports="5900 5901 5902 5903" +# +# VNC has a poor default in that if the client appears to be emanating +# from the local machine, then raw encoding is preferred. With ssh port +# redirection we appear to be coming from the localhost, but we are not. +# We pass this encoding list to the viewer to give lowest preference to +# raw encoding: +# +tunnel_encodings="copyrect tight zrle hextile zlib corre rre" + +if [ "$USER" = "runge" ]; then + cmd="x11vnc.expt -nap -q -bg -rfbauth .vnc/passwd -display" + viewer="vncviewerz" +fi + +if [ "X$1" = "X-s" ]; then + shift + rsh=ssh +elif [ "X$1" = "X-S" ]; then + shift + rsh=ssh + tunnel=1 + cmd=`echo "$cmd" | sed -e 's/ / -localhost /'` +fi + +remote=$1 +if echo "$remote" | grep ':' > /dev/null; then + : +else + remote="$remote:0" +fi + +host=`echo "$remote" | awk -F: '{print $1}'` +disp=`echo "$remote" | awk -F: '{print $2}'` +disp=":$disp" +if [ "X$host" = "X" ]; then + echo "bad host." + exit 1 +fi + +# start the remote x11vnc: +if [ $tunnel ]; then + # much more kludgy for tunnelling: + tmp=/tmp/rx11vnc.$$ + redir="" + used_ports=`netstat -an | egrep '(ESTABLISHED|LISTEN) *$' \ + | sed -e 's/^[ ]*//' -e 's/^tcp[ 0-9][ 0-9]*//' \ + -e 's/[ ].*$//' -e 's/^.*[^0-9]//' | sort -nu` + for p in $tunnel_ports + do + ok=1 + for u in $used_ports + do + if [ "X$p" = "X$u" ]; then + echo "port $u is in use. skipping it" + ok= + break + fi + done + if [ $ok ]; then + redir="$redir -L $p:localhost:$p" + fi + done + # + # Have ssh put the command in the bg, then we look for PORT= + # in the tmp file. The sleep at the end is to give us enough + # time to connect thru the port redir, otherwise ssh will exit + # before we can connect. + # + time=15 + $rsh -f $redir $host "$cmd $disp; echo END; sleep $time" > $tmp + + i=0 + while [ $i -lt $time ] + do + sleep 1 + if grep '^PORT=' $tmp > /dev/null; then + port=`grep '^PORT=' $tmp | sed -e 's/PORT=//'` + if [ "X$port" != "X" ]; then + break + fi + fi + i=`expr $i + 1` + done + cat $tmp + rm -f $tmp +else + port=`$rsh $host "$cmd $disp" | grep '^PORT=' | sed -e 's/PORT=//'` +fi + +echo "x11vnc port is '$port'" + +# now start up the viewer on this end: +if echo "$port" | grep '^[0-9][0-9]*$' > /dev/null; then + if [ $port -lt 6000 -a $port -ge 5900 ]; then + # vncviewer special cases 0-99 + port=`expr $port - 5900` + fi + if [ $tunnel ]; then + $viewer -encodings "$tunnel_encodings" "localhost:$port" + else + $viewer "$host:$port" + fi +else + echo "bad port." + exit 1 +fi diff --git a/x11vnc/misc/rx11vnc.pl b/x11vnc/misc/rx11vnc.pl new file mode 100755 index 0000000..cf4b437 --- /dev/null +++ b/x11vnc/misc/rx11vnc.pl @@ -0,0 +1,199 @@ + #!/bin/sh -- # A comment mentioning perl +eval 'exec perl -S $0 ${1+"$@"}' + if 0; +# +# Here is the remote x11vnc command. +# Modify to your needs, required to have %DISP item that expands to X display +# and the -bg option to go into the background. +# +$x11vnc_cmd = "x11vnc -localhost -nap -q -bg -display %DISP"; + +# +# We will redir local ports to these remote ports hoping the remote +# x11vnc selects one of them: +# +@tunnel_ports = qw(5900 5901 5902 5903 5904); + +# +# We need to specify the encoding preferences since vncviewer will +# mistakeningly prefer "raw" encoding for local connection. required to +# have %VNC_ITEM to expand to localhost:<port> + +# One really needs an -encodings option otherwise the vncviewer will +# prefer 'raw' which is very slow. +# +$viewer_cmd = "vncviewer -encodings 'copyrect tight zrle hextile zlib corre rre' %VNC_DISP"; +$sleep_time = 15; + +if ($ENV{USER} eq 'runge') { + # my personal kludges: + $viewer_cmd =~ s/vncviewer/vncviewerz/; # for tight + $x11vnc_cmd .= ' -rfbauth .vnc/passwd'; # I always want rfbauth +} + +chop($Program = `basename $0`); + +$Usage = <<"END"; + +$Program: wrapper to tunnel vncviewer <-> x11vnc VNC traffic through a ssh + encrypted tunnel port redirection. + +Usage: $Program <options> <remote-Xdisplay> + +Options: + -l <user> ssh login as remote user <user> + + -rfbauth <remote-auth-file> this option is passed to the remote + x11vnc command for passwd file. + +Notes: + +Example: $Program snoopy:0 + +END + +LOOP: +while (@ARGV) { + $_ = shift; + CASE: { + /^-display$/ && ($remote_xdisplay = shift, last CASE); + /^-rfbauth$/ && ($x11vnc_cmd .= ' -rfbauth ' . shift, last CASE); + /^-l$/ && ($remote_user = ' -l ' . shift, last CASE); + /^--$/ && (last LOOP); # -- means end of switches + /^-(-.*)$/ && (unshift(@ARGV, $1), last CASE); + /^(-h|-help)$/ && ((print STDOUT $Usage), exit 0, last CASE); + if ( /^-(..+)$/ ) { # split bundled switches: + local($y, $x) = ($1, ''); + (unshift(@ARGV, $y), last CASE) if $y =~ /^-/; + foreach $x (reverse(split(//, $y))) { unshift(@ARGV,"-$x") }; + last CASE; + } + /^-/ && ((print STDERR "Invalid arg: $_\n$Usage"), exit 1, last CASE); + unshift(@ARGV,$_); + last LOOP; + } +} + +select(STDERR); $| = 1; +select(STDOUT); $| = 1; + +# Determine the remote X display to connect to: +$remote_xdisplay = shift if $remote_xdisplay eq ''; +if ($remote_xdisplay !~ /:/) { + $remote_xdisplay .= ':0'; # assume they mean :0 over there. +} +if ($remote_xdisplay =~ /:/) { + $host = $`; + $disp = ':' . $'; +} else { + die "bad X display: $remote_xdisplay, must be <host>:<display>\n"; +} + +# +# Get list of local ports in use so we can avoid them: +# (tested on Linux and Solaris) +# +open(NETSTAT, "netstat -an|") || die "netstat -an: $!"; +while (<NETSTAT>) { + chomp ($line = $_); + next unless $line =~ /(ESTABLISHED|LISTEN|WAIT2?)\s*$/; + $line =~ s/^\s*//; + $line =~ s/^tcp[\s\d]*//; + $line =~ s/\s.*$//; + $line =~ s/^.*\D//; + if ($line !~ /^\d+$/) { + die "bad netstat line: $line from $_"; + } + $used_port{$line} = 1; +} +close(NETSTAT); + +# +# Now match up free local ports with the desired remote ports +# (note that the remote ones could be in use but that won't stop +# the ssh with port redirs from succeeding) +# +$lport = 5900; +$cnt = 0; +foreach $rport (@tunnel_ports) { + while ($used_port{$lport}) { + $lport++; + $cnt++; + die "too hard to find local ports 5900-$lport" if $cnt > 200; + } + $port_map{$rport} = $lport; + $lport++; +} + +$redir = ''; +foreach $rport (@tunnel_ports) { + $redir .= " -L $port_map{$rport}:localhost:$rport"; +} + +# +# Have ssh put the command in the bg, then we look for PORT= in the +# tmp file. The sleep at the end is to give us enough time to connect +# thru the port redir, otherwise ssh will exit before we can connect. +# + +# This is the x11vnc cmd for the remote side: +$cmd = $x11vnc_cmd; +$cmd =~ s/%DISP/$disp/; + +# This is the ssh cmd for the local side (this machine): +$ssh_cmd = "ssh -f $remote_user $redir $host '$cmd; echo END; sleep $sleep_time'"; +$ssh_cmd =~ s/ / /g; +print STDERR "running ssh command:\n\n$ssh_cmd\n\n"; + +# +# Run ssh and redir into a tmp file (assumes ssh will use /dev/tty +# for password/passphrase dialog) +# +$tmp = "/tmp/rx.$$"; +system("$ssh_cmd > $tmp"); + +# Now watch for the PORT=XXXX message: +$sleep = 0; +$rport = ''; +print STDERR "\nWaiting for x11vnc to indicate its port .."; +while ($sleep < $sleep_time + 10) { + print STDERR "."; + sleep(1); + $sleep++; + if (`cat $tmp` =~ /PORT=(\d+)/) { + $rport = $1; + # wait 1 more second for output: + sleep(1); + if (`cat $tmp` =~ /PORT=(\d+)/) { + $rport = $1; + } + last; + } +} +print STDERR "\n"; + +if (! $rport) { + print STDERR `cat $tmp`; + unlink($tmp); + die "could not determine remote port.\n"; +} +unlink($tmp); + +# Find the remote to local mapping: +$lport = $port_map{$rport}; +print STDERR "remote port is: $rport (corresponds to port $lport here)\n"; +if (! $lport) { + die "could not determine local port redir.\n"; +} + +# Apply the special casing vncviewer does for 5900 <= port < 6000 +if ($lport < 6000 && $lport >= 5900) { + $lport = $lport - 5900; +} + +# Finally, run the viewer. +$cmd = $viewer_cmd; +$cmd =~ s/%VNC_DISP/localhost:$lport/; + +print STDERR "running vncviewer command:\n\n$cmd\n\n"; +system($cmd); diff --git a/x11vnc/misc/shm_clear b/x11vnc/misc/shm_clear new file mode 100755 index 0000000..16d5cb6 --- /dev/null +++ b/x11vnc/misc/shm_clear @@ -0,0 +1,97 @@ +#!/bin/sh +# +# shm_clear: clean out unattached (NATTACH=0) shm segments. +# See ipcs(1) and ipcrm(1). Tested on Linux and Solaris. +# +# Usage: +# shm_clear list and prompt for removal of your unattached shm segments. +# shm_clear -y assume "yes" to all the removal prompts. +# shm_clear -l only list (all of) your shm segments and exit. +# + +#set -xv +if echo "$1" | grep '^-h' > /dev/null; then + # -h or -help + tail +3 $0 | head -9 + exit +fi + +if [ "X$USER" = "X" ]; then + USER=$LOGNAME +fi +l_arg="shmid.*owner|CREATOR|$USER" + +# set up OS dependent cmdline opts, etc. +if [ `uname` = "Linux" ]; then + m_arg="-m" + r_arg="shm" + g_arg="^0x" + s_cmd="ipcs $m_arg -i %ID" + awkcut='{print $2, $6}' +elif [ `uname` = "SunOS" ]; then + m_arg="-ma" + r_arg="-m" + g_arg="^m" + s_cmd="ipcs $m_arg | egrep ' %ID |CREATOR' | grep -v IPC.status" + awkcut='{print $2, $9}' +else + echo unsupported OS: `uname` + exit 1 +fi + +list() { + if [ "X$1" = "X-L" ]; then + l_arg="$l_arg|." + echo "All shm segments for all:" + else + echo "All shm segments for $USER:" + fi + ipcs $m_arg | egrep "$l_arg" + echo +} + +show() { + cmd=`echo "$s_cmd" | sed -e "s/%ID/$1/g"` + eval $cmd +} + +remove() { + echo ipcrm $r_arg $1 + ipcrm $r_arg $1 +} + +if [ "X$1" = "X-l" -o "X$1" = "X-L" ]; then + # list only. both attached and unattached listed. + list $1 + exit 0 +fi + +if [ "X$1" = "X-y" ]; then + shift + yes=1 # assume "yes" to all delete questions. +else + yes="" +fi + +list + +ids=`ipcs $m_arg | grep "$g_arg" | grep $USER | awk "$awkcut" | grep ' 0$' | awk '{print $1}'` +if [ "X$ids" = "X" ]; then + echo "No unattached shmids for $USER." +fi + +for id in $ids +do + if [ $yes ]; then + : + else + echo "-------------------------------------" + show $id + printf "\nDelete? [y]/n " + read x + if echo "$x" | grep -i n > /dev/null; then + continue + fi + fi + remove $id +done diff --git a/x11vnc/misc/slide.pl b/x11vnc/misc/slide.pl new file mode 100755 index 0000000..0c90d0e --- /dev/null +++ b/x11vnc/misc/slide.pl @@ -0,0 +1,112 @@ + #!/bin/sh -- # A comment mentioning perl +eval 'exec perl -S $0 ${1+"$@"}' + if 0; +# +# slide.pl: amusing example slideshow program for use with x11vnc -rawfb mode. +# +# E.g. x11vnc -rawfb map:/tmp/foo@640x480x32:ff/ff00/ff0000 -pipeinput slide.pl +# +# requires: jpegtopnm(1), (maybe LSB too). +# + +@jpegs = qw( + dr_fun_new.jpg canon.jpg go_microsoft.jpg jonathan2.jpg + michelle1.jpg novm.jpg photo-008.jpg presrange.jpg +); + +# Or: +# @jpegs = @ARGV; +# @jpegs = <*.jpg>; + +# this is x11vnc's -rawfb value: +if ($ENV{X11VNC_RAWFB_STR} =~ m,:(.*)@(\d+)x(\d+)x(\d+),) { + $fb = $1; # filename + $W = $2; # width + $H = $3; # height +} else { + die "No usable X11VNC_RAWFB_STR\n"; +} + +open(FB, ">$fb") || die "$!"; + +# make a solid background: +$ones = "\377" x ($W * 4); +$grey = "\340" x ($W * 4); +for ($y = 0; $y < $H; $y++) { + print FB $grey; +} + +# this is rather slow with many jpegs... oh well. +foreach $pic (@jpegs) { + print STDERR "loading '$pic' please wait ...\n"; + open(JPEG, "jpegtopnm '$pic' 2>/dev/null|") || die "$!"; + while (<JPEG>) { + next if /^P\d/; + if (/^(\d+)\s+(\d+)\s*$/) { + $Jpeg{$pic}{w} = $1; + $Jpeg{$pic}{h} = $2; + } + last if /^255$/; + } + $data = ''; + while (<JPEG>) { + $data .= $_; + } + close(JPEG); + + # need to put in a 4th 0 byte after RGB for 32bpp. 24bpp doesn't work. + # (MSB might be other way around). + + $new = ''; + for ($l = 0; $l < int(length($data)/3); $l++) { + $new .= substr($data, $l * 3, 3) . "\0"; + } + $Jpeg{$pic}{data} = $new; + $data = ''; $new = ''; + + if ($pic eq $jpegs[0]) { + showpic(0); + } +} + +$N = scalar(@jpegs); +print STDERR "\nFinished loading $N images. Click Button or Spacebar for next.\n"; +$I = 0; + +while (<>) { + # read the next user input event, watch for button press or spacebar: + last if /^Keysym.* [qQ] /; + next unless /^(Pointer.*ButtonPress|Keysym.*space.*KeyPress)/; + $I = ($I + 1) % $N; + showpic($I); +} + +sub showpic { + my($i) = @_; + + my $pic = $jpegs[$i]; + my $h = $Jpeg{$pic}{h}; + my $w = $Jpeg{$pic}{w}; + + my $dy = int(($H - $h)/2); + my $dx = int(($W - $w)/2); + + print STDERR "showing pic $i: $pic\t$w x $h +$dy+$dx\n"; + + # clear screen: + seek(FB, 0, 0); + for ($y = 0; $y < $H; $y++) { + print FB $ones; + } + + # insert new picture: + for ($y = 0; $y < $h; $y++) { + seek(FB, (($y + $dy) * $W + $dx) * 4, 0); + $line = substr($Jpeg{$pic}{data}, $y * $w * 4, $w * 4); + print FB $line; + } +} + +close(FB); +#unlink($fb); # this (probably) won't kill x11vnc +print STDERR "$0 done.\n"; diff --git a/x11vnc/misc/vcinject.pl b/x11vnc/misc/vcinject.pl new file mode 100755 index 0000000..b371d4e --- /dev/null +++ b/x11vnc/misc/vcinject.pl @@ -0,0 +1,113 @@ + #!/bin/sh -- # A comment mentioning perl +eval 'exec perl -S $0 ${1+"$@"}' + if 0; +# +# vcinject.pl: simple hack to inject keystrokes into Linux VC tty. +# See LinuxVNC.c for a more careful treatment using C and public API. +# +# Usage: vcinject.pl <N> (or /dev/ttyN) +# +# This is an example x11vnc -pipeinput program E.g.: +# +# x11vnc -rawfb map:/dev/fb0@1024x768x16 -pipeinput "vcinject.pl /dev/tty3" +# +# (see fbset(8) for obtaining fb info). +# +# It reads lines like this from STDIN: +# +# Keysym <id> <down> <n> <Keysym> ... +# +# <id> is ignored, it uses the rest to deduce the keystrokes to send +# to the console. +# + +$tty = shift; +$tty = "/dev/tty$tty" if $tty =~ /^\d+$/; + +warn "strange tty device: $tty\n" if $tty !~ m,^/dev/tty\d+$,; + +open(TTY, ">$tty") || die "open $tty: $!\n"; +$fd = fileno(TTY); + +$linux_ioctl_syscall = 54; # common knowledge, eh? :-) +$TIOCSTI = 0x5412; + +%Map = qw( + Escape 27 + Tab 9 + Return 13 + BackSpace 8 + Home 1 + End 5 + Up 16 + Down 14 + Right 6 + Left 2 + Next 6 + Prior 2 +); +# the latter few above seem to be vi specials. (since they are normally +# escape sequences, e.g. ESC [ 5 ~) + +sub lookup { + my($down, $key, $name) = @_; + + my $n = -1; + $name =~ s/^KP_//; + + # algorithm borrowed from LinuxVNC.c: + if (! $down) { + if ($name =~ /^Control/) { + $control--; + } + return $n; + } + + if ($name =~ /^Control/) { + $control++; + } else { + if (exists($Map{$name})) { + $n = $Map{$name}; + } + if ($control && $name =~ /^[A-z]$/) { + $n = ord($name); + # shift down to the Control zone: + if ($name =~ /[a-z]/) { + $n -= (ord("a") - 1); + } else { + $n -= (ord("A") - 1); + } + } + if ($n < 0 && $key < 256) { + $n = $key; + } + } + return $n; +} + +$control = 0; +$debug = 0; + +while (<>) { + chomp; + if (/^\w+$/) { + # for debugging, you type the keysym in manually. + $_ = "Keysym 1 0 999 $_ None"; + } + next unless /^Keysym/; + + my ($j, $id, $down, $k, $keysym, $rest) = split(' ', $_); + + $n = lookup($down, $k, $keysym); + if ($n < 0 || $n > 255) { + print STDERR "skip: '$keysym' -> $n\n" if $down && $debug; + next; + } + + $n_p = pack("c", $n); + $ret = syscall($linux_ioctl_syscall, $fd, $TIOCSTI, $n_p); + + print STDERR "ctrl=$control $keysym/$k syscall(" . + "$linux_ioctl_syscall, $fd, $TIOCSTI, $n) = $ret\n" if $debug; + +} diff --git a/x11vnc/misc/x11vnc_loop b/x11vnc/misc/x11vnc_loop new file mode 100755 index 0000000..1a3e0a2 --- /dev/null +++ b/x11vnc/misc/x11vnc_loop @@ -0,0 +1,89 @@ +#!/bin/sh +# +# x11vnc_loop: +# +# Example startup script for connecting x11vnc to an X display +# at system boot up and having it reconnect when the X server restarts. +# +# Run, in rc.local say, via, e.g.: +# +# /path/to/x11vnc_loop 1>> /var/tmp/x11vnc_loop.log 2>&1 & +# +# call with argument "once" or a number to limit the number of loops. +# +########################################################################## +# The following needs to be customized: +x11vnc_cmd=x11vnc # or use full path (or set PATH). +pwfile=/path/to/vnc/passwd # always use a password +display=:0 # display of interest +restart_sleep=5 # pause between X server restarts. + +# modify cmdline args if desired: +x11vnc_args="-display $display -rfbauth $pwfile -forever -nap" + +# you may need to customize the "grep", etc, below in get_xauthority_file() +########################################################################## + +if [ "X$1" != "X" ]; then + max=$1 + shift +fi + +get_xauthority_file() { + # + # We need to find the MIT-COOKIE file... this not portable at all, + # depends on OS, distro, desktop, phase of moon, etc... + # + # If the cookie file was fixed and you knew it, you could just + # return it here e.g.: + # + ## echo "/var/gdm/:0.Xauth"; return + # + # or, if you knew the directory, you could look for the youngest + # file there and return it e.g.: + # + ## echo `ls -t /var/lib/xdm/authdir/authfiles/* | head -1`; return + + # this hack tries to grep it out of ps output... + xauth="" + for i in 1 2 3 + do + # very linux specific, and you likely need to tweak.. + patt="X11R6.*/X.*-auth" + xauth=`ps wwwaux | grep "$patt" \ + | egrep -v 'grep|Xprt' | head -1 \ + | sed -e 's/^.*-auth//' | awk '{print $1}'` + + if [ "X$xauth" != "X" ]; then + break + fi + sleep 2 # wait a bit in case X server is restarting slowly. + done + echo $xauth +} + +try=1 +while [ 1 ] +do + echo "`date` $0 try number: $try"; try=`expr $try + 1` + + auth=`get_xauthority_file` + if [ ! -r "$auth" ]; then + echo "`date` bad auth file: \"$auth\"" + else + cmd="$x11vnc_cmd $x11vnc_args" + sleep 1 + echo "`date` running: $cmd -auth $auth" + # run x11vnc: + $cmd -auth $auth + if [ "X$max" = "Xonce" ]; then + exit $? + fi + fi + if echo "$max" | grep '[0-9]' > /dev/null; then + if [ $try -gt $max ]; then + exit + fi + fi + sleep $restart_sleep +done diff --git a/x11vnc/tkx11vnc b/x11vnc/tkx11vnc index 6115a85..d3fea5d 100755 --- a/x11vnc/tkx11vnc +++ b/x11vnc/tkx11vnc @@ -112,17 +112,17 @@ Screen overlay overlay_nocursor -- + =D solid + solid_color: visual: flashcmap shiftcmap: notruecolor -- - clip: =P blackout: xinerama - -- - =D solid - solid_color: + clip: + rawfb: -- = xrandr =-C:resize,newfbsize,exit xrandr_mode: @@ -170,6 +170,8 @@ Misc noprimary nolookup -- + xtrap + -- bg =-C:ignore,exit sigpipe: =0 inetd @@ -2883,7 +2885,7 @@ proc start_x11vnc {} { proc run_remote_cmd {opts} { global menu_var x11vnc_prog x11vnc_cmdline x11vnc_xdisplay - global x11vnc_auth_file + global x11vnc_auth_file x11vnc_connect_file set debug [in_debug_mode] @@ -2902,13 +2904,18 @@ proc run_remote_cmd {opts} { lappend cmd $x11vnc_prog; - if {$x11vnc_xdisplay != ""} { - lappend cmd "-display" - lappend cmd $x11vnc_xdisplay - } - if {$x11vnc_auth_file != ""} { - lappend cmd "-auth" - lappend cmd $x11vnc_auth_file + if {$x11vnc_connect_file != ""} { + lappend cmd "-connect" + lappend cmd $x11vnc_connect_file + } else { + if {$x11vnc_xdisplay != ""} { + lappend cmd "-display" + lappend cmd $x11vnc_xdisplay + } + if {$x11vnc_auth_file != ""} { + lappend cmd "-auth" + lappend cmd $x11vnc_auth_file + } } lappend cmd "-sync" foreach word $opts { @@ -2998,7 +3005,7 @@ proc try_connect {} { # main: global env x11vnc_prog x11vnc_cmdline x11vnc_xdisplay x11vnc_connect; -global x11vnc_auth_file beginner_mode simple_gui_created +global x11vnc_auth_file x11vnc_connect_file beginner_mode simple_gui_created global helpall helptext helpremote helplabel hostname; global all_settings reply_xdisplay always_update global max_text_height max_text_width @@ -3069,6 +3076,12 @@ if {[info exists env(X11VNC_CONNECT)]} { set x11vnc_connect 0; } +if {[info exists env(X11VNC_CONNECT_FILE)]} { + set x11vnc_connect_file $env(X11VNC_CONNECT_FILE); +} else { + set x11vnc_connect_file ""; +} + if {[info exists env(X11VNC_XDISPLAY)]} { set x11vnc_xdisplay $env(X11VNC_XDISPLAY); set x11vnc_connect 1 diff --git a/x11vnc/tkx11vnc.h b/x11vnc/tkx11vnc.h index 512a45f..c3642e6 100644 --- a/x11vnc/tkx11vnc.h +++ b/x11vnc/tkx11vnc.h @@ -118,17 +118,17 @@ " overlay\n" " overlay_nocursor\n" " --\n" +" =D solid\n" +" solid_color:\n" " visual:\n" " flashcmap\n" " shiftcmap:\n" " notruecolor\n" " --\n" -" clip:\n" " =P blackout:\n" " xinerama\n" -" --\n" -" =D solid\n" -" solid_color:\n" +" clip:\n" +" rawfb:\n" " --\n" " = xrandr\n" " =-C:resize,newfbsize,exit xrandr_mode:\n" @@ -176,6 +176,8 @@ " noprimary\n" " nolookup\n" " --\n" +" xtrap\n" +" --\n" " bg\n" " =-C:ignore,exit sigpipe:\n" " =0 inetd\n" @@ -2889,7 +2891,7 @@ "\n" "proc run_remote_cmd {opts} {\n" " global menu_var x11vnc_prog x11vnc_cmdline x11vnc_xdisplay\n" -" global x11vnc_auth_file\n" +" global x11vnc_auth_file x11vnc_connect_file\n" "\n" " set debug [in_debug_mode]\n" "\n" @@ -2908,13 +2910,18 @@ "\n" " lappend cmd $x11vnc_prog;\n" "\n" -" if {$x11vnc_xdisplay != \"\"} {\n" -" lappend cmd \"-display\"\n" -" lappend cmd $x11vnc_xdisplay\n" -" }\n" -" if {$x11vnc_auth_file != \"\"} {\n" -" lappend cmd \"-auth\"\n" -" lappend cmd $x11vnc_auth_file\n" +" if {$x11vnc_connect_file != \"\"} {\n" +" lappend cmd \"-connect\"\n" +" lappend cmd $x11vnc_connect_file\n" +" } else {\n" +" if {$x11vnc_xdisplay != \"\"} {\n" +" lappend cmd \"-display\"\n" +" lappend cmd $x11vnc_xdisplay\n" +" }\n" +" if {$x11vnc_auth_file != \"\"} {\n" +" lappend cmd \"-auth\"\n" +" lappend cmd $x11vnc_auth_file\n" +" }\n" " }\n" " lappend cmd \"-sync\"\n" " foreach word $opts {\n" @@ -3004,7 +3011,7 @@ "# main:\n" "\n" "global env x11vnc_prog x11vnc_cmdline x11vnc_xdisplay x11vnc_connect;\n" -"global x11vnc_auth_file beginner_mode simple_gui_created\n" +"global x11vnc_auth_file x11vnc_connect_file beginner_mode simple_gui_created\n" "global helpall helptext helpremote helplabel hostname;\n" "global all_settings reply_xdisplay always_update\n" "global max_text_height max_text_width\n" @@ -3075,6 +3082,12 @@ " set x11vnc_connect 0;\n" "}\n" "\n" +"if {[info exists env(X11VNC_CONNECT_FILE)]} {\n" +" set x11vnc_connect_file $env(X11VNC_CONNECT_FILE);\n" +"} else {\n" +" set x11vnc_connect_file \"\";\n" +"}\n" +"\n" "if {[info exists env(X11VNC_XDISPLAY)]} {\n" " set x11vnc_xdisplay $env(X11VNC_XDISPLAY);\n" " set x11vnc_connect 1\n" diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1 index e1d4cf8..08f253e 100644 --- a/x11vnc/x11vnc.1 +++ b/x11vnc/x11vnc.1 @@ -2,7 +2,7 @@ .TH X11VNC "1" "April 2005" "x11vnc " "User Commands" .SH NAME x11vnc - allow VNC connections to real X11 displays - version: 0.7.2pre, lastmod: 2005-04-03 + version: 0.7.2pre, lastmod: 2005-04-10 .SH SYNOPSIS .B x11vnc [OPTION]... @@ -180,16 +180,18 @@ is taken as a floating point number, alternatively the notation "m/n" may be used to denote fractions exactly, e.g. \fB-scale\fR 2/3 .IP -Scaling Options: can be added after \fIfraction\fR via -":", to supply multiple ":" options use commas. -If you just want a quick, rough scaling without -blending, append ":nb" to \fIfraction\fR (e.g. \fB-scale\fR -1/3:nb). For compatibility with vncviewers the scaled -width is adjusted to be a multiple of 4: to disable -this use ":n4". More esoteric options: ":in" use -interpolation scheme even when shrinking, ":pad", -pad scaled width and height to be multiples of scaling -denominator (e.g. 3 for 2/3). +Scaling Options: can be added after \fIfraction\fR +via ":", to supply multiple ":" options use +commas. If you just want a quick, rough scaling +without blending, append ":nb" to \fIfraction\fR +(e.g. \fB-scale\fR 1/3:nb). No blending is the default +for 8bpp indexed color, to force blending for this +case use ":fb". For compatibility with vncviewers +the scaled width is adjusted to be a multiple of 4: +to disable this use ":n4". More esoteric options: +":in" use interpolation scheme even when shrinking, +":pad", pad scaled width and height to be multiples +of scaling denominator (e.g. 3 for 2/3). .PP \fB-scale_cursor\fR \fIfrac\fR .IP @@ -564,6 +566,15 @@ 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 +\fB-xtrap\fR +.IP +Use the DEC-XTRAP extension for keystroke and mouse +input insertion. For use on legacy systems, e.g. X11R5, +running an incomplete or missing XTEST extension. +By default DEC-XTRAP will be used if XTEST server grab +control is missing, use \fB-xtrap\fR to do the keystroke and +mouse insertion via DEC-XTRAP as well. +.PP \fB-xrandr\fR \fI[mode]\fR .IP If the display supports the XRANDR (X Resize, Rotate @@ -613,6 +624,12 @@ Write stderr messages to file \fIlogfile\fR instead of to the terminal. Same as "\fB-logfile\fR \fIfile\fR". To append to the file use "\fB-oa\fR \fIfile\fR" or "\fB-logappend\fR \fIfile\fR". .PP +\fB-flag\fR \fIfile\fR +.IP +Write the "PORT=NNNN" (e.g. PORT=5900) string to +\fIfile\fR in addition to stdout. This option could be +useful by wrapper script to detect when x11vnc is ready. +.PP \fB-rc\fR \fIfilename\fR .IP Use \fIfilename\fR instead of $HOME/.x11vncrc for rc file. @@ -1142,6 +1159,64 @@ this mode is very wasteful of memory I/O resources It may be of use in video capture-like applications, or where window tearing is a problem. .PP +\fB-rawfb\fR \fIstring\fR +.IP +Experimental option, instead of polling X, poll the +memory object specified in \fIstring\fR. For shared +memory segments it is of the form: "shm:N@WxHxB" +which specifies a shmid N and framebuffer width, height, +and bits per pixel. To memory map +.IR mmap (2) +a file use: +"map:/path/to/a/file@WxHxB". If there is trouble +with mmap, use "file:/..." for slower +.IR lseek (2) +based +reading. +.IP +Optional suffixes are ":R/G/B" and "+O" to specify +red, green, and blue masks and an offset into the +memory object. If the masks are not provided x11vnc +guesses them based on the bpp. +.IP +Examples: +\fB-rawfb\fR shm:210337933@800x600x32:ff/ff00/ff0000 +\fB-rawfb\fR map:/dev/fb0@1024x768x32 +\fB-rawfb\fR map:/tmp/Xvfb_screen0@640x480x8+3232 +\fB-rawfb\fR file:/tmp/my.pnm@250x200x24+37 +.IP +(see +.IR ipcs (1) +and +.IR fbset (1) +for the first two examples) +.IP +All user input is discarded. Most of the X11 (screen, +keyboard, mouse) options do not make sense and many +will cause this mode to crash, so please think twice +before setting/changing them. If you don't want x11vnc +to close the DISPLAY in rawfb mode, then capitalize +the prefix, SHM:, MAP: etc. Keeping the display open +enables defautl remote control channel. +.PP +\fB-pipeinput\fR \fIcmd\fR +.IP +Another experimental option: it lets you supply an +extern command in \fIcmd\fR that x11vnc will pipe all of +the user input events to in a simple format. By default +x11vnc will not process any of the user input events. +If you prefix \fIcmd\fR with "tee:" it will both send +them to the pipe command and process them. For a +description of the format run "\fB-pipeinput\fR \fItee:cat\fR". +Another prefix is "reopen" which means to reopen pipe +if it exits. Separate multiple prefixes with commas. +.IP +In combination with \fB-rawfb\fR one might be able to +do amusing things (e.g. control non-X devices). +To facilitate this, if \fB-rawfb\fR is in effect then the +value is stored in X11VNC_RAWFB_STR for the pipe command +to use if it wants. Do 'env | grep X11VNC' for more. +.PP \fB-gui\fR \fI[gui-opts]\fR .IP Start up a simple tcl/tk gui based on the the remote @@ -1373,6 +1448,10 @@ xinerama enable \fB-xinerama\fR mode. (if applicable) .IP noxinerama disable \fB-xinerama\fR mode. .IP +xtrap enable \fB-xtrap\fR input mode. +.IP +noxtrap disable \fB-xtrap\fR input mode. +.IP xrandr enable \fB-xrandr\fR mode. (if applicable) .IP noxrandr disable \fB-xrandr\fR mode. @@ -1525,6 +1604,8 @@ snapfb enable \fB-snapfb\fR mode. .IP nosnapfb disable \fB-snapfb\fR mode. .IP +rawfb:str set \fB-rawfb\fR mode to "str". +.IP progressive:n set libvncserver \fB-progressive\fR slice height parameter to n. .IP @@ -1622,39 +1703,39 @@ scale_cursor viewonly noviewonly shared noshared forever noforever once timeout deny lock nodeny unlock connect allowonce allow localhost nolocalhost listen lookup nolookup accept gone shm noshm flipbyteorder -noflipbyteorder onetile noonetile solid_color solid -nosolid blackout xinerama noxinerama xrandr noxrandr -xrandr_mode padgeom quiet q noquiet modtweak nomodtweak -xkb noxkb skip_keycodes add_keysyms noadd_keysyms -clear_mods noclear_mods clear_keys noclear_keys -remap repeat norepeat fb nofb bell nobell sel nosel -primary noprimary cursorshape nocursorshape cursorpos -nocursorpos cursor show_cursor noshow_cursor nocursor -arrow xfixes noxfixes xdamage noxdamage xd_area -xd_mem alphacut alphafrac alpharemove noalpharemove -alphablend noalphablend xwarp xwarppointer noxwarp -noxwarppointer buttonmap dragging nodragging +noflipbyteorder onetile noonetile solid_color +solid nosolid blackout xinerama noxinerama xtrap +noxtrap xrandr noxrandr xrandr_mode padgeom quiet q +noquiet modtweak nomodtweak xkb noxkb skip_keycodes +add_keysyms noadd_keysyms clear_mods noclear_mods +clear_keys noclear_keys remap repeat norepeat fb nofb +bell nobell sel nosel primary noprimary cursorshape +nocursorshape cursorpos nocursorpos cursor show_cursor +noshow_cursor nocursor arrow xfixes noxfixes xdamage +noxdamage xd_area xd_mem alphacut alphafrac alpharemove +noalpharemove alphablend noalphablend xwarp xwarppointer +noxwarp noxwarppointer buttonmap dragging nodragging pointer_mode pm input_skip input client_input speeds debug_pointer dp nodebug_pointer nodp debug_keyboard dk nodebug_keyboard nodk deferupdate defer wait rfbwait nap nonap sb screen_blank fs gaps grow fuzz snapfb -nosnapfb progressive rfbport http nohttp httpport +nosnapfb rawfb progressive rfbport http nohttp httpport httpdir enablehttpproxy noenablehttpproxy alwaysshared noalwaysshared nevershared noalwaysshared dontdisconnect nodontdisconnect desktop noremote .IP aro= display vncdisplay desktopname http_url auth users rootshift clipshift scale_str scaled_x scaled_y -scale_numer scale_denom scale_fac scaling_noblend -scaling_nomult4 scaling_pad scaling_interpolate inetd -safer unsafe passwdfile using_shm logfile o rc norc -h help V version lastmod bg sigpipe threads clients -client_count pid ext_xtest ext_xtrap ext_xkb ext_xshm -ext_xinerama ext_overlay ext_xfixes ext_xdamage -ext_xrandr rootwin num_buttons button_mask mouse_x -mouse_y bpp depth indexed_color dpy_x dpy_y wdpy_x -wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth -passwd +scale_numer scale_denom scale_fac scaling_blend +scaling_nomult4 scaling_pad scaling_interpolate +inetd safer unsafe passwdfile using_shm logfile o +flag rc norc h help V version lastmod bg sigpipe +threads clients client_count pid ext_xtest ext_xtrap +ext_xkb ext_xshm ext_xinerama ext_overlay ext_xfixes +ext_xdamage ext_xrandr rootwin num_buttons button_mask +mouse_x mouse_y bpp depth indexed_color dpy_x dpy_y +wdpy_x wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y +rfbauth passwd .PP \fB-sync\fR .IP diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c index d98a4c1..ef3faf4 100644 --- a/x11vnc/x11vnc.c +++ b/x11vnc/x11vnc.c @@ -139,6 +139,8 @@ #endif #if OLD_TREE +/* BEGIN OLD TREE */ + /* * if you have a very old tree (LibVNCServer 0.6) and get errors these may * be need to be uncommented. LibVNCServer <= 0.5 is no longer supported. @@ -170,6 +172,7 @@ #define LIBVNCSERVER_HAVE_PWD_H 1 #define LIBVNCSERVER_HAVE_SYS_WAIT_H 1 #define LIBVNCSERVER_HAVE_UTMPX_H 1 +#define LIBVNCSERVER_HAVE_MMAP 1 /* #define LIBVNCSERVER_HAVE_LIBXINERAMA 1 @@ -177,15 +180,17 @@ #define LIBVNCSERVER_HAVE_LIBXDAMAGE 1 */ -#endif /* OLD_TREE */ -/****************************************************************************/ +/* END OLD TREE */ +#endif +/****************************************************************************/ /* Standard includes and libvncserver */ #include <unistd.h> #include <signal.h> #include <sys/utsname.h> +#include <errno.h> #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -291,6 +296,16 @@ #define LIBVNCSERVER_HAVE_PWD_H 0 #define REMOTE_CONTROL 0 #endif + +/* + * Not recommended unless you know what you are getting into, but if you + * define the HARDWIRE_PASSWD or HARDWIRE_VIEWPASSWD variables here or in + * CPPFLAGS you can set a default -passwd and -viewpasswd string values, + * perhaps this would be better than nothing on an embedded system, etc. + * These default values will be overridden by the command line. + * We don't even give an example ;-) + */ + /****************************************************************************/ @@ -308,7 +323,7 @@ #if LIBVNCSERVER_HAVE_XTEST #include <X11/extensions/XTest.h> #endif -static int xtest_base_event_type = 0; +int xtest_base_event_type = 0; #if LIBVNCSERVER_HAVE_LIBXTRAP #define NEED_EVENTS @@ -317,7 +332,7 @@ static int xtest_base_event_type = 0; #include <X11/extensions/xtraplibp.h> XETC *trap_ctx = NULL; #endif -static int xtrap_base_event_type = 0; +int xtrap_base_event_type = 0; #if LIBVNCSERVER_HAVE_XKEYBOARD #include <X11/XKBlib.h> @@ -351,6 +366,10 @@ extern int h_errno; #include <utmpx.h> #endif +#if LIBVNCSERVER_HAVE_MMAP +#include <sys/mman.h> +#endif + /* * overlay/multi-depth screen reading support * undef SOLARIS_OVERLAY or IRIX_OVERLAY if there are problems building. @@ -400,8 +419,8 @@ int alt_arrow = 1; #if LIBVNCSERVER_HAVE_LIBXFIXES #include <X11/extensions/Xfixes.h> -#endif static int xfixes_base_event_type = 0; +#endif int xdamage_present = 0; @@ -409,15 +428,15 @@ int use_xdamage = 1; /* just use the xdamage rects. for scanline hints */ #if LIBVNCSERVER_HAVE_LIBXDAMAGE #include <X11/extensions/Xdamage.h> Damage xdamage = 0; -#endif static int xdamage_base_event_type = 0; +#endif int xdamage_max_area = 20000; /* pixels */ double xdamage_memory = 1.0; /* in units of NSCAN */ int xdamage_tile_count; /* date +'lastmod: %Y-%m-%d' */ -char lastmod[] = "0.7.2pre lastmod: 2005-04-03"; +char lastmod[] = "0.7.2pre lastmod: 2005-04-10"; int hack_val = 0; /* X display info */ @@ -442,6 +461,7 @@ XImage **tile_row; /* for all possible row runs */ XImage *fb0; XImage *snaprect = NULL; /* for XShmGetImage (fs_factor) */ XImage *snap = NULL; /* the full snap fb */ +XImage *raw_fb_image = NULL; /* the raw fb */ #if !LIBVNCSERVER_HAVE_XSHM /* @@ -466,8 +486,16 @@ char *http_dir = NULL; char vnc_desktop_name[256]; char *main_fb; /* our copy of the X11 fb */ char *rfb_fb; /* same as main_fb unless transformation */ -char *snap_fb = NULL; /* used under -snapfb */ char *fake_fb = NULL; /* used under -padgeom */ +char *snap_fb = NULL; /* used under -snapfb */ +char *raw_fb = NULL; +char *raw_fb_addr = NULL; +int raw_fb_offset = 0; +int raw_fb_shm = 0; +int raw_fb_mmap = 0; +int raw_fb_seek = 0; +int raw_fb_fd = -1; + int rfb_bytes_per_line; int main_bytes_per_line; unsigned long main_red_mask, main_green_mask, main_blue_mask; @@ -504,7 +532,7 @@ typedef struct _ClientData { char *scale_str = NULL; double scale_fac = 1.0; int scaling = 0; -int scaling_noblend = 0; /* no blending option (very course) */ +int scaling_blend = 1; /* for 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 */ @@ -515,7 +543,7 @@ int scale_numer = 0, scale_denom = 0; /* n/m */ char *scale_cursor_str = NULL; double scale_cursor_fac = 1.0; int scaling_cursor = 0; -int scaling_cursor_noblend = 0; +int scaling_cursor_blend = 1; int scaling_cursor_interpolate = 0; int scale_cursor_numer = 0, scale_cursor_denom = 0; @@ -602,6 +630,7 @@ double dtime(double *); void initialize_blackouts(char *); void initialize_blackouts_and_xinerama(void); +void initialize_clipshift(void); void initialize_keyboard_and_pointer(void); void initialize_allowed_input(void); void initialize_modtweak(void); @@ -624,7 +653,9 @@ void destroy_xdamage_if_needed(void); void initialize_xrandr(void); XImage *initialize_xdisplay_fb(void); +void initialize_pipeinput(void); void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client); +void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client); void XTestFakeKeyEvent_wr(Display*, KeyCode, Bool, unsigned long); void XTestFakeButtonEvent_wr(Display*, unsigned int, Bool, unsigned long); @@ -646,8 +677,11 @@ void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force); enum rfbNewClientAction new_client(rfbClientPtr client); void set_nofb_params(void); +void set_raw_fb_params(int); void nofb_hook(rfbClientPtr client); void pointer(int mask, int x, int y, rfbClientPtr client); +void pipe_pointer(int mask, int x, int y, rfbClientPtr client); +int check_pipeinput(void); void cursor_position(int, int); void read_vnc_connect_prop(void); @@ -722,6 +756,7 @@ char *auth_file = NULL; /* -auth/-xauth */ char *visual_str = NULL; /* -visual */ char *logfile = NULL; /* -o, -logfile */ int logfile_append = 0; +char *flagfile = NULL; /* -flag */ char *passwdfile = NULL; /* -passwdfile */ char *blackout_str = NULL; /* -blackout */ char *clip_str = NULL; /* -clip */ @@ -776,10 +811,16 @@ int use_modifier_tweak = 1; /* use the shift/altgr modifier tweak */ int use_iso_level3 = 0; /* ISO_Level3_Shift instead of Mode_switch */ int clear_mods = 0; /* -clear_mods (1) and -clear_keys (2) */ int nofb = 0; /* do not send any fb updates */ +char *raw_fb_str = NULL; /* used under -rawfb */ +char *pipeinput_str = NULL; /* -pipeinput [tee,reopen,keycodes:]cmd */ +char *pipeinput_opts = NULL; +FILE *pipeinput_fh = NULL; +int pipeinput_tee = 0; unsigned long subwin = 0x0; /* -id, -sid */ int subwin_wait_mapped = 0; +int xtrap_input = 0; /* -xtrap for user input insertion */ int xinerama = 0; /* -xinerama */ int xrandr = 0; /* -xrandr */ int xrandr_present = 0; @@ -857,29 +898,12 @@ int visual_depth = 0; int overlay = 0; int overlay_cursor = 1; -#if LIBVNCSERVER_HAVE_XSHM -int xshm_present = 1; -#else int xshm_present = 0; -#endif -#if LIBVNCSERVER_HAVE_XTEST -int xtest_present = 1; -#else int xtest_present = 0; -#endif -#if LIBVNCSERVER_HAVE_LIBXTRAP -int xtrap_present = 1; -#else int xtrap_present = 0; -#endif -#if LIBVNCSERVER_HAVE_XKEYBOARD -int xkb_present = 1; -#else int xkb_present = 0; -#endif int xinerama_present = 0; - /* tile heuristics: */ double fs_frac = 0.75; /* threshold tile fraction to do fullscreen updates. */ int tile_fuzz = 2; /* tolerance for suspecting changed tiles touching */ @@ -2253,6 +2277,24 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth, * blue mask). Note we read from the root window(!) then free * the data. */ + + if (raw_fb) { /* raw_fb hack */ + XImage *xi; + xi = (XImage *) malloc(sizeof(XImage)); + memset(xi, 0, sizeof(XImage)); + xi->depth = depth; + xi->bits_per_pixel = (depth == 24) ? 32 : depth; + xi->format = format; + xi->xoffset = offset; + xi->data = data; + xi->width = width; + xi->height = height; + xi->bitmap_pad = bitmap_pad; + xi->bytes_per_line = bytes_per_line ? bytes_per_line : + xi->width * xi->bits_per_pixel / 8; + return xi; + } + if (overlay) { XImage *xi; xi = xreadscreen(disp, window, 0, 0, width, height, False); @@ -2270,8 +2312,52 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth, width, height, bitmap_pad, bytes_per_line); } -void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h) { +void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h) { + char *src, *dst; + int line, pixelsize = bpp/8; + if (! raw_fb_seek) { + src = (raw_fb_addr + raw_fb_offset) + + raw_fb_image->bytes_per_line*y + pixelsize*x; + dst = dest->data; + + for (line = 0; line < h; line++) { + memcpy(dst, src, w * pixelsize); + src += raw_fb_image->bytes_per_line; + dst += dest->bytes_per_line; + } + } else{ + int n, len, del, sz = w * pixelsize; + int bpl = raw_fb_image->bytes_per_line; + off_t off = (off_t) (raw_fb_offset + bpl*y + pixelsize*x); + + lseek(raw_fb_fd, off, SEEK_SET); + dst = dest->data; + + for (line = 0; line < h; line++) { + len = sz; + del = 0; + while (len > 0) { + n = read(raw_fb_fd, dst + del, len); + + if (n > 0) { + del += n; + len -= n; + } else if (n == 0) { + break; + } else { + /* overkill... */ + if (errno != EINTR && errno != EAGAIN) { + break; + } + } + } + dst += dest->bytes_per_line; + } + } +} + +void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h) { /* default (w=0, h=0) is the fill the entire XImage */ if (w < 1) { w = dest->width; @@ -2291,17 +2377,44 @@ void copy_image(XImage *dest, int x, int y, unsigned int w, unsigned int h) { src += snap->bytes_per_line; dst += dest->bytes_per_line; } + + } else if (raw_fb) { + copy_raw_fb(dest, x, y, w, h); + } else if (using_shm && w == dest->width && h == dest->height) { XShmGetImage_wr(dpy, window, dest, x, y, AllPlanes); + } else { XGetSubImage_wr(dpy, window, x, y, w, h, AllPlanes, ZPixmap, dest, 0, 0); } } +#define DEBUG_SKIPPED_INPUT(dbg, str) \ + if (dbg) { \ + rfbLog("skipped input: %s\n", str); \ + } + /* * wrappers for XTestFakeKeyEvent, etc.. + * also for XTrap equivalents XESimulateXEventRequest */ + +void XTRAP_FakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, + unsigned long delay) { + + if (! xtrap_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTRAP"); + return; + } +#if LIBVNCSERVER_HAVE_LIBXTRAP + XESimulateXEventRequest(trap_ctx, down ? KeyPress : KeyRelease, + key, 0, 0, 0); +#else + DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTRAP-build"); +#endif +} + void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, unsigned long delay) { if (debug_keyboard) { @@ -2309,41 +2422,81 @@ void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down, key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)), down ? "down":"up"); } - if (! xtest_present) { - return; - } if (down) { last_keyboard_input = -key; } else { last_keyboard_input = key; } + + if (xtrap_input) { + return XTRAP_FakeKeyEvent_wr(dpy, key, down, delay); + } + + if (! xtest_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "keyboard: no-XTEST"); + return; + } #if LIBVNCSERVER_HAVE_XTEST XTestFakeKeyEvent(dpy, key, down, delay); #endif } -/* XTRAP: XESimulateXEventRequest(tc, KeyPress, key, 0, 0, 0); */ + +void XTRAP_FakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, + unsigned long delay) { + + if (! xtrap_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTRAP"); + return; + } +#if LIBVNCSERVER_HAVE_LIBXTRAP + XESimulateXEventRequest(trap_ctx, + is_press ? ButtonPress : ButtonRelease, button, 0, 0, 0); +#else + DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTRAP-build"); +#endif +} void XTestFakeButtonEvent_wr(Display* dpy, unsigned int button, Bool is_press, unsigned long delay) { + + if (xtrap_input) { + return XTRAP_FakeButtonEvent_wr(dpy, button, is_press, delay); + } + if (! xtest_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "button: no-XTEST"); return; } #if LIBVNCSERVER_HAVE_XTEST XTestFakeButtonEvent(dpy, button, is_press, delay); #endif } -/* XTRAP: XESimulateXEventRequest(tc, ButtonPress, button, 0, 0, 0); */ -void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y, +void XTRAP_FakeMotionEvent_wr(Display* dpy, int screen, int x, int y, unsigned long delay) { - if (! xtest_present) { + + if (! xtrap_present) { + DEBUG_SKIPPED_INPUT(debug_keyboard, "motion: no-XTRAP"); return; } +#if LIBVNCSERVER_HAVE_LIBXTRAP + XESimulateXEventRequest(trap_ctx, MotionNotify, 0, x, y, 0); +#else + DEBUG_SKIPPED_INPUT(debug_keyboard, "motion: no-XTRAP-build"); +#endif +} + +void XTestFakeMotionEvent_wr(Display* dpy, int screen, int x, int y, + unsigned long delay) { + + if (xtrap_input) { + return XTRAP_FakeMotionEvent_wr(dpy, screen, x, y, delay); + } + #if LIBVNCSERVER_HAVE_XTEST XTestFakeMotionEvent(dpy, screen, x, y, delay); #endif } -/* XTRAP: XESimulateXEventRequest(tc, MotionNotify, 0, x, y, 0); */ Bool XTestCompareCurrentCursorWithWindow_wr(Display* dpy, Window w) { if (! xtest_present) { @@ -2376,17 +2529,6 @@ Bool XTestCompareCursorWithWindow_wr(Display* dpy, Window w, Cursor cursor) { #endif #endif -int XTestGrabControl_wr(Display* dpy, Bool impervious) { - if (! xtest_present) { - return 0; - } -#if LIBVNCSERVER_HAVE_XTEST && LIBVNCSERVER_HAVE_XTESTGRABCONTROL - return XTestGrabControl(dpy, impervious); -#else - return 0; -#endif -} - Bool XTestQueryExtension_wr(Display *dpy, int *ev, int *er, int *maj, int *min) { #if LIBVNCSERVER_HAVE_XTEST @@ -2414,32 +2556,86 @@ Bool XETrapQueryExtension_wr(Display *dpy, int *ev, int *er, int *op) { #endif } -void disable_grabserver(void) { -#if LIBVNCSERVER_HAVE_XTEST && LIBVNCSERVER_HAVE_XTESTGRABCONTROL - if (XTestGrabControl_wr(dpy, True)) { - return; +int XTestGrabControl_wr(Display *dpy, Bool impervious) { + if (! xtest_present) { + return 0; } +#if LIBVNCSERVER_HAVE_XTEST && LIBVNCSERVER_HAVE_XTESTGRABCONTROL + XTestGrabControl(dpy, impervious); + return 1; +#else + return 0; #endif +} + +int XTRAP_GrabControl_wr(Display *dpy, Bool impervious) { + if (! xtrap_present) { + return 0; + } #if LIBVNCSERVER_HAVE_LIBXTRAP - if (xtrap_present) { + else { ReqFlags requests; - trap_ctx = XECreateTC(dpy, 0, NULL); + if (! impervious) { + if (trap_ctx) { + XEFreeTC(trap_ctx); + } + trap_ctx = NULL; + return 1; + } + if (! trap_ctx) { - rfbLog("DEC-XTRAP XECreateTC failed. Watch out for" - "XGrabServer from wm's\n"); - return; + trap_ctx = XECreateTC(dpy, 0, NULL); + if (! trap_ctx) { + rfbLog("DEC-XTRAP XECreateTC failed. Watch " + "out for XGrabServer from wm's\n"); + return 0; + } + XEStartTrapRequest(trap_ctx); + memset(requests, 0, sizeof(requests)); + BitTrue(requests, X_GrabServer); + BitTrue(requests, X_UngrabServer); + XETrapSetRequests(trap_ctx, True, requests); + XETrapSetGrabServer(trap_ctx, True); } - XEStartTrapRequest(trap_ctx); - memset(requests, 0, sizeof(requests)); - BitTrue(requests, X_GrabServer); - BitTrue(requests, X_UngrabServer); - XETrapSetRequests(trap_ctx, True, requests); - XETrapSetGrabServer(trap_ctx, True); - return; + return 1; } #endif - rfbLog("No XTEST or DEC-XTRAP protection from XGrabServer.\n"); + return 0; +} + +void disable_grabserver(void) { + int ok = 0; + + if (! xtrap_input) { + if (XTestGrabControl_wr(dpy, True)) { + XTRAP_GrabControl_wr(dpy, False); + rfbLog("GrabServer control via XTEST.\n"); + ok = 1; + } else { + if (XTRAP_GrabControl_wr(dpy, True)) { + ok = 1; + rfbLog("Using DEC-XTRAP for protection from " + "XGrabServer.\n"); + } + } + } else { + if (XTRAP_GrabControl_wr(dpy, True)) { + XTestGrabControl_wr(dpy, False); + rfbLog("GrabServer control via DEC-XTRAP.\n"); + ok = 1; + } else { + if (XTestGrabControl_wr(dpy, True)) { + ok = 1; + rfbLog("DEC-XTRAP XGrabServer protection not " + "available, using XTEST.\n"); + } + } + } + if (! ok) { + rfbLog("No XTEST or DEC-XTRAP protection from XGrabServer.\n"); + rfbLog("Deadlock if your window manager calls XGrabServer!!\n"); + } } @@ -2454,6 +2650,8 @@ int exit_sig = 0; void clean_shm(int quick) { int i, cnt = 0; + if (raw_fb) quick = 1; /* raw_fb hack */ + /* * to avoid deadlock, etc, under quick=1 we just delete the shm * areas and leave the X stuff hanging. @@ -2501,6 +2699,10 @@ void clean_up_exit (int ret) { /* remove the shm areas: */ clean_shm(0); + if (! dpy) { + exit(ret); /* raw_rb hack */ + } + /* X keyboard cleanups */ delete_added_keycodes(); @@ -3090,6 +3292,8 @@ static int run_user_command(char *cmd, rfbClientPtr client, char *mode) { static void client_gone(rfbClientPtr client) { client_count--; + if (client_count < 0) client_count = 0; + rfbLog("client_count: %d\n", client_count); if (no_autorepeat && client_count == 0) { @@ -3829,7 +4033,7 @@ static int accept_client(rfbClientPtr client) { */ static void check_connect_file(char *file) { FILE *in; - char line[1024], host[1024]; + char line[VNC_CONNECT_MAX], host[VNC_CONNECT_MAX]; static int first_warn = 1, truncate_ok = 1; static time_t last_time = 0; time_t now = time(0); @@ -3862,11 +4066,19 @@ static void check_connect_file(char *file) { return; } - if (fgets(line, 1024, in) != NULL) { + if (fgets(line, VNC_CONNECT_MAX, in) != NULL) { if (sscanf(line, "%s", host) == 1) { if (strlen(host) > 0) { char *str = strdup(host); - rfbLog("read connect file: %s\n", host); + if (strlen(str) > 38) { + char trim[100]; + trim[0] = '\0'; + strncat(trim, str, 38); + rfbLog("read connect file: %s ...\n", + trim); + } else { + rfbLog("read connect file: %s\n", str); + } client_connect = str; } } @@ -4141,8 +4353,11 @@ enum rfbNewClientAction new_client(rfbClientPtr client) { client->clientGoneHook = client_gone; client_count++; - if (no_autorepeat && client_count == 1) { - /* first client, turn off X server autorepeat */ + if (no_autorepeat && client_count == 1 && ! view_only) { + /* + * first client, turn off X server autorepeat + * XXX handle dynamic change of view_only and per-client. + */ autorepeat(0); } if (use_solid_bg && client_count == 1) { @@ -5486,6 +5701,8 @@ void initialize_allowed_input(void) { } void initialize_keyboard_and_pointer(void) { + if (raw_fb && ! dpy) return; /* raw_fb hack */ + if (use_modifier_tweak) { initialize_modtweak(); } @@ -5747,6 +5964,39 @@ void get_allowed_input(rfbClientPtr client, allowed_input_t *input) { } } +/* for -pipeinput mode */ +void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { + int can_input = 0, uid; + allowed_input_t input; + char *name; + ClientData *cd = (ClientData *) client->clientData; + + if (pipeinput_fh == NULL) { + return; + } + + if (! view_only) { + get_allowed_input(client, &input); + if (input.motion || input.button) { + can_input = 1; /* XXX distinguish later */ + } + } + uid = cd->uid; + if (! can_input) { + uid = -uid; + } + + X_LOCK; + name = XKeysymToString(keysym); + X_UNLOCK; + + fprintf(pipeinput_fh, "Keysym %d %d %u %s %s\n", uid, down, + keysym, name, down ? "KeyPress" : "KeyRelease"); + + fflush(pipeinput_fh); + check_pipeinput(); +} + /* * key event handler. See the above functions for contortions for * running under -modtweak. @@ -5767,6 +6017,19 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { X_UNLOCK; } + if (pipeinput_fh != NULL) { + pipe_keyboard(down, keysym, client); + if (! pipeinput_tee) { + if (! view_only || raw_fb) { /* raw_fb hack */ + last_keyboard_client = client; + last_event = last_input = time(0); + got_user_input++; + got_keyboard_input++; + } + return; + } + } + if (view_only) { return; } @@ -6230,6 +6493,68 @@ static void update_x11_pointer_mask(int mask) { button_mask = mask; } +/* for -pipeinput */ + + +void pipe_pointer(int mask, int x, int y, rfbClientPtr client) { + int can_input = 0, uid; + allowed_input_t input; + ClientData *cd = (ClientData *) client->clientData; + char hint[MAX_BUTTONS * 20]; + + if (pipeinput_fh == NULL) { + return; + } + + if (! view_only) { + get_allowed_input(client, &input); + if (input.motion || input.button) { + can_input = 1; /* XXX distinguish later */ + } + } + uid = cd->uid; + if (! can_input) { + uid = -uid; + } + + hint[0] = '\0'; + if (mask == button_mask) { + strcat(hint, "None"); + } else { + int i, old, new, m = 1, cnt = 0; + for (i=0; i<MAX_BUTTONS; i++) { + char s[20]; + + old = button_mask & m; + new = mask & m; + m = m << 1; + + if (old == new) { + continue; + } + if (hint[0] != '\0') { + strcat(hint, ","); + } + if (new && ! old) { + sprintf(s, "ButtonPress-%d", i+1); + cnt++; + } else if (! new && old) { + sprintf(s, "ButtonRelease-%d", i+1); + cnt++; + } + strcat(hint, s); + } + if (! cnt) { + strcpy(hint, "None"); + } + } + + fprintf(pipeinput_fh, "Pointer %d %d %d %d %s\n", uid, x, y, + mask, hint); + fflush(pipeinput_fh); + check_pipeinput(); +} + /* * Actual callback from libvncserver when it gets a pointer event. * This may queue pointer events rather than sending them immediately @@ -6253,13 +6578,6 @@ void pointer(int mask, int x, int y, rfbClientPtr client) { } } - if (view_only) { - return; - } - get_allowed_input(client, &input); - if (! input.motion && ! input.button) { - return; - } if (scaling) { /* map from rfb size to X11 size: */ x = ((double) x / scaled_x) * dpy_x; @@ -6268,6 +6586,29 @@ void pointer(int mask, int x, int y, rfbClientPtr client) { y = nfix(y, dpy_y); } + if (pipeinput_fh != NULL && mask >= 0) { + pipe_pointer(mask, x, y, client); + if (! pipeinput_tee) { + if (! view_only || raw_fb) { /* raw_fb hack */ + got_user_input++; + got_keyboard_input++; + last_pointer_client = client; + } + if (view_only && raw_fb) { + /* raw_fb hack track button state */ + button_mask = mask; + } + return; + } + } + + if (view_only) { + return; + } + get_allowed_input(client, &input); + if (! input.motion && ! input.button) { + return; + } if (mask >= 0) { /* * mask = -1 is a special case call from scan_for_updates() @@ -6383,6 +6724,199 @@ void pointer(int mask, int x, int y, rfbClientPtr client) { } } +int check_pipeinput(void) { + if (! pipeinput_fh) { + return 1; + } + if (ferror(pipeinput_fh)) { + rfbLog("pipeinput pipe has ferror. %p\n", pipeinput_fh); + + if (pipeinput_opts && strstr(pipeinput_opts, "reopen")) { + rfbLog("restarting -pipeinput pipe...\n"); + initialize_pipeinput(); + if (pipeinput_fh) { + return 1; + } else { + return 0; + } + } else { + rfbLog("closing -pipeinput pipe...\n"); + pclose(pipeinput_fh); + pipeinput_fh = NULL; + return 0; + } + } + return 1; +} + +void initialize_pipeinput(void) { + char *p; + char pid[16]; + + if (pipeinput_fh != NULL) { + rfbLog("closing pipeinput stream: %p\n", pipeinput_fh); + pclose(pipeinput_fh); + pipeinput_fh = NULL; + } + + pipeinput_tee = 0; + if (pipeinput_opts) { + free(pipeinput_opts); + pipeinput_opts = NULL; + } + + if (! pipeinput_str) { + return; + } + + /* look for options: tee, reopen, ... */ + p = strchr(pipeinput_str, ':'); + if (p != NULL) { + char *str, *opt, *q; + int got = 0; + *p = '\0'; + str = strdup(pipeinput_str); + opt = strdup(pipeinput_str); + *p = ':'; + q = strtok(str, ","); + while (q) { + if (!strcmp(q, "key") || !strcmp(q, "keycodes")) { + got = 1; + } + if (!strcmp(q, "reopen")) { + got = 1; + } + if (!strcmp(q, "tee")) { + pipeinput_tee = 1; + got = 1; + } + q = strtok(NULL, ","); + } + if (got) { + pipeinput_opts = opt; + } else { + free(opt); + } + free(str); + p++; + } else { + p = pipeinput_str; + } + + /* set up useful environment for child process */ + sprintf(pid, "%d", (int) getpid()); + set_env("X11VNC_PID", pid); + if (program_name) { + /* e.g. for remote control -R */ + set_env("X11VNC_PROG", program_name); + } + if (program_cmdline) { + set_env("X11VNC_CMDLINE", program_cmdline); + } + if (raw_fb_str) { + set_env("X11VNC_RAWFB_STR", raw_fb_str); + } + + rfbLog("pipeinput: starting: \"%s\"...\n", p); + pipeinput_fh = popen(p, "w"); + + if (! pipeinput_fh) { + rfbLog("popen(\"%s\", \"w\") failed.\n", p); + rfbLogPerror("popen"); + rfbLog("Disabling -pipeinput mode.\n"); + return; + } + + fprintf(pipeinput_fh, "%s", +"# \n" +"# Format of the -pipeinput stream:\n" +"# --------------------------------\n" +"#\n" +"# Lines like these beginning with '#' are to be ignored.\n" +"#\n" +"# Pointer events (mouse motion and button clicks) come in the form:\n" +"#\n" +"#\n" +"# Pointer <client#> <x> <y> <mask> <hint>\n" +"#\n" +"#\n" +"# The <client#> is a decimal integer uniquely identifying the client\n" +"# that generated the event. If it is negative that means this event\n" +"# would have been discarded since the client was viewonly.\n" +"#\n" +"# <x> and <y> are decimal integers reflecting the position on the screen\n" +"# the event took place at.\n" +"#\n" +"# <mask> is the button mask indicating the button press state, as normal\n" +"# 0 means no buttons pressed, 1 means button 1 is down 3 (11) means buttons\n" +"# 1 and 2 are down, etc.\n" +"#\n" +"# <hint> is a string containing no spaces and may be ignored.\n" +"# It contains some interpretation about what has happened.\n" +"# It can be:\n" +"#\n" +"# None (nothing to report)\n" +"# ButtonPress-N (this event will cause button-1 to be pressed) \n" +"# ButtonRelease-N (this event will cause button-1 to be released) \n" +"#\n" +"# if two more more buttons change state in one event they are listed\n" +"# separated by commas.\n" +"#\n" +"# One might parse a Pointer like with:\n" +"#\n" +"# int client, x, y, mask; char *hint;\n" +"# sscanf(line, \"Pointer %d %d %d %s\", &client, &x, &y, &mask, &hint);\n" +"#\n" +"#\n" +"# Keysym events (keyboard presses and releases) come in the form:\n" +"#\n" +"#\n" +"# Keysym <client#> <down> <keysym#> <keysym-name> <hint>\n" +"#\n" +"#\n" +"# The <client#> is as with Pointer.\n" +"#\n" +"# <down> is a decimal either 1 or 0 indicating KeyPress or KeyRelease,\n" +"# respectively.\n" +"#\n" +"# <keysym#> is a decimal integer incidating the Keysym of the event.\n" +"#\n" +"# <keysym-name> is the corresponding Keysym name.\n" +"#\n" +"# See the file /usr/include/X11/keysymdef.h for the mappings.\n" +"# You basically remove the leading 'XK_' prefix from the macro name in\n" +"# that file to get the Keysym name.\n" +"#\n" +"# One might parse a Pointer like with:\n" +"#\n" +"# int client, down, keysym; char *name, *hint;\n" +"# sscanf(line, \"Keysym %d %d %s %s\", &client, &down, &keysym, &name, &hint);\n" +"#\n" +"# The <hint> value is currently just None, KeyPress, or KeyRelease.\n" +"#\n" +"# In the future <hint> will provide a hint for the sequence of KeyCodes\n" +"# (i.e. keyboard scancodes) that x11vnc would inject to an X display to\n" +"# simulate the Keysym.\n" +"#\n" +"# You see, some Keysyms will require more than one injected Keycode to\n" +"# generate the symbol. E.g. the Keysym \"ampersand\" going down usually\n" +"# requires a Shift key going down, then the key with the \"&\" on it going\n" +"# down, and, perhaps, the Shift key going up (that is how x11vnc does it).\n" +"#\n" +"# The Keysym => Keycode(s) stuff gets pretty messy. Hopefully the Keysym\n" +"# info will be enough for most purposes (having identical keyboards on\n" +"# both sides helps).\n" +"#\n" +"# Here comes yours stream:\n" +"# END_OF_TOP\n" +); + fflush(pipeinput_fh); + if (raw_fb_str) { + /* the pipe program may actually create the fb */ + sleep(1); + } +} + /* -- xkb_bell.c -- */ /* * Bell event handling. Requires XKEYBOARD extension. @@ -7067,6 +7601,9 @@ void check_xevents(void) { static time_t last_sync = 0; time_t now = time(0); + if (! dpy) { /* raw_fb hack */ + return; + } if (now > last_init_check+1) { last_init_check = now; initialize_xevents(); @@ -7102,7 +7639,7 @@ void check_xevents(void) { if (no_autorepeat && have_clients && no_repeat_countdown) { static time_t last_check = 0; - if (now > last_check + 1) { + if (now > last_check + 1 && ! view_only) { last_check = now; X_UNLOCK; if (get_autorepeat_state() != 0) { @@ -8202,6 +8739,7 @@ char *process_remote_cmd(char *cmd, int stringonly) { } rfbLog("process_remote_cmd: disable viewonly mode.\n"); view_only = 0; + if (raw_fb) set_raw_fb_params(0); } else if (!strcmp(p, "shared")) { if (query) { @@ -8551,6 +9089,8 @@ char *process_remote_cmd(char *cmd, int stringonly) { } rfbLog("process_remote_cmd: turning off noshm mode.\n"); using_shm = 1; + if (raw_fb) set_raw_fb_params(0); + if (orig != using_shm) { do_new_fb(1); } else { @@ -8647,6 +9187,7 @@ char *process_remote_cmd(char *cmd, int stringonly) { } solid_str = new; use_solid_bg = 1; + if (raw_fb) set_raw_fb_params(0); if (doit && client_count) { solid_bg(0); @@ -8662,6 +9203,7 @@ char *process_remote_cmd(char *cmd, int stringonly) { solid_str = strdup(solid_default); } use_solid_bg = 1; + if (raw_fb) set_raw_fb_params(0); if (client_count && !orig) { solid_bg(0); } @@ -8735,6 +9277,30 @@ char *process_remote_cmd(char *cmd, int stringonly) { xinerama = 0; initialize_blackouts_and_xinerama(); + } else if (!strcmp(p, "xtrap")) { + if (query) { + snprintf(buf, bufn, "ans=%s:%d", p, xtrap_input); + goto qry; + } + rfbLog("process_remote_cmd: enable xtrap input mode." + "(if applicable).\n"); + if (! xtrap_input) { + xtrap_input = 1; + disable_grabserver(); + } + + } else if (!strcmp(p, "noxtrap")) { + if (query) { + snprintf(buf, bufn, "ans=%s:%d", p, !xtrap_input); + goto qry; + } + rfbLog("process_remote_cmd: disable xtrap input mode." + "(if applicable).\n"); + if (xtrap_input) { + xtrap_input = 0; + disable_grabserver(); + } + } else if (!strcmp(p, "xrandr")) { int orig = xrandr; if (query) { @@ -8743,6 +9309,7 @@ char *process_remote_cmd(char *cmd, int stringonly) { if (xrandr_present) { rfbLog("process_remote_cmd: enable xrandr mode.\n"); xrandr = 1; + if (raw_fb) set_raw_fb_params(0); if (! xrandr_mode) { xrandr_mode = strdup("default"); } @@ -9033,7 +9600,7 @@ char *process_remote_cmd(char *cmd, int stringonly) { if (no_repeat_countdown >= 0) { no_repeat_countdown = 2; } - if (client_count) { + if (client_count && ! view_only) { autorepeat(0); /* disable if any clients */ } @@ -9767,6 +10334,29 @@ char *process_remote_cmd(char *cmd, int stringonly) { do_new_fb(1); } + } else if (strstr(p, "rawfb") == p) { + COLON_CHECK("rawfb:") + if (query) { + snprintf(buf, bufn, "ans=%s%s%s", p, co, + NONUL(raw_fb_str)); + goto qry; + } + p += strlen("rawfb:"); + if (raw_fb_str) free(raw_fb_str); + raw_fb_str = strdup(p); + + rfbLog("process_remote_cmd: setting -rawfb to:\n" + "\t'%s'\n", p); + + if (*raw_fb_str == '\0') { + free(raw_fb_str); + raw_fb_str = NULL; + rfbLog("restoring per-rawfb settings...\n"); + set_raw_fb_params(1); + } + rfbLog("hang on tight, here we go...\n"); + do_new_fb(1); + } else if (strstr(p, "progressive") == p) { int f; COLON_CHECK("progressive:") @@ -9962,13 +10552,22 @@ char *process_remote_cmd(char *cmd, int stringonly) { /* read-only variables that can only be queried: */ if (!strcmp(p, "display")) { - char *d = DisplayString(dpy); - if (! d) d = "unknown"; - if (*d == ':') { - snprintf(buf, bufn, "aro=%s:%s%s", p, - this_host(), d); + if (raw_fb) { + snprintf(buf, bufn, "aro=%s:rawfb:%p", + p, raw_fb_addr); + } else if (! dpy) { + snprintf(buf, bufn, "aro=%s:%s", p, + "no-display"); } else { - snprintf(buf, bufn, "aro=%s:%s", p, d); + char *d; + d = DisplayString(dpy); + if (! d) d = "unknown"; + if (*d == ':') { + snprintf(buf, bufn, "aro=%s:%s%s", p, + this_host(), d); + } else { + snprintf(buf, bufn, "aro=%s:%s", p, d); + } } } else if (!strcmp(p, "vncdisplay")) { snprintf(buf, bufn, "aro=%s:%s", p, @@ -10004,8 +10603,8 @@ char *process_remote_cmd(char *cmd, int stringonly) { snprintf(buf, bufn, "aro=%s:%d", p, scale_denom); } else if (!strcmp(p, "scale_fac")) { snprintf(buf, bufn, "aro=%s:%f", p, scale_fac); - } else if (!strcmp(p, "scaling_noblend")) { - snprintf(buf, bufn, "aro=%s:%d", p, scaling_noblend); + } else if (!strcmp(p, "scaling_blend")) { + snprintf(buf, bufn, "aro=%s:%d", p, scaling_blend); } else if (!strcmp(p, "scaling_nomult4")) { snprintf(buf, bufn, "aro=%s:%d", p, scaling_nomult4); } else if (!strcmp(p, "scaling_pad")) { @@ -10025,6 +10624,8 @@ char *process_remote_cmd(char *cmd, int stringonly) { snprintf(buf, bufn, "aro=%s:%d", p, !using_shm); } else if (!strcmp(p, "logfile") || !strcmp(p, "o")) { snprintf(buf, bufn, "aro=%s:%s", p, NONUL(logfile)); + } else if (!strcmp(p, "flag")) { + snprintf(buf, bufn, "aro=%s:%s", p, NONUL(flagfile)); } else if (!strcmp(p, "rc")) { snprintf(buf, bufn, "aro=%s:%s", p, NONUL(rc_rcfile)); } else if (!strcmp(p, "norc")) { @@ -10137,8 +10738,10 @@ char *process_remote_cmd(char *cmd, int stringonly) { usleep(20*1000); } } else { - set_vnc_connect_prop(buf); - XFlush(dpy); + if (dpy) { /* raw_fb hack */ + set_vnc_connect_prop(buf); + XFlush(dpy); + } } #endif return NULL; @@ -11087,7 +11690,7 @@ void setup_cursors(void) { } /* scale = NULL zeroes everything */ parse_scale_string(scale, &scale_cursor_fac, &scaling_cursor, - &scaling_cursor_noblend, &j, &j, &scaling_cursor_interpolate, + &scaling_cursor_blend, &j, &j, &scaling_cursor_interpolate, &scale_cursor_numer, &scale_cursor_denom); for (i=0; i<n; i++) { @@ -11170,9 +11773,13 @@ void setup_cursors(void) { * looking cursors (i.e. two-color). */ int x, y, k = 0, bw; + int black = 0, white = 1; char d, m; - int black = BlackPixel(dpy, scr); - int white = WhitePixel(dpy, scr); + + if (dpy) { /* raw_fb hack */ + black = BlackPixel(dpy, scr); + white = WhitePixel(dpy, scr); + } rfb_curs->richSource = (char *)calloc(ci->wx * ci->wy, 1); @@ -11338,7 +11945,7 @@ void initialize_xfixes(void) { rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h, int xhot, int yhot, int Bpp) { rfbCursorPtr c; - static unsigned long black, white; + static unsigned long black = 0, white = 1; static int first = 1; char *bitmap, *rich, *alpha; char *new_pixels = NULL; @@ -11346,7 +11953,7 @@ rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h, int send_alpha = 0, alpha_shift, thresh; int i, x, y; - if (first) { + if (first && dpy) { /* raw_fb hack */ X_LOCK; black = BlackPixel(dpy, scr); white = WhitePixel(dpy, scr); @@ -11365,7 +11972,7 @@ rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h, new_pixels = (char *) malloc(4 * w * h); - scale_rect(scale_cursor_fac, scaling_cursor_noblend, + scale_rect(scale_cursor_fac, scaling_cursor_blend, scaling_cursor_interpolate, 4, (char *) pixels, 4*W, new_pixels, 4*w, W, H, w, h, @@ -12215,6 +12822,8 @@ void check_x11_pointer(void) { int x, y; unsigned int mask; + if (raw_fb) return; /* raw_fb hack */ + X_LOCK; ret = XQueryPointer(dpy, rootwin, &root_w, &child_w, &root_x, &root_y, &win_x, &win_y, &mask); @@ -12408,7 +13017,7 @@ void debug_colormap(XImage *fb) { if (! fb) { return; } - if (fb->bits_per_pixel != 8) { + if (fb->bits_per_pixel > 8) { return; } @@ -12424,8 +13033,13 @@ void debug_colormap(XImage *fb) { } fprintf(stderr, "\nColormap histogram for current screen contents:\n"); for (i=0; i < NCOLOR; i++) { - fprintf(stderr, " %03d: %7d", i, histo[i]); - if ((i+1) % 4 == 0) { + unsigned short r = screen->colourMap.data.shorts[i*3+0]; + unsigned short g = screen->colourMap.data.shorts[i*3+1]; + unsigned short b = screen->colourMap.data.shorts[i*3+2]; + + fprintf(stderr, " %03d: %7d %04x/%04x/%04x", i, histo[i], + r, g, b); + if ((i+1) % 2 == 0) { fprintf(stderr, "\n"); } } @@ -12542,6 +13156,105 @@ void set_nofb_params(void) { } } +char *raw_fb_orig_dpy = NULL; + +void set_raw_fb_params(int restore) { + static int first = 1; + static int vo0, us0, sm0, ws0, wp0, wb0, na0, tn0; + static int xr0, sb0; + static char *mc0; + + /* + * set turn off a bunch of parameters not compatible with + * -rawfb mode: 1) ignoring the X server 2) ignoring user input. + */ + + if (first) { + /* at least save the initial settings... */ + vo0 = view_only; + us0 = use_snapfb; + sm0 = using_shm; + ws0 = watch_selection; + wp0 = watch_primary; + wb0 = watch_bell; + na0 = no_autorepeat; + tn0 = take_naps; + mc0 = multiple_cursors_mode; + xr0 = xrandr; + sb0 = use_solid_bg; + + first = 0; + } + + if (restore) { + view_only = vo0; + use_snapfb = us0; + using_shm = sm0; + watch_selection = ws0; + watch_primary = wp0; + watch_bell = wb0; + no_autorepeat = na0; + take_naps = tn0; + multiple_cursors_mode = mc0; + xrandr = xr0; + use_solid_bg = sb0; + + if (! dpy && raw_fb_orig_dpy) { + dpy = XOpenDisplay(raw_fb_orig_dpy); + if (dpy) { + rfbLog("reopened DISPLAY: %s\n", + raw_fb_orig_dpy); + } else { + rfbLog("WARNING: failed to reopen " + "DISPLAY: %s\n", raw_fb_orig_dpy); + } + } + return; + } + + if (! view_only) { + rfbLog("rawfb: setting view_only\n"); + view_only = 1; + } + if (use_snapfb) { + rfbLog("rawfb: turning off use_snapfb\n"); + use_snapfb = 0; + } + if (using_shm) { + rfbLog("rawfb: turning off using_shm\n"); + using_shm = 0; + } + if (watch_selection) { + rfbLog("rawfb: turning off watch_selection\n"); + watch_selection = 0; + } + if (watch_primary) { + rfbLog("rawfb: turning off watch_primary\n"); + watch_primary = 0; + } + if (watch_bell) { + rfbLog("rawfb: turning off watch_bell\n"); + watch_bell = 0; + } + if (no_autorepeat) { + rfbLog("rawfb: turning off no_autorepeat\n"); + no_autorepeat = 0; + } + if (take_naps) { + rfbLog("rawfb: turning off take_naps\n"); + take_naps = 0; + } + multiple_cursors_mode = strdup("arrow"); + if (xrandr) { + rfbLog("rawfb: turning off xrandr\n"); + xrandr = 0; + } + if (use_solid_bg) { + rfbLog("rawfb: turning off use_solid_bg\n"); + use_solid_bg = 0; + } +} + /* * Presumably under -nofb the clients will never request the framebuffer. * However, we have gotten such a request... so let's just give them @@ -12672,6 +13385,288 @@ void initialize_snap_fb(void) { snap_fb = snap->data; } + +XImage *initialize_raw_fb(void) { + char *str, *q; + int w, h, b, shmid = 0; + unsigned long rm = 0, gm = 0, bm = 0; + static XImage ximage_struct; /* n.b.: not (XImage *) */ + int closedpy = 1; + + if (raw_fb_addr || raw_fb_seek) { + if (raw_fb_shm) { + shmdt(raw_fb_addr); +#if LIBVNCSERVER_HAVE_MMAP + } else if (raw_fb_mmap) { + munmap(raw_fb_addr, raw_fb_mmap); + if (raw_fb_fd >= 0) { + close(raw_fb_fd); + } +#endif + } else if (raw_fb_seek) { + if (raw_fb_fd >= 0) { + close(raw_fb_fd); + } + } + raw_fb_addr = NULL; + } + if (! raw_fb_str) { + return NULL; + } + + + str = strdup(raw_fb_str); + + /* + * uppercase means do not close the display (e.g. for remote control) + */ + if (strstr(str, "SHM:") == str) { + closedpy = 0; + str[0] = 's'; str[1] = 'h'; str[2] = 'm'; + } else if (strstr(str, "MAP:") == str) { + closedpy = 0; + str[0] = 'm'; str[1] = 'a'; str[2] = 'p'; + } else if (strstr(str, "MMAP:") == str) { + closedpy = 0; + str[0] = 'm'; str[1] = 'm'; str[2] = 'a'; str[3] = 'p'; + } else if (strstr(str, "FILE:") == str) { + str[0] = 'f'; str[1] = 'i'; str[2] = 'l'; str[3] = 'e'; + closedpy = 0; + } + + if (! raw_fb_orig_dpy && dpy) { + raw_fb_orig_dpy = strdup(DisplayString(dpy)); + } +#ifndef BOLDLY_CLOSE_DISPLAY +#define BOLDLY_CLOSE_DISPLAY 1 +#endif +#if BOLDLY_CLOSE_DISPLAY + if (closedpy) { + if (dpy) { + XCloseDisplay(dpy); /* yow! */ + } + dpy = 0; + } +#endif + + /* + * -rawfb shm:163938442@640x480x32:ff/ff00/ff0000+3000 + * -rawfb map:/path/to/file@640x480x32:ff/ff00/ff0000 + * -rawfb file:/path/to/file@640x480x32:ff/ff00/ff0000 + */ + + raw_fb_offset = 0; + + /* +O offset */ + if ((q = strrchr(str, '+')) != NULL) { + if (sscanf(q, "+%d", &raw_fb_offset) == 1) { + *q = '\0'; + } else { + raw_fb_offset = 0; + } + } + /* :R/G/B masks */ + if ((q = strrchr(str, ':')) != NULL) { + if (sscanf(q, ":%lx/%lx/%lx", &rm, &gm, &bm) == 3) { + *q = '\0'; + } else if (sscanf(q, ":0x%lx/0x%lx/0x%lx", &rm, &gm, &bm)== 3) { + *q = '\0'; + } else if (sscanf(q, ":%lu/%lu/%lu", &rm, &gm, &bm) == 3) { + *q = '\0'; + } else { + rm = 0; + gm = 0; + bm = 0; + } + } + if ((q = strrchr(str, '@')) == NULL) { + rfbLog("invalid rawfb str: %s\n", raw_fb_str); + clean_up_exit(1); + } + /* @WxHxB */ + if (sscanf(q, "@%dx%dx%d", &w, &h, &b) != 3) { + rfbLog("invalid rawfb str: %s\n", raw_fb_str); + clean_up_exit(1); + } + + dpy_x = wdpy_x = w; + dpy_y = wdpy_y = h; + off_x = 0; + off_y = 0; + + raw_fb_shm = 0; + raw_fb_mmap = 0; + raw_fb_seek = 0; + raw_fb_fd = -1; + raw_fb_addr = NULL; + + *q = '\0'; + if (sscanf(str, "shm:%d", &shmid) == 1) { + /* shm:N */ + raw_fb_addr = (char *) shmat(shmid, 0, SHM_RDONLY); + if (! raw_fb_addr) { + rfbLog("failed to attach to shm: %d, %s\n", shmid, + raw_fb_str); + rfbLogPerror("shmat"); + clean_up_exit(1); + } + raw_fb_shm = 1; + rfbLog("rawfb: shm: %d W: %d H: %d B: %d addr: %p\n", + shmid, w, h, b, raw_fb_addr); + + } else if (strstr(str, "map:") == str || strstr(str, "mmap:") == str + || strstr(str, "file:") == str) { + /* map:/path/... or file:/path */ + int fd, do_mmap = 1, size; + struct stat sbuf; + + if (*str == 'f') { + do_mmap = 0; + } + q = strchr(str, ':'); + q++; + + fd = open(q, O_RDONLY); + if (fd < 0) { + rfbLog("failed to open file: %s, %s\n", q, raw_fb_str); + rfbLogPerror("open"); + clean_up_exit(1); + } + raw_fb_fd = fd; + + size = w*h*b/8 + raw_fb_offset; + if (fstat(fd, &sbuf) == 0) { + if (S_ISREG(sbuf.st_mode)) { + if (0) size = sbuf.st_size; + } else { + rfbLog("non-regular file: %s\n", q); + } + } + + if (do_mmap) { +#if LIBVNCSERVER_HAVE_MMAP + raw_fb_addr = mmap(0, size, PROT_READ, MAP_SHARED, + fd, 0); + + if (raw_fb_addr == MAP_FAILED || raw_fb_addr == NULL) { + rfbLog("failed to mmap file: %s, %s\n", + q, raw_fb_str); + rfbLog(" raw_fb_addr: %p\n", raw_fb_addr); + rfbLogPerror("mmap"); + clean_up_exit(1); + } + raw_fb_mmap = size; + + rfbLog("rawfb: mmap file: %s\n", q); + rfbLog(" w: %d h: %d b: %d addr: %p sz: %d\n", w, h, + b, raw_fb_addr, size); +#else + rfbLog("mmap(2) not supported on system, using" + " slower lseek(2)\n"); + raw_fb_seek = size; +#endif + } else { + raw_fb_seek = size; + + rfbLog("rawfb: seek file: %s\n", q); + rfbLog(" W: %d H: %d B: %d sz: %d\n", w, h, b, size); + } + } else { + rfbLog("invalid rawfb str: %s\n", raw_fb_str); + clean_up_exit(1); + } + + if (! raw_fb_image) { + raw_fb_image = &ximage_struct; + } + + raw_fb = (char *) malloc(w*h*b/8); + raw_fb_image->data = raw_fb; + raw_fb_image->format = ZPixmap; + raw_fb_image->width = w; + raw_fb_image->height = h; + raw_fb_image->bits_per_pixel = b; + raw_fb_image->depth = (b == 32) ? 24 : b; + raw_fb_image->bytes_per_line = w*b/8; + + if (rm == 0 && gm == 0 && bm == 0) { + /* guess masks... */ + if (b == 24 || b == 32) { + rm = 0xff0000; + gm = 0x00ff00; + bm = 0x0000ff; + } else if (b == 16) { + rm = 0xf800; + gm = 0x07e0; + bm = 0x001f; + } else if (b == 8) { + rm = 0x07; + gm = 0x38; + bm = 0xc0; + } + } + + raw_fb_image->red_mask = rm; + raw_fb_image->green_mask = gm; + raw_fb_image->blue_mask = bm; + + if (raw_fb_addr) { + memcpy(raw_fb, raw_fb_addr + raw_fb_offset, w*h*(b/8)); + } else { + memset(raw_fb, 0xff, w*h*(b/8)); + } + + rfbLog("rawfb: raw_fb %p\n", raw_fb); + + free(str); + + initialize_clipshift(); + + return raw_fb_image; +} + +void initialize_clipshift(void) { + clipshift = 0; + cdpy_x = cdpy_y = coff_x = coff_y = 0; + if (clip_str) { + int w, h, x, y, bad = 0; + if (parse_geom(clip_str, &w, &h, &x, &y, wdpy_x, wdpy_y)) { + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x + w > wdpy_x) { + w = wdpy_x - x; + } + if (y + h > wdpy_y) { + h = wdpy_y - y; + } + if (w <= 0 || h <= 0) { + bad = 1; + } + } else { + bad = 1; + } + if (bad) { + rfbLog("skipping invalid -clip WxH+X+Y: %s\n", + clip_str); + } else { + /* OK, change geom behind everyone's back... */ + cdpy_x = w; + cdpy_y = h; + coff_x = x; + coff_y = y; + + clipshift = 1; + + dpy_x = cdpy_x; + dpy_y = cdpy_y; + } + } +} + /* * initialize a fb for the X display */ @@ -12682,6 +13677,10 @@ XImage *initialize_xdisplay_fb(void) { XErrorHandler old_handler; int subwin_bs; + if (raw_fb_str) { + return initialize_raw_fb(); + } + X_LOCK; if (subwin) { if (subwin_wait_mapped) { @@ -12761,45 +13760,7 @@ XImage *initialize_xdisplay_fb(void) { X_LOCK; } - clipshift = 0; - cdpy_x = cdpy_y = coff_x = coff_y = 0; - if (clip_str) { - int w, h, x, y, bad = 0; - if (parse_geom(clip_str, &w, &h, &x, &y, wdpy_x, wdpy_y)) { - if (x < 0) { - x = 0; - } - if (y < 0) { - y = 0; - } - if (x + w > wdpy_x) { - w = wdpy_x - x; - } - if (y + h > wdpy_y) { - h = wdpy_y - y; - } - if (w <= 0 || h <= 0) { - bad = 1; - } - } else { - bad = 1; - } - if (bad) { - rfbLog("skipping invalid -clip WxH+X+Y: %s\n", - clip_str); - } else { - /* OK, change geom behind everyone's back... */ - cdpy_x = w; - cdpy_y = h; - coff_x = x; - coff_y = y; - - clipshift = 1; - - dpy_x = cdpy_x; - dpy_y = cdpy_y; - } - } + initialize_clipshift(); /* initialize depth to reasonable value, visual_id may override */ depth = DefaultDepth(dpy, scr); @@ -12951,7 +13912,7 @@ XImage *initialize_xdisplay_fb(void) { return fb; } -void parse_scale_string(char *str, double *factor, int *scaling, int *noblend, +void parse_scale_string(char *str, double *factor, int *scaling, int *blend, int *nomult4, int *pad, int *interpolate, int *numer, int *denom) { int m, n; @@ -12960,7 +13921,7 @@ void parse_scale_string(char *str, double *factor, int *scaling, int *noblend, *factor = 1.0; *scaling = 0; - *noblend = 0; + *blend = 1; *nomult4 = 0; *pad = 0; *interpolate = 0; @@ -12974,7 +13935,10 @@ void parse_scale_string(char *str, double *factor, int *scaling, int *noblend, if ( (p = strchr(tstr, ':')) != NULL) { /* options */ if (strstr(p+1, "nb") != NULL) { - *noblend = 1; + *blend = 0; + } + if (strstr(p+1, "fb") != NULL) { + *blend = 2; } if (strstr(p+1, "n4") != NULL) { *nomult4 = 1; @@ -13050,6 +14014,9 @@ int scale_round(int len, double fac) { double eps = 0.000001; len = (int) (len * fac + eps); + if (len < 1) { + len = 1; + } return len; } @@ -13057,7 +14024,7 @@ void setup_scaling(int *width_in, int *height_in) { int width = *width_in; int height = *height_in; - parse_scale_string(scale_str, &scale_fac, &scaling, &scaling_noblend, + parse_scale_string(scale_str, &scale_fac, &scaling, &scaling_blend, &scaling_nomult4, &scaling_pad, &scaling_interpolate, &scale_numer, &scale_denom); @@ -13239,7 +14206,7 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { } if (! have_masks && screen->serverFormat.bitsPerPixel == 8 - && CellsOfScreen(ScreenOfDisplay(dpy, scr))) { + && dpy && CellsOfScreen(ScreenOfDisplay(dpy, scr))) { /* indexed color */ if (!quiet) { rfbLog("X display %s is 8bpp indexed color\n", @@ -13265,9 +14232,15 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { * color, static color, etc.... */ if (! quiet) { - rfbLog("X display %s is %dbpp depth=%d true " - "color\n", DisplayString(dpy), fb->bits_per_pixel, - fb->depth); + if (raw_fb) { + rfbLog("Raw fb at addr %p is %dbpp depth=%d " + "true color\n", raw_fb_addr, + fb->bits_per_pixel, fb->depth); + } else { + rfbLog("X display %s is %dbpp depth=%d true " + "color\n", DisplayString(dpy), + fb->bits_per_pixel, fb->depth); + } } indexed_color = 0; @@ -14693,7 +15666,7 @@ static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, if (! using_shm) { /* we only need the XImage created */ xim = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, - 0, NULL, w, h, BitmapPad(dpy), 0); + 0, NULL, w, h, raw_fb ? 32 : BitmapPad(dpy), 0); X_UNLOCK; @@ -14795,9 +15768,10 @@ void shm_delete(XShmSegmentInfo *shm) { } void shm_clean(XShmSegmentInfo *shm, XImage *xim) { + X_LOCK; #if LIBVNCSERVER_HAVE_XSHM - if (shm != NULL && shm->shmid != -1) { + if (shm != NULL && shm->shmid != -1 && dpy) { XShmDetach_wr(dpy, shm); } #endif @@ -15154,7 +16128,7 @@ weights for this scaled pixel are: * the loop over the 4 pixels. */ -void scale_rect(double factor, int noblend, int interpolate, int Bpp, +void scale_rect(double factor, int blend, int interpolate, int Bpp, char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line, int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark) { /* @@ -15237,7 +16211,7 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp, break; } } - if (noblend || ! shrink || interpolate) { + if (! blend || ! shrink || interpolate) { ; } else if (n != 0) { if (Nx % n == 0 && Ny % n == 0) { @@ -15262,12 +16236,12 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp, break; } } - if (noblend && factor > 1.0 && n) { + if (! blend && factor > 1.0 && n) { mag_int = n; } } - if (mark && factor > 1.0 && ! noblend) { + if (mark && factor > 1.0 && blend) { /* * kludge: correct for interpolating blurring leaking * up or left 1 destination pixel. @@ -15299,7 +16273,7 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp, j2 = nfix(j2, ny) + 1; /* special case integer magnification with no blending */ - if (mark && noblend && mag_int && Bpp != 3) { + if (mark && ! blend && mag_int && Bpp != 3) { int jmin, jmax, imin, imax; /* outer loop over *source* pixels */ @@ -15383,7 +16357,7 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp, I1 = (int) FLOOR(x1); if (I1 >= Nx) I1 = Nx - 1; - if (noblend && use_noblend_shortcut) { + if (! blend && use_noblend_shortcut) { /* * The noblend case involves no weights, * and 1 pixel, so just copy the value @@ -15445,14 +16419,14 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp, /* see comments for I, x1, x2, etc. below */ if (constant_weights) { ; - } else if (noblend) { + } else if (! blend) { if (J != J1) { continue; } wy = 1.0; /* interpolation scheme: */ - } else if (!shrink || interpolate) { + } else if (! shrink || interpolate) { if (J >= Ny) { continue; } else if (J == J1) { @@ -15478,13 +16452,15 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp, if (constant_weights) { ; - } else if (noblend) { + } else if (! blend) { /* * Ugh, PseudoColor colormap is * bad news, to avoid random * colors just take the first * pixel. Or user may have * specified :nb to fraction. + * The :fb will force blending + * for this case. */ if (I != I1) { continue; @@ -15492,7 +16468,7 @@ void scale_rect(double factor, int noblend, int interpolate, int Bpp, wx = 1.0; /* interpolation scheme: */ - } else if (!shrink || interpolate) { + } else if (! shrink || interpolate) { if (I >= Nx) { continue; /* off edge */ } else if (I == I1) { @@ -15612,11 +16588,23 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) { if (! screen->serverFormat.trueColour) { /* * PseudoColor colormap... blending leads to random colors. + * User can override with ":fb" */ - scaling_noblend = 1; + if (scaling_blend == 1) { + /* :fb option sets it to 2 */ + if (default_visual->class == StaticGray) { + /* + * StaticGray can be blended OK, otherwise + * user can disable with :nb + */ + ; + } else { + scaling_blend = 0; + } + } } - scale_rect(scale_fac, scaling_noblend, scaling_interpolate, bpp/8, + scale_rect(scale_fac, scaling_blend, scaling_interpolate, bpp/8, main_fb, main_bytes_per_line, rfb_fb, rfb_bytes_per_line, dpy_x, dpy_y, scaled_x, scaled_y, X1, Y1, X2, Y2, 1); } @@ -15624,6 +16612,11 @@ 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) { if (damage_time != 0) { + /* + * This is not XDAMAGE, rather a hack for testing + * were we allow the framebuffer to be corrupted for + * damage_delay seconds. + */ int debug = 0; if (time(0) > damage_time + damage_delay) { if (! quiet) { @@ -17056,6 +18049,9 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int simple_gui, fprintf(stderr, "gui: could not connect to: '%s', try" " again manually.\n", x11vnc_xdisplay); } + if (client_connect_file) { + set_env("X11VNC_CONNECT_FILE", client_connect_file); + } if (dpy) { XCloseDisplay(dpy); } @@ -18473,16 +19469,18 @@ static void print_help(int mode) { " the notation \"m/n\" may be used to denote fractions\n" " exactly, e.g. -scale 2/3\n" "\n" -" Scaling Options: can be added after \"fraction\" via\n" -" \":\", to supply multiple \":\" options use commas.\n" -" If you just want a quick, rough scaling without\n" -" blending, append \":nb\" to \"fraction\" (e.g. -scale\n" -" 1/3:nb). For compatibility with vncviewers the scaled\n" -" width is adjusted to be a multiple of 4: to disable\n" -" this use \":n4\". More esoteric options: \":in\" use\n" -" interpolation scheme even when shrinking, \":pad\",\n" -" pad scaled width and height to be multiples of scaling\n" -" denominator (e.g. 3 for 2/3).\n" +" Scaling Options: can be added after \"fraction\"\n" +" via \":\", to supply multiple \":\" options use\n" +" commas. If you just want a quick, rough scaling\n" +" without blending, append \":nb\" to \"fraction\"\n" +" (e.g. -scale 1/3:nb). No blending is the default\n" +" for 8bpp indexed color, to force blending for this\n" +" case use \":fb\". For compatibility with vncviewers\n" +" the scaled width is adjusted to be a multiple of 4:\n" +" to disable this use \":n4\". More esoteric options:\n" +" \":in\" use interpolation scheme even when shrinking,\n" +" \":pad\", pad scaled width and height to be multiples\n" +" of scaling denominator (e.g. 3 for 2/3).\n" "\n" "-scale_cursor frac By default if -scale is supplied the cursor shape is\n" " scaled by the same factor. Depending on your usage,\n" @@ -18755,6 +19753,13 @@ static void print_help(int mode) { " In general on XINERAMA displays you may need to use the\n" " -xwarppointer option if the mouse pointer misbehaves.\n" "\n" +"-xtrap Use the DEC-XTRAP extension for keystroke and mouse\n" +" input insertion. For use on legacy systems, e.g. X11R5,\n" +" running an incomplete or missing XTEST extension.\n" +" By default DEC-XTRAP will be used if XTEST server grab\n" +" control is missing, use -xtrap to do the keystroke and\n" +" mouse insertion via DEC-XTRAP as well.\n" +"\n" "-xrandr [mode] If the display supports the XRANDR (X Resize, Rotate\n" " and Reflection) extension, and you expect XRANDR events\n" " to occur to the display while x11vnc is running, this\n" @@ -18794,9 +19799,13 @@ static void print_help(int mode) { "-o logfile Write stderr messages to file \"logfile\" instead of\n" " to the terminal. Same as \"-logfile file\". To append\n" " to the file use \"-oa file\" or \"-logappend file\".\n" -"-rc filename Use \"filename\" instead of $HOME/.x11vncrc for rc file.\n" +"-flag file Write the \"PORT=NNNN\" (e.g. PORT=5900) string to\n" +" \"file\" in addition to stdout. This option could be\n" +" useful by wrapper script to detect when x11vnc is ready.\n" "\n" +"-rc filename Use \"filename\" instead of $HOME/.x11vncrc for rc file.\n" "-norc Do not process any .x11vncrc file for options.\n" +"\n" "-h, -help Print this help text.\n" "-?, -opts Only list the x11vnc options.\n" "-V, -version Print program version and last modification date.\n" @@ -19177,6 +20186,7 @@ static void print_help(int mode) { " by checking the tile near the boundary. Default: %d\n" "-fuzz n Tolerance in pixels to mark a tiles edges as changed.\n" " Default: %d\n" +"\n" "-snapfb Instead of polling the X display framebuffer (fb) for\n" " changes, periodically copy all of X display fb into main\n" " memory and examine that copy for changes. Under some\n" @@ -19191,6 +20201,52 @@ static void print_help(int mode) { " It may be of use in video capture-like applications,\n" " or where window tearing is a problem.\n" "\n" +"-rawfb string Experimental option, instead of polling X, poll the\n" +" memory object specified in \"string\". For shared\n" +" memory segments it is of the form: \"shm:N@WxHxB\"\n" +" which specifies a shmid N and framebuffer width, height,\n" +" and bits per pixel. To memory map mmap(2) a file use:\n" +" \"map:/path/to/a/file@WxHxB\". If there is trouble\n" +" with mmap, use \"file:/...\" for slower lseek(2) based\n" +" reading.\n" +"\n" +" Optional suffixes are \":R/G/B\" and \"+O\" to specify\n" +" red, green, and blue masks and an offset into the\n" +" memory object. If the masks are not provided x11vnc\n" +" guesses them based on the bpp.\n" +"\n" +" Examples:\n" +" -rawfb shm:210337933@800x600x32:ff/ff00/ff0000\n" +" -rawfb map:/dev/fb0@1024x768x32\n" +" -rawfb map:/tmp/Xvfb_screen0@640x480x8+3232\n" +" -rawfb file:/tmp/my.pnm@250x200x24+37\n" +"\n" +" (see ipcs(1) and fbset(1) for the first two examples)\n" +"\n" +" All user input is discarded. Most of the X11 (screen,\n" +" keyboard, mouse) options do not make sense and many\n" +" will cause this mode to crash, so please think twice\n" +" before setting/changing them. If you don't want x11vnc\n" +" to close the DISPLAY in rawfb mode, then capitalize\n" +" the prefix, SHM:, MAP: etc. Keeping the display open\n" +" enables defautl remote control channel.\n" +"\n" +"-pipeinput cmd Another experimental option: it lets you supply an\n" +" extern command in \"cmd\" that x11vnc will pipe all of\n" +" the user input events to in a simple format. By default\n" +" x11vnc will not process any of the user input events.\n" +" If you prefix \"cmd\" with \"tee:\" it will both send\n" +" them to the pipe command and process them. For a\n" +" description of the format run \"-pipeinput tee:cat\".\n" +" Another prefix is \"reopen\" which means to reopen pipe\n" +" if it exits. Separate multiple prefixes with commas.\n" +"\n" +" In combination with -rawfb one might be able to\n" +" do amusing things (e.g. control non-X devices).\n" +" To facilitate this, if -rawfb is in effect then the\n" +" value is stored in X11VNC_RAWFB_STR for the pipe command\n" +" to use if it wants. Do 'env | grep X11VNC' for more.\n" +"\n" "-gui [gui-opts] Start up a simple tcl/tk gui based on the the remote\n" " control options -remote/-query described below.\n" " Requires the \"wish\" program to be installed on the\n" @@ -19367,6 +20423,8 @@ static void print_help(int mode) { " rectangle use \"-WxH+X+Y\" to delete one\n" " xinerama enable -xinerama mode. (if applicable)\n" " noxinerama disable -xinerama mode.\n" +" xtrap enable -xtrap input mode.\n" +" noxtrap disable -xtrap input mode.\n" " xrandr enable -xrandr mode. (if applicable)\n" " noxrandr disable -xrandr mode.\n" " xrandr_mode:mode set the -xrandr mode to \"mode\".\n" @@ -19448,6 +20506,7 @@ static void print_help(int mode) { " fuzz:n set -fuzz to n.\n" " snapfb enable -snapfb mode.\n" " nosnapfb disable -snapfb mode.\n" +" rawfb:str set -rawfb mode to \"str\".\n" " progressive:n set libvncserver -progressive slice\n" " height parameter to n.\n" " desktop:str set -desktop name to str for new clients.\n" @@ -19515,39 +20574,39 @@ static void print_help(int mode) { " forever noforever once timeout deny lock nodeny unlock\n" " connect allowonce allow localhost nolocalhost listen\n" " lookup nolookup accept gone shm noshm flipbyteorder\n" -" noflipbyteorder onetile noonetile solid_color solid\n" -" nosolid blackout xinerama noxinerama xrandr noxrandr\n" -" xrandr_mode padgeom quiet q noquiet modtweak nomodtweak\n" -" xkb noxkb skip_keycodes add_keysyms noadd_keysyms\n" -" clear_mods noclear_mods clear_keys noclear_keys\n" -" remap repeat norepeat fb nofb bell nobell sel nosel\n" -" primary noprimary cursorshape nocursorshape cursorpos\n" -" nocursorpos cursor show_cursor noshow_cursor nocursor\n" -" arrow xfixes noxfixes xdamage noxdamage xd_area\n" -" xd_mem alphacut alphafrac alpharemove noalpharemove\n" -" alphablend noalphablend xwarp xwarppointer noxwarp\n" -" noxwarppointer buttonmap dragging nodragging\n" +" noflipbyteorder onetile noonetile solid_color\n" +" solid nosolid blackout xinerama noxinerama xtrap\n" +" noxtrap xrandr noxrandr xrandr_mode padgeom quiet q\n" +" noquiet modtweak nomodtweak xkb noxkb skip_keycodes\n" +" add_keysyms noadd_keysyms clear_mods noclear_mods\n" +" clear_keys noclear_keys remap repeat norepeat fb nofb\n" +" bell nobell sel nosel primary noprimary cursorshape\n" +" nocursorshape cursorpos nocursorpos cursor show_cursor\n" +" noshow_cursor nocursor arrow xfixes noxfixes xdamage\n" +" noxdamage xd_area xd_mem alphacut alphafrac alpharemove\n" +" noalpharemove alphablend noalphablend xwarp xwarppointer\n" +" noxwarp noxwarppointer buttonmap dragging nodragging\n" " pointer_mode pm input_skip input client_input speeds\n" " debug_pointer dp nodebug_pointer nodp debug_keyboard dk\n" " nodebug_keyboard nodk deferupdate defer wait rfbwait\n" " nap nonap sb screen_blank fs gaps grow fuzz snapfb\n" -" nosnapfb progressive rfbport http nohttp httpport\n" +" nosnapfb rawfb progressive rfbport http nohttp httpport\n" " httpdir enablehttpproxy noenablehttpproxy alwaysshared\n" " noalwaysshared nevershared noalwaysshared dontdisconnect\n" " nodontdisconnect desktop noremote\n" "\n" " aro= display vncdisplay desktopname http_url auth\n" " users rootshift clipshift scale_str scaled_x scaled_y\n" -" scale_numer scale_denom scale_fac scaling_noblend\n" -" scaling_nomult4 scaling_pad scaling_interpolate inetd\n" -" safer unsafe passwdfile using_shm logfile o rc norc\n" -" h help V version lastmod bg sigpipe threads clients\n" -" client_count pid ext_xtest ext_xtrap ext_xkb ext_xshm\n" -" ext_xinerama ext_overlay ext_xfixes ext_xdamage\n" -" ext_xrandr rootwin num_buttons button_mask mouse_x\n" -" mouse_y bpp depth indexed_color dpy_x dpy_y wdpy_x\n" -" wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth\n" -" passwd\n" +" scale_numer scale_denom scale_fac scaling_blend\n" +" scaling_nomult4 scaling_pad scaling_interpolate\n" +" inetd safer unsafe passwdfile using_shm logfile o\n" +" flag rc norc h help V version lastmod bg sigpipe\n" +" threads clients client_count pid ext_xtest ext_xtrap\n" +" ext_xkb ext_xshm ext_xinerama ext_overlay ext_xfixes\n" +" ext_xdamage ext_xrandr rootwin num_buttons button_mask\n" +" mouse_x mouse_y bpp depth indexed_color dpy_x dpy_y\n" +" wdpy_x wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y\n" +" rfbauth passwd\n" "\n" "-sync By default -remote commands are run asynchronously, that\n" " is, the request is posted and the program immediately\n" @@ -19716,9 +20775,21 @@ void set_vnc_desktop_name(void) { } fflush(stderr); if (inetd) { - ; /* should not occur (port) */ + ; /* should not occur (port != 0) */ } else { fprintf(stdout, "PORT=%d\n", screen->port); + fflush(stdout); + if (flagfile) { + FILE *flag = fopen(flagfile, "w"); + if (flag) { + fprintf(flag, "PORT=%d\n",screen->port); + fflush(flag); + fclose(flag); + } else { + rfbLog("could not open flag file: %s\n", + flagfile); + } + } } fflush(stdout); } @@ -20012,7 +21083,7 @@ int main(int argc, char* argv[]) { char *remote_cmd = NULL; char *query_cmd = NULL; char *gui_str = NULL; - int pw_loc = -1; + int pw_loc = -1, got_passwd = 0, got_rfbauth = 0; int vpw_loc = -1; int dt = 0, bg = 0; int got_rfbwait = 0, got_deferupdate = 0, got_defer = 0; @@ -20214,6 +21285,8 @@ int main(int argc, char* argv[]) { blackout_str = strdup(argv[++i]); } else if (!strcmp(arg, "-xinerama")) { xinerama = 1; + } else if (!strcmp(arg, "-xtrap")) { + xtrap_input = 1; } else if (!strcmp(arg, "-xrandr")) { xrandr = 1; if (i < argc-1) { @@ -20235,6 +21308,9 @@ int main(int argc, char* argv[]) { CHECK_ARGC logfile_append = 1; logfile = strdup(argv[++i]); + } else if (!strcmp(arg, "-flag")) { + CHECK_ARGC + flagfile = strdup(argv[++i]); } else if (!strcmp(arg, "-rc")) { i++; /* done above */ } else if (!strcmp(arg, "-norc")) { @@ -20433,6 +21509,12 @@ int main(int argc, char* argv[]) { tile_fuzz = atoi(argv[++i]); } else if (!strcmp(arg, "-snapfb")) { use_snapfb = 1; + } else if (!strcmp(arg, "-rawfb")) { + CHECK_ARGC + raw_fb_str = strdup(argv[++i]); + } else if (!strcmp(arg, "-pipeinput")) { + CHECK_ARGC + pipeinput_str = strdup(argv[++i]); } else if (!strcmp(arg, "-gui")) { launch_gui = 1; if (i < argc-1) { @@ -20479,6 +21561,10 @@ int main(int argc, char* argv[]) { } if (!strcmp(arg, "-passwd")) { pw_loc = i; + got_passwd = 1; + } + if (!strcmp(arg, "-rfbauth")) { + got_rfbauth = 1; } if (!strcmp(arg, "-rfbwait")) { got_rfbwait = 1; @@ -20579,6 +21665,7 @@ int main(int argc, char* argv[]) { line[len-1] = '\0'; } argv_vnc[argc_vnc++] = strdup("-passwd"); + got_passwd = 1; if (!strcmp(line, "__EMPTY__")) { argv_vnc[argc_vnc++] = strdup(""); } else if ((q = strstr(line, "__ENDPASSWD__")) !=NULL) { @@ -20640,6 +21727,19 @@ int main(int argc, char* argv[]) { } } } +#ifdef HARDWIRE_PASSWD + if (! got_rfbauth && ! got_passwd) { + argv_vnc[argc_vnc++] = strdup("-passwd"); + argv_vnc[argc_vnc++] = strdup(HARDWIRE_PASSWD); + got_passwd = 1; + pw_loc = 100; + } +#endif +#ifdef HARDWIRE_VIEWPASSWD + if (! got_rfbauth && got_passwd && ! viewonly_passwd) { + viewonly_passwd = strdup(HARDWIRE_VIEWPASSWD); + } +#endif if (viewonly_passwd && pw_loc < 0) { rfbLog("-passwd must be supplied when using -viewpasswd\n"); exit(1); @@ -20713,6 +21813,9 @@ int main(int argc, char* argv[]) { } } + if (raw_fb_str) { + set_raw_fb_params(0); + } if (! got_deferupdate) { char tmp[40]; /* XXX not working yet in libvncserver */ @@ -20742,6 +21845,9 @@ int main(int argc, char* argv[]) { allow_list = strdup("127.0.0.1"); } + /* set OS struct UT */ + uname(&UT); + if (! quiet) { fprintf(stderr, "\n"); fprintf(stderr, "Settings:\n"); @@ -20791,6 +21897,7 @@ int main(int argc, char* argv[]) { fprintf(stderr, " blackout: %s\n", blackout_str ? blackout_str : "null"); fprintf(stderr, " xinerama: %d\n", xinerama); + fprintf(stderr, " xtrap: %d\n", xtrap_input); fprintf(stderr, " xrandr: %d\n", xrandr); fprintf(stderr, " xrandrmode: %s\n", xrandr_mode ? xrandr_mode : "null"); @@ -20799,6 +21906,8 @@ int main(int argc, char* argv[]) { fprintf(stderr, " logfile: %s\n", logfile ? logfile : "null"); fprintf(stderr, " logappend: %d\n", logfile_append); + fprintf(stderr, " flag: %s\n", flagfile ? flagfile + : "null"); fprintf(stderr, " rc_file: \"%s\"\n", rc_rcfile ? rc_rcfile : "null"); fprintf(stderr, " norc: %d\n", rc_norc); @@ -20855,6 +21964,10 @@ int main(int argc, char* argv[]) { fprintf(stderr, " grow_fill: %d\n", grow_fill); fprintf(stderr, " tile_fuzz: %d\n", tile_fuzz); fprintf(stderr, " snapfb: %d\n", use_snapfb); + fprintf(stderr, " rawfb: %s\n", raw_fb_str + ? raw_fb_str : "null"); + fprintf(stderr, " pipeinput: %s\n", pipeinput_str + ? pipeinput_str : "null"); fprintf(stderr, " gui: %d\n", launch_gui); fprintf(stderr, " gui_mode: %s\n", gui_str ? gui_str : "null"); @@ -20909,6 +22022,12 @@ int main(int argc, char* argv[]) { dpy = XOpenDisplay(""); } + if (! dpy && raw_fb_str) { + rfbLog("continuing without X display in -rawfb mode, " + "hold on tight..\n"); + goto raw_fb_pass_go_and_collect_200_dollars; + } + if (! dpy && ! use_dpy && ! getenv("DISPLAY")) { int i, s = 4; rfbLog("\a\n"); @@ -20951,13 +22070,6 @@ int main(int argc, char* argv[]) { exit(rc); } - if (! dt) { - static char str[] = "-desktop"; - argv_vnc[argc_vnc++] = str; - argv_vnc[argc_vnc++] = choose_title(use_dpy); - rfb_desktop_name = strdup(argv_vnc[argc_vnc-1]); - } - #if LIBVNCSERVER_HAVE_LIBXFIXES if (! XFixesQueryExtension(dpy, &xfixes_base_event_type, &er)) { if (! quiet) { @@ -21101,12 +22213,14 @@ int main(int argc, char* argv[]) { xtest_present = 0; use_xwarppointer = 1; } else { + xtest_present = 1; xtest_base_event_type = ev; } if (! XETrapQueryExtension_wr(dpy, &ev, &er, &maj)) { xtrap_present = 0; } else { + xtrap_present = 1; xtrap_base_event_type = ev; } @@ -21118,9 +22232,6 @@ int main(int argc, char* argv[]) { */ disable_grabserver(); - /* set OS struct UT */ - uname(&UT); - /* check for OS with small shm limits */ if (using_shm && ! single_copytile) { if (limit_shm()) { @@ -21185,6 +22296,17 @@ int main(int argc, char* argv[]) { } #endif + raw_fb_pass_go_and_collect_200_dollars: + + if (! dt) { + static char str[] = "-desktop"; + argv_vnc[argc_vnc++] = str; + argv_vnc[argc_vnc++] = choose_title(use_dpy); + rfb_desktop_name = strdup(argv_vnc[argc_vnc-1]); + } + + initialize_pipeinput(); + /* * Create the XImage corresponding to the display framebuffer. */ |