diff options
author | runge <runge> | 2008-10-19 16:33:22 +0000 |
---|---|---|
committer | runge <runge> | 2008-10-19 16:33:22 +0000 |
commit | 8938cda1e7e09d946475fddaba46194baf7e6388 (patch) | |
tree | 6aacd449c9b71749d4b05d6278011b2615377e36 /x11vnc | |
parent | 73f19d71e0dbdf4f5237e89bd431b971dacbca99 (diff) | |
download | libtdevnc-8938cda1e7e09d946475fddaba46194baf7e6388.tar.gz libtdevnc-8938cda1e7e09d946475fddaba46194baf7e6388.zip |
Sync SSVNC changes: fullscreen fixes, local scaling, -chatonly, iso-8859-1/utf8 etc., etc.
Diffstat (limited to 'x11vnc')
9 files changed, 5521 insertions, 1205 deletions
diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/bin/Darwin.Power.Macintosh/vncviewer.sh b/x11vnc/misc/enhanced_tightvnc_viewer/bin/Darwin.Power.Macintosh/vncviewer.sh index 18e2f31..92dcefb 100755 --- a/x11vnc/misc/enhanced_tightvnc_viewer/bin/Darwin.Power.Macintosh/vncviewer.sh +++ b/x11vnc/misc/enhanced_tightvnc_viewer/bin/Darwin.Power.Macintosh/vncviewer.sh @@ -14,7 +14,7 @@ if [ "X$SSVNC_DYLD_LIBRARY_PATH" != "X" ]; then export DYLD_LIBRARY_PATH fi -if [ "X$DISPLAY" != "X" ]; then +if [ "X$DISPLAY" != "X" -a "X$DARWIN_COTVNC" != "X1" ]; then "$dir/vncviewer.x11" "$@" else args="" diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/bin/ssvnc b/x11vnc/misc/enhanced_tightvnc_viewer/bin/ssvnc index 69dbf6b..2880a8e 100755 --- a/x11vnc/misc/enhanced_tightvnc_viewer/bin/ssvnc +++ b/x11vnc/misc/enhanced_tightvnc_viewer/bin/ssvnc @@ -140,7 +140,10 @@ if [ -f "$dir/util/ultraftp.jar" ]; then export SSVNC_ULTRA_FTP_JAR fi -if [ "X$WISH" = "Xwish" ]; then +if [ "X$1" = "X-cmd" ]; then + shift + exec ssvnc_cmd "$@" +elif [ "X$WISH" = "Xwish" ]; then exec ssvnc.tcl "$@" else exec $WISH $dir/util/ssvnc.tcl "$@" diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/bin/ssvnc_cmd b/x11vnc/misc/enhanced_tightvnc_viewer/bin/ssvnc_cmd index 3d355d3..5d52304 100755 --- a/x11vnc/misc/enhanced_tightvnc_viewer/bin/ssvnc_cmd +++ b/x11vnc/misc/enhanced_tightvnc_viewer/bin/ssvnc_cmd @@ -209,7 +209,7 @@ fi if [ "X$DARWIN_COTVNC" != "X1" -a "X$VNCVIEWERCMD" = "Xvncviewer" ]; then hstr=`$VNCVIEWERCMD -h 2>&1 | head -5` - if echo "$hstr" | grep '^TightVNC.*version 1\.[23]' > /dev/null; then + if echo "$hstr" | grep 'SSVNC.*TightVNC.*version 1\.3' > /dev/null; then # we need to avoid raw encoding use_ours=1 fi @@ -245,6 +245,8 @@ if [ $use_ours = 1 ]; then # avoid system vncviewer app-defaults #XFILESEARCHPATH="/tmp/path/nowhere"; export XFILESEARCHPATH + SSVNC_USE_OURS=1; export SSVNC_USE_OURS + if [ "X$base" = "Xtightvncviewer" ]; then $VNCVIEWERCMD -encodings 'copyrect tight zrle zlib hextile' "$@" else diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/bin/util/ss_vncviewer b/x11vnc/misc/enhanced_tightvnc_viewer/bin/util/ss_vncviewer index 9b456b2..75020df 100755 --- a/x11vnc/misc/enhanced_tightvnc_viewer/bin/util/ss_vncviewer +++ b/x11vnc/misc/enhanced_tightvnc_viewer/bin/util/ss_vncviewer @@ -229,6 +229,22 @@ do ;; "-grab") VNCVIEWER_GRAB_SERVER=1; export VNCVIEWER_GRAB_SERVER ;; + "-x11cursor") VNCVIEWER_X11CURSOR=1; export VNCVIEWER_X11CURSOR + ;; + "-rawlocal") VNCVIEWER_RAWLOCAL=1; export VNCVIEWER_RAWLOCAL + ;; + "-scale") shift; SSVNC_SCALE="$1"; export SSVNC_SCALE + ;; + "-ssvnc_encodings") shift; VNCVIEWER_ENCODINGS="$1"; export VNCVIEWER_ENCODINGS + ;; + "-rfbversion") shift; VNCVIEWER_RFBVERSION="$1"; export VNCVIEWER_RFBVERSION + ;; + "-nobell") VNCVIEWER_NOBELL=1; export VNCVIEWER_NOBELL + ;; + "-popupfix") VNCVIEWER_POPUP_FIX=1; export VNCVIEWER_POPUP_FIX + ;; + "-realvnc4") VNCVIEWER_IS_REALVNC4=1; export VNCVIEWER_IS_REALVNC4 + ;; "-h"*) help; exit 0 ;; "--h"*) help; exit 0 @@ -273,6 +289,7 @@ if [ "X$reverse" != "X" ]; then echo "*Warning*: -listen and a single proxy/gateway does not make sense." sleep 3 fi + SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE fi fi if [ "X$ssh_cmd" = "X" ]; then @@ -342,6 +359,9 @@ if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then use_ssh="" use_sshssl="" direct_connect=1 + if echo "$SSVNC_ULTRA_DSM" | grep 'noultra:' > /dev/null; then + SSVNC_NO_ULTRA_DSM=1; export SSVNC_NO_ULTRA_DSM + fi fi # (possibly) tell the vncviewer to only listen on lo: @@ -1448,9 +1468,16 @@ Kecho proxy=$proxy echo "" echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode." echo "" - echo "$VNCVIEWERCMD" "$@" -listen $N + N2=$N + if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then + N2=`echo "$N2" | sed -e 's/://g'` + if [ $N2 -le 200 ]; then + N2=`expr $N2 + 5500` + fi + fi + echo "$VNCVIEWERCMD" "$@" -listen $N2 echo "" - $VNCVIEWERCMD "$@" -listen $N + $VNCVIEWERCMD "$@" -listen $N2 fi exit $? @@ -1536,14 +1563,19 @@ if [ "X$direct_connect" != "X" ]; then echo "" echo "Using UltraVNC DSM Plugin key for encryption:" echo "" - echo " $SSVNC_ULTRA_DSM PORT HOST:PORT" + ustr=`echo "$SSVNC_ULTRA_DSM" | sed -e 's/pw=[^ ]*/pw=******/g'` + echo " $ustr PORT HOST:PORT" echo "" elif [ "X$getport" = "X" ]; then echo "" echo "Running viewer for direct connection:" - echo "" - echo "** NOTE: THERE WILL BE NO SSL OR SSH ENCRYPTION **" - echo "" + if echo X"$@" | grep chatonly > /dev/null; then + : + else + echo "" + echo "** NOTE: THERE WILL BE NO SSL OR SSH ENCRYPTION **" + echo "" + fi fi x="" if [ "X$SSVNC_NO_ENC_WARN" != "X" ]; then @@ -1594,9 +1626,25 @@ if [ "X$direct_connect" != "X" ]; then if [ "X$reverse" = "X" ]; then hostdisp="$host:$disp" if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then - hostdisp="exec=$SSVNC_ULTRA_DSM 0 $host:$port" + if [ "X$SSVNC_USE_OURS" = "X1" ]; then + hostdisp="exec=$SSVNC_ULTRA_DSM 0 $host:$port" + else + pf=`findfree 5970` + cmd="$SSVNC_ULTRA_DSM -$pf $host:$port" + pf=`expr $pf - 5900` + hostdisp="localhost:$pf" + ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'` + echo "Running:" + echo + echo "$ustr &" + echo + $cmd & + dsm_pid=$! + sleep 2 + fi fi - echo "$VNCVIEWERCMD" "$@" "$hostdisp" + hostdisp2=`echo "$hostdisp" | sed -e 's/pw=[^ ]*/pw=******/g'` + echo "$VNCVIEWERCMD" "$@" "$hostdisp2" trap "final" 0 2 15 echo "" $VNCVIEWERCMD "$@" "$hostdisp" @@ -1614,13 +1662,17 @@ if [ "X$direct_connect" != "X" ]; then trap "final" 0 2 15 if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then echo "NOTE: The ultravnc_dsm_helper only runs once. So after the first LISTEN" - echo " ends, you will have to Press Ctrl-C and restart for a new connection." + echo " ends, you may have to Press Ctrl-C and restart for another connection." echo "" + SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE + VNCVIEWER_LISTEN_LOCALHOST=1 + export VNCVIEWER_LISTEN_LOCALHOST dport=`expr 5500 + $disp` cmd="$SSVNC_ULTRA_DSM $dport localhost:$use" + ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'` echo "Running:" echo - echo "$cmd &" + echo "$ustr &" echo $cmd & dsm_pid=$! @@ -1630,9 +1682,16 @@ if [ "X$direct_connect" != "X" ]; then disp=`expr $disp - 5500` fi fi - echo "$VNCVIEWERCMD" "$@" -listen $disp + disp2=$disp + if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then + disp2=`echo "$disp2" | sed -e 's/://g'` + if [ $disp2 -le 200 ]; then + disp2=`expr $disp2 + 5500` + fi + fi + echo "$VNCVIEWERCMD" "$@" -listen $disp2 echo "" - $VNCVIEWERCMD "$@" -listen $disp + $VNCVIEWERCMD "$@" -listen $disp2 fi exit $? fi @@ -1793,7 +1852,7 @@ if [ "X$stunnel_exec" = "X" ]; then if [ "X$mycert" != "X" ]; then sleep 1 echo "" - echo "(pausing for possible certificate passphrase dialog)" + echo "(** pausing for possible certificate passphrase dialog **)" echo "" sleep 4 fi @@ -1829,7 +1888,14 @@ else echo "" echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode." echo "" - echo "$VNCVIEWERCMD" "$@" -listen $N + N2=$N + if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then + N2=`echo "$N2" | sed -e 's/://g'` + if [ $N2 -le 200 ]; then + N2=`expr $N2 + 5500` + fi + fi + echo "$VNCVIEWERCMD" "$@" -listen $N2 trap "final" 0 2 15 echo "" if [ "X$proxy" != "X" ]; then @@ -1838,7 +1904,7 @@ else PPROXY_KILLPID=+1; export PPROXY_KILLPID; $ptmp & fi - $VNCVIEWERCMD "$@" -listen $N + $VNCVIEWERCMD "$@" -listen $N2 fi sleep 1 diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/bin/util/ssvnc.tcl b/x11vnc/misc/enhanced_tightvnc_viewer/bin/util/ssvnc.tcl index 4ba5a86..9848362 100755 --- a/x11vnc/misc/enhanced_tightvnc_viewer/bin/util/ssvnc.tcl +++ b/x11vnc/misc/enhanced_tightvnc_viewer/bin/util/ssvnc.tcl @@ -8,7 +8,7 @@ exec wish "$0" "$@" # ssvnc.tcl: gui wrapper to the programs in this # package. Also sets up service port forwarding. # -set version 1.0.20 +set version 1.0.21 set buck_zero $argv0 @@ -362,9 +362,8 @@ proc help {} { and any VNC server can be made to do this by using, e.g., STUNNEL or socat on the remote side. - Automatic SSH tunnels are described below. - - See Tip 5) below for how to disable encryption. + * Automatic SSH Tunnels are described below. + * See Tip 5) below for how to Disable Encryption. Port numbers: @@ -380,6 +379,10 @@ proc help {} { If you must use a TCP port less than 200, specify a negative value, e.g.: 24.67.132.27:-80 + For Reverse VNC connections (listening viewer, See Tip 6 below and + Options -> Help), the port mapping is similar, except "listening + display :0" corresponds to port 5500, :1 to 5501, etc. + SSL Certificate Verification: @@ -828,14 +831,20 @@ proc help {} { For mode II when tunnelling via SSL, you probably should also disable "Verify All Certs" unless you have taken the steps beforehand to - import the VNC server's certificate, or have previously accepted it - using another method. With the mode II proxying scheme, there is - no way to "Fetch Cert" and check if it has been previously accepted. + import the VNC server's certificate, or have previously accepted + it using another method. With the mode II proxying scheme, there + is no way to do the initial "Fetch Cert" and check if it has been + previously accepted. + + Even when you disable "Verify All Certs", you are free to set a + ServerCert or CertsDir under "Certs ..." to authenticate the VNC + Server against. Also, after the connection you MUST terminate the listening VNC Viewer (Ctrl-C) and connect again (the proxy only runs once.) In Windows, go to the System Tray and terminate the Listening VNC Viewer. - Subsequent connection attempts after the first one will fail. + Subsequent connection attempts after the first one will fail unless + you return to the GUI and restart listening. BTW, the x11vnc VNC server command for the mode II case would be something like: @@ -910,10 +919,6 @@ proc help {} { port 5500). Then click on the "Listen" button and finally have the user run your Single Click III EXE. - For SC III, you will also need to enable the setting in the Options - menu "UltraVNC Single Click III Bug", otherwise the STUNNEL connection - may drop after 2-15 minutes. - Note that in Listening SSL mode you MUST supply a MyCert or use the "listen.pem" one you are prompted to create. @@ -996,21 +1001,52 @@ proc help {} { 4) Pressing the "Load" button or pressing Ctrl-L or Clicking the Right mouse button on the main GUI will invoke the Load dialog. - 5) If you want to do a Direct VNC connection, WITH **NO** SSL OR SSH - ENCRYPTION, use the "vnc://" prefix, e.g. vnc://far-away.east:0 - This also works for reverse connections (see below). + Pressing Ctrl-A on the main GUI will bring up the Advanced + Options Panel. + + 5) If you want to make a Direct VNC connection, WITH **NO** SSL OR + SSH ENCRYPTION, use the "vnc://" prefix in the VNC Host:Display + entry box, e.g. "vnc://far-away.east:0" This also works for + reverse connections (e.g. vnc://0 more info below). Use Vnc:// + to avoid being prompted if you are sure you want no encryption. + + Apologies that we do not make this easy to figure out how to do + (e.g. a button on the main panel), but the goal of SSVNC is + secure and encrypted connections! + + Often SSVNC is used to connect to x11vnc where the Unix username + and password is sent over the channel. It would be a very bad + idea to let that data be sent over an unencrypted connection. + In general, it is not wise to have a plaintext VNC connection. + + So we force you to learn about and supply the "vnc://" or "Vnc://" + prefix to the host:port to disable encryption rather than simply + click on an option and not think too much about the consequences. + + Note that even the VNC Password challenge-response method (the + password is not sent in plaintext) leaves your VNC password + susceptible a dictionary attack unless encryption is used. + + The prefix will be stored in any profile that you save so you + do not have to enter it every time. + + Set the env var SSVNC_NO_ENC_WARN=1 to skip the warning prompts. - Sorry we do not make this easy to figure out how to do (e.g. a - button on the main panel), but the goal of SSVNC is secure - connections! Set the env var SSVNC_NO_ENC_WARN=1 to skip the - warning prompts. Using capitalized: Vnc:// will also skip the - prompts. + Using capitalized: Vnc:// will also skip the prompts, for example, + "Vnc://far-away.east:0" in the VNC Host:Display entry box. - 6) Reverse VNC connections are possible as well. Go to Options and - select "Reverse VNC connection". In the 'VNC Host:Display' entry - box put in the number (e.g. "0" or ":0") that corresponds to the - Listening display (0 -> port 5500). See the Options Help for more - info. + 6) Reverse VNC connections (Listening) are possible as well. + In this case the VNC Server initiates the connection to your + waiting (i.e. listening) SSVNC viewer. + + Go to Options and select "Reverse VNC connection". In the 'VNC + Host:Display' entry box put in the number (e.g. "0" or ":0", or + ":1", etc) that corresponds to the Listening display (0 -> port + 5500, 1 -> port 5501, etc.) you want to use. Then clicking on + 'Listen' puts your SSVNC viewer in a "listening" state on that + port number, waiting for a connection from the VNC Server. + + See the Options Help for more info. 7) On Unix to have SSVNC act as a general STUNNEL redirector (i.e. no VNC), put the desired host:port in VNC Host:Display (use a @@ -1526,6 +1562,11 @@ set msg { Clicking on this button will return you to the full SSVNC Mode. + Unix ssvncviewer: + + Clicking on this button will popup a menu for setting options + of the Unix (and Mac OS X) provided SSVNC vncviewer. + ~/.ssvncrc file: @@ -1781,18 +1822,28 @@ set msg { Reverse VNC Connection: - Reverse (listening) VNC connections are possible. + Reverse (listening) VNC connections are possible as well. + + In this case the VNC Server initiates the connection to your + waiting (i.e. listening) SSVNC viewer. For SSL connections in the 'VNC Host:Display' entry box put in - the number (e.g. "0" or ":0") that corresponds to the Listening - display (0 -> port 5500). For example x11vnc can then be used: - "x11vnc ... -ssl SAVE -connect hostname:port". + the number (e.g. "0" or ":0" or ":1", etc.) that corresponds to + the Listening display (0 -> port 5500, 1 -> port 5501, etc.) you + want to use. For example x11vnc can then be used via: + "x11vnc ... -ssl SAVE -connect hostname:port" using the "port" + with the one you chose. + + Clicking on the 'Listen' button puts your SSVNC viewer + in a "listening" state on that port number, waiting for a + connection from the VNC Server. Then a VNC server should establish a reverse connection to - that port on this machine (e.g. -connect this-machine:5500) + that port on this machine (e.g. -connect this-machine:5500 + or -connect this-machine:5503, etc.) Server SSL certificates will be verified, however you WILL - NOTE be prompted about unrecognized ones; rather, you MUST + NOT be prompted about unrecognized ones; rather, you MUST set up the correct Server certificate (e.g. by importing). prior to any connections. @@ -1844,32 +1895,6 @@ set msg { unless it is a double proxy where the 2nd host is the machine with the VNC server. - UltraVNC Single Click III Bug: - - The UltraVNC Single Click III (SSL) server works with SSVNC; - it makes a reverse connection to it via an SSL tunnel: - - http://www.uvnc.com/pchelpware/SCIII/index.html - - Unfortunately the SSL implementation used by UltraVNC SC III - is incompatible with OpenSSL in that the connection will be - dropped after 2-15 minutes due to an unexpected packet. - - However this can be worked around in STUNNEL by setting - configution item 'options = ALL'. Enabling 'UltraVNC Single - Click III Bug' passes this setting to STUNNEL. - - On Windows 'options = ALL' is used by default for stunnel. - On Unix and MacOSX you will need to select this option. - - Setting this option may provide a workaround for other SSL - VNC servers. - - BTW, you can set the environment variable STUNNEL_EXTRA_OPTS_USER - to add any lines to the STUNNEL global config that you want to. - See the stunnel(8) man page for more details. - - View Only: Have VNC Viewer ignore mouse and keyboard input. @@ -2322,19 +2347,20 @@ proc set_defaults {} { global ts_mode ts_desktop_size ts_desktop_depth choose_desktop_geom global additional_port_redirs additional_port_redirs_list global stunnel_local_protection stunnel_local_protection_type ssh_local_protection multiple_listen - global ultra_dsm ultra_dsm_type ultra_dsm_file + global ultra_dsm ultra_dsm_type ultra_dsm_file ultra_dsm_noultra ultra_dsm_salt global sound_daemon_remote_cmd sound_daemon_remote_port sound_daemon_kill sound_daemon_restart global sound_daemon_local_cmd sound_daemon_local_port sound_daemon_local_kill sound_daemon_x11vnc sound_daemon_local_start global smb_su_mode smb_mount_list global use_port_knocking port_knocking_list - global ycrop_string extra_sleep use_listen use_unixpw use_x11vnc_find unixpw_username - global use_uvnc_ssl_bug + global ycrop_string ssvnc_scale sbwid_string rfbversion ssvnc_encodings use_x11cursor use_nobell use_rawlocal use_popupfix extra_sleep use_listen use_unixpw use_x11vnc_find unixpw_username + global disable_ssl_workarounds disable_ssl_workarounds_type global include_list set defs(use_viewonly) 0 set defs(use_listen) 0 - set defs(use_uvnc_ssl_bug) 0 + set defs(disable_ssl_workarounds) 0 + set defs(disable_ssl_workarounds_type) "none" set defs(use_unixpw) 0 set defs(unixpw_username) "" set defs(use_x11vnc_find) 0 @@ -2392,13 +2418,15 @@ proc set_defaults {} { set defs(additional_port_redirs_list) "" set defs(stunnel_local_protection) 0 - set defs(stunnel_local_protection_type) "none" + set defs(stunnel_local_protection_type) "exec" set defs(ssh_local_protection) 0 set defs(multiple_listen) 0 set defs(ultra_dsm) 0 set defs(ultra_dsm_file) "" set defs(ultra_dsm_type) "guess" + set defs(ultra_dsm_noultra) 0 + set defs(ultra_dsm_salt) "" set defs(cups_local_server) "" set defs(cups_remote_port) "" @@ -2420,6 +2448,14 @@ proc set_defaults {} { set defs(sound_daemon_x11vnc) 0 set defs(ycrop_string) "" + set defs(ssvnc_scale) "" + set defs(sbwid_string) "" + set defs(rfbversion) "" + set defs(ssvnc_encodings) "" + set defs(use_x11cursor) 0 + set defs(use_nobell) 0 + set defs(use_rawlocal) 0 + set defs(use_popupfix) 0 set defs(extra_sleep) "" set defs(use_port_knocking) 0 set defs(port_knocking_list) "" @@ -2458,10 +2494,10 @@ proc set_defaults {} { } proc do_viewer_windows {n} { - global use_alpha use_grab use_ssh use_sshssl use_viewonly use_fullscreen use_bgr233 + global use_alpha use_grab use_x11cursor use_nobell use_ssh use_sshssl use_viewonly use_fullscreen use_bgr233 global use_nojpeg use_raise_on_beep use_compresslevel use_quality global change_vncviewer change_vncviewer_path vncviewer_realvnc4 - global use_listen use_uvnc_ssl_bug env + global use_listen disable_ssl_workarounds disable_ssl_workarounds_type env set cmd "vncviewer" if {$change_vncviewer && $change_vncviewer_path != ""} { @@ -2897,7 +2933,8 @@ proc launch_windows_ssh {hp file n} { global is_win9x env global use_sshssl use_ssh putty_pw global port_knocking_list - global use_listen use_uvnc_ssl_bug listening_name + global use_listen listening_name + global disable_ssl_workarounds disable_ssl_workarounds_type global ts_only global debug_netstat @@ -3363,6 +3400,7 @@ proc launch_windows_ssh {hp file n} { catch {destroy .o} catch {destroy .oa} + catch {destroy .os} if { ![do_port_knock $ssh_host start]} { catch {file delete $file} @@ -3766,6 +3804,7 @@ proc darwin_terminal_cmd {{title ""} {cmd ""} {bg 0}} { set fh "" catch {set fh [open $tmp w 0755]} + catch {[exec chmod 755 $tmp]} if {$fh == ""} { raise . tk_messageBox -type ok -icon error -message "Cannot open temporary file: $tmp" -title "Cannot open file" @@ -4707,9 +4746,11 @@ proc repeater_proxy_check {proxy} { set force 1 } } - global use_listen + global use_listen ultra_dsm if {! $use_listen} { - if {$force} { + if {$ultra_dsm != ""} { + return 1; + } elseif {$force} { mesg "WARNING: repeater:// ID:nnn proxy must use Listen Mode" after 1000 } else { @@ -4880,7 +4921,8 @@ proc reset_stunnel_extra_opts {} { proc launch_unix {hp} { global smb_redir_0 smb_mounts env global vncauth_passwd use_unixpw unixpw_username unixpw_passwd - global ssh_only ts_only + global ssh_only ts_only use_x11cursor use_nobell use_rawlocal use_popupfix ssvnc_scale + global ssvnc_encodings globalize @@ -4933,17 +4975,31 @@ proc launch_unix {hp} { set ssvnc_multiple_listen0 "" if {[regexp -nocase {sslrepeater://} $hp]} { - if {! $use_uvnc_ssl_bug} { - set use_uvnc_ssl_bug 1 - mesg "Enabling 'UltraVNC Single Click III Bug'" + if {$disable_ssl_workarounds} { + set disable_ssl_workarounds 0 + mesg "Disabling SSL workarounds for 'UVNC Single Click III Bug'" after 400 } } - if {$use_uvnc_ssl_bug && ! $use_ssh} { - if [info exists env(STUNNEL_EXTRA_OPTS)] { - set stunnel_extra_opts0 $env(STUNNEL_EXTRA_OPTS) + if [info exists env(STUNNEL_EXTRA_OPTS)] { + set stunnel_extra_opts0 $env(STUNNEL_EXTRA_OPTS) + if {$disable_ssl_workarounds} { + if {$disable_ssl_workarounds_type == "none"} { + ; + } elseif {$disable_ssl_workarounds_type == "noempty"} { + set env(STUNNEL_EXTRA_OPTS) "$env(STUNNEL_EXTRA_OPTS)\noptions = DONT_INSERT_EMPTY_FRAGMENTS" + } + } else { set env(STUNNEL_EXTRA_OPTS) "$env(STUNNEL_EXTRA_OPTS)\noptions = ALL" + } + } else { + if {$disable_ssl_workarounds} { + if {$disable_ssl_workarounds_type == "none"} { + ; + } elseif {$disable_ssl_workarounds_type == "noempty"} { + set env(STUNNEL_EXTRA_OPTS) "options = DONT_INSERT_EMPTY_FRAGMENTS" + } } else { set env(STUNNEL_EXTRA_OPTS) "options = ALL" } @@ -4974,13 +5030,25 @@ proc launch_unix {hp} { } } if {$ultra_dsm} { - if {![file exists $ultra_dsm_file]} { + if {![file exists $ultra_dsm_file] && ![regexp {pw=} $ultra_dsm_file]} { mesg "DSM key file does exist: $ultra_dsm_file" bell after 1000 return } + global vncauth_passwd + if {$ultra_dsm_file == "pw=VNCPASSWORD" || $ultra_dsm_file == "pw=VNCPASSWD"} { + if {![info exists vncauth_passwd] || $vncauth_passwd == ""} { + mesg "For DSM pw=VNCPASSWD you must supply the VNC Password" + bell + after 1000 + return + } + } set dsm "ultravnc_dsm_helper " + if {$ultra_dsm_noultra} { + append dsm "noultra:" + } if {$use_listen} { append dsm "rev:" } @@ -4989,7 +5057,16 @@ proc launch_unix {hp} { } else { append dsm $ultra_dsm_type } - append dsm " $ultra_dsm_file" + if {$ultra_dsm_noultra} { + if {$ultra_dsm_salt != ""} { + append dsm "@$ultra_dsm_salt" + } + } + if {$ultra_dsm_file == "pw=VNCPASSWORD" || $ultra_dsm_file == "pw=VNCPASSWD"} { + append dsm " pw=$vncauth_passwd" + } else { + append dsm " $ultra_dsm_file" + } set env(SSVNC_ULTRA_DSM) $dsm } if {$ssh_local_protection} { @@ -5255,6 +5332,30 @@ proc launch_unix {hp} { if {$use_grab} { set cmd "$cmd -grab" } + if {$use_x11cursor} { + set cmd "$cmd -x11cursor" + } + if {$use_nobell} { + set cmd "$cmd -nobell" + } + if {$use_rawlocal} { + set cmd "$cmd -rawlocal" + } + if {$use_popupfix} { + set cmd "$cmd -popupfix" + } + if {$ssvnc_scale != ""} { + set cmd "$cmd -scale '$ssvnc_scale'" + } + if {$ssvnc_encodings != ""} { + set cmd "$cmd -ssvnc_encodings '$ssvnc_encodings'" + } + if {$rfbversion != ""} { + set cmd "$cmd -rfbversion '$rfbversion'" + } + if {$vncviewer_realvnc4} { + set cmd "$cmd -realvnc4" + } if {$use_listen} { set cmd "$cmd -listen" } @@ -5274,8 +5375,6 @@ proc launch_unix {hp} { } } - set cmd "$cmd $hp" - set do_vncspacewrapper 0 if {$change_vncviewer && $change_vncviewer_path != ""} { set path [string trim $change_vncviewer_path] @@ -5346,11 +5445,23 @@ proc launch_unix {hp} { set realvnc4 0 set realvnc3 1 } + if {$realvnc4} { + set cmd "$cmd -realvnc4" + } + + set cmd "$cmd $hp" set passwdfile "" if {$vncauth_passwd != ""} { global use_listen - set passwdfile "$env(SSVNC_HOME)/.vncauth_tmp.[tpid]" + set footest [mytmp /tmp/.check.[tpid]] + catch {file delete $footest} + global mktemp + set passwdfile "/tmp/.vncauth_tmp.[tpid]" + if {$mktemp == ""} { + set passwdfile "$env(SSVNC_HOME)/.vncauth_tmp.[tpid]" + } + set passwdfile [mytmp $passwdfile] catch {exec vncstorepw $vncauth_passwd $passwdfile} catch {exec chmod 600 $passwdfile} @@ -5446,6 +5557,7 @@ proc launch_unix {hp} { } global ycrop_string + global sbwid_string catch {unset env(VNCVIEWER_SBWIDTH)} catch {unset env(VNCVIEWER_YCROP)} if {[info exists ycrop_string] && $ycrop_string != ""} { @@ -5457,12 +5569,18 @@ proc launch_unix {hp} { if {$t != ""} { set env(VNCVIEWER_YCROP) $t } - #catch {puts "VNCVIEWER_SBWIDTH $env(VNCVIEWER_SBWIDTH)"} - #catch {puts "VNCVIEWER_YCROP $env(VNCVIEWER_YCROP)"} + } + if {[info exists sbwid_string] && $sbwid_string != ""} { + set t $sbwid_string + set env(VNCVIEWER_SBWIDTH) $sbwid_string + if {$t != ""} { + set env(VNCVIEWER_SBWIDTH) $t + } } catch {destroy .o} catch {destroy .oa} + catch {destroy .os} update if {$use_sound && $sound_daemon_local_start && $sound_daemon_local_cmd != ""} { @@ -5471,7 +5589,6 @@ proc launch_unix {hp} { set sound_daemon_local_pid "" #exec sh -c "$sound_daemon_local_cmd " >& /dev/null </dev/null & set sound_daemon_local_pid [exec sh -c "echo \$\$; exec $sound_daemon_local_cmd </dev/null 1>/dev/null 2>/dev/null &"] -#puts "A $sound_daemon_local_pid" update after 500 } @@ -5522,8 +5639,15 @@ proc launch_unix {hp} { set env(SSVNC_EXTRA_SLEEP) $extra_sleep } - unix_terminal_cmd $geometry "SSL/SSH VNC Viewer $hp" \ - "$te$cmd; set +xv; ulimit -c 0; trap 'printf \"Paused. Press Enter to exit:\"; read x' QUIT; echo; echo $m; echo; echo sleep 5; echo; sleep 6" 0 $xrm1 $xrm2 $xrm3 + set sstx "SSL/SSH VNC Viewer" + set hptx $hp + global use_listen + if {$use_listen} { + set sstx "SSVNC" + set hptx "$hp (Press Ctrl-C to Stop Listening)" + } + unix_terminal_cmd $geometry "$sstx $hptx" \ + "$te$cmd; set +xv; ulimit -c 0; trap 'printf \"Paused. Press Enter to exit:\"; read x' QUIT; echo; echo $m; echo; echo sleep 5; echo; sleep 5" 0 $xrm1 $xrm2 $xrm3 set env(SS_VNCVIEWER_SSH_CMD) "" set env(SS_VNCVIEWER_USE_C) "" @@ -5786,7 +5910,7 @@ proc launch {{hp ""}} { global mycert svcert crtdir global pids_before pids_after pids_new global env - global use_ssl use_ssh use_sshssl use_listen use_uvnc_ssl_bug + global use_ssl use_ssh use_sshssl use_listen disable_ssl_workarounds global vncdisplay set debug 0 @@ -6151,10 +6275,14 @@ proc launch {{hp ""}} { } else { puts $fh "client = yes" } - # WRT, UltraVNC Single Click III Bug: - # Wow, on Windows we've been using 'options = ALL' - # all along! Duh. OK keep it... - puts $fh "options = ALL" + global disable_ssl_workarounds disable_ssl_workarounds_type + if {$disable_ssl_workarounds} { + if {$disable_ssl_workarounds_type == "noempty"} { + puts $fh "options = DONT_INSERT_EMPTY_FRAGMENTS" + } + } else { + puts $fh "options = ALL" + } puts $fh "taskbar = yes" puts $fh "RNDbytes = 2048" @@ -6287,6 +6415,7 @@ proc launch {{hp ""}} { } else { catch {destroy .o} catch {destroy .oa} + catch {destroy .os} wm withdraw . } @@ -6418,6 +6547,7 @@ proc direct_connect_windows {{hp ""}} { catch {destroy .o} catch {destroy .oa} + catch {destroy .os} wm withdraw . if {$use_listen} { @@ -10728,79 +10858,89 @@ proc help_advanced_opts {} { Brief descriptions: - CUPS Print tunnelling: redirect localhost:6631 (say) on the VNC - server to your local CUPS server. + CUPS Print tunnelling: - ESD/ARTSD Audio tunnelling: redirect localhost:16001 (say) on - the VNC server to your local ESD, etc. sound server. + Redirect localhost:6631 (say) on the VNC server to your local + CUPS server. - SMB mount tunnelling: redirect localhost:1139 (say) on the VNC - server and through that mount SMB file shares from your local - server. The remote machine must be Linux with smbmount installed. + ESD/ARTSD Audio tunnelling: - Additional Port Redirs: specify additional -L port:host:port and - -R port:host:port cmdline options for SSH to enable additional - services. + Redirect localhost:16001 (say) on the VNC server to your local + ESD, etc. sound server. - SSH Local Port Protections: and LD_PRELOAD hack to limit the - number of SSH port redirections to 1 and within the first - 15 seconds. So there is a smaller window when the user can try - to use your tunnel compared to the duration of your session. + SMB mount tunnelling: - STUNNEL Local Port Protections: Try to prevent Untrusted Local - Users (see the main Help panel) from using your STUNNEL tunnel - to connect to the remote VNC Server. + Redirect localhost:1139 (say) on the VNC server and through + that mount SMB file shares from your local server. The remote + machine must be Linux with smbmount installed. - UltraVNC DSM Encryption Plugin: on Unix, by using the supplied - tool, ultravnc_dsm_helper, encrypted connections to UltraVNC - servers using their plugins is enabled. + Additional Port Redirs: - Multiple LISTEN Connections: allow multiple VNC servers to - reverse connect at the same time and so display each of their - desktops on your screen at the same time. + Specify additional -L port:host:port and -R port:host:port + cmdline options for SSH to enable additional services. - Change VNC Viewer: specify a non-bundled VNC Viewer (e.g. - UltraVNC or RealVNC) to run instead of the bundled TightVNC Viewer. + SSH Local Port Protections: - Port Knocking: for "closed port" services, first "knock" on the - firewall ports in a certain way to open the door for SSH or SSL. - The port can also be closed when the encrypted VNC connection - finishes. + An LD_PRELOAD hack to limit the number of SSH port redirections + to 1 and within the first 15 seconds. So there is a smaller + window when the user can try to use your tunnel compared to + the duration of your session. - Use XGrabServer: On Unix only, use the XGrabServer workaround - for old window managers. + STUNNEL Local Port Protections: - Cursor Alphablending: Use the x11vnc alpha hack for translucent - cursors (requires Unix, 32bpp and same endianness) + Try to prevent Untrusted Local Users (see the main Help panel) + from using your STUNNEL tunnel to connect to the remote VNC + Server. - Y Crop: this is for x11vnc's -ncache client side caching scheme - with our Unix TightVNC viewer. Sets the Y value to "crop" the - viewer size at (below the cut is the pixel cache region you do - not want to see). If the screen is tall (H > 2*W) ycropping - will be autodetected, or you can set to -1 to force autodection. - Otherwise, set it to the desired Y value. You can also set - the scrollbar width (very thin by default) by appending ",sb=N" - (or use ",sb=N" by itself to just set the scrollbar width). + UltraVNC DSM Encryption Plugin: - Include: Profile template(s) to load before loading a profile - (Load button). For example if you Save a profile called "globals" + On Unix only, by using the supplied tool, ultravnc_dsm_helper, + encrypted connections to UltraVNC servers using their plugins + is enabled. Support for secret key encryption to Non-UltraVNC + DSM servers is also supported, e.g. x11vnc -enc blowfish:my.key + + Change VNC Viewer: + + Specify a non-bundled VNC Viewer (e.g. UltraVNC or RealVNC) + to run instead of the bundled TightVNC Viewer. + + Port Knocking: + + For "closed port" services, first "knock" on the firewall ports + in a certain way to open the door for SSH or SSL. The port + can also be closed when the encrypted VNC connection finishes. + + Include: + + Profile template(s) to load before loading a profile (Load + button). For example if you Save a profile called "globals" that has some settings you use often, then just supply "Include: globals" to have them applied. You may supply a comma or space - separated list of templates to include. They can be full path - names or basenames relative to the profiles directory. You do - not need to supply the .vnc suffix. The non-default settings - in them will be applied first, and then any values in the loaded - Profile will override them. + separated list of templates to include. They can be full + path names or basenames relative to the profiles directory. + You do not need to supply the .vnc suffix. The non-default + settings in them will be applied first, and then any values in + the loaded Profile will override them. + + Sleep: - Sleep: Enter a number to indicate how many extra seconds to sleep + Enter a number to indicate how many extra seconds to sleep while waiting for the VNC viewer to start up. On Windows this can give extra time to enter the Putty/Plink password, etc. - ssh-agent: On Unix only: restart the GUI in the presence of - ssh-agent(1) (e.g. in case you forgot to start your agent before - starting this GUI). An xterm will be used to enter passphrases, - etc. This can avoid repeatedly entering passphrases for the SSH - logins (note this requires setting up and distributing SSH keys). + Unix ssvncviewer: + + Display a popup menu with options that apply to the special + Unix SSVNC VNC Viewer (perhaps called 'ssvncviewer') provided by + this SSVNC package. This only applies to Unix or Mac OS X. + + Use ssh-agent: + + On Unix only: restart the GUI in the presence of ssh-agent(1) + (e.g. in case you forgot to start your agent before starting + this GUI). An xterm will be used to enter passphrases, etc. + This can avoid repeatedly entering passphrases for the SSH logins + (note this requires setting up and distributing SSH keys). About the CheckButtons: @@ -10814,6 +10954,111 @@ proc help_advanced_opts {} { jiggle_text .ah.f.t } +proc help_ssvncviewer_opts {} { + toplev .av + + scroll_text_dismiss .av.f + + center_win .av + + wm title .av "Unix SSVNC viewer Options Help" + + set msg { + These Unix SSVNC VNC Viewer Options apply only on Unix or Mac OS X + when using the viewer (ssvncviewer) supplied by this SSVNC package. + + Brief descriptions: + + Multiple LISTEN Connections: + + Allow multiple VNC servers to reverse connect at the same time + and so display each of their desktops on your screen at the + same time. + + Use X11 Cursor: + + When drawing the mouse cursor shape locally, use an X11 cursor + instead of drawing it directly into the framebuffer. This + can sometimes give better response, and avoid problems under + 'Scaling'. + + Disable Bell: + + Disable beeps coming from remote side. + + Use Raw Local: + + Use the VNC Raw encoding for 'localhost' connections (instead + of assuming there is a local tunnel, SSL or SSH, going to the + remote machine. + + Use Popup Fix: + + Enable a fix that warps the popup (F8) to the mouse pointer. + + Use XGrabServer (for fullscreen): + + On Unix only, use the XGrabServer workaround for older window + managers. Sometimes also needed on recent (2008) GNOME. This + workaround can make going into/out-of Fullscreen work better. + + Cursor Alphablending: + + Use the x11vnc alpha hack for translucent cursors (requires Unix, + 32bpp and same endianness) + + Scaling: + + Use viewer-side (i.e. local) scaling of the VNC screen. Supply + a fraction, e.g. 0.75 or 3/4, or a WxH geometry, e.g. 1280x1024, + or the string 'fit' to fill the current screen. Use 'auto' + to scale the desktop to match the viewer window size. + + Y Crop: + + This is for x11vnc's -ncache client side caching scheme with our + Unix TightVNC viewer. Sets the Y value to "crop" the viewer + size at (below the cut is the pixel cache region you do not + want to see). If the screen is tall (H > 2*W) ycropping will + be autodetected, or you can set to -1 to force autodection. + Otherwise, set it to the desired Y value. You can also set + the scrollbar width (very thin by default) by appending ",sb=N" + (or use ",sb=N" by itself to just set the scrollbar width). + + ScrollBar Width: + + This is for x11vnc's -ncache client side caching scheme with our + Unix TightVNC viewer. For Y-Crop mode, set the size of the + scrollbars (often one want it to be very narrow, e.g. 2 pixels + to be less distracting. + + + These are environment variables one may set to affect the options + of the SSVNC vncviewer: + + VNCVIEWER_ALPHABLEND (-alpha, see Cursor Alphablending above) + VNCVIEWER_POPUP_FIX (-popupfix, warp popup to mouse location) + VNCVIEWER_GRAB_SERVER (-graball, see Use XGrabServer above) + VNCVIEWER_YCROP (-ycrop, see Y Crop above) + VNCVIEWER_SBWIDTH (-sbwidth, see ScrollBar Width above) + VNCVIEWER_RFBVERSION (-rfbversion, e.g. 3.6) + VNCVIEWER_ENCODINGS (-encodings, e.g. "copyrect zrle hextile") + VNCVIEWER_BELL (-bell) + VNCVIEWER_X11CURSOR (-x11cursor, see Use X11 Cursor above) + VNCVIEWER_RAWLOCAL (-rawlocal, see Use Raw Local above) + SSVNC_SCALE (-scale, see Scaling above) + SSVNC_MULTIPLE_LISTEN (-multilisten, see Mulitple LISTEN above) + SSVNC_UNIXPW (-unixpw) + SSVNC_UNIXPW_NOESC (do not send escape in -unixpw mode) + SSVNC_NOSOLID (do not do solid region speedup in + scaling mode.) + +} + + .av.f.t insert end $msg + jiggle_text .av.f.t +} + proc set_viewer_path {} { global change_vncviewer_path unix_dialog_resize .chviewer @@ -10993,7 +11238,7 @@ proc stunnel_sec_dialog {} { On Unix, for STUNNEL SSL tunnels we provide two options as extra safeguards against untrusted local users. Both only apply to Unix/MacOSX. - Note that Both options are *ignored* in reverse connection (Listen) mode. + Note that Both options are *IGNORED* in reverse connection (Listen) mode. 1) The first one 'Use stunnel EXEC mode' (it is mutually exclusive with option 2). For this case the modified SSVNC Unix viewer must be @@ -11038,6 +11283,95 @@ proc stunnel_sec_dialog {} { wm resizable .stlsec 1 0 } +proc disable_ssl_workarounds_dialog {} { + global disable_ssl_workarounds disable_ssl_workarounds_type + + toplev .sslwrk + wm title .sslwrk "Disable SSL Workarounds" + + global help_font uname + scroll_text .sslwrk.f 86 36 + + apply_bg .sslwrk.f + + set msg { + Some SSL implementations are incomplete or buggy or do not work properly + with other implementations. SSVNC uses STUNNEL for its SSL encryption, + and STUNNEL uses the OpenSSL SSL implementation. + + This causes some problems with non-OpenSSL implementations on the VNC server + side. The most noticable one is the UltraVNC Single Click III (SSL) server: + + http://www.uvnc.com/pchelpware/SCIII/index.html + + It can make a reverse connection to SSVNC via an encrypted SSL tunnel. + + Unfortunately, in the default operation with STUNNEL the connection will be + dropped after 2-15 minutes due to an unexpected packet. + + Because of this, by default SSVNC will enable some SSL workarounds to make + connections like these work. This is the STUNNEL 'options = ALL' setting: + it enables a basic set of SSL workarounds. + + You can read all about these workarounds in the stunnel(8) manpage and the + OpenSSL SSL_CTX_set_options(3) manpage. + + Why are we mentioning this? STUNNELS's 'options = ALL' lowers the SSL + security a little bit. If you know you do not have an incompatible SSL + implementation on the server side (e.g. any one using OpenSSL is compatible, + x11vnc in particular), then you can regain that little bit of security by + selecting the "Disable SSL Workarounds" option. + + "Disable All SSL Workarounds" selected below will do that. On the other hand, + choose "Keep the DONT_INSERT_EMPTY_FRAGMENTS Workaround" to retain that one, + commonly needed workaround. + + BTW, you can set the environment variable STUNNEL_EXTRA_OPTS_USER to add + any lines to the STUNNEL global config that you want to. See the stunnel(8) + man page for more details. +} + .sslwrk.f.t insert end $msg + + radiobutton .sslwrk.none -relief ridge -anchor w -variable disable_ssl_workarounds_type -value "none" -text "Disable All Workarounds" + radiobutton .sslwrk.noempty -relief ridge -anchor w -variable disable_ssl_workarounds_type -value "noempty" -text "Keep the DONT_INSERT_EMPTY_FRAGMENTS Workaround" + + button .sslwrk.cancel -text "Cancel" -command {set disable_ssl_workarounds 0; destroy .sslwrk} + bind .sslwrk <Escape> {set disable_ssl_workarounds 0; destroy .sslwrk} + wm protocol .sslwrk WM_DELETE_WINDOW {set disable_ssl_workarounds 0; destroy .sslwrk} + button .sslwrk.done -text "Done" -command {destroy .sslwrk} + + pack .sslwrk.f .sslwrk.none .sslwrk.noempty .sslwrk.cancel .sslwrk.done -side top -fill x + + center_win .sslwrk + wm resizable .sslwrk 1 0 +} + +proc update_no_ultra_dsm {} { + global ultra_dsm_noultra + global ultra_dsm_type + + foreach b {bf des3 aes aes256 l e} { + if {! $ultra_dsm_noultra} { + .ultradsm.nou.$b configure -state disabled + } else { + .ultradsm.nou.$b configure -state normal + } + } + if {! $ultra_dsm_noultra} { + if {$ultra_dsm_type == "arc4"} { + ; + } elseif {$ultra_dsm_type == "aesv2"} { + ; + } elseif {$ultra_dsm_type == "msrc4"} { + ; + } elseif {$ultra_dsm_type == "msrc4_sc"} { + ; + } else { + set ultra_dsm_type guess + } + } +} + proc ultra_dsm_dialog {} { global ultra_dsm ultra_dsm_file ultra_dsm_type @@ -11045,20 +11379,28 @@ proc ultra_dsm_dialog {} { wm title .ultradsm "UltraVNC DSM Encryption Plugin" global help_font - eval text .ultradsm.t -width 80 -height 24 $help_font - apply_bg .ultradsm.t + scroll_text .ultradsm.f 85 35 set msg { On Unix with the provided SSVNC vncviewer, you can connect to an UltraVNC - server that is using one of its encryption plugins: MSRC4 (not yet - supported), ARC4, or AESV2. + server that is using one of its encryption plugins: MSRC4, ARC4, or AESV2. + + See the end of this text for how to use symmetric encryption with NON-UltraVNC + servers (for example, x11vnc 0.9.5 or later). + + You will need to specify the corresponding UltraVNC encryption key (created + by you using an UltraVNC server or viewer). It is usually called 'rc4.key' + (for MSRC4), 'arc4.key' (for ARC4), and 'aesv2.key' (for AESV2). Specify + the path to it or Browse for it. Also, specify which type of plugin it is + (or use 'guess' to have it guess via the before mentioned filenames). + + The choice "UVNC SC" enables a special workaround for use with UltraVNC + Single Click and the MSRC4 plugin. It may not be needed on recent SC. + + You can also specify pw=my-password instead of a keyfile. - You will need to specify the corresponding UltraVNC encryption key - (created by you using an UltraVNC server or viewer). It is usually - called 'rc4.key' (for MSRC4), 'arc4.key' (for ARC4), and 'aesv2.key' - (for AESV2). Specify the path to it or browse for it. Also, specify - which type of plugin it is (or use 'guess' to have it guess via the - before mentioned filenames). + Use the literal string 'pw=VNCPASSWD' to have the VNC password that you + entered into the 'VNC Password:' be used for the pw=... SSL and SSH tunnels do not apply in this mode (any settings are ignored.) @@ -11069,11 +11411,18 @@ proc ultra_dsm_dialog {} { vncviewer had to be modified to support it. The tight and zlib encodings currently do not work in this mode and are disabled. - Note that this program also requires the utility tool named - 'ultravnc_dsm_helper' that should be included in your SSVNC kit. + Note that this mode also requires the utility tool named 'ultravnc_dsm_helper' + that should be included in your SSVNC kit. + + Select Non-Ultra DSM to use symmetric encryption to a Non-UltraVNC server + via a supported symmetric key cipher. x11vnc supports symmetric + encryption via, e.g., "x11vnc -enc aesv2:./my.key". Extra ciphers are + enabled for this mode (e.g. blowfish and 3des). You can also set the random + salt size and initialization vector size in Salt,IV for example "8,16". + See the x11vnc and 'ultravnc_dsm_helper -help' documentation for more info. } - .ultradsm.t insert end $msg + .ultradsm.f.t insert end $msg frame .ultradsm.path label .ultradsm.path.l -text "Ultra DSM Keyfile:" @@ -11085,7 +11434,7 @@ proc ultra_dsm_dialog {} { pack .ultradsm.path.b -side left frame .ultradsm.key - label .ultradsm.key.l -text "Type of Key: " + label .ultradsm.key.l -text "Type of Key: " radiobutton .ultradsm.key.guess -pady 1 -anchor w -variable ultra_dsm_type -value guess \ -text "Guess" radiobutton .ultradsm.key.arc4 -pady 1 -anchor w -variable ultra_dsm_type -value arc4 \ @@ -11096,13 +11445,43 @@ proc ultra_dsm_dialog {} { radiobutton .ultradsm.key.msrc4 -pady 1 -anchor w -variable ultra_dsm_type -value msrc4 \ -text "MSRC4" - .ultradsm.key.msrc4 configure -state disabled + + radiobutton .ultradsm.key.msrc4_sc -pady 1 -anchor w -variable ultra_dsm_type -value msrc4_sc \ + -text "UVNC SC" pack .ultradsm.key.l -side left pack .ultradsm.key.guess -side left pack .ultradsm.key.arc4 -side left pack .ultradsm.key.aesv2 -side left pack .ultradsm.key.msrc4 -side left + pack .ultradsm.key.msrc4_sc -side left + + frame .ultradsm.nou + checkbutton .ultradsm.nou.cb -text "Non-Ultra DSM" -variable ultra_dsm_noultra -command update_no_ultra_dsm + radiobutton .ultradsm.nou.bf -pady 1 -anchor w -variable ultra_dsm_type -value blowfish \ + -text "Blowfish" + + radiobutton .ultradsm.nou.des3 -pady 1 -anchor w -variable ultra_dsm_type -value 3des \ + -text "3DES" + + radiobutton .ultradsm.nou.aes -pady 1 -anchor w -variable ultra_dsm_type -value "aes-cfb" \ + -text "AES-CFB" + + radiobutton .ultradsm.nou.aes256 -pady 1 -anchor w -variable ultra_dsm_type -value "aes256" \ + -text "AES-256" + + label .ultradsm.nou.l -text " Salt,IV" + entry .ultradsm.nou.e -width 6 -textvariable ultra_dsm_salt + + pack .ultradsm.nou.cb -side left + pack .ultradsm.nou.bf -side left + pack .ultradsm.nou.des3 -side left + pack .ultradsm.nou.aes -side left + pack .ultradsm.nou.aes256 -side left + pack .ultradsm.nou.l -side left + pack .ultradsm.nou.e -side left -expand 0 + + update_no_ultra_dsm button .ultradsm.cancel -text "Cancel" -command {destroy .ultradsm; set ultra_dsm 0} bind .ultradsm <Escape> {destroy .ultradsm; set ultra_dsm 0} @@ -11110,7 +11489,7 @@ proc ultra_dsm_dialog {} { button .ultradsm.done -text "Done" -command {destroy .ultradsm; catch {raise .oa}} bind .ultradsm.path.e <Return> {destroy .ultradsm; catch {raise .oa}} - pack .ultradsm.t .ultradsm.path .ultradsm.key .ultradsm.cancel .ultradsm.done -side top -fill x + pack .ultradsm.f .ultradsm.path .ultradsm.key .ultradsm.nou .ultradsm.cancel .ultradsm.done -side top -fill x center_win .ultradsm wm resizable .ultradsm 1 0 @@ -11229,6 +11608,59 @@ proc multilisten_dialog {} { wm resizable .multil 1 0 } +proc use_grab_dialog {} { + global usg_grab + + toplev .usegrb + wm title .usegrb "Use XGrabServer (for fullscreen)" + + global help_font + eval text .usegrb.t -width 85 -height 29 $help_font + + apply_bg .usegrb.t + + set msg { + On Unix, some Window managers and some Desktops make it difficult for the + SSVNC Unix VNC viewer to go into full screen mode (F9) and/or return. + + Sometimes one can go into full screen mode, but then your keystrokes or + Mouse actions do not get through. This can leave you trapped because you + cannot inject input (F9 again) to get out of full screen mode. (Tip: + press Ctrl-Alt-F2 for a console login shell; then kill your vncviewer + process, e.g. pkill vncviewer; then Alt-F7 to get back to your desktop) + + We have seen this in some very old Window managers (e.g. fvwm2 circa + 1998) and some very new Desktops (e.g. GNOME circa 2008). We try + to work around the problem on recent desktops by using the NEW_WM + interface, but if you use Fullscreen, you may need to use this option. + + The default for the SSVNC Unix VNC viewer is '-grabkbd' mode where it will + try to exclusively grab the keyboard. This often works correctly. + + However if Fullscreen is not working properly, try setting this + 'Use XGrabServer' option to enable '-graball' mode where it tries to grab + the entire X server. This usually works, but can be a bit flakey. + + Sometimes toggling F9 a few times gets lets the vncviewer fill the whole + screen. Sometimes tapping F9 very quickly gets it to snap in. If GNOME + (or whatever desktop) is still showing its taskbars, it is recommended + you toggle F9 until it isn't. Otherwise, it is not clear who gets the input. + + Best of luck. +} + .usegrb.t insert end $msg + + button .usegrb.cancel -text "Cancel" -command {set use_grab 0; destroy .usegrb} + bind .usegrb <Escape> {set use_grab 0; destroy .usegrb} + wm protocol .usegrb WM_DELETE_WINDOW {set use_grab 0; destroy .usegrb} + button .usegrb.done -text "Done" -command {destroy .usegrb} + + pack .usegrb.t .usegrb.cancel .usegrb.done -side top -fill x + + center_win .usegrb + wm resizable .usegrb 1 0 +} + proc find_netcat {} { global is_windows @@ -12013,12 +12445,12 @@ proc set_ts_options {} { checkbutton .ot.b$i -anchor w -variable change_vncviewer -text \ "Change VNC Viewer" \ - -command {if {$change_vncviewer} {change_vncviewer_dialog}} + -command change_vncviewer_dialog_wrap incr i checkbutton .ot.b$i -anchor w -variable use_x11_macosx -text \ "X11 viewer MacOSX" \ - -command {if {$use_x11_macosx} {set darwin_cotvnc 0} else {set darwin_cotvnc 1}; catch {destroy .ot}; set_ts_options} + -command {if {$use_x11_macosx} {set darwin_cotvnc 0} else {set darwin_cotvnc 1}; set_darwin_cotvnc_buttons} if {$uname != "Darwin"} {.ot.b$i configure -state disabled} incr i @@ -12091,6 +12523,8 @@ proc set_ts_adv_options {} { checkbutton .ot2.b$i -anchor w -variable use_bgr233 -text \ "Client 8bit Color" if {$darwin_cotvnc} {.ot2.b$i configure -state disabled} + global darwin_cotvnc_blist + set darwin_cotvnc_blist(.ot2.b$i) 1 incr i checkbutton .ot2.b$i -anchor w -variable choose_ncache -text \ @@ -12120,6 +12554,18 @@ proc set_ts_adv_options {} { -command {destroy .ot2; to_ssvnc} incr i } + button .ot2.b$i -anchor w -text " Unix ssvncviewer ..." \ + -command {set_ssvncviewer_options} + if {$is_windows} { + .ot2.b$i configure -state disabled + } + global change_vncviewer + if {$change_vncviewer} { + .ot2.b$i configure -state disabled + } + global ts_uss_button + set ts_uss_button .ot2.b$i + incr i for {set j 1} {$j < $i} {incr j} { pack .ot2.b$j -side top -fill x @@ -12140,6 +12586,25 @@ proc set_ts_adv_options {} { focus .ot2 } +proc change_vncviewer_dialog_wrap {} { + global change_vncviewer ts_uss_button + if {$change_vncviewer} { + change_vncviewer_dialog + catch {tkwait window .chviewer} + } + if {$change_vncviewer} { + catch {.oa.ss configure -state disabled} + } else { + catch {.oa.ss configure -state normal} + } + if [info exists ts_uss_button] { + if {$change_vncviewer} { + catch {$ts_uss_button configure -state disabled} + } else { + catch {$ts_uss_button configure -state normal} + } + } +} proc set_advanced_options {} { global use_cups use_sound use_smbmnt @@ -12204,6 +12669,14 @@ proc set_advanced_options {} { if {$is_windows} {.oa.b$i configure -state disabled} incr i + checkbutton .oa.b$i -anchor w -variable disable_ssl_workarounds -text \ + "Disable SSL Workarounds" \ + -command {if {$disable_ssl_workarounds} {disable_ssl_workarounds_dialog}} + global disable_ssl_workarounds_button + set disable_ssl_workarounds_button .oa.b$i + if {$use_ssh} {.oa.b$i configure -state disabled} + incr i + checkbutton .oa.b$i -anchor w -variable ultra_dsm -text \ "UltraVNC DSM Encryption Plugin" \ -command {if {$ultra_dsm} {ultra_dsm_dialog}} @@ -12212,18 +12685,9 @@ proc set_advanced_options {} { if {$is_windows} {.oa.b$i configure -state disabled} incr i - checkbutton .oa.b$i -anchor w -variable multiple_listen -text \ - "Multiple LISTEN Connections" \ - -command {if {$multiple_listen} {multilisten_dialog}} - global multiple_listen_button use_listen - set multiple_listen_button .oa.b$i - if {$is_windows} {.oa.b$i configure -state disabled} - if {!$use_listen} {.oa.b$i configure -state disabled} - incr i - checkbutton .oa.b$i -anchor w -variable change_vncviewer -text \ "Change VNC Viewer" \ - -command {if {$change_vncviewer} {change_vncviewer_dialog}} + -command change_vncviewer_dialog_wrap incr i checkbutton .oa.b$i -anchor w -variable use_port_knocking -text \ @@ -12231,29 +12695,6 @@ proc set_advanced_options {} { -command {if {$use_port_knocking} {port_knocking_dialog}} incr i - checkbutton .oa.b$i -anchor w -variable use_grab -text \ - "Use XGrabServer" - if {$darwin_cotvnc} {.oa.b$i configure -state disabled} - set ix $i - incr i - - checkbutton .oa.b$i -anchor w -variable use_alpha -text \ - "Cursor alphablending (32bpp required)" - if {$darwin_cotvnc} {.oa.b$i configure -state disabled} - set ia $i - incr i - - - - global ycrop_string - frame .oa.b$i - label .oa.b$i.l -text "Y Crop: " - entry .oa.b$i.e -width 10 -textvariable ycrop_string - pack .oa.b$i.l -side left - pack .oa.b$i.e -side right -expand 1 -fill x - - incr i - global include_list frame .oa.b$i label .oa.b$i.l -text "Include:" @@ -12272,16 +12713,27 @@ proc set_advanced_options {} { incr i - if {$is_windows} { - .oa.b$ix configure -state disabled - .oa.b$ia configure -state disabled - } - for {set j 1} {$j < $i} {incr j} { pack .oa.b$j -side top -fill x } - button .oa.sa -text "Use ssh-agent" -command ssh_agent_restart + global uname + set t1 " Unix ssvncviewer ..." + if {$uname == "Darwin" } { regsub {^ *} $t1 "" t1 } + button .oa.ss -anchor w -text $t1 -command set_ssvncviewer_options + pack .oa.ss -side top -fill x + if {$is_windows} { + .oa.ss configure -state disabled + } + global change_vncviewer + if {$change_vncviewer} { + .oa.ss configure -state disabled + } + + set t2 " Use ssh-agent" + if {$uname == "Darwin" } { regsub {^ *} $t2 "" t2 } + + button .oa.sa -anchor w -text $t2 -command ssh_agent_restart pack .oa.sa -side top -fill x if {$is_windows} { .oa.sa configure -state disabled @@ -12309,6 +12761,198 @@ proc set_advanced_options {} { focus .oa } +proc set_ssvncviewer_options {} { + global is_windows darwin_cotvnc + global use_ssh use_sshssl use_x11cursor use_rawlocal use_popupfix use_alpha use_grab use_nobell + global ssvnc_scale + + if {$is_windows} { + return + } + + catch {destroy .oa} + toplev .os + wm title .os "Unix ssvncviewer Options" + + set darwinlist [list] + + set i 1 + + checkbutton .os.b$i -anchor w -variable multiple_listen -text \ + "Multiple LISTEN Connections" \ + -command {if {$multiple_listen} {multilisten_dialog}} + global multiple_listen_button use_listen + set multiple_listen_button .os.b$i + if {$is_windows} {.os.b$i configure -state disabled} + if {!$use_listen} {.os.b$i configure -state disabled} + lappend darwinlist .os.b$i; if {$darwin_cotvnc} {.os.b$i configure -state disabled} + incr i + + + checkbutton .os.b$i -anchor w -variable use_x11cursor -text \ + "Use X11 Cursor" + lappend darwinlist .os.b$i; if {$darwin_cotvnc} {.os.b$i configure -state disabled} + incr i + + checkbutton .os.b$i -anchor w -variable use_nobell -text \ + "Disable Bell" + lappend darwinlist .os.b$i; if {$darwin_cotvnc} {.os.b$i configure -state disabled} + incr i + + checkbutton .os.b$i -anchor w -variable use_rawlocal -text \ + "Use Raw Local" + lappend darwinlist .os.b$i; if {$darwin_cotvnc} {.os.b$i configure -state disabled} + incr i + + checkbutton .os.b$i -anchor w -variable use_popupfix -text \ + "Use Popup Fix" + lappend darwinlist .os.b$i; if {$darwin_cotvnc} {.os.b$i configure -state disabled} + incr i + + checkbutton .os.b$i -anchor w -variable use_grab -text \ + "Use XGrabServer (for fullscreen)" \ + -command {if {$use_grab} {use_grab_dialog}} + lappend darwinlist .os.b$i; if {$darwin_cotvnc} {.os.b$i configure -state disabled} + incr i + + checkbutton .os.b$i -anchor w -variable use_alpha -text \ + "Cursor alphablending (32bpp required)" + lappend darwinlist .os.b$i; if {$darwin_cotvnc} {.os.b$i configure -state disabled} + incr i + + frame .os.b$i -height 2; incr i + + set relief ridge + frame .os.b$i -relief $relief -borderwidth 2 + + label .os.b$i.l -font fixed -anchor w -text "Examples: '0.75', '1024x768', 'fit' (fill screen), or 'auto'"; + + global ssvnc_scale + frame .os.b$i.f + label .os.b$i.f.l -text "Scaling: " + lappend darwinlist .os.b$i.f.l; if {$darwin_cotvnc} {.os.b$i.f.l configure -state disabled} + entry .os.b$i.f.e -width 10 -textvariable ssvnc_scale + lappend darwinlist .os.b$i.f.e; if {$darwin_cotvnc} {.os.b$i.f.e configure -state disabled} + pack .os.b$i.f.l -side left + pack .os.b$i.f.e -side right -expand 1 -fill x + + pack .os.b$i.f .os.b$i.l -side top -fill x + + incr i + + frame .os.b$i -height 2; incr i + + frame .os.b$i -relief $relief -borderwidth 2 + + label .os.b$i.l -font fixed -anchor w -text "Enter the max height in pixels, e.g. '900'"; + + global ycrop_string + frame .os.b$i.f + label .os.b$i.f.l -text "Y Crop: " + lappend darwinlist .os.b$i.f.l; if {$darwin_cotvnc} {.os.b$i.f.l configure -state disabled} + entry .os.b$i.f.e -width 10 -textvariable ycrop_string + lappend darwinlist .os.b$i.f.e; if {$darwin_cotvnc} {.os.b$i.f.e configure -state disabled} + pack .os.b$i.f.l -side left + pack .os.b$i.f.e -side right -expand 1 -fill x + + pack .os.b$i.f .os.b$i.l -side top -fill x + + incr i + + frame .os.b$i -height 2; incr i + + frame .os.b$i -relief $relief -borderwidth 2 + + label .os.b$i.l -font fixed -anchor w -text "Enter the scrollbar width in pixels, e.g. '4'"; + + global sbwid_string + frame .os.b$i.f + label .os.b$i.f.l -text "ScrollBar Width: " + lappend darwinlist .os.b$i.f.l; if {$darwin_cotvnc} {.os.b$i.f.l configure -state disabled} + entry .os.b$i.f.e -width 10 -textvariable sbwid_string + lappend darwinlist .os.b$i.f.e; if {$darwin_cotvnc} {.os.b$i.f.e configure -state disabled} + pack .os.b$i.f.l -side left + pack .os.b$i.f.e -side right -expand 1 -fill x + + pack .os.b$i.f .os.b$i.l -side top -fill x + + incr i + + frame .os.b$i -height 2; incr i + + frame .os.b$i -relief $relief -borderwidth 2 + + label .os.b$i.l -font fixed -anchor w -text "Enter the RFB version to pretend to be using, e.g. '3.4'"; + label .os.b$i.l2 -font fixed -anchor w -text "Sometimes needed for UltraVNC: 3.4, 3.6, 3.14, 3.16"; + + global rfbversion + frame .os.b$i.f + label .os.b$i.f.l -text "RFB Version: " + lappend darwinlist .os.b$i.f.l; if {$darwin_cotvnc} {.os.b$i.f.l configure -state disabled} + entry .os.b$i.f.e -width 10 -textvariable rfbversion + lappend darwinlist .os.b$i.f.e; if {$darwin_cotvnc} {.os.b$i.f.e configure -state disabled} + pack .os.b$i.f.l -side left + pack .os.b$i.f.e -side right -expand 1 -fill x + + pack .os.b$i.f .os.b$i.l .os.b$i.l2 -side top -fill x + + incr i + + frame .os.b$i -height 2; incr i + + frame .os.b$i -relief $relief -borderwidth 2 + + label .os.b$i.l1 -font fixed -anchor w -text "List encodings in preferred order, for example"; + label .os.b$i.l2 -font fixed -anchor w -text "'copyrect zrle tight' The list of encodings is:"; + label .os.b$i.l3 -font fixed -anchor w -text "copyrect tight zrle zywrle hextile zlib corre rre raw"; + + global ssvnc_encodings + frame .os.b$i.f + label .os.b$i.f.l -text "Encodings: " + lappend darwinlist .os.b$i.f.l; if {$darwin_cotvnc} {.os.b$i.f.l configure -state disabled} + entry .os.b$i.f.e -width 10 -textvariable ssvnc_encodings + lappend darwinlist .os.b$i.f.e; if {$darwin_cotvnc} {.os.b$i.f.e configure -state disabled} + pack .os.b$i.f.l -side left + pack .os.b$i.f.e -side right -expand 1 -fill x + + pack .os.b$i.f .os.b$i.l1 .os.b$i.l2 .os.b$i.l3 -side top -fill x + + incr i + + frame .os.b$i -height 2; incr i + + for {set j 1} {$j < $i} {incr j} { + pack .os.b$j -side top -fill x + } + + frame .os.b + button .os.b.done -text "Done" -command {destroy .os} + bind .os <Escape> {destroy .os} + wm protocol .os WM_DELETE_WINDOW {destroy .os} + button .os.b.help -text "Help" -command help_ssvncviewer_opts + + global use_listen + if {$use_listen} { + button .os.b.connect -text "Listen" -command launch + } else { + button .os.b.connect -text "Connect" -command launch + } + + pack .os.b.help .os.b.connect .os.b.done -fill x -expand 1 -side left + + pack .os.b -side top -fill x + + global darwin_cotvnc_blist + foreach b $darwinlist { + set darwin_cotvnc_blist($b) 1 + } + + center_win .os + wm resizable .os 1 0 + focus .os +} + + proc in_path {cmd} { global env set p $env(PATH) @@ -12431,6 +13075,7 @@ proc adv_ssh_tog {on} { proc adv_listen_ssl_tog {on} { global stunnel_local_protection_button is_windows + global disable_ssl_workarounds_button if [info exists stunnel_local_protection_button] { if {$on} { catch {$stunnel_local_protection_button configure -state normal} @@ -12438,6 +13083,13 @@ proc adv_listen_ssl_tog {on} { catch {$stunnel_local_protection_button configure -state disabled} } } + if [info exists disable_ssl_workarounds_button] { + if {$on} { + catch {$disable_ssl_workarounds_button configure -state normal} + } else { + catch {$disable_ssl_workarounds_button configure -state disabled} + } + } if {$is_windows} { catch {$stunnel_local_protection_button configure -state disabled} } @@ -12558,10 +13210,12 @@ proc listen_adjust {} { catch {.b.conn configure -text "Listen"} catch {.o.b.connect configure -text "Listen"} catch {$multiple_listen_button configure -state normal} + catch {mesg "Listen :N -> Port 5500+N, i.e. :0 -> 5500, :1 -> 5501, :2 -> 5502 ..."} } else { catch {.b.conn configure -text "Connect"} catch {.o.b.connect configure -text "Connect"} catch {$multiple_listen_button configure -state disabled} + catch {mesg "Switched to Forward Connection mode."} } if {$is_windows} { catch {$multiple_listen_button configure -state disabled} @@ -12618,6 +13272,20 @@ proc x11vnc_find_adjust {which} { regsub -all {[ ][ ]*} $remote_ssh_cmd " " remote_ssh_cmd } +proc set_darwin_cotvnc_buttons {} { + global darwin_cotvnc uname darwin_cotvnc_blist + + if {$uname == "Darwin" && [info exists darwin_cotvnc_blist]} { + foreach b [array names darwin_cotvnc_blist] { + if {$darwin_cotvnc} { + catch {$b configure -state disabled} + } else { + catch {$b configure -state normal} + } + } + } +} + proc set_options {} { global use_alpha use_grab use_ssh use_sshssl use_viewonly use_fullscreen use_bgr233 global use_nojpeg use_raise_on_beep use_compresslevel use_quality use_x11_macosx @@ -12627,6 +13295,7 @@ proc set_options {} { global use_x11vnc_find x11vnc_find_widget global use_x11vnc_xlogin x11vnc_xlogin_widget uvnc_bug_widget global ts_only + global darwin_cotvnc_blist if {$ts_only} { set_ts_options return @@ -12666,19 +13335,14 @@ proc set_options {} { "Unix Username & Password" -command {unixpw_adjust} if {$is_windows} {.o.b$i configure -state disabled} if {$darwin_cotvnc} {.o.b$i configure -state disabled} + set darwin_cotvnc_blist(.o.b$i) 1 incr i checkbutton .o.b$i -anchor w -variable use_listen -text \ - "Reverse VNC Connection (-LISTEN)" -command {listen_adjust; if {$vncdisplay == ""} {set vncdisplay ":0"}; if {$use_listen} {destroy .o}} + "Reverse VNC Connection (-LISTEN)" -command {listen_adjust; if {$vncdisplay == ""} {set vncdisplay ":0"} else {set vncdisplay ""}; if {$use_listen} {destroy .o}} #if {$is_windows} {.o.b$i configure -state disabled} - if {$darwin_cotvnc} {.o.b$i configure -state disabled} - incr i - - checkbutton .o.b$i -anchor w -variable use_uvnc_ssl_bug -text \ - "UltraVNC Single Click III Bug" - if {$is_windows} {.o.b$i configure -state disabled} - if {$use_ssh && !$use_sshssl} {.o.b$i configure -state disabled} - set uvnc_bug_widget ".o.b$i" + #if {$darwin_cotvnc} {.o.b$i configure -state disabled} + #set darwin_cotvnc_blist(.o.b$i) 1 incr i checkbutton .o.b$i -anchor w -variable use_viewonly -text \ @@ -12692,27 +13356,31 @@ proc set_options {} { checkbutton .o.b$i -anchor w -variable use_raise_on_beep -text \ "Raise On Beep" if {$darwin_cotvnc} {.o.b$i configure -state disabled} + set darwin_cotvnc_blist(.o.b$i) 1 incr i checkbutton .o.b$i -anchor w -variable use_bgr233 -text \ "Use 8bit color (-bgr233)" if {$darwin_cotvnc} {.o.b$i configure -state disabled} + set darwin_cotvnc_blist(.o.b$i) 1 incr i checkbutton .o.b$i -anchor w -variable use_nojpeg -text \ "Do not use JPEG (-nojpeg)" if {$darwin_cotvnc} {.o.b$i configure -state disabled} + set darwin_cotvnc_blist(.o.b$i) 1 incr i checkbutton .o.b$i -anchor w -variable use_x11_macosx -text \ "Use X11 vncviewer on MacOSX" \ - -command {if {$use_x11_macosx} {set darwin_cotvnc 0} else {set darwin_cotvnc 1}; catch {destroy .o}; set_options} + -command {if {$use_x11_macosx} {set darwin_cotvnc 0} else {set darwin_cotvnc 1}; set_darwin_cotvnc_buttons} if {$uname != "Darwin"} {.o.b$i configure -state disabled} incr i menubutton .o.b$i -anchor w -menu .o.b$i.m -textvariable compresslevel_text -relief groove set compresslevel_text "Compress Level: $use_compresslevel" if {$darwin_cotvnc} {.o.b$i configure -state disabled} + set darwin_cotvnc_blist(.o.b$i) 1 menu .o.b$i.m -tearoff 0 for {set j -1} {$j < 10} {incr j} { @@ -12731,6 +13399,7 @@ proc set_options {} { menubutton .o.b$i -anchor w -menu .o.b$i.m -textvariable quality_text -relief groove set quality_text "Quality: $use_quality" if {$darwin_cotvnc} {.o.b$i configure -state disabled} + set darwin_cotvnc_blist(.o.b$i) 1 menu .o.b$i.m -tearoff 0 for {set j -1} {$j < 10} {incr j} { @@ -12808,6 +13477,7 @@ proc set_options {} { regsub {^ *} $t2 "" t2 regsub {^ *} $t3 "" t3 } + button .o.advanced -anchor w -text $t1 -command set_advanced_options button .o.clear -anchor w -text $t2 -command set_defaults button .o.delete -anchor w -text $t3 -command {destroy .o; delete_profile} @@ -12890,7 +13560,12 @@ proc print_help {} { help_advanced_opts set str [.ah.f.t get 1.0 end] puts "${b}Advanced Options Help:\n$str" - destroy .oh + destroy .ah + + help_ssvncviewer_opts + set str [.av.f.t get 1.0 end] + puts "${b}ssvncviewer Options Help:\n$str" + destroy .av help_certs set str [.ch.f.t get 1.0 end] @@ -13144,6 +13819,7 @@ if {! $is_windows} { catch {set uname [exec uname]} } + set darwin_cotvnc 0 if {$uname == "Darwin"} { if {! [info exists env(DISPLAY)]} { @@ -13163,6 +13839,9 @@ if {$uname == "Darwin"} { catch {option add *Button.font {System 10} widgetDefault} } +##for testing macosx +##set uname Darwin; set darwin_cotvnc 1 + set putty_pw "" global scroll_text_focus @@ -13357,6 +14036,8 @@ bind . <Shift-B2-ButtonRelease> {toggle_tsonly} bind .l <Shift-ButtonRelease> {toggle_tsonly} bind . <Control-h> {toggle_sshonly} bind . <Control-T> {to_ssvnc} +bind . <Control-a> {set_advanced_options} +bind . <Control-u> {set_ssvncviewer_options} global entered_gui_top button_gui_top set entered_gui_top 0 diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/build.unix b/x11vnc/misc/enhanced_tightvnc_viewer/build.unix index 2740f0e..d4899f2 100755 --- a/x11vnc/misc/enhanced_tightvnc_viewer/build.unix +++ b/x11vnc/misc/enhanced_tightvnc_viewer/build.unix @@ -134,14 +134,16 @@ libs="$tmp/libs" mkdir -p $libs || exit 1 for liba in libz.a libjpeg.a libssl.a libcrypto.a do - if [ "X$SSVNC_BUILD_NO_STATIC" != "X" ]; then + if [ "X$SSVNC_BUILD_STATIC" = "X" ]; then break fi for dir in /usr/lib /lib /usr/local/lib /usr/pkg/lib /usr/sfw/lib /usr/openwin/lib do if [ "$name" = "Linux.x86_64" -o "$name" = "Linux.ppc64" ] ; then dir64=`echo "$dir" | sed -e 's,lib,lib64,'` - if [ -d $dir64 ]; then + if [ "X$SSVNC_BUILD_NO_LINUX64" != "X" ]; then + : + elif [ -d $dir64 ]; then dir=$dir64 fi fi @@ -151,7 +153,7 @@ do fi done done -if [ "X$SSVNC_BUILD_NO_STATIC" = "X" ]; then +if [ "X$SSVNC_BUILD_STATIC" != "X" ]; then echo "Found these static archive libraries, will try to use them..." ls -ld $libs ls -l $libs @@ -180,7 +182,7 @@ END fi fi -if [ -d /var/tmp/LIBS -a "X$SSVNC_BUILD_NO_STATIC" = "X" ]; then +if [ -d /var/tmp/LIBS -a "X$SSVNC_BUILD_STATIC" != "X" ]; then LDFLAGS_OS="$LDFLAGS_OS -L/var/tmp/LIBS" fi @@ -435,6 +437,15 @@ if [ "X$SSVNC_BUILD_SKIP_VNCSTOREPW" = "X" ]; then cd "$start" cp -p $tmp/vncstorepw/vncstorepw $tmp/vncstorepw/lim_accept.so $dest echo "" + + cd $tmp/vncstorepw + make clean + + env LD_SSL="-L$start/$libs $LDFLAGS_OS" CPP_SSL="$CPPFLAGS_OS" make ultravnc_dsm_helper + + cd "$start" + cp -p $tmp/vncstorepw/ultravnc_dsm_helper $dest + echo "" fi diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/man/man1/ssvncviewer.1 b/x11vnc/misc/enhanced_tightvnc_viewer/man/man1/ssvncviewer.1 index 5c55402..8abe960 100644 --- a/x11vnc/misc/enhanced_tightvnc_viewer/man/man1/ssvncviewer.1 +++ b/x11vnc/misc/enhanced_tightvnc_viewer/man/man1/ssvncviewer.1 @@ -11,7 +11,7 @@ .\" License as specified in the file LICENCE.TXT that comes with the .\" TightVNC distribution. .\" -.TH ssvncviewer 1 "August 2008" "" "SSVNC" +.TH ssvncviewer 1 "October 2008" "" "SSVNC" .SH NAME ssvncviewer \- an X viewer client for VNC .SH SYNOPSIS @@ -246,6 +246,16 @@ Use alphablending transparency for local cursors requires: x11vnc server, both client and server must be 32bpp and same endianness. .TP +\fB\-scale\fR \fIstr\fR +Scale the desktop locally. The string "str" can +a floating point ratio, e.g. "0.9", or a fraction, +e.g. "3/4", or WxH, e.g. 1280x1024. Use "fit" +to fit in the current screen size. +Use "auto" to fit in the window size. +Note that scaling is done in software and can be slow +and requires more memory. "str" can also be set by +the env. var. SSVNC_SCALE. +.TP \fB\-ycrop\fR n Only show the top n rows of the framebuffer. For use with x11vnc \fB\-ncache\fR client caching option @@ -356,6 +366,11 @@ THAT supply -ultradsm to tell THIS viewer to modify the RFB data sent so as to work with the UltraVNC Server. For some reason, each RFB msg type must be sent twice under DSM. .TP +\fB\-chatonly\fR +Try to be a client that only does UltraVNC text chat. This +mode is used by x11vnc to present a chat window on the physical +X11 console (i.e. to chat with the person at the display). +.TP \fB-env\fR \fIVAR=VALUE\fR To save writing a shell script to set environment variables, specify as many as you need on the command line. For example, @@ -386,8 +401,10 @@ XENVIRONMENT or XAPPLRESDIR. 256 colors ~ -bgr233 default # of colors. 64 colors ~ -bgr222 / -use64 8 colors ~ -bgr111 / -use8 + Scale Viewer ~ -scale Set Y Crop (y-max) ~ -ycrop Set Scrollbar Width ~ -sbwidth + XGrabServer ~ -graball UltraVNC Extensions: diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/src/patches/_bundle b/x11vnc/misc/enhanced_tightvnc_viewer/src/patches/_bundle index bcd18a8..cf14543 100755 --- a/x11vnc/misc/enhanced_tightvnc_viewer/src/patches/_bundle +++ b/x11vnc/misc/enhanced_tightvnc_viewer/src/patches/_bundle @@ -1,7 +1,7 @@ #!/bin/sh rm -rf ./src/tmp/* || exit 1 -vers=1.0.20 +vers=1.0.21 cd .. || exit 1 diff --git a/x11vnc/misc/enhanced_tightvnc_viewer/src/patches/tight-vncviewer-full.patch b/x11vnc/misc/enhanced_tightvnc_viewer/src/patches/tight-vncviewer-full.patch index ce0c545..e8897a9 100644 --- a/x11vnc/misc/enhanced_tightvnc_viewer/src/patches/tight-vncviewer-full.patch +++ b/x11vnc/misc/enhanced_tightvnc_viewer/src/patches/tight-vncviewer-full.patch @@ -664,7 +664,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/Vncviewer vnc_unixsrc/vncview + diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/vncviewer/argsresources.c --- vnc_unixsrc.orig/vncviewer/argsresources.c 2007-02-04 17:10:31.000000000 -0500 -+++ vnc_unixsrc/vncviewer/argsresources.c 2008-09-14 14:27:29.000000000 -0400 ++++ vnc_unixsrc/vncviewer/argsresources.c 2008-10-17 22:04:19.000000000 -0400 @@ -31,9 +31,9 @@ char *fallback_resources[] = { @@ -677,7 +677,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v <Enter>: SelectionToVNC()\\n\ <Leave>: SelectionFromVNC()", -@@ -45,8 +45,58 @@ +@@ -45,8 +45,60 @@ "*viewport.useRight: True", "*viewport*Scrollbar*thumb: None", @@ -732,15 +732,24 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + "*desktop.baseTranslations:\ - <Key>F8: ShowPopup()\\n\ -+ <Key>F8: ShowPopup()\\n\ -+ <Key>F9: ToggleFullScreen()\\n\ ++ <KeyPress>F8: ShowPopup()\\n\ ++ <KeyRelease>F8: Noop()\\n\ ++ <KeyPress>F9: ToggleFullScreen()\\n\ ++ <KeyRelease>F9: Noop()\\n\ <ButtonPress>: SendRFBEvent()\\n\ <ButtonRelease>: SendRFBEvent()\\n\ <Motion>: SendRFBEvent()\\n\ -@@ -58,23 +108,58 @@ +@@ -58,23 +110,65 @@ "*serverDialog.dialog.value.translations: #override\\n\ <Key>Return: ServerDialogDone()", ++ "*scaleDialogPREV.dialog.label: Scale: Enter 'none' 'auto' 'aspect'\\nor fraction (e.g. 0.75 or 3/4).\\ncurrent value:", ++ ++ "*scaleDialog.dialog.label: Scale: Enter 'none' (same as '1' or '1.0'),\\na geometry WxH (e.g. 1280x1024), or\\na fraction (e.g. 0.75 or 3/4).\\nUse 'fit' for full screen size.\\nUse 'auto' to match window size.\\nCurrent value:", ++ "*scaleDialog.dialog.value:", ++ "*scaleDialog.dialog.value.translations: #override\\n\ ++ <Key>Return: ScaleDialogDone()", ++ + "*ycropDialog.dialog.label: Y Crop (max-height in pixels):", + "*ycropDialog.dialog.value:", + "*ycropDialog.dialog.value.translations: #override\\n\ @@ -751,10 +760,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + "*scbarDialog.dialog.value.translations: #override\\n\ + <Key>Return: ScbarDialogDone()", + -+ "*scaleDialog.dialog.label: Integer n for 1/n server scaling:", -+ "*scaleDialog.dialog.value:", -+ "*scaleDialog.dialog.value.translations: #override\\n\ -+ <Key>Return: ScaleDialogDone()", ++ "*scaleNDialog.dialog.label: Integer n for 1/n server scaling:", ++ "*scaleNDialog.dialog.value:", ++ "*scaleNDialog.dialog.value.translations: #override\\n\ ++ <Key>Return: ScaleNDialogDone()", + "*passwordDialog.dialog.label: Password:", "*passwordDialog.dialog.value:", @@ -801,7 +810,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v "*popup*button1.label: Dismiss popup", "*popup*button1.translations: #override\\n\ -@@ -84,7 +169,7 @@ +@@ -84,7 +178,7 @@ "*popup*button2.translations: #override\\n\ <Btn1Down>,<Btn1Up>: Quit()", @@ -810,7 +819,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v "*popup*button3.type: toggle", "*popup*button3.translations: #override\\n\ <Visible>: SetFullScreenState()\\n\ -@@ -105,16 +190,315 @@ +@@ -105,16 +199,323 @@ "*popup*button7.label: Send ctrl-alt-del", "*popup*button7.translations: #override\\n\ <Btn1Down>,<Btn1Up>: SendRFBEvent(keydown,Control_L)\ @@ -931,48 +940,56 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + <Visible>: Set8ColorsState()\\n\ + <Btn1Down>,<Btn1Up>: toggle() Toggle8Colors() HidePopup()", + -+ "*popup*button27.label: Set Y Crop (y-max)", ++ "*popup*button27.label: Scale Viewer", + "*popup*button27.translations: #override\\n\ -+ <Btn1Down>,<Btn1Up>: HidePopup() SetYCrop()", ++ <Btn1Down>,<Btn1Up>: HidePopup() SetScale()", + -+ "*popup*button28.label: Set Scrollbar Width", ++ "*popup*button28.label: Set Y Crop (y-max)", + "*popup*button28.translations: #override\\n\ -+ <Btn1Down>,<Btn1Up>: HidePopup() SetScbar()", ++ <Btn1Down>,<Btn1Up>: HidePopup() SetYCrop()", + -+ "*popup*button29.label: UltraVNC Extensions:", ++ "*popup*button29.label: Set Scrollbar Width", + "*popup*button29.translations: #override\\n\ -+ <Btn1Down>,<Btn1Up>: HidePopup()", ++ <Btn1Down>,<Btn1Up>: HidePopup() SetScbar()", + -+ "*popup*button30.label: - Set 1/n Server Scale", ++ "*popup*button30.label: XGrabServer", ++ "*popup*button30.type: toggle", + "*popup*button30.translations: #override\\n\ -+ <Btn1Down>,<Btn1Up>: HidePopup() ShowScaleN()", ++ <Visible>: SetXGrabState()\\n\ ++ <Btn1Down>,<Btn1Up>: toggle() ToggleXGrab() HidePopup()", + -+ "*popup*button31.label: - Text Chat", -+ "*popup*button31.type: toggle", ++ "*popup*button31.label: UltraVNC Extensions:", + "*popup*button31.translations: #override\\n\ ++ <Btn1Down>,<Btn1Up>: HidePopup()", ++ ++ "*popup*button32.label: - Set 1/n Server Scale", ++ "*popup*button32.translations: #override\\n\ ++ <Btn1Down>,<Btn1Up>: HidePopup() ShowScaleN()", ++ ++ "*popup*button33.label: - Text Chat", ++ "*popup*button33.type: toggle", ++ "*popup*button33.translations: #override\\n\ + <Visible>: SetTextChatState()\\n\ + <Btn1Down>,<Btn1Up>: toggle() ToggleTextChat() HidePopup()", + -+ "*popup*button32.label: - File Transfer", -+ "*popup*button32.type: toggle", -+ "*popup*button32.translations: #override\\n\ ++ "*popup*button34.label: - File Transfer", ++ "*popup*button34.type: toggle", ++ "*popup*button34.translations: #override\\n\ + <Visible>: SetFileXferState()\\n\ + <Btn1Down>,<Btn1Up>: toggle() ToggleFileXfer() HidePopup()", + -+ "*popup*button33.label: - Single Window", -+ "*popup*button33.type: toggle", -+ "*popup*button33.translations: #override\\n\ ++ "*popup*button35.label: - Single Window", ++ "*popup*button35.type: toggle", ++ "*popup*button35.translations: #override\\n\ + <Visible>: SetSingleWindowState()\\n\ + <Btn1Down>,<Btn1Up>: toggle() ToggleSingleWindow() HidePopup()", + -+ "*popup*button34.label: - Disable Remote Input", -+ "*popup*button34.type: toggle", -+ "*popup*button34.translations: #override\\n\ ++ "*popup*button36.label: - Disable Remote Input", ++ "*popup*button36.type: toggle", ++ "*popup*button36.translations: #override\\n\ + <Visible>: SetServerInputState()\\n\ + <Btn1Down>,<Btn1Up>: toggle() ToggleServerInput() HidePopup()", + -+ "*popup*button35.label:", -+ "*popup*button36.label:", + "*popup*button37.label:", + "*popup*button38.label:", + @@ -1131,7 +1148,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v NULL }; -@@ -124,7 +508,7 @@ +@@ -124,7 +525,7 @@ * from a dialog box. */ @@ -1140,7 +1157,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v int vncServerPort = 0; -@@ -135,6 +519,7 @@ +@@ -135,6 +536,7 @@ */ AppData appData; @@ -1148,7 +1165,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v static XtResource appDataResourceList[] = { {"shareDesktop", "ShareDesktop", XtRBool, sizeof(Bool), -@@ -155,14 +540,38 @@ +@@ -155,14 +557,38 @@ {"userLogin", "UserLogin", XtRString, sizeof(String), XtOffsetOf(AppData, userLogin), XtRImmediate, (XtPointer) 0}, @@ -1189,7 +1206,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v {"nColours", "NColours", XtRInt, sizeof(int), XtOffsetOf(AppData, nColours), XtRImmediate, (XtPointer) 256}, -@@ -179,9 +588,12 @@ +@@ -179,9 +605,12 @@ {"requestedDepth", "RequestedDepth", XtRInt, sizeof(int), XtOffsetOf(AppData, requestedDepth), XtRImmediate, (XtPointer) 0}, @@ -1203,7 +1220,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v {"wmDecorationWidth", "WmDecorationWidth", XtRInt, sizeof(int), XtOffsetOf(AppData, wmDecorationWidth), XtRImmediate, (XtPointer) 4}, -@@ -191,6 +603,9 @@ +@@ -191,6 +620,9 @@ {"popupButtonCount", "PopupButtonCount", XtRInt, sizeof(int), XtOffsetOf(AppData, popupButtonCount), XtRImmediate, (XtPointer) 0}, @@ -1213,21 +1230,16 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v {"debug", "Debug", XtRBool, sizeof(Bool), XtOffsetOf(AppData, debug), XtRImmediate, (XtPointer) False}, -@@ -206,8 +621,13 @@ - {"bumpScrollPixels", "BumpScrollPixels", XtRInt, sizeof(int), +@@ -207,7 +639,7 @@ XtOffsetOf(AppData, bumpScrollPixels), XtRImmediate, (XtPointer) 20}, -+#if 0 {"compressLevel", "CompressionLevel", XtRInt, sizeof(int), - XtOffsetOf(AppData, compressLevel), XtRImmediate, (XtPointer) -1}, -+#endif -+ -+ {"compressLevel", "CompressionLevel", XtRInt, sizeof(int), +- XtOffsetOf(AppData, compressLevel), XtRImmediate, (XtPointer) -1}, + XtOffsetOf(AppData, compressLevel), XtRImmediate, (XtPointer) 7}, {"qualityLevel", "QualityLevel", XtRInt, sizeof(int), XtOffsetOf(AppData, qualityLevel), XtRImmediate, (XtPointer) 6}, -@@ -218,14 +638,55 @@ +@@ -218,14 +650,58 @@ {"useRemoteCursor", "UseRemoteCursor", XtRBool, sizeof(Bool), XtOffsetOf(AppData, useRemoteCursor), XtRImmediate, (XtPointer) True}, @@ -1254,13 +1266,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + {"grabAll", "GrabAll", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, grabAll), XtRImmediate, (XtPointer) False}, + -+#if 0 -+ {"useBackingstore", "UseBackingstore", XtRBool, sizeof(Bool), -+ XtOffsetOf(AppData, useBackingstore), XtRImmediate, (XtPointer) True}, -+#else -+ {"useBackingstore", "UseBackingstore", XtRBool, sizeof(Bool), -+ XtOffsetOf(AppData, useBackingstore), XtRImmediate, (XtPointer) False}, -+#endif ++ {"useXserverBackingStore", "UseXserverBackingStore", XtRBool, sizeof(Bool), ++ XtOffsetOf(AppData, useXserverBackingStore), XtRImmediate, (XtPointer) False}, + + {"overrideRedir", "OverrideRedir", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, overrideRedir), XtRImmediate, (XtPointer) True}, @@ -1277,15 +1284,23 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + {"chatActive", "ChatActive", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, chatActive), XtRImmediate, (XtPointer) False}, + ++ {"chatOnly", "ChatOnly", XtRBool, sizeof(Bool), ++ XtOffsetOf(AppData, chatOnly), XtRImmediate, (XtPointer) False}, ++ + {"fileActive", "FileActive", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, fileActive), XtRImmediate, (XtPointer) False}, + + {"popupFix", "PopupFix", XtRBool, sizeof(Bool), -+ XtOffsetOf(AppData, popupFix), XtRImmediate, (XtPointer) False} ++ XtOffsetOf(AppData, popupFix), XtRImmediate, (XtPointer) False}, ++ ++ {"scale", "Scale", XtRString, sizeof(String), ++ XtOffsetOf(AppData, scale), XtRImmediate, (XtPointer) 0} ++ ++ /* check commas */ }; -@@ -242,8 +703,26 @@ +@@ -242,8 +718,25 @@ {"-noraiseonbeep", "*raiseOnBeep", XrmoptionNoArg, "False"}, {"-passwd", "*passwordFile", XrmoptionSepArg, 0}, {"-user", "*userLogin", XrmoptionSepArg, 0}, @@ -1307,13 +1322,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + {"-sbwidth", "*sbwidth", XrmoptionSepArg, 0}, + {"-env", "*envDummy", XrmoptionSepArg, 0}, + {"-ycrop", "*yCrop", XrmoptionSepArg, 0}, -+ {"-sbwidth", "*sbwidth", XrmoptionSepArg, 0}, + {"-rawlocal", "*useRawLocal", XrmoptionNoArg, "True"}, + {"-alpha", "*useCursorAlpha", XrmoptionNoArg, "True"}, {"-owncmap", "*forceOwnCmap", XrmoptionNoArg, "True"}, {"-truecolor", "*forceTrueColour", XrmoptionNoArg, "True"}, {"-truecolour", "*forceTrueColour", XrmoptionNoArg, "True"}, -@@ -253,7 +732,19 @@ +@@ -253,7 +746,21 @@ {"-nojpeg", "*enableJPEG", XrmoptionNoArg, "False"}, {"-nocursorshape", "*useRemoteCursor", XrmoptionNoArg, "False"}, {"-x11cursor", "*useX11Cursor", XrmoptionNoArg, "True"}, @@ -1326,17 +1340,21 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + {"-grabkeyboard", "*grabKeyboard", XrmoptionNoArg, "True"}, + {"-nograbkeyboard","*grabKeyboard", XrmoptionNoArg, "False"}, + {"-nooverride", "*overrideRedir", XrmoptionNoArg, "False"}, -+ {"-bs", "*useBackingstore", XrmoptionNoArg, "True"}, -+ {"-nobs", "*useBackingstore", XrmoptionNoArg, "False"}, ++ {"-bs", "*useXserverBackingStore", XrmoptionNoArg, "True"}, ++ {"-nobs", "*useXserverBackingStore", XrmoptionNoArg, "False"}, + {"-popupfix", "*popupFix", XrmoptionNoArg, "True"}, + {"-noshm", "*useShm", XrmoptionNoArg, "False"}, -+ {"-termchat", "*termChat", XrmoptionNoArg, "True"} ++ {"-termchat", "*termChat", XrmoptionNoArg, "True"}, ++ {"-chatonly", "*chatOnly", XrmoptionNoArg, "True"}, ++ {"-scale", "*scale", XrmoptionSepArg, 0}, }; -@@ -268,15 +759,77 @@ +@@ -267,16 +774,84 @@ + static XtActionsRec actions[] = { {"SendRFBEvent", SendRFBEvent}, {"ShowPopup", ShowPopup}, ++ {"Noop", Noop}, {"HidePopup", HidePopup}, + {"HideScaleN", HideScaleN}, + {"HideQuality", HideQuality}, @@ -1352,11 +1370,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v {"ServerDialogDone", ServerDialogDone}, + {"YCropDialogDone", YCropDialogDone}, + {"ScbarDialogDone", ScbarDialogDone}, ++ {"ScaleNDialogDone", ScaleNDialogDone}, + {"ScaleDialogDone", ScaleDialogDone}, {"PasswordDialogDone", PasswordDialogDone}, {"Pause", Pause}, {"RunCommand", RunCommand}, {"Quit", Quit}, ++ {"HideChat", HideChat}, + {"Toggle8bpp", Toggle8bpp}, + {"Toggle16bpp", Toggle16bpp}, + {"ToggleFullColor", ToggleFullColor}, @@ -1377,7 +1397,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + {"ToggleSingleWindow", ToggleSingleWindow}, + {"ToggleTextChat", ToggleTextChat}, + {"ToggleFileXfer", ToggleFileXfer}, ++ {"ToggleXGrab", ToggleXGrab}, + {"DoServerScale", DoServerScale}, ++ {"SetScale", SetScale}, + {"SetYCrop", SetYCrop}, + {"SetScbar", SetScbar}, + {"ShowScaleN", ShowScaleN}, @@ -1408,11 +1430,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + {"SetServerInputState", SetServerInputState}, + {"SetSingleWindowState", SetSingleWindowState}, + {"SetTextChatState", SetTextChatState}, -+ {"SetFileXferState", SetFileXferState} ++ {"SetFileXferState", SetFileXferState}, ++ {"SetXGrabState", SetXGrabState} }; -@@ -302,11 +855,13 @@ +@@ -302,11 +877,14 @@ void usage(void) { @@ -1424,11 +1447,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v "Usage: %s [<OPTIONS>] [<HOST>][:<DISPLAY#>]\n" " %s [<OPTIONS>] [<HOST>][::<PORT#>]\n" + " %s [<OPTIONS>] exec=[CMD ARGS...]\n" ++ " %s [<OPTIONS>] fd=n\n" + " %s [<OPTIONS>] /path/to/unix/socket\n" " %s [<OPTIONS>] -listen [<DISPLAY#>]\n" " %s -help\n" "\n" -@@ -332,10 +887,209 @@ +@@ -332,10 +910,230 @@ " -autopass\n" "\n" "Option names may be abbreviated, e.g. -bgr instead of -bgr233.\n" @@ -1459,7 +1483,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + " that does not involve a listening socket. This mode does\n" + " not work for -listen reverse connections.\n" + "\n" -+ " Note: If the host:port contains a '/' it is interpreted as a\n" ++ " If the host:port is specified as \"fd=n\" then it is assumed\n" ++ " n is an already opened file descriptor to the socket. (i.e\n" ++ " the parent did fork+exec)\n" ++ "\n" ++ " If the host:port contains a '/' it is interpreted as a\n" + " unix-domain socket (AF_LOCAL insead of AF_INET)\n" + "\n" + " -multilisten As in -listen (reverse connection listening) except\n" @@ -1487,6 +1515,16 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + " requires: x11vnc server, both client and server\n" + " must be 32bpp and same endianness.\n" + "\n" ++ " -scale str Scale the desktop locally. The string \"str\" can\n" ++ " a floating point ratio, e.g. \"0.9\", or a fraction,\n" ++ " e.g. \"3/4\", or WxH, e.g. 1280x1024. Use \"fit\"\n" ++ " to fit in the current screen size. Use \"auto\" to\n" ++ " fit in the window size.\n" ++ "\n" ++ " Note that scaling is done in software and can be slow\n" ++ " and requires more memory. \"str\" can also be set by\n" ++ " the env. var. SSVNC_SCALE.\n" ++ "\n" + " -ycrop n Only show the top n rows of the framebuffer. For\n" + " use with x11vnc -ncache client caching option\n" + " to help \"hide\" the pixel cache region.\n" @@ -1587,6 +1625,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + " RFB data sent so as to work with the UltraVNC Server. For\n" + " some reason, each RFB msg type must be sent twice under DSM.\n" + "\n" ++ " -chatonly Try to be a client that only does UltraVNC text chat. This\n" ++ " mode is used by x11vnc to present a chat window on the\n" ++ " physical X11 console (i.e. chat with the person at the\n" ++ " display).\n" ++ "\n" + " -env VAR=VALUE To save writing a shell script to set environment variables,\n" + " specify as many as you need on the command line. For\n" + " example, -env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi\n" @@ -1615,8 +1658,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + " 256 colors ~ -bgr233 default # of colors.\n" + " 64 colors ~ -bgr222 / -use64\n" + " 8 colors ~ -bgr111 / -use8\n" ++ " Scale Viewer ~ -scale\n" + " Set Y Crop (y-max) ~ -ycrop\n" + " Set Scrollbar Width ~ -sbwidth\n" ++ " XGrabServer ~ -graball\n" + "\n" + " UltraVNC Extensions:\n" + "\n" @@ -1631,7 +1676,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + " Note: the Ultravnc extensions only apply to servers that support\n" + " them. x11vnc/libvncserver supports some of them.\n" + "\n" -+ "\n", programName, programName, programName, programName, programName, programName); ++ "\n", programName, programName, programName, programName, programName, programName, programName); exit(1); } +#if 0 @@ -1640,18 +1685,30 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v /* -@@ -350,6 +1104,7 @@ - int i; - char *vncServerName, *colonPos; - int len, portOffset; -+ int disp; +@@ -347,73 +1145,153 @@ + void + GetArgsAndResources(int argc, char **argv) + { +- int i; +- char *vncServerName, *colonPos; +- int len, portOffset; ++ int i; ++ char *vncServerName, *colonPos; ++ int len, portOffset; ++ int disp; /* Turn app resource specs into our appData structure for the rest of the program to use */ -@@ -357,6 +1112,29 @@ - XtGetApplicationResources(toplevel, &appData, appDataResourceList, - XtNumber(appDataResourceList), 0, 0); +- XtGetApplicationResources(toplevel, &appData, appDataResourceList, +- XtNumber(appDataResourceList), 0, 0); ++ XtGetApplicationResources(toplevel, &appData, appDataResourceList, ++ XtNumber(appDataResourceList), 0, 0); ++ ++ /* ++ * we allow setting of some by env, to avoid clash with other ++ * viewer's cmdlines (e.g. change viewer in SSVNC). ++ */ + if (getenv("VNCVIEWER_ALPHABLEND")) { + appData.useCursorAlpha = True; + } @@ -1667,66 +1724,175 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/argsresources.c vnc_unixsrc/v + appData.yCrop = n; + } + } ++ if (getenv("VNCVIEWER_RFBVERSION") && strcmp(getenv("VNCVIEWER_RFBVERSION"), "")) { ++ appData.rfbVersion = strdup(getenv("VNCVIEWER_RFBVERSION")); ++ } ++ if (getenv("VNCVIEWER_ENCODINGS") && strcmp(getenv("VNCVIEWER_ENCODINGS"), "")) { ++ appData.encodingsString = strdup(getenv("VNCVIEWER_ENCODINGS")); ++ } ++ if (getenv("VNCVIEWER_NOBELL")) { ++ appData.useBell = False; ++ } ++ if (getenv("VNCVIEWER_X11CURSOR")) { ++ appData.useX11Cursor = True; ++ } ++ if (getenv("VNCVIEWER_RAWLOCAL")) { ++ appData.useRawLocal = True; ++ } ++ if (getenv("VNCVIEWER_SBWIDTH")) { ++ int n = atoi(getenv("VNCVIEWER_SBWIDTH")); ++ if (n != 0) { ++ appData.sbWidth = n; ++ } ++ } + if (getenv("VNCVIEWER_ULTRADSM")) { + appData.ultraDSM = True; + } + if (getenv("SSVNC_ULTRA_DSM") && strcmp(getenv("SSVNC_ULTRA_DSM"), "")) { + appData.ultraDSM = True; + } ++ if (getenv("SSVNC_NO_ULTRA_DSM")) { ++ appData.ultraDSM = False; ++ } ++ if (getenv("SSVNC_SCALE") && strcmp(getenv("SSVNC_SCALE"), "")) { ++ if (appData.scale == NULL) { ++ appData.scale = strdup(getenv("SSVNC_SCALE")); ++ } ++ } + -+ + /* Add our actions to the actions table so they can be used in widget resource specs */ -@@ -376,6 +1154,10 @@ - return; - } +- XtAppAddActions(appContext, actions, XtNumber(actions)); ++ XtAppAddActions(appContext, actions, XtNumber(actions)); + /* Check any remaining command-line arguments. If -listen was specified + there should be none. Otherwise the only argument should be the VNC + server name. If not given then pop up a dialog box and wait for the + server name to be entered. */ + +- if (listenSpecified) { +- if (argc != 1) { +- fprintf(stderr,"\n%s -listen: invalid command line argument: %s\n", +- programName, argv[1]); +- usage(); +- } +- return; +- } +- +- if (argc == 1) { +- vncServerName = DoServerDialog(); +- appData.passwordDialog = True; +- } else if (argc != 2) { +- usage(); +- } else { +- vncServerName = argv[1]; +- +- if (!isatty(0)) +- appData.passwordDialog = True; +- if (vncServerName[0] == '-') +- usage(); +- } +- +- if (strlen(vncServerName) > 255) { +- fprintf(stderr,"VNC server name too long\n"); +- exit(1); +- } +- +- colonPos = strchr(vncServerName, ':'); +- if (colonPos == NULL) { +- /* No colon -- use default port number */ +- strcpy(vncServerHost, vncServerName); +- vncServerPort = SERVER_PORT_OFFSET; +- } else { +- memcpy(vncServerHost, vncServerName, colonPos - vncServerName); +- vncServerHost[colonPos - vncServerName] = '\0'; +- len = strlen(colonPos + 1); +- portOffset = SERVER_PORT_OFFSET; +- if (colonPos[1] == ':') { +- /* Two colons -- interpret as a port number */ +- colonPos++; +- len--; +- portOffset = 0; +- } +- if (!len || strspn(colonPos + 1, "0123456789") != len) { +- usage(); +- } +- vncServerPort = atoi(colonPos + 1) + portOffset; +- } ++ if (listenSpecified) { ++ if (argc != 1) { ++ fprintf(stderr,"\n%s -listen: invalid command line argument: %s\n", ++ programName, argv[1]); ++ usage(); ++ } ++ return; ++ } ++ + if (appData.useBGR233 && appData.useBGR565) { + appData.useBGR233 = 0; + } + - if (argc == 1) { - vncServerName = DoServerDialog(); - appData.passwordDialog = True; -@@ -390,13 +1172,23 @@ - usage(); - } - ++ if (argc == 1) { ++ vncServerName = DoServerDialog(); ++ appData.passwordDialog = True; ++ } else if (argc != 2) { ++ usage(); ++ } else { ++ vncServerName = argv[1]; + - if (strlen(vncServerName) > 255) { - fprintf(stderr,"VNC server name too long\n"); - exit(1); - } - - colonPos = strchr(vncServerName, ':'); -- if (colonPos == NULL) { -+ if (strstr(vncServerName, "exec=") == vncServerName) { -+ /* special exec-external-command case */ -+ strcpy(vncServerHost, vncServerName); -+ vncServerPort = SERVER_PORT_OFFSET; -+ if (! appData.ultraDSM) { -+ if (strstr(vncServerName, "ultravnc_dsm_helper")) { -+ appData.ultraDSM = True; -+ } -+ } -+ } else if (colonPos == NULL) { - /* No colon -- use default port number */ - strcpy(vncServerHost, vncServerName); - vncServerPort = SERVER_PORT_OFFSET; -@@ -414,6 +1206,13 @@ - if (!len || strspn(colonPos + 1, "0123456789") != len) { - usage(); - } ++ if (!isatty(0)) { ++ appData.passwordDialog = True; ++ } ++ if (vncServerName[0] == '-') { ++ usage(); ++ } ++ } ++ ++ ++ if (strlen(vncServerName) > 255) { ++ fprintf(stderr,"VNC server name too long\n"); ++ exit(1); ++ } ++ ++ colonPos = strchr(vncServerName, ':'); ++ if (strstr(vncServerName, "exec=") == vncServerName) { ++ /* special exec-external-command case */ ++ strcpy(vncServerHost, vncServerName); ++ vncServerPort = SERVER_PORT_OFFSET; ++ } else if (strstr(vncServerName, "fd=") == vncServerName) { ++ /* special exec-external-command case */ ++ strcpy(vncServerHost, vncServerName); ++ vncServerPort = SERVER_PORT_OFFSET; ++ } else if (colonPos == NULL) { ++ /* No colon -- use default port number */ ++ strcpy(vncServerHost, vncServerName); ++ vncServerPort = SERVER_PORT_OFFSET; ++ } else { ++ memcpy(vncServerHost, vncServerName, colonPos - vncServerName); ++ vncServerHost[colonPos - vncServerName] = '\0'; ++ len = strlen(colonPos + 1); ++ portOffset = SERVER_PORT_OFFSET; ++ if (colonPos[1] == ':') { ++ /* Two colons -- interpret as a port number */ ++ colonPos++; ++ len--; ++ portOffset = 0; ++ } ++ if (!len || strspn(colonPos + 1, "0123456789") != len) { ++ usage(); ++ } +#if 0 - vncServerPort = atoi(colonPos + 1) + portOffset; ++ vncServerPort = atoi(colonPos + 1) + portOffset; +#else -+ disp = atoi(colonPos + 1); -+ if (portOffset != 0 && disp >= 100) -+ portOffset = 0; -+ vncServerPort = disp + portOffset; ++ disp = atoi(colonPos + 1); ++ if (portOffset != 0 && disp >= 100) { ++ portOffset = 0; ++ } ++ vncServerPort = disp + portOffset; +#endif - } ++ } } diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/colour.c vnc_unixsrc/vncviewer/colour.c --- vnc_unixsrc.orig/vncviewer/colour.c 2002-04-30 09:07:31.000000000 -0400 @@ -2066,7 +2232,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/colour.c vnc_unixsrc/vncviewe diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/corre.c vnc_unixsrc/vncviewer/corre.c --- vnc_unixsrc.orig/vncviewer/corre.c 2000-06-11 08:00:53.000000000 -0400 -+++ vnc_unixsrc/vncviewer/corre.c 2007-02-17 22:50:15.000000000 -0500 ++++ vnc_unixsrc/vncviewer/corre.c 2008-10-05 15:16:01.000000000 -0400 @@ -29,6 +29,18 @@ #define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP) #define CARDBPP CONCAT2E(CARD,BPP) @@ -2075,7 +2241,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/corre.c vnc_unixsrc/vncviewer + { \ + XGCValues _gcv; \ + _gcv.foreground = color; \ -+ if (!appData.useBackingstore) { \ ++ if (!appData.useXserverBackingStore) { \ + FillScreen(x, y, w, h, _gcv.foreground); \ + } else { \ + XChangeGC(dpy, gc, GCForeground, &_gcv); \ @@ -2149,17 +2315,22 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cp_it vnc_unixsrc/vncviewer/c +ls -l ./vncviewer $dest $yy $HOME/etv_col/Linux.i686/vncviewer diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewer/cursor.c --- vnc_unixsrc.orig/vncviewer/cursor.c 2003-01-15 04:46:52.000000000 -0500 -+++ vnc_unixsrc/vncviewer/cursor.c 2007-03-17 22:48:34.000000000 -0400 -@@ -39,7 +39,7 @@ ++++ vnc_unixsrc/vncviewer/cursor.c 2008-10-18 09:35:02.000000000 -0400 +@@ -38,8 +38,11 @@ + static Bool prevSoftCursorSet = False; - static Pixmap rcSavedArea; +-static Pixmap rcSavedArea; -static CARD8 *rcSource, *rcMask; ++static Pixmap rcSavedArea, rcSavedArea_0; ++static int rcSavedArea_w = -1, rcSavedArea_h = -1; ++static char *rcSavedScale = NULL; ++static int rcSavedScale_len = 0; +static CARD8 *rcSource = NULL, *rcMask; static int rcHotX, rcHotY, rcWidth, rcHeight; static int rcCursorX = 0, rcCursorY = 0; static int rcLockX, rcLockY, rcLockWidth, rcLockHeight; -@@ -48,8 +48,8 @@ +@@ -48,8 +51,13 @@ static Bool SoftCursorInLockedArea(void); static void SoftCursorCopyArea(int oper); static void SoftCursorDraw(void); @@ -2167,78 +2338,488 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe -static void FreeX11Cursor(); +void FreeSoftCursor(void); +void FreeX11Cursor(); ++ ++extern XImage *image; ++extern XImage *image_scale; ++extern int scale_x, scale_y; ++int scale_round(int n, double factor); /* Copied from Xvnc/lib/font/util/utilbitmap.c */ static unsigned char _reverse_byte[0x100] = { -@@ -195,6 +195,7 @@ - buf = malloc(bytesMaskData); - if (buf == NULL) { - free(rcSource); -+ rcSource = NULL; - return False; - } +@@ -91,6 +99,8 @@ + static Bool prevXCursorSet = False; + static Cursor prevXCursor; -@@ -209,6 +210,7 @@ - /* Read and convert background and foreground colors. */ - if (!ReadFromRFBServer((char *)&rgb, sz_rfbXCursorColors)) { - free(rcSource); -+ rcSource = NULL; - free(buf); - return False; - } -@@ -218,6 +220,7 @@ - /* Read 1bpp pixel data into a temporary buffer. */ - if (!ReadFromRFBServer(buf, bytesMaskData)) { - free(rcSource); -+ rcSource = NULL; - free(buf); - return False; - } -@@ -257,6 +260,7 @@ ++extern double scale_factor_x; ++extern double scale_factor_y; - if (!ReadFromRFBServer((char *)rcSource, width * height * bytesPerPixel)) { - free(rcSource); -+ rcSource = NULL; - free(buf); - return False; - } -@@ -267,6 +271,7 @@ + Bool HandleXCursor(int xhot, int yhot, int width, int height) + { +@@ -167,148 +177,179 @@ - if (!ReadFromRFBServer(buf, bytesMaskData)) { - free(rcSource); -+ rcSource = NULL; - free(buf); - return False; - } -@@ -274,6 +279,7 @@ - rcMask = malloc(width * height); - if (rcMask == NULL) { - free(rcSource); -+ rcSource = NULL; - free(buf); - return False; - } -@@ -429,41 +435,63 @@ - rcLockY + rcLockHeight > rcCursorY - rcHotY); + Bool HandleCursorShape(int xhot, int yhot, int width, int height, CARD32 enc) + { +- int bytesPerPixel; +- size_t bytesPerRow, bytesMaskData; +- Drawable dr; +- rfbXCursorColors rgb; +- CARD32 colors[2]; +- char *buf; +- CARD8 *ptr; +- int x, y, b; +- +- bytesPerPixel = myFormat.bitsPerPixel / 8; +- bytesPerRow = (width + 7) / 8; +- bytesMaskData = bytesPerRow * height; +- dr = DefaultRootWindow(dpy); +- +- FreeSoftCursor(); ++ int bytesPerPixel; ++ size_t bytesPerRow, bytesMaskData; ++ Drawable dr; ++ rfbXCursorColors rgb; ++ CARD32 colors[2]; ++ char *buf; ++ CARD8 *ptr; ++ int x, y, b; ++ ++ bytesPerPixel = myFormat.bitsPerPixel / 8; ++ bytesPerRow = (width + 7) / 8; ++ bytesMaskData = bytesPerRow * height; ++ dr = DefaultRootWindow(dpy); + +- if (width * height == 0) +- return True; +- +- /* Allocate memory for pixel data and temporary mask data. */ ++ FreeSoftCursor(); + +- rcSource = malloc(width * height * bytesPerPixel); +- if (rcSource == NULL) +- return False; +- +- buf = malloc(bytesMaskData); +- if (buf == NULL) { +- free(rcSource); +- return False; +- } ++ if (width * height == 0) { ++ return True; ++ } + +- /* Read and decode cursor pixel data, depending on the encoding type. */ ++ /* Allocate memory for pixel data and temporary mask data. */ + +- if (enc == rfbEncodingXCursor) { +- if (appData.useX11Cursor) { +- HandleXCursor(xhot, yhot, width, height); +- return True; +- } ++ rcSource = malloc(width * height * bytesPerPixel); ++ if (rcSource == NULL) { ++ return False; ++ } + +- /* Read and convert background and foreground colors. */ +- if (!ReadFromRFBServer((char *)&rgb, sz_rfbXCursorColors)) { +- free(rcSource); +- free(buf); +- return False; +- } +- colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue); +- colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue); ++ buf = malloc(bytesMaskData); ++ if (buf == NULL) { ++ free(rcSource); ++ rcSource = NULL; ++ return False; ++ } + +- /* Read 1bpp pixel data into a temporary buffer. */ +- if (!ReadFromRFBServer(buf, bytesMaskData)) { +- free(rcSource); +- free(buf); +- return False; +- } ++ /* Read and decode cursor pixel data, depending on the encoding type. */ + +- /* Convert 1bpp data to byte-wide color indices. */ +- ptr = rcSource; +- for (y = 0; y < height; y++) { +- for (x = 0; x < width / 8; x++) { +- for (b = 7; b >= 0; b--) { +- *ptr = buf[y * bytesPerRow + x] >> b & 1; +- ptr += bytesPerPixel; +- } +- } +- for (b = 7; b > 7 - width % 8; b--) { +- *ptr = buf[y * bytesPerRow + x] >> b & 1; +- ptr += bytesPerPixel; +- } +- } ++ if (enc == rfbEncodingXCursor) { ++ if (appData.useX11Cursor) { ++ HandleXCursor(xhot, yhot, width, height); ++ return True; ++ } ++ ++ /* Read and convert background and foreground colors. */ ++ if (!ReadFromRFBServer((char *)&rgb, sz_rfbXCursorColors)) { ++ free(rcSource); ++ rcSource = NULL; ++ free(buf); ++ return False; ++ } ++ colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue); ++ colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue); ++ ++ /* Read 1bpp pixel data into a temporary buffer. */ ++ if (!ReadFromRFBServer(buf, bytesMaskData)) { ++ free(rcSource); ++ rcSource = NULL; ++ free(buf); ++ return False; ++ } ++ ++ /* Convert 1bpp data to byte-wide color indices. */ ++ ptr = rcSource; ++ for (y = 0; y < height; y++) { ++ for (x = 0; x < width / 8; x++) { ++ for (b = 7; b >= 0; b--) { ++ *ptr = buf[y * bytesPerRow + x] >> b & 1; ++ ptr += bytesPerPixel; ++ } ++ } ++ for (b = 7; b > 7 - width % 8; b--) { ++ *ptr = buf[y * bytesPerRow + x] >> b & 1; ++ ptr += bytesPerPixel; ++ } ++ } ++ ++ /* Convert indices into the actual pixel values. */ ++ switch (bytesPerPixel) { ++ case 1: ++ for (x = 0; x < width * height; x++) { ++ rcSource[x] = (CARD8)colors[rcSource[x]]; ++ } ++ break; ++ case 2: ++ for (x = 0; x < width * height; x++) { ++ ((CARD16 *)rcSource)[x] = (CARD16)colors[rcSource[x * 2]]; ++ } ++ break; ++ case 4: ++ for (x = 0; x < width * height; x++) { ++ ((CARD32 *)rcSource)[x] = colors[rcSource[x * 4]]; ++ } ++ break; ++ } ++ ++ } else { /* enc == rfbEncodingRichCursor */ ++ if (!ReadFromRFBServer((char *)rcSource, width * height * bytesPerPixel)) { ++ free(rcSource); ++ rcSource = NULL; ++ free(buf); ++ return False; ++ } ++ } + +- /* Convert indices into the actual pixel values. */ +- switch (bytesPerPixel) { +- case 1: +- for (x = 0; x < width * height; x++) +- rcSource[x] = (CARD8)colors[rcSource[x]]; +- break; +- case 2: +- for (x = 0; x < width * height; x++) +- ((CARD16 *)rcSource)[x] = (CARD16)colors[rcSource[x * 2]]; +- break; +- case 4: +- for (x = 0; x < width * height; x++) +- ((CARD32 *)rcSource)[x] = colors[rcSource[x * 4]]; +- break; +- } ++ /* Read and decode mask data. */ + +- } else { /* enc == rfbEncodingRichCursor */ ++ if (!ReadFromRFBServer(buf, bytesMaskData)) { ++ free(rcSource); ++ rcSource = NULL; ++ free(buf); ++ return False; ++ } + +- if (!ReadFromRFBServer((char *)rcSource, width * height * bytesPerPixel)) { +- free(rcSource); +- free(buf); +- return False; +- } ++ rcMask = malloc(width * height); ++ if (rcMask == NULL) { ++ free(rcSource); ++ rcSource = NULL; ++ free(buf); ++ return False; ++ } + +- } ++ ptr = rcMask; ++ for (y = 0; y < height; y++) { ++ for (x = 0; x < width / 8; x++) { ++ for (b = 7; b >= 0; b--) { ++ *ptr++ = buf[y * bytesPerRow + x] >> b & 1; ++ } ++ } ++ for (b = 7; b > 7 - width % 8; b--) { ++ *ptr++ = buf[y * bytesPerRow + x] >> b & 1; ++ } ++ } + +- /* Read and decode mask data. */ ++ free(buf); + +- if (!ReadFromRFBServer(buf, bytesMaskData)) { +- free(rcSource); +- free(buf); +- return False; +- } ++ /* Set remaining data associated with cursor. */ + +- rcMask = malloc(width * height); +- if (rcMask == NULL) { +- free(rcSource); +- free(buf); +- return False; +- } ++ dr = DefaultRootWindow(dpy); + +- ptr = rcMask; +- for (y = 0; y < height; y++) { +- for (x = 0; x < width / 8; x++) { +- for (b = 7; b >= 0; b--) { +- *ptr++ = buf[y * bytesPerRow + x] >> b & 1; +- } +- } +- for (b = 7; b > 7 - width % 8; b--) { +- *ptr++ = buf[y * bytesPerRow + x] >> b & 1; +- } +- } ++ if (scale_x > 0) { ++ int w = scale_round(width, scale_factor_x) + 2; ++ int h = scale_round(height, scale_factor_y) + 2; ++ rcSavedArea = XCreatePixmap(dpy, dr, w, h, visdepth); ++ rcSavedArea_w = w; ++ rcSavedArea_h = h; ++ } else { ++ rcSavedArea = XCreatePixmap(dpy, dr, width, height, visdepth); ++ rcSavedArea_w = width; ++ rcSavedArea_h = height; ++ } ++ rcSavedArea_0 = XCreatePixmap(dpy, dr, width, height, visdepth); + +- free(buf); ++if (0) fprintf(stderr, "rcSavedArea_wh: %d %d scale_x: %d\n", rcSavedArea_w, rcSavedArea_h, scale_x); + +- /* Set remaining data associated with cursor. */ ++ if (rcSavedScale_len < 4 * width * height + 4096) { ++ if (rcSavedScale) { ++ free(rcSavedScale); ++ } ++ rcSavedScale = (char *) malloc(2 * 4 * width * height + 4096); ++ } + +- dr = DefaultRootWindow(dpy); +- rcSavedArea = XCreatePixmap(dpy, dr, width, height, visdepth); +- rcHotX = xhot; +- rcHotY = yhot; +- rcWidth = width; +- rcHeight = height; ++ rcHotX = xhot; ++ rcHotY = yhot; ++ rcWidth = width; ++ rcHeight = height; + +- SoftCursorCopyArea(OPER_SAVE); +- SoftCursorDraw(); ++ SoftCursorCopyArea(OPER_SAVE); ++ SoftCursorDraw(); + +- rcCursorHidden = False; +- rcLockSet = False; ++ rcCursorHidden = False; ++ rcLockSet = False; + +- prevSoftCursorSet = True; +- return True; ++ prevSoftCursorSet = True; ++ return True; } -+extern XImage *image; + /********************************************************************* +@@ -319,20 +360,27 @@ + + Bool HandleCursorPos(int x, int y) + { +- if (appData.useX11Cursor) { +- if (appData.fullScreen) +- XWarpPointer(dpy, None, desktopWin, 0, 0, 0, 0, x, y); +- +- return True; +- } ++ if (x < 0) x = 0; ++ if (y < 0) y = 0; + +- if (x >= si.framebufferWidth) +- x = si.framebufferWidth - 1; +- if (y >= si.framebufferHeight) +- y = si.framebufferHeight - 1; ++ //fprintf(stderr, "xy: %d %d\n", x, y); + +- SoftCursorMove(x, y); +- return True; ++ if (x >= si.framebufferWidth) { ++ x = si.framebufferWidth - 1; ++ } ++ if (y >= si.framebufferHeight) { ++ y = si.framebufferHeight - 1; ++ } ++ ++ if (appData.useX11Cursor) { ++ if (appData.fullScreen) { ++ XWarpPointer(dpy, None, desktopWin, 0, 0, 0, 0, x, y); ++ } ++ return True; ++ } + - static void SoftCursorCopyArea(int oper) ++ SoftCursorMove(x, y); ++ return True; + } + + /********************************************************************* +@@ -348,30 +396,31 @@ { + int newX, newY; + +- if (!prevSoftCursorSet) +- return; ++ if (!prevSoftCursorSet) { ++ return; ++ } + +- if (!rcLockSet) { +- rcLockX = x; +- rcLockY = y; +- rcLockWidth = w; +- rcLockHeight = h; +- rcLockSet = True; +- } else { +- newX = (x < rcLockX) ? x : rcLockX; +- newY = (y < rcLockY) ? y : rcLockY; +- rcLockWidth = (x + w > rcLockX + rcLockWidth) ? +- (x + w - newX) : (rcLockX + rcLockWidth - newX); +- rcLockHeight = (y + h > rcLockY + rcLockHeight) ? +- (y + h - newY) : (rcLockY + rcLockHeight - newY); +- rcLockX = newX; +- rcLockY = newY; +- } ++ if (!rcLockSet) { ++ rcLockX = x; ++ rcLockY = y; ++ rcLockWidth = w; ++ rcLockHeight = h; ++ rcLockSet = True; ++ } else { ++ newX = (x < rcLockX) ? x : rcLockX; ++ newY = (y < rcLockY) ? y : rcLockY; ++ rcLockWidth = (x + w > rcLockX + rcLockWidth) ? ++ (x + w - newX) : (rcLockX + rcLockWidth - newX); ++ rcLockHeight = (y + h > rcLockY + rcLockHeight) ? ++ (y + h - newY) : (rcLockY + rcLockHeight - newY); ++ rcLockX = newX; ++ rcLockY = newY; ++ } + +- if (!rcCursorHidden && SoftCursorInLockedArea()) { +- SoftCursorCopyArea(OPER_RESTORE); +- rcCursorHidden = True; +- } ++ if (!rcCursorHidden && SoftCursorInLockedArea()) { ++ SoftCursorCopyArea(OPER_RESTORE); ++ rcCursorHidden = True; ++ } + } + + /********************************************************************* +@@ -381,15 +430,16 @@ + + void SoftCursorUnlockScreen(void) + { +- if (!prevSoftCursorSet) +- return; ++ if (!prevSoftCursorSet) { ++ return; ++ } + +- if (rcCursorHidden) { +- SoftCursorCopyArea(OPER_SAVE); +- SoftCursorDraw(); +- rcCursorHidden = False; +- } +- rcLockSet = False; ++ if (rcCursorHidden) { ++ SoftCursorCopyArea(OPER_SAVE); ++ SoftCursorDraw(); ++ rcCursorHidden = False; ++ } ++ rcLockSet = False; + } + + /********************************************************************* +@@ -401,19 +451,19 @@ + + void SoftCursorMove(int x, int y) + { +- if (prevSoftCursorSet && !rcCursorHidden) { +- SoftCursorCopyArea(OPER_RESTORE); +- rcCursorHidden = True; +- } ++ if (prevSoftCursorSet && !rcCursorHidden) { ++ SoftCursorCopyArea(OPER_RESTORE); ++ rcCursorHidden = True; ++ } + +- rcCursorX = x; +- rcCursorY = y; ++ rcCursorX = x; ++ rcCursorY = y; + +- if (prevSoftCursorSet && !(rcLockSet && SoftCursorInLockedArea())) { +- SoftCursorCopyArea(OPER_SAVE); +- SoftCursorDraw(); +- rcCursorHidden = False; +- } ++ if (prevSoftCursorSet && !(rcLockSet && SoftCursorInLockedArea())) { ++ SoftCursorCopyArea(OPER_SAVE); ++ SoftCursorDraw(); ++ rcCursorHidden = False; ++ } + } + + +@@ -429,41 +479,170 @@ + rcLockY + rcLockHeight > rcCursorY - rcHotY); + } + +-static void SoftCursorCopyArea(int oper) +-{ - int x, y, w, h; -+ int x, y, w, h; ++void new_pixmap(int w, int h) { - x = rcCursorX - rcHotX; - y = rcCursorY - rcHotY; - if (x >= si.framebufferWidth || y >= si.framebufferHeight) - return; -+ x = rcCursorX - rcHotX; -+ y = rcCursorY - rcHotY; -+ if (x >= si.framebufferWidth || y >= si.framebufferHeight) { -+ return; -+ } - +- - w = rcWidth; - h = rcHeight; - if (x < 0) { @@ -2253,6 +2834,51 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe - } else if (y + h > si.framebufferHeight) { - h = si.framebufferHeight - y; - } ++ XFreePixmap(dpy, rcSavedArea); + +- if (oper == OPER_SAVE) { +- /* Save screen area in memory. */ +-#ifdef MITSHM +- if (appData.useShm) +- XSync(dpy, False); +-#endif +- XCopyArea(dpy, desktopWin, rcSavedArea, gc, x, y, w, h, 0, 0); +- } else { +- /* Restore screen area. */ +- XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y); +- } ++ if (w > 0 && h > 0) { ++ rcSavedArea = XCreatePixmap(dpy, DefaultRootWindow(dpy), w, h, visdepth); ++ rcSavedArea_w = w; ++ rcSavedArea_h = h; ++ ++ } else if (image_scale != NULL && scale_x > 0) { ++ int w2 = scale_round(rcWidth, scale_factor_x) + 2; ++ int h2 = scale_round(rcHeight, scale_factor_y) + 2; ++ rcSavedArea = XCreatePixmap(dpy, DefaultRootWindow(dpy), w2, h2, visdepth); ++ rcSavedArea_w = w2; ++ rcSavedArea_h = h2; ++ } else { ++ rcSavedArea = XCreatePixmap(dpy, DefaultRootWindow(dpy), rcWidth, rcHeight, visdepth); ++ rcSavedArea_w = rcWidth; ++ rcSavedArea_h = rcHeight; ++ } ++} ++ ++extern int XError_ign; ++ ++static void SoftCursorCopyArea(int oper) { ++ int x, y, w, h; ++ int xs, ys, ws, hs; ++ static int scale_saved = 0, ss_w, ss_h; ++ int db = 0; ++ ++ x = rcCursorX - rcHotX; ++ y = rcCursorY - rcHotY; ++ if (x >= si.framebufferWidth || y >= si.framebufferHeight) { ++ return; ++ } ++ + w = rcWidth; + h = rcHeight; + if (x < 0) { @@ -2267,50 +2893,124 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe + } else if (y + h > si.framebufferHeight) { + h = si.framebufferHeight - y; + } - -- if (oper == OPER_SAVE) { -- /* Save screen area in memory. */ ++ ++ if (image_scale != NULL && scale_x > 0) { ++ int i, t = 1; ++ xs = (int) (x * scale_factor_x); ++ ys = (int) (y * scale_factor_y); ++ ws = scale_round(w, scale_factor_x); ++ hs = scale_round(h, scale_factor_y); ++ ++ if (xs > 0) xs -= 1; ++ if (ys > 0) ys -= 1; ++ ws += 2; ++ hs += 2; ++ } ++ ++ XError_ign = 1; ++ + if (oper == OPER_SAVE) { + /* Save screen area in memory. */ -+//fprintf(stderr, "OPER_SAVE\n"); -+#if 0 - #ifdef MITSHM -- if (appData.useShm) -- XSync(dpy, False); -+ if (appData.useShm) { -+ XSync(dpy, False); -+ } else - #endif -- XCopyArea(dpy, desktopWin, rcSavedArea, gc, x, y, w, h, 0, 0); -- } else { -- /* Restore screen area. */ -- XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y); -- } -+ { -+ XSync(dpy, False); -+ } -+#endif -+ if (appData.useBackingstore) { ++ scale_saved = 0; ++ if (appData.useXserverBackingStore) { + XSync(dpy, False); + XCopyArea(dpy, desktopWin, rcSavedArea, gc, x, y, w, h, 0, 0); + } else { -+ XPutImage(dpy, rcSavedArea, gc, image, x, y, 0, 0, w, h); ++ if (image_scale != NULL && scale_x > 0) { ++ int Bpp = image_scale->bits_per_pixel / 8; ++ int Bpl = image_scale->bytes_per_line; ++ int i; ++ char *src = image_scale->data + y * Bpl + x * Bpp; ++ char *dst = rcSavedScale; ++ ++ if (ws > rcSavedArea_w || hs > rcSavedArea_h) { ++ new_pixmap(0, 0); ++ } ++ ++if (db) fprintf(stderr, "save: %dx%d+%d+%d\n", ws, hs, xs, ys); ++ ++ XPutImage(dpy, rcSavedArea, gc, image, xs, ys, 0, 0, ws, hs); ++ ++ XPutImage(dpy, rcSavedArea_0, gc, image_scale, x, y, 0, 0, w, h); ++ ++ scale_saved = 1; ++ ss_w = ws; ++ ss_h = hs; ++ ++ for (i=0; i < h; i++) { ++ memcpy(dst, src, Bpp * w); ++ src += Bpl; ++ dst += Bpp * w; ++ } ++ } else { ++if (db) fprintf(stderr, "SAVE: %dx%d+%d+%d\n", w, h, x, y); ++ if (w > rcSavedArea_w || h > rcSavedArea_h) { ++ new_pixmap(0, 0); ++ } ++ ++ XPutImage(dpy, rcSavedArea, gc, image, x, y, 0, 0, w, h); ++ } + } + } else { -+//fprintf(stderr, "OPER_RESTORE\n"); ++ ++#define XE(s) if (XError_ign > 1) {fprintf(stderr, "X-%d\n", (s)); db = 1;} ++ + /* Restore screen area. */ -+ if (appData.useBackingstore) { ++ if (appData.useXserverBackingStore) { + XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y); ++XE(1) + XGetSubImage(dpy, rcSavedArea, 0, 0, w, h, AllPlanes, ZPixmap, image, x, y); ++XE(2) ++ + } else { -+ XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y); -+ XGetSubImage(dpy, rcSavedArea, 0, 0, w, h, AllPlanes, ZPixmap, image, x, y); ++ if (image_scale != NULL && scale_x > 0) { ++ int Bpp = image_scale->bits_per_pixel / 8; ++ int Bpl = image_scale->bytes_per_line; ++ int i; ++ char *dst = image_scale->data + y * Bpl + x * Bpp; ++ char *src = rcSavedScale; ++ ++ XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, ws, hs, xs, ys); ++XE(3) ++ XGetSubImage(dpy, rcSavedArea, 0, 0, ws, hs, AllPlanes, ZPixmap, image, xs, ys); ++XE(4) ++if (db) fprintf(stderr, "rstr: %dx%d+%d+%d\n", ws, hs, xs, ys); ++ ++ for (i=0; i < h; i++) { ++ memcpy(dst, src, Bpp * w); ++ src += Bpp * w; ++ dst += Bpl; ++ } ++ } else { ++ ++ if (scale_saved) { ++ XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, ss_w, ss_h, x, y); ++XE(5) ++ XGetSubImage(dpy, rcSavedArea, 0, 0, ss_w, ss_h, AllPlanes, ZPixmap, image, x, y); ++XE(6) ++ new_pixmap(w, h); ++ } else { ++ XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y); ++XE(7) ++ XGetSubImage(dpy, rcSavedArea, 0, 0, w, h, AllPlanes, ZPixmap, image, x, y); ++XE(8) ++ } ++ ++if (db) fprintf(stderr, "RSTR: %dx%d+%d+%d\n", w, h, x, y); ++ ++ } + } + } ++ ++ if (XError_ign > 1) { ++ fprintf(stderr, "XError_ign: %d, oper: %s\n", XError_ign, oper ? "restore" : "save"); ++ } ++ ++ XError_ign = 0; } static void SoftCursorDraw(void) -@@ -472,6 +500,139 @@ +@@ -472,43 +651,182 @@ int offset, bytesPerPixel; char *pos; @@ -2327,13 +3027,25 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe + alphablend = 1; + } + -+ bytesPerPixel = myFormat.bitsPerPixel / 8; -+ + bytesPerPixel = myFormat.bitsPerPixel / 8; + +- /* FIXME: Speed optimization is possible. */ +- for (y = 0; y < rcHeight; y++) { +- y0 = rcCursorY - rcHotY + y; +- if (y0 >= 0 && y0 < si.framebufferHeight) { +- for (x = 0; x < rcWidth; x++) { +- x0 = rcCursorX - rcHotX + x; +- if (x0 >= 0 && x0 < si.framebufferWidth) { +- offset = y * rcWidth + x; +- if (rcMask[offset]) { +- pos = (char *)&rcSource[offset * bytesPerPixel]; +- CopyDataToScreen(pos, x0, y0, 1, 1); +- } + if (alphablend && bytesPerPixel == 4) { + unsigned long pixel, put, *upos, *upix; + int got_alpha = 0, rsX, rsY, rsW, rsH; + static XImage *alpha_image = NULL; -+ static int iwidth = 128; ++ static int iwidth = 192; + + if (! alpha_image) { + /* watch out for tiny fb (rare) */ @@ -2347,7 +3059,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe + /* initialize an XImage with a chunk of desktopWin */ + alpha_image = XGetImage(dpy, desktopWin, 0, 0, iwidth, iwidth, + AllPlanes, ZPixmap); -+ } + } +- } +- } + + /* first check if there is any non-zero alpha channel data at all: */ + for (y = 0; y < rcHeight; y++) { @@ -2374,9 +3088,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe + goto oldway; + } + -+ /* load the saved fb patch in to image (faster way?) */ -+ XGetSubImage(dpy, rcSavedArea, 0, 0, rcWidth, rcHeight, -+ AllPlanes, ZPixmap, alpha_image, 0, 0); ++ /* load the saved fb patch in to alpha_image (faster way?) */ ++ if (image_scale != NULL && scale_x > 0) { ++ XGetSubImage(dpy, rcSavedArea_0, 0, 0, rcWidth, rcHeight, AllPlanes, ZPixmap, alpha_image, 0, 0); ++ } else { ++ XGetSubImage(dpy, rcSavedArea, 0, 0, rcWidth, rcHeight, AllPlanes, ZPixmap, alpha_image, 0, 0); ++ } ++ + upix = (unsigned long *)alpha_image->data; + + /* if the richcursor is clipped, the fb patch will be smaller */ @@ -2443,17 +3161,28 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe + } + } + return; -+ } + } +oldway: +#endif + - bytesPerPixel = myFormat.bitsPerPixel / 8; - - /* FIXME: Speed optimization is possible. */ -@@ -490,25 +651,26 @@ - } - } - } ++ bytesPerPixel = myFormat.bitsPerPixel / 8; ++ ++ /* FIXME: Speed optimization is possible. */ ++ for (y = 0; y < rcHeight; y++) { ++ y0 = rcCursorY - rcHotY + y; ++ if (y0 >= 0 && y0 < si.framebufferHeight) { ++ for (x = 0; x < rcWidth; x++) { ++ x0 = rcCursorX - rcHotX + x; ++ if (x0 >= 0 && x0 < si.framebufferWidth) { ++ offset = y * rcWidth + x; ++ if (rcMask[offset]) { ++ pos = (char *)&rcSource[offset * bytesPerPixel]; ++ CopyDataToScreen(pos, x0, y0, 1, 1); ++ } ++ } ++ } ++ } ++ } + XSync(dpy, False); } @@ -2470,6 +3199,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe + if (prevSoftCursorSet) { + SoftCursorCopyArea(OPER_RESTORE); + XFreePixmap(dpy, rcSavedArea); ++ XFreePixmap(dpy, rcSavedArea_0); + free(rcSource); + rcSource = NULL; + free(rcMask); @@ -2493,22 +3223,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewe - diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncviewer/desktop.c --- vnc_unixsrc.orig/vncviewer/desktop.c 2004-05-28 13:29:29.000000000 -0400 -+++ vnc_unixsrc/vncviewer/desktop.c 2008-09-05 19:12:25.000000000 -0400 -@@ -28,21 +28,40 @@ ++++ vnc_unixsrc/vncviewer/desktop.c 2008-10-17 22:12:57.000000000 -0400 +@@ -28,28 +28,473 @@ #include <X11/extensions/XShm.h> #endif -+/* we don't have Xvlib working yet... not all cards supply RGB @ 32bpp */ -+#define XVLIB__dont -+#ifdef XVLIB -+#include <X11/extensions/Xvlib.h> -+XvImage *xv_image; -+XvPortID xv_port = None; -+int xv_width = 640; -+int xv_height = 480; -+#endif -+ -+ +#include <X11/cursorfont.h> + GC gc; @@ -2518,6 +3237,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview +Cursor dotCursor3 = None; +Cursor dotCursor4 = None; +Cursor bogoCursor = None; ++Cursor waitCursor = None; Widget form, viewport, desktop; static Bool modifierPressed[256]; @@ -2525,6 +3245,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview -static XImage *image = NULL; +XImage *image = NULL; +XImage *image_ycrop = NULL; ++XImage *image_scale = NULL; ++ ++int image_is_shm = 0; static Cursor CreateDotCursor(); +static Cursor CreateBogoCursor(); @@ -2536,100 +3259,399 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + static XtResource desktopBackingStoreResources[] = { { - XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0, -@@ -50,6 +69,138 @@ +- XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0, +- XtRImmediate, (XtPointer) Always, ++ XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0, ++ XtRImmediate, (XtPointer) Always, }, }; -+#ifdef XVLIB -+void setup_xv(void) { -+ int a, p, f; -+ int num_adaptors; -+ XvAdaptorInfo *adaptor_info; -+ XvImageFormatValues *formats, *format = NULL; -+ int nformats; ++double scale_factor_x = 0.0; ++double scale_factor_y = 0.0; ++int scale_x = 0, scale_y = 0; ++int scale_round(int len, double fac); + -+ if (xv_port != None) { -+ return; ++double last_rescale = 0.0; ++double last_fullscreen = 0.0; ++double start_time = 0.0; ++ ++int prev_fb_width = -1; ++int prev_fb_height = -1; ++ ++void get_scale_values(double *fx, double *fy) { ++ char *s = appData.scale; ++ double f, frac_x = -1.0, frac_y = -1.0; ++ int n, m; ++ int xmax = si.framebufferWidth; ++ int ymax = si.framebufferHeight; ++ ++ if (appData.yCrop > 0) { ++ ymax = appData.yCrop; + } -+ XvQueryAdaptors (dpy, RootWindow(dpy, DefaultScreen(dpy)), &num_adaptors, &adaptor_info); -+ for (a = 0; a < num_adaptors; a++) { -+ fprintf(stderr, "Adapator \"%s\" has %d ports\n", -+ adaptor_info[a].name, -+ adaptor_info[a].num_ports); ++ ++ if (sscanf(s, "%d/%d", &n, &m) == 2) { ++ if (m == 0) { ++ frac_x = 1.0; ++ } else { ++ frac_x = ((double) n) / ((double) m); ++ } + } -+ for (a = 0; a < num_adaptors; a++) { -+ for (p = 0; a < adaptor_info[a].num_ports; p++) { -+ if (XvGrabPort(dpy, adaptor_info[a].base_id + p, CurrentTime) == Success) { -+ xv_port = adaptor_info[a].base_id + p; -+ break; -+ } ++ if (sscanf(s, "%dx%d", &n, &m) == 2) { ++ frac_x = ((double) n) / ((double) xmax); ++ frac_y = ((double) m) / ((double) ymax); ++ } ++ if (!strcasecmp(s, "fit")) { ++ frac_x = ((double) dpyWidth) / ((double) xmax); ++ frac_y = ((double) dpyHeight) / ((double) ymax); ++ } ++ if (!strcasecmp(s, "auto")) { ++ Dimension w, h; ++ XtVaGetValues(toplevel, XtNheight, &h, XtNwidth, &w, NULL); ++ fprintf(stderr, "auto: %dx%d\n", w, h); ++ if (w > 32 && h > 32) { ++ frac_x = ((double) w) / ((double) xmax); ++ frac_y = ((double) h) / ((double) ymax); + } + } -+ formats = XvListImageFormats (dpy, xv_port, &nformats); -+ for (f=0; f < nformats; f++) { -+fprintf(stderr, "f=%d\n", f); -+fprintf(stderr, "formats[f].type: %d\n", formats[f].type); -+fprintf(stderr, "formats[f].format: %d\n", formats[f].format); -+fprintf(stderr, "formats[f].bits_per_pixel: %d\n", formats[f].bits_per_pixel); -+fprintf(stderr, "formats[f].num_planes: %d\n", formats[f].num_planes); -+fprintf(stderr, "formats[f].scanline_order: %d\n", formats[f].scanline_order); -+fprintf(stderr, "formats[f].component_order: %s\n", formats[f].component_order); -+ if (formats[f].type != XvRGB) continue; -+ if (formats[f].format != XvPacked) continue; -+ if (formats[f].bits_per_pixel != 32) continue; -+ if (formats[f].num_planes != 1) continue; -+ if (formats[f].scanline_order != XvTopToBottom) continue; -+ if (strcmp (formats[f].component_order, "BGRX") != 0) continue; -+ format = &formats[f]; -+ break; ++ if (frac_x < 0.0 && sscanf(s, "%lf", &f) == 1) { ++ if (f > 0.0) { ++ frac_x = f; ++ } + } -+// fprintf(stderr, "y_sample_bits %d u_sample_bits %d v_sample_bits %d\n", -+// format->y_sample_bits, format->u_sample_bits, format->v_sample_bits); -+// fprintf(stderr, "component_order: %s\n", format->component_order); + -+ xv_image = XvCreateImage (dpy, xv_port, format->id, NULL, si.framebufferWidth, si.framebufferHeight); ++ if (frac_y < 0.0) { ++ frac_y = frac_x; ++ } ++ ++ if (fx != NULL) { ++ *fx = frac_x; ++ } ++ if (fy != NULL) { ++ *fy = frac_y; ++ } +} -+#endif + -+void create_image() { -+ image = NULL; -+ image_ycrop = NULL; ++void try_create_image(void); ++void put_image(int src_x, int src_y, int dst_x, int dst_y, int width, int height, int solid); ++void create_image(); + -+//fprintf(stderr, "useShm: %d\n", appData.useShm); ++// toplevel -> form -> viewport -> desktop + ++void adjust_Xt_win(int w, int h) { ++ int x, y, dw, dh, h0 = h; ++ int mw = w, mh = h; ++ int autoscale = 0; + -+#ifdef MITSHM ++ if (!appData.fullScreen && appData.scale != NULL && !strcmp(appData.scale, "auto")) { ++ autoscale = 1; ++ mw = dpyWidth; ++ mh = dpyHeight; ++ } ++ ++ if (appData.yCrop > 0) { ++ int ycrop = appData.yCrop; ++ if (image_scale && scale_factor_y > 0.0) { ++ ycrop = scale_round(ycrop, scale_factor_y); ++ if (!autoscale) { ++ mh = ycrop; ++ } ++ } ++ XtVaSetValues(toplevel, XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, ycrop, NULL); ++ XtVaSetValues(form, XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, ycrop, NULL); ++ h0 = ycrop; ++ } else { ++ XtVaSetValues(toplevel, XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, h, NULL); ++ } ++ ++ fprintf(stderr, "adjust_Xt_win: %dx%d & %dx%d\n", w, h, w, h0); ++ ++ XtVaSetValues(desktop, XtNwidth, w, XtNheight, h, NULL); ++ ++ XtResizeWidget(desktop, w, h, 0); ++ ++ if (!autoscale) { ++ dw = appData.wmDecorationWidth; ++ dh = appData.wmDecorationHeight; ++ ++ x = (dpyWidth - w - dw)/2; ++ y = (dpyHeight - h0 - dh)/2; ++ ++ XtConfigureWidget(toplevel, x + dw, y + dh, w, h0, 0); ++ } ++} ++ ++void rescale_image(void) { ++ double frac_x, frac_y; ++ int w, h; ++ ++ if (image == NULL) { ++ create_image(); ++ return; ++ } ++ ++ if (appData.useXserverBackingStore) { ++ create_image(); ++ return; ++ } ++ ++ if (image == NULL && image_scale == NULL) { ++ create_image(); ++ return; ++ } ++ ++ if (appData.scale == NULL) { ++ /* switching to not scaled */ ++ frac_x = frac_y = 1.0; ++ } else { ++ get_scale_values(&frac_x, &frac_y); ++ if (frac_x < 0.0) { ++ create_image(); ++ return; ++ } ++ } ++ ++ last_rescale = dnow(); ++ ++ SoftCursorLockArea(0, 0, si.framebufferWidth, si.framebufferHeight); ++ ++ if (image_scale == NULL) { ++ /* switching from not scaled */ ++ int i, start_over = 0; ++ int Bpl = image->bytes_per_line; ++ char *dst, *src = image->data; ++ ++ image_scale = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, ++ si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); ++ ++ image_scale->data = (char *) malloc(image_scale->bytes_per_line * image_scale->height); ++ ++ fprintf(stderr, "rescale_image: switching from not scaled. created image_scale %dx%d\n", image_scale->width, image_scale->height); ++ fprintf(stderr, "rescale_image: copying image -> image_scale %dx%d -> %dx%d\n", image->width, image->height, image_scale->width, image_scale->height); ++ ++ dst = image_scale->data; ++ ++ /* copy from image->data */ ++ for (i=0; i < image->height; i++) { ++ memcpy(dst, src, Bpl); ++ dst += Bpl; ++ src += Bpl; ++ } ++ } ++ ++ /* now destroy image */ ++ if (image && image->data) { ++ if (UsingShm()) { ++ ShmCleanup(); ++ } ++ XDestroyImage(image); ++ fprintf(stderr, "rescale_image: destroyed 'image'\n"); ++ image = NULL; ++ } ++ if (image_ycrop && image_ycrop->data) { ++ XDestroyImage(image_ycrop); ++ fprintf(stderr, "rescale_image: destroyed 'image_ycrop'\n"); ++ image_ycrop = NULL; ++ } ++ ++ if (frac_x == 1.0 && frac_y == 1.0) { ++ /* switching to not scaled */ ++ fprintf(stderr, "rescale_image: switching to not scaled.\n"); ++ w = si.framebufferWidth; ++ h = si.framebufferHeight; ++ ++ scale_factor_x = 0.0; ++ scale_factor_y = 0.0; ++ scale_x = 0; ++ scale_y = 0; ++ } else { ++ w = scale_round(si.framebufferWidth, frac_x); ++ h = scale_round(si.framebufferHeight, frac_y); ++ ++ scale_factor_x = frac_x; ++ scale_factor_y = frac_y; ++ scale_x = w; ++ scale_y = h; ++ } ++ ++ adjust_Xt_win(w, h); ++ ++ fprintf(stderr, "rescale: %dx%d %.4f %.4f\n", w, h, scale_factor_x, scale_factor_y); ++ ++ try_create_image(); ++ ++ if (image && image->data && image_scale && frac_x == 1.0 && frac_y == 1.0) { ++ /* switched to not scaled */ ++ int i; ++ int Bpl = image->bytes_per_line; ++ char *dst = image->data; ++ char *src = image_scale->data; ++ ++ fprintf(stderr, "rescale_image: switching to not scaled.\n"); ++ ++ for (i=0; i < image->height; i++) { ++ memcpy(dst, src, Bpl); ++ dst += Bpl; ++ src += Bpl; ++ } ++ XDestroyImage(image_scale); ++ fprintf(stderr, "rescale_image: destroyed 'image_scale'\n"); ++ image_scale = NULL; ++ } ++ ++ if (appData.yCrop > 0) { ++ int ycrop = appData.yCrop; ++ /* do the top part first so they can see it earlier */ ++ put_image(0, 0, 0, 0, si.framebufferWidth, ycrop, 0); ++ if (si.framebufferHeight > ycrop) { ++ /* this is a big fb and so will take a long time */ ++ if (waitCursor != None) { ++ XDefineCursor(dpy, desktopWin, waitCursor); ++ XSync(dpy, False); ++ } ++ put_image(0, 0, 0, 0, si.framebufferWidth, si.framebufferHeight - ycrop, 0); ++ if (waitCursor != None) { ++ Xcursors(1); ++ if (appData.useX11Cursor) { ++ XSetWindowAttributes attr; ++ unsigned long valuemask = 0; ++ if (appData.viewOnly) { ++ attr.cursor = dotCursor4; ++ } else { ++ attr.cursor = dotCursor3; ++ } ++ valuemask |= CWCursor; ++ XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); ++ } ++ } ++ } ++ } else { ++ put_image(0, 0, 0, 0, si.framebufferWidth, si.framebufferHeight, 0); ++ } ++ ++ SoftCursorUnlockScreen(); ++ ++ fprintf(stderr, "rescale: image_scale=0x%x image=0x%x image_ycrop=0x%x\n", image_scale, image, image_ycrop); ++ last_rescale = dnow(); ++ ++} ++ ++void try_create_image(void) { ++ ++ image_is_shm = 0; + if (appData.useShm) { ++#ifdef MITSHM + image = CreateShmImage(0); + if (!image) { + if (appData.yCrop > 0) { -+ image_ycrop = CreateShmImage(1); -+ if (!image_ycrop) { -+ appData.useShm = False; ++ if (appData.scale != NULL && scale_x > 0) { ++ ; + } else { -+ fprintf(stderr, "created smaller image_ycrop " -+ "shm image\n"); ++ image_ycrop = CreateShmImage(1); ++ if (!image_ycrop) { ++ appData.useShm = False; ++ } else { ++ fprintf(stderr, "created smaller image_ycrop shm image: %dx%d\n", ++ image_ycrop->width, image_ycrop->height); ++ } + } + } else { + appData.useShm = False; + } ++ } else { ++ image_is_shm = 1; ++ fprintf(stderr, "created shm image: %dx%d\n", image->width, image->height); + } -+ } +#endif ++ } + + if (!image) { -+ image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, -+ si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); ++ fprintf(stderr, "try_create_image: shm image create fail: image == NULL\n"); ++ if (scale_x > 0) { ++ image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, ++ scale_x, scale_y, BitmapPad(dpy), 0); ++ } else { ++ image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, ++ si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); ++ } + + image->data = malloc(image->bytes_per_line * image->height); ++ + if (!image->data) { -+ fprintf(stderr,"malloc failed\n"); ++ fprintf(stderr, "try_create_image: malloc failed\n"); + exit(1); + } else { -+ fprintf(stderr, "created non-shm image\n"); ++ fprintf(stderr, "try_create_image: created *non-shm* image: %dx%d\n", image->width, image->height); ++ } ++ } ++} ++ ++void create_image() { ++ image = NULL; ++ image_ycrop = NULL; ++ image_scale = NULL; ++ ++ fprintf(stderr, "create_image()\n"); ++ ++ if (CreateShmImage(-1) == NULL) { ++ appData.useShm = False; ++ } ++ if (appData.scale != NULL) { ++ if (appData.useXserverBackingStore) { ++ fprintf(stderr, "Cannot scale when using X11 backingstore.\n"); ++ } else { ++ double frac_x = -1.0, frac_y = -1.0; ++ ++ scale_factor_x = 0.0; ++ scale_factor_y = 0.0; ++ scale_x = 0; ++ scale_y = 0; ++ ++ get_scale_values(&frac_x, &frac_y); ++ ++ if (frac_x < 0.0) { ++ fprintf(stderr, "Cannot figure out scale factor!\n"); ++ } else { ++ int w, h, hyc; ++ ++ w = scale_round(si.framebufferWidth, frac_x); ++ h = scale_round(si.framebufferHeight, frac_y); ++ hyc = h; ++ if (appData.yCrop > 0) { ++ hyc = scale_round(appData.yCrop, frac_y); ++ } ++ ++ /* image scale is full framebuffer */ ++ image_scale = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, ++ si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); ++ ++ image_scale->data = (char *) malloc(image_scale->bytes_per_line * image_scale->height); ++ ++ fprintf(stderr, "create_image: created image_scale %dx%d\n", image_scale->width, image_scale->height); ++ ++ if (!image_scale->data) { ++ fprintf(stderr, "create_image: malloc failed\n"); ++ XDestroyImage(image_scale); ++ fprintf(stderr, "create_image: destroyed 'image_scale'\n"); ++ image_scale = NULL; ++ } else { ++ int h2; ++ scale_factor_x = frac_x; ++ scale_factor_y = frac_y; ++ scale_x = w; ++ scale_y = h; ++ ++ XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, hyc, NULL); ++ ++ h2 = scale_round(si.framebufferHeight, frac_y); ++ XtVaSetValues(desktop, XtNwidth, w, XtNheight, h2, NULL); ++ ++ } ++ fprintf(stderr, "create_image: scale: %dx%d %.4f %.4f\n", w, h, ++ scale_factor_x, scale_factor_y); ++ } + } + } ++ try_create_image(); +} + +int old_width = 0; @@ -2652,8 +3674,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + return 864; + } else if (w == 1280) { + return 1024; ++ } else if (w == 1440) { ++ return 900; + } else if (w == 1600) { + return 1200; ++ } else if (w == 1680) { ++ return 1050; + } else if (w == 1920) { + return 1200; + } else { @@ -2676,12 +3702,26 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview /* * DesktopInitBeforeRealization creates the "desktop" widget and the viewport -@@ -59,89 +210,320 @@ +@@ -59,91 +504,964 @@ void DesktopInitBeforeRealization() { - int i; + int i; ++ int h = si.framebufferHeight; ++ int w = si.framebufferWidth; ++ double frac_x = 1.0, frac_y = 1.0; ++ ++ start_time = dnow(); ++ ++ prev_fb_width = si.framebufferWidth; ++ prev_fb_height = si.framebufferHeight; ++ ++ if (appData.scale != NULL) { ++ get_scale_values(&frac_x, &frac_y); ++ w = scale_round(w, frac_x); ++ h = scale_round(h, frac_y); ++ } - form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel, - XtNborderWidth, 0, @@ -2700,51 +3740,28 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - NULL); + desktop = XtVaCreateManagedWidget("desktop", coreWidgetClass, viewport, + XtNborderWidth, 0, NULL); -+ -+ XtVaSetValues(desktop, XtNwidth, si.framebufferWidth, -+ XtNheight, si.framebufferHeight, NULL); -+ -+ XtAddEventHandler(desktop, LeaveWindowMask|ExposureMask, -+ True, HandleBasicDesktopEvent, NULL); -+ -+ -+ check_tall(); -+ -+ if (appData.yCrop) { -+ int wm, hm; -+ if (appData.yCrop < 0) { -+ appData.yCrop = guessCrop(); -+ fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop); -+ } -+ hm = appData.yCrop; -+ if (0 && appData.sbWidth <= 6 && appData.sbWidth > 0) { -+ hm += appData.sbWidth; -+ } -+ XtVaSetValues(toplevel, XtNmaxHeight, hm, NULL); -+ XtVaSetValues(form, XtNmaxHeight, hm, NULL); -+ XtVaSetValues(viewport, XtNforceBars, False, NULL); -+ } -+ old_width = si.framebufferWidth; -+ old_height = si.framebufferHeight; - XtVaSetValues(desktop, XtNwidth, si.framebufferWidth, - XtNheight, si.framebufferHeight, NULL); -+ for (i = 0; i < 256; i++) { -+ modifierPressed[i] = False; -+ } ++ XtVaSetValues(desktop, XtNwidth, w, XtNheight, h, NULL); - XtAddEventHandler(desktop, LeaveWindowMask|ExposureMask, - True, HandleBasicDesktopEvent, NULL); -+ create_image(); -+} ++ XtAddEventHandler(desktop, LeaveWindowMask|EnterWindowMask|ExposureMask, ++ True, HandleBasicDesktopEvent, NULL); - for (i = 0; i < 256; i++) - modifierPressed[i] = False; -+static Widget scrollbar_y = NULL; ++ if (appData.yCrop) { ++ int wm, hm; ++ if (appData.yCrop < 0) { ++ appData.yCrop = guessCrop(); ++ fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop); ++ } ++ hm = appData.yCrop; - image = NULL; -+static int xsst = 2; -+#include <X11/Xaw/Scrollbar.h> ++ fprintf(stderr, "ycrop h: %d -> %d\n", hm, (int) (hm*frac_y)); -#ifdef MITSHM - if (appData.useShm) { @@ -2753,7 +3770,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - appData.useShm = False; - } -#endif -- ++ hm *= frac_y; + - if (!image) { - image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, - si.framebufferWidth, si.framebufferHeight, @@ -2765,6 +3783,27 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - exit(1); - } - } ++ XtVaSetValues(toplevel, XtNmaxHeight, hm, XtNheight, hm, NULL); ++ XtVaSetValues(form, XtNmaxHeight, hm, XtNheight, hm, NULL); ++ XtVaSetValues(viewport, XtNforceBars, False, NULL); ++ XSync(dpy, False); ++ } ++ ++ old_width = si.framebufferWidth; ++ old_height = si.framebufferHeight; ++ ++ for (i = 0; i < 256; i++) { ++ modifierPressed[i] = False; ++ } ++ ++ create_image(); + } + ++static Widget scrollbar_y = NULL; ++ ++static int xsst = 2; ++#include <X11/Xaw/Scrollbar.h> ++ +static XtCallbackProc Scrolled(Widget w, XtPointer closure, XtPointer call_data) { + Position x, y; + XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL); @@ -2779,7 +3818,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + float t = 0.0; + XtVaSetValues(w, XtNtopOfThumb, &t, NULL); + } - } ++} ++ +static XtCallbackProc Jumped(Widget w, XtPointer closure, XtPointer call_data) { + float top = *((float *) call_data); + Position x, y; @@ -2799,7 +3839,6 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + } +} + -+ +extern double dnow(void); + +void check_things() { @@ -2810,12 +3849,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + int h = si.framebufferHeight; + double now = dnow(); + static double last = 0; ++ double fac = image_scale ? scale_factor_y : 1.0; + + if (first) { + first = 0; + SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, si.framebufferHeight, False); + } -+ if (appData.yCrop > 0 && appData.yCrop < dpyHeight && h > 2*w && now > last_scrollbar + 0.25) { ++ if (appData.yCrop > 0 && appData.yCrop * fac < dpyHeight && h > 2*w && now > last_scrollbar + 0.25) { + Widget wv, wh, wc; + Position x0, y0; + Position x1, y1; @@ -2836,13 +3876,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + sb = 2; + } + if (w0 != sb || h1 != sb) { -+ fprintf(stderr, "Very tall (-ncache) fb, setting scrollbar thickness to: %d pixels\n", sb); ++ fprintf(stderr, "Very tall (-ncache) fb, setting scrollbar thickness to: %d pixels (%d/%d)\n\n", sb, w0, h1); + + XtUnmanageChild(wv); + XtUnmanageChild(wh); + XtUnmanageChild(wc); + -+ XtVaSetValues(wv, XtNwidth, sb, XtNx, x0 + (w0 - sb), NULL); ++ XtVaSetValues(wv, XtNwidth, sb, XtNx, x0 + (w0 - sb), NULL); + XtVaSetValues(wh, XtNheight, sb, XtNy, y1 + (h1 - sb), NULL); + w2 = w2 + (w0 - sb); + h2 = h2 + (h1 - sb); @@ -2853,18 +3893,54 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + XtManageChild(wv); + XtManageChild(wh); + XtManageChild(wc); ++ ++ appData.sbWidth = sb; + } + } + last_scrollbar = dnow(); + } + -+ if (now <= last + 1.0) { ++ if (now <= last + 0.25) { + return; + } - ++ ++ /* e.g. xrandr resize */ + dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); + dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); + ++ if (appData.scale != NULL) { ++ static Dimension last_w = 0, last_h = 0; ++ static double last_resize = 0.0; ++ Dimension w, h; ++ if (last_w == 0) { ++ XtVaGetValues(toplevel, XtNwidth, &last_w, XtNheight, &last_h, NULL); ++ last_resize = now; ++ } ++ if (now < last_resize + 0.5) { ++ ; ++ } else if (appData.fullScreen) { ++ ; ++ } else if (!strcmp(appData.scale, "auto")) { ++ XtVaGetValues(toplevel, XtNwidth, &w, XtNheight, &h, NULL); ++ if (w < 32 || h < 32) { ++ ; ++ } else if (last_w != w || last_h != h) { ++ Window rr, cr, r = DefaultRootWindow(dpy); ++ int rx, ry, wx, wy; ++ unsigned int mask; ++ /* make sure mouse buttons not pressed */ ++ if (XQueryPointer(dpy, r, &rr, &cr, &rx, &ry, &wx, &wy, &mask)) { ++ if (mask == 0) { ++ rescale_image(); ++ last_w = w; ++ last_h = h; ++ last_resize = dnow(); ++ } ++ } ++ } ++ } ++ } ++ + last = dnow(); +} @@ -2943,15 +4019,15 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore, + NULL, 0); + -+ if (appData.useBackingstore) { ++ if (appData.useXserverBackingStore) { + Screen *s = DefaultScreenOfDisplay(dpy); + if (DoesBackingStore(s) != Always) { + fprintf(stderr, "X server does not do backingstore, disabling it.\n"); -+ appData.useBackingstore = False; ++ appData.useXserverBackingStore = False; + } + } + -+ if (appData.useBackingstore) { ++ if (appData.useXserverBackingStore) { + XtVaGetApplicationResources(desktop, (XtPointer)&attr.backing_store, + desktopBackingStoreResources, 1, NULL); + valuemask |= CWBackingStore; @@ -2970,6 +4046,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + valuemask |= CWCursor; + } + bogoCursor = XCreateFontCursor(dpy, XC_bogosity); ++ waitCursor = XCreateFontCursor(dpy, XC_watch); + + XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); + @@ -3002,36 +4079,603 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + FreeX11Cursor(); + FreeSoftCursor(); +} ++ ++ ++#define CEIL(x) ( (double) ((int) (x)) == (x) ? \ ++ (double) ((int) (x)) : (double) ((int) (x) + 1) ) ++#define FLOOR(x) ( (double) ((int) (x)) ) ++ ++#if 0 ++static int nfix(int i, int n) { ++ if (i < 0) { ++ i = 0; ++ } else if (i >= n) { ++ i = n - 1; ++ } ++ return i; ++} ++#else ++#define nfix(i, n) ( i < 0 ? 0 : ( (i >= n) ? (n - 1) : i ) ) ++#endif ++ ++int scale_round(int len, double fac) { ++ double eps = 0.000001; ++ ++ len = (int) (len * fac + eps); ++ if (len < 1) { ++ len = 1; ++ } ++ return len; ++} ++ ++static void scale_rect(double factor_x, double factor_y, int blend, int interpolate, ++ int *px, int *py, int *pw, int *ph, int solid) { ++ ++ int i, j, i1, i2, j1, j2; /* indices for scaled fb (dest) */ ++ int I, J, I1, I2, J1, J2; /* indices for main fb (source) */ ++ ++ double w, wx, wy, wtot; /* pixel weights */ ++ ++ double x1, y1, x2, y2; /* x-y coords for destination pixels edges */ ++ double dx, dy; /* size of destination pixel */ ++ double ddx=0, ddy=0; /* for interpolation expansion */ ++ ++ char *src, *dest; /* pointers to the two framebuffers */ ++ ++ unsigned short us = 0; ++ unsigned char uc = 0; ++ unsigned int ui = 0; ++ ++ int use_noblend_shortcut = 1; ++ int shrink; /* whether shrinking or expanding */ ++ static int constant_weights = -1, mag_int = -1; ++ static int last_Nx = -1, last_Ny = -1, cnt = 0; ++ static double last_factor = -1.0; ++ int b, k; ++ double pixave[4]; /* for averaging pixel values */ ++ ++ /* internal */ ++ ++ int X1, X2, Y1, Y2; ++ ++ int Nx = si.framebufferWidth; ++ int Ny = si.framebufferHeight; ++ ++ int nx = scale_round(Nx, factor_x); ++ int ny = scale_round(Ny, factor_y); ++ ++ int Bpp = image->bits_per_pixel / 8; ++ int dst_bytes_per_line = image->bytes_per_line; ++ int src_bytes_per_line = image_scale->bytes_per_line; ++ ++ unsigned long main_red_mask = image->red_mask; ++ unsigned long main_green_mask = image->green_mask; ++ unsigned long main_blue_mask = image->blue_mask; ++ int mark = 1, n; ++ ++ char *src_fb = image_scale->data; ++ char *dst_fb = image->data; ++ ++ static int nosolid = -1; ++ int sbdy = 3; ++ double fmax = factor_x > factor_y ? factor_x : factor_y; ++ double fmin = factor_x < factor_y ? factor_x : factor_y; - XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); -+void put_image(int src_x, int src_y, int dst_x, int dst_y, int width, -+ int height) { -+ -+#ifdef XVLIB -+ if (xv_width > 0) { -+ if (xv_port == None) { -+ setup_xv(); -+ } -+ if (xv_port != None) { -+ double ratw = (double) xv_width / si.framebufferWidth; -+ double rath = (double) xv_height / si.framebufferHeight; -+ XvPutImage(dpy, xv_port, desktopWin, gc, xv_image, -+ src_x, src_y, width, height, -+ (int) ratw * dst_x, (int) rath * dst_y, -+ (int) ratw * width, (int) rath * height); -+ return; ++ X1 = *px; ++ X2 = *px + *pw; ++ Y1 = *py; ++ Y2 = *py + *ph; ++ ++ if (fmax > 1.0) { ++ /* try to avoid problems with bleeding... */ ++ sbdy = (int) (2.0 * fmax * sbdy); ++ } ++ ++ //fprintf(stderr, "scale_rect: %dx%d+%d+%d\n", *pw, *ph, *px, *py); ++ ++ *px = (int) (*px * factor_x); ++ *py = (int) (*py * factor_y); ++ *pw = scale_round(*pw, factor_x); ++ *ph = scale_round(*ph, factor_y); ++ ++ if (nosolid < 0) { ++ if (getenv("SSVNC_NOSOLID")) { ++ nosolid = 1; ++ } else { ++ nosolid = 0; + } + } -+#endif ++ if (nosolid) solid = 0; ++ ++#define rfbLog printf ++/* Begin taken from x11vnc scale: */ ++ ++ if (factor_x <= 1.0 || factor_y <= 1.0) { ++ shrink = 1; ++ } else { ++ shrink = 0; ++ interpolate = 1; ++ } ++ ++ /* ++ * N.B. width and height (real numbers) of a scaled pixel. ++ * both are > 1 (e.g. 1.333 for -scale 3/4) ++ * they should also be equal but we don't assume it. ++ * ++ * This new way is probably the best we can do, take the inverse ++ * of the scaling factor to double precision. ++ */ ++ dx = 1.0/factor_x; ++ dy = 1.0/factor_y; ++ ++ /* ++ * There is some speedup if the pixel weights are constant, so ++ * let's special case these. ++ * ++ * If scale = 1/n and n divides Nx and Ny, the pixel weights ++ * are constant (e.g. 1/2 => equal on 2x2 square). ++ */ ++ if (factor_x != last_factor || Nx != last_Nx || Ny != last_Ny) { ++ constant_weights = -1; ++ mag_int = -1; ++ last_Nx = Nx; ++ last_Ny = Ny; ++ last_factor = factor_x; ++ } ++ ++ if (constant_weights < 0 && factor_x != factor_y) { ++ constant_weights = 0; ++ mag_int = 0; ++ } else if (constant_weights < 0) { ++ int n = 0; ++ double factor = factor_x; ++ ++ constant_weights = 0; ++ mag_int = 0; ++ ++ for (i = 2; i<=128; i++) { ++ double test = ((double) 1)/ i; ++ double diff, eps = 1.0e-7; ++ diff = factor - test; ++ if (-eps < diff && diff < eps) { ++ n = i; ++ break; ++ } ++ } ++ if (! blend || ! shrink || interpolate) { ++ ; ++ } else if (n != 0) { ++ if (Nx % n == 0 && Ny % n == 0) { ++ static int didmsg = 0; ++ if (mark && ! didmsg) { ++ didmsg = 1; ++ rfbLog("scale_and_mark_rect: using " ++ "constant pixel weight speedup " ++ "for 1/%d\n", n); ++ } ++ constant_weights = 1; ++ } ++ } ++ ++ n = 0; ++ for (i = 2; i<=32; i++) { ++ double test = (double) i; ++ double diff, eps = 1.0e-7; ++ diff = factor - test; ++ if (-eps < diff && diff < eps) { ++ n = i; ++ break; ++ } ++ } ++ if (! blend && factor > 1.0 && n) { ++ mag_int = n; ++ } ++ } ++if (0) fprintf(stderr, "X1: %d Y1: %d X2: %d Y2: %d\n", X1, Y1, X2, Y2);//G ++ ++ if (mark && !shrink && blend) { ++ /* ++ * kludge: correct for interpolating blurring leaking ++ * up or left 1 destination pixel. ++ */ ++ if (X1 > 0) X1--; ++ if (Y1 > 0) Y1--; ++ } ++ ++ /* ++ * find the extent of the change the input rectangle induces in ++ * the scaled framebuffer. ++ */ ++ ++ /* Left edges: find largest i such that i * dx <= X1 */ ++ i1 = FLOOR(X1/dx); ++ ++ /* Right edges: find smallest i such that (i+1) * dx >= X2+1 */ ++ i2 = CEIL( (X2+1)/dx ) - 1; ++ ++ /* To be safe, correct any overflows: */ ++ i1 = nfix(i1, nx); ++ i2 = nfix(i2, nx) + 1; /* add 1 to make a rectangle upper boundary */ ++ ++ /* Repeat above for y direction: */ ++ j1 = FLOOR(Y1/dy); ++ j2 = CEIL( (Y2+1)/dy ) - 1; ++ ++ j1 = nfix(j1, ny); ++ j2 = nfix(j2, ny) + 1; ++ ++ /* ++ * special case integer magnification with no blending. ++ * vision impaired magnification usage is interested in this case. ++ */ ++ if (mark && ! blend && mag_int && Bpp != 3) { ++ int jmin, jmax, imin, imax; ++ ++ /* outer loop over *source* pixels */ ++ for (J=Y1; J < Y2; J++) { ++ jmin = J * mag_int; ++ jmax = jmin + mag_int; ++ for (I=X1; I < X2; I++) { ++ /* extract value */ ++ src = src_fb + J*src_bytes_per_line + I*Bpp; ++ if (Bpp == 4) { ++ ui = *((unsigned int *)src); ++ } else if (Bpp == 2) { ++ us = *((unsigned short *)src); ++ } else if (Bpp == 1) { ++ uc = *((unsigned char *)src); ++ } ++ imin = I * mag_int; ++ imax = imin + mag_int; ++ /* inner loop over *dest* pixels */ ++ for (j=jmin; j<jmax; j++) { ++ dest = dst_fb + j*dst_bytes_per_line + imin*Bpp; ++ for (i=imin; i<imax; i++) { ++ if (Bpp == 4) { ++ *((unsigned int *)dest) = ui; ++ } else if (Bpp == 2) { ++ *((unsigned short *)dest) = us; ++ } else if (Bpp == 1) { ++ *((unsigned char *)dest) = uc; ++ } ++ dest += Bpp; ++ } ++ } ++ } ++ } ++ goto markit; ++ } ++ ++ /* set these all to 1.0 to begin with */ ++ wx = 1.0; ++ wy = 1.0; ++ w = 1.0; ++ ++ /* ++ * Loop over destination pixels in scaled fb: ++ */ ++ for (j=j1; j<j2; j++) { ++ int jbdy = 1, I1_solid; ++ ++ y1 = j * dy; /* top edge */ ++ if (y1 > Ny - 1) { ++ /* can go over with dy = 1/scale_fac */ ++ y1 = Ny - 1; ++ } ++ y2 = y1 + dy; /* bottom edge */ ++ ++ /* Find main fb indices covered by this dest pixel: */ ++ J1 = (int) FLOOR(y1); ++ J1 = nfix(J1, Ny); ++ ++ if (shrink && ! interpolate) { ++ J2 = (int) CEIL(y2) - 1; ++ J2 = nfix(J2, Ny); ++ } else { ++ J2 = J1 + 1; /* simple interpolation */ ++ ddy = y1 - J1; ++ } ++ ++ /* destination char* pointer: */ ++ dest = dst_fb + j*dst_bytes_per_line + i1*Bpp; ++ ++ if (solid) { ++ if (j1+sbdy <= j && j < j2-sbdy) { ++ jbdy = 0; ++ x1 = (i1+sbdy) * dx; ++ if (x1 > Nx - 1) { ++ x1 = Nx - 1; ++ } ++ I1_solid = (int) FLOOR(x1); ++ if (I1_solid >= Nx) I1_solid = Nx - 1; ++ } ++ } ++ ++ for (i=i1; i<i2; i++) { ++ int solid_skip = 0; ++ ++ if (solid) { ++ /* if the region is solid, we can use the noblend speedup */ ++ if (!jbdy && i1+sbdy <= i && i < i2-sbdy) { ++ solid_skip = 1; ++ /* pixels all the same so use X1: */ ++ I1 = I1_solid; ++ goto jsolid; ++ } ++ } ++ ++ x1 = i * dx; /* left edge */ ++ if (x1 > Nx - 1) { ++ /* can go over with dx = 1/scale_fac */ ++ x1 = Nx - 1; ++ } ++ x2 = x1 + dx; /* right edge */ ++ ++ /* Find main fb indices covered by this dest pixel: */ ++ I1 = (int) FLOOR(x1); ++ if (I1 >= Nx) I1 = Nx - 1; ++ ++ jsolid: ++ cnt++; ++ ++ if ((!blend && use_noblend_shortcut) || solid_skip) { ++ /* ++ * The noblend case involves no weights, ++ * and 1 pixel, so just copy the value ++ * directly. ++ */ ++ src = src_fb + J1*src_bytes_per_line + I1*Bpp; ++ if (Bpp == 4) { ++ *((unsigned int *)dest) ++ = *((unsigned int *)src); ++ } else if (Bpp == 2) { ++ *((unsigned short *)dest) ++ = *((unsigned short *)src); ++ } else if (Bpp == 1) { ++ *(dest) = *(src); ++ } else if (Bpp == 3) { ++ /* rare case */ ++ for (k=0; k<=2; k++) { ++ *(dest+k) = *(src+k); ++ } ++ } ++ dest += Bpp; ++ continue; ++ } ++ ++ if (shrink && ! interpolate) { ++ I2 = (int) CEIL(x2) - 1; ++ if (I2 >= Nx) I2 = Nx - 1; ++ } else { ++ I2 = I1 + 1; /* simple interpolation */ ++ ddx = x1 - I1; ++ } ++//if (first) fprintf(stderr, " I1=%d I2=%d J1=%d J2=%d\n", I1, I2, J1, J2);//G ++ ++ /* Zero out accumulators for next pixel average: */ ++ for (b=0; b<4; b++) { ++ pixave[b] = 0.0; /* for RGB weighted sums */ ++ } ++ ++ /* ++ * wtot is for accumulating the total weight. ++ * It should always sum to 1/(scale_fac * scale_fac). ++ */ ++ wtot = 0.0; ++ ++ /* ++ * Loop over source pixels covered by this dest pixel. ++ * ++ * These "extra" loops over "J" and "I" make ++ * the cache/cacheline performance unclear. ++ * For example, will the data brought in from ++ * src for j, i, and J=0 still be in the cache ++ * after the J > 0 data have been accessed and ++ * we are at j, i+1, J=0? The stride in J is ++ * main_bytes_per_line, and so ~4 KB. ++ * ++ * Typical case when shrinking are 2x2 loop, so ++ * just two lines to worry about. ++ */ ++ for (J=J1; J<=J2; J++) { ++ /* see comments for I, x1, x2, etc. below */ ++ if (constant_weights) { ++ ; ++ } else if (! blend) { ++ if (J != J1) { ++ continue; ++ } ++ wy = 1.0; ++ ++ /* interpolation scheme: */ ++ } else if (! shrink || interpolate) { ++ if (J >= Ny) { ++ continue; ++ } else if (J == J1) { ++ wy = 1.0 - ddy; ++ } else if (J != J1) { ++ wy = ddy; ++ } ++ ++ /* integration scheme: */ ++ } else if (J < y1) { ++ wy = J+1 - y1; ++ } else if (J+1 > y2) { ++ wy = y2 - J; ++ } else { ++ wy = 1.0; ++ } ++ ++ src = src_fb + J*src_bytes_per_line + I1*Bpp; ++ ++ for (I=I1; I<=I2; I++) { ++ ++ /* Work out the weight: */ ++ ++ if (constant_weights) { ++ ; ++ } 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; ++ } ++ wx = 1.0; ++ ++ /* interpolation scheme: */ ++ } else if (! shrink || interpolate) { ++ if (I >= Nx) { ++ continue; /* off edge */ ++ } else if (I == I1) { ++ wx = 1.0 - ddx; ++ } else if (I != I1) { ++ wx = ddx; ++ } ++ ++ /* integration scheme: */ ++ } else if (I < x1) { ++ /* ++ * source left edge (I) to the ++ * left of dest left edge (x1): ++ * fractional weight ++ */ ++ wx = I+1 - x1; ++ } else if (I+1 > x2) { ++ /* ++ * source right edge (I+1) to the ++ * right of dest right edge (x2): ++ * fractional weight ++ */ ++ wx = x2 - I; ++ } else { ++ /* ++ * source edges (I and I+1) completely ++ * inside dest edges (x1 and x2): ++ * full weight ++ */ ++ wx = 1.0; ++ } ++ ++ w = wx * wy; ++ wtot += w; ++ ++ /* ++ * We average the unsigned char value ++ * instead of char value: otherwise ++ * the minimum (char 0) is right next ++ * to the maximum (char -1)! This way ++ * they are spread between 0 and 255. ++ */ ++ if (Bpp == 4) { ++ /* unroll the loops, can give 20% */ ++ pixave[0] += w * ((unsigned char) *(src )); ++ pixave[1] += w * ((unsigned char) *(src+1)); ++ pixave[2] += w * ((unsigned char) *(src+2)); ++ pixave[3] += w * ((unsigned char) *(src+3)); ++ } else if (Bpp == 2) { ++ /* ++ * 16bpp: trickier with green ++ * split over two bytes, so we ++ * use the masks: ++ */ ++ us = *((unsigned short *) src); ++ pixave[0] += w*(us & main_red_mask); ++ pixave[1] += w*(us & main_green_mask); ++ pixave[2] += w*(us & main_blue_mask); ++ } else if (Bpp == 1) { ++ pixave[0] += w * ++ ((unsigned char) *(src)); ++ } else { ++ for (b=0; b<Bpp; b++) { ++ pixave[b] += w * ++ ((unsigned char) *(src+b)); ++ } ++ } ++ src += Bpp; ++ } ++ } ++ ++ if (wtot <= 0.0) { ++ wtot = 1.0; ++ } ++ wtot = 1.0/wtot; /* normalization factor */ ++ ++ /* place weighted average pixel in the scaled fb: */ ++ if (Bpp == 4) { ++ *(dest ) = (char) (wtot * pixave[0]); ++ *(dest+1) = (char) (wtot * pixave[1]); ++ *(dest+2) = (char) (wtot * pixave[2]); ++ *(dest+3) = (char) (wtot * pixave[3]); ++ } else if (Bpp == 2) { ++ /* 16bpp / 565 case: */ ++ pixave[0] *= wtot; ++ pixave[1] *= wtot; ++ pixave[2] *= wtot; ++ us = (main_red_mask & (int) pixave[0]) ++ | (main_green_mask & (int) pixave[1]) ++ | (main_blue_mask & (int) pixave[2]); ++ *( (unsigned short *) dest ) = us; ++ } else if (Bpp == 1) { ++ *(dest) = (char) (wtot * pixave[0]); ++ } else { ++ for (b=0; b<Bpp; b++) { ++ *(dest+b) = (char) (wtot * pixave[b]); ++ } ++ } ++ dest += Bpp; ++ } ++ } ++ markit: ++/* End taken from x11vnc scale: */ ++ if (0) {} ++} ++ ++void put_image(int src_x, int src_y, int dst_x, int dst_y, int width, ++ int height, int solid) { ++ int db = 0; ++ int xmax = si.framebufferWidth; ++ int ymax = si.framebufferHeight; + ++if (db || 0) fprintf(stderr, "put_image(%d %d %d %d %d %d)\n", src_x, src_y, dst_x, dst_y, width, height); ++ ++ if (image_scale) { ++ int i; ++ for (i=0; i < 2; i++) { ++ if (src_x > 0) src_x--; ++ if (src_y > 0) src_y--; ++ } ++ for (i=0; i < 4; i++) { ++ if (src_x + width < xmax) width++; ++ if (src_y + height < ymax) height++; ++ } ++if (db) fprintf(stderr, "put_image(%d %d %d %d %d %d)\n", src_x, src_y, dst_x, dst_y, width, height); ++if (db) fprintf(stderr, "scale_rect(%d %d %d %d)\n", src_x, src_y, width, height); ++ ++ scale_rect(scale_factor_x, scale_factor_y, 1, 0, &src_x, &src_y, &width, &height, solid); ++ dst_x = src_x; ++ dst_y = src_y; ++ } ++ +#ifdef MITSHM + if (appData.useShm) { ++ double fac = image_scale ? scale_factor_y : 1.0; + if (image_ycrop == NULL) { -+//fprintf(stderr, "shm not image_ycrop\n"); -+ XShmPutImage(dpy, desktopWin, gc, image, src_x, src_y, -+ dst_x, dst_y, width, height, False); -+ } else if ((width < 32 && height < 32) || height > appData.yCrop) { -+//fprintf(stderr, "non-shmB image %d %d %d %d %d %d\n", src_x, src_y, dst_x, dst_y, width, height); ++ if (image_is_shm) { ++ XShmPutImage(dpy, desktopWin, gc, image, src_x, src_y, ++ dst_x, dst_y, width, height, False); ++ } else { ++ XPutImage(dpy, desktopWin, gc, image, src_x, src_y, ++ dst_x, dst_y, width, height); ++ } ++ } else if ((width < 32 && height < 32) || height > appData.yCrop * fac) { + XPutImage(dpy, desktopWin, gc, image, src_x, src_y, + dst_x, dst_y, width, height); + } else { @@ -3046,29 +4690,60 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + src += Bpl; + dst += Bpl2; + } -+//fprintf(stderr, "shm image_ycrop %d %d %d %d %d %d\n", 0, 0, dst_x, dst_y, width, height); + XShmPutImage(dpy, desktopWin, gc, image_ycrop, 0, 0, + dst_x, dst_y, width, height, False); + } + } else +#endif + { -+//fprintf(stderr, "non-shmA image %d %d %d %d %d %d\n", src_x, src_y, dst_x, dst_y, width, height); + XPutImage(dpy, desktopWin, gc, image, src_x, src_y, + dst_x, dst_y, width, height); + } ++} ++ ++//fprintf(stderr, "non-shmB image %d %d %d %d %d %d\n", src_x, src_y, dst_x, dst_y, width, height); ++//fprintf(stderr, "shm image_ycrop %d %d %d %d %d %d\n", 0, 0, dst_x, dst_y, width, height); ++//fprintf(stderr, "non-shmA image %d %d %d %d %d %d\n", src_x, src_y, dst_x, dst_y, width, height); ++ ++void releaseAllPressedModifiers(void) { ++ int i; ++ static int debug_release = -1; ++ if (debug_release < 0) { ++ if (getenv("SSVNC_DEBUG_RELEASE")) { ++ debug_release = 1; ++ } else { ++ debug_release = 0; ++ } ++ } ++ if (debug_release) fprintf(stderr, "into releaseAllPressedModifiers()\n"); ++ for (i = 0; i < 256; i++) { ++ if (modifierPressed[i]) { ++ SendKeyEvent(XKeycodeToKeysym(dpy, i, 0), False); ++ modifierPressed[i] = False; ++ if (debug_release) fprintf(stderr, "releasing[%d] %s\n", i, XKeysymToString(XKeycodeToKeysym(dpy, i, 0))); ++ } ++ } } ++#define PR_EXPOSE fprintf(stderr, "Expose: %04dx%04d+%04d+%04d %04d/%04d/%04d now: %8.4f rescale: %8.4f fullscreen: %8.4f\n", width, height, x, y, si.framebufferWidth, appData.yCrop, si.framebufferHeight, now - start_time, now - last_rescale, now - last_fullscreen); -@@ -152,39 +534,53 @@ + /* + * HandleBasicDesktopEvent - deal with expose and leave events. +@@ -152,39 +1470,116 @@ static void HandleBasicDesktopEvent(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont) { - int i; + int i, x, y, width, height; ++ static double last_expose = 0.0; ++ double now = dnow(); - switch (ev->type) { ++ if (0) { ++ PR_EXPOSE; ++ } ++ + switch (ev->type) { case Expose: case GraphicsExpose: @@ -3080,11 +4755,20 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + width = ev->xexpose.width; + height = ev->xexpose.height; + -+//fprintf(stderr, "Expose: %dx%d+%d+%d\n", width, height, x, y); -+ if (x + width > si.framebufferWidth) { -+ width = si.framebufferWidth - x; -+ if (width <= 0) { -+ break; ++ if (image_scale) { ++ int i; ++ x /= scale_factor_x; ++ y /= scale_factor_y; ++ width /= scale_factor_x; ++ height /= scale_factor_y; ++ /* make them a little wider to avoid painting errors */ ++ for (i=0; i < 3; i++) { ++ if (x > 0) x--; ++ if (y > 0) y--; ++ } ++ for (i=0; i < 6; i++) { ++ if (x + width < si.framebufferWidth) width++; ++ if (y + height < si.framebufferHeight) height++; + } + } @@ -3092,7 +4776,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - ev->xexpose.width = si.framebufferWidth - ev->xexpose.x; - if (ev->xexpose.width <= 0) break; - } -- ++ if (x + width > si.framebufferWidth) { ++ width = si.framebufferWidth - x; ++ if (width <= 0) { ++ break; ++ } ++ } + - if (ev->xexpose.y + ev->xexpose.height > si.framebufferHeight) { - ev->xexpose.height = si.framebufferHeight - ev->xexpose.y; - if (ev->xexpose.height <= 0) break; @@ -3107,11 +4797,49 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - SendFramebufferUpdateRequest(ev->xexpose.x, ev->xexpose.y, - ev->xexpose.width, ev->xexpose.height, False); - break; -+ if (appData.useBackingstore) { ++ if (appData.useXserverBackingStore) { + SendFramebufferUpdateRequest(x, y, width, height, False); + } else { -+ put_image(x, y, x, y, width, height); -+ XSync(dpy, False); ++ int ok = 1; ++ double delay = 2.5; ++ if (appData.fullScreen && now < last_fullscreen + delay) { ++ int xmax = si.framebufferWidth; ++ int ymax = si.framebufferHeight; ++ if (appData.yCrop > 0) { ++ ymax = appData.yCrop; ++ } ++ xmax = scale_round(xmax, scale_factor_x); ++ ymax = scale_round(ymax, scale_factor_y); ++ if (dpyWidth < xmax) { ++ xmax = dpyWidth; ++ } ++ if (dpyHeight < ymax) { ++ ymax = dpyHeight; ++ } ++ if (x != 0 && y != 0) { ++ ok = 0; ++ } ++ if (width < 0.9 * xmax) { ++ ok = 0; ++ } ++ if (height < 0.9 * ymax) { ++ ok = 0; ++ } ++ } ++ if (appData.yCrop > 0) { ++ if (now < last_fullscreen + delay || now < last_rescale + delay) { ++ if (y + height > appData.yCrop) { ++ height = appData.yCrop - y; ++ } ++ } ++ } ++ if (ok) { ++ put_image(x, y, x, y, width, height, 0); ++ XSync(dpy, False); ++ } else { ++ fprintf(stderr, "Skip "); ++ PR_EXPOSE; ++ } + } + break; @@ -3123,11 +4851,14 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - } - } - break; -+ for (i = 0; i < 256; i++) { -+ if (modifierPressed[i]) { -+ SendKeyEvent(XKeycodeToKeysym(dpy, i, 0), False); -+ modifierPressed[i] = False; -+ } ++ releaseAllPressedModifiers(); ++ if (appData.fullScreen) { ++ fs_ungrab(1); ++ } ++ break; ++ case EnterNotify: ++ if (appData.fullScreen) { ++ fs_grab(1); + } + break; } @@ -3135,7 +4866,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview } -@@ -201,6 +597,13 @@ +@@ -201,6 +1596,13 @@ * button2 down, 3 for both, etc). */ @@ -3149,7 +4880,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview void SendRFBEvent(Widget w, XEvent *ev, String *params, Cardinal *num_params) { -@@ -208,12 +611,62 @@ +@@ -208,12 +1610,71 @@ char keyname[256]; int buttonMask, x, y; @@ -3157,6 +4888,15 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - if (BumpScroll(ev)) - return; - } ++ if (ev->type == MotionNotify || ev->type == KeyRelease) { ++ static double last = 0.0; ++ double now = dnow(); ++ if (now > last + 0.25) { ++ check_things(); ++ last = now; ++ } ++ } ++ + if (appData.fullScreen && ev->type == MotionNotify) { + if (BumpScroll(ev)) { + return; @@ -3217,7 +4957,18 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview if (*num_params != 0) { if (strncasecmp(params[0],"key",3) == 0) { -@@ -329,26 +782,161 @@ +@@ -245,8 +1706,8 @@ + fprintf(stderr, "Invalid params: SendRFBEvent(fbupdate)\n"); + return; + } +- SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, +- si.framebufferHeight, False); ++ SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, si.framebufferHeight, False); ++ + } else if (strcasecmp(params[0],"ptr") == 0) { + if (*num_params == 4) { + x = atoi(params[1]); +@@ -329,26 +1790,185 @@ * CreateDotCursor. */ @@ -3284,7 +5035,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 1, 1); + XFreePixmap(dpy, src); + XFreePixmap(dpy, msk); -+ + +- return cursor; + return cursor; +} +#endif @@ -3312,9 +5064,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview +void +FillScreen(int x, int y, int width, int height, unsigned long fill) +{ -+ int bpp = image->bits_per_pixel; -+ int Bpp = image->bits_per_pixel / 8; -+ int Bpl = image->bytes_per_line; ++ XImage *im = image_scale ? image_scale : image; ++ int bpp = im->bits_per_pixel; ++ int Bpp = im->bits_per_pixel / 8; ++ int Bpl = im->bytes_per_line; + int h, widthInBytes = width * Bpp; + static char *buf = NULL; + static int buflen = 0; @@ -3325,6 +5078,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + int b0, b1, b2; + +//fprintf(stderr, "FillImage bpp=%d %04dx%04d+%04d+%04d -- 0x%x\n", bpp, width, height, x, y, fill); ++ if (appData.chatOnly) { ++ return; ++ } + + if (widthInBytes > buflen || !buf) { + if (buf) { @@ -3356,46 +5112,65 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + *(uip+h) = (unsigned int) fill; + } + } - -- return cursor; -+ scr = image->data + y * Bpl + x * Bpp; ++ ++ scr = im->data + y * Bpl + x * Bpp; + + for (h = 0; h < height; h++) { + memcpy(scr, buf, widthInBytes); + scr += Bpl; + } -+ put_image(x, y, x, y, width, height); ++ put_image(x, y, x, y, width, height, 1); + maybe_sync(width, height); +} + +void copy_rect(int x, int y, int width, int height, int src_x, int src_y) { + char *src, *dst; + int i; -+ int Bpp = image->bits_per_pixel / 8; -+ int Bpl = image->bytes_per_line; ++ XImage *im = image_scale ? image_scale : image; ++ int Bpp = im->bits_per_pixel / 8; ++ int Bpl = im->bytes_per_line; ++ int did2 = 0; + +//fprintf(stderr, "copy_rect: %04dx%04d+%04d+%04d -- %04d %04d Bpp=%d Bpl=%d\n", width, height, x, y, src_x, src_y, Bpp, Bpl); ++ copyrect2: ++ + if (y < src_y) { -+ src = image->data + src_y * Bpl + src_x * Bpp; -+ dst = image->data + y * Bpl + x * Bpp; ++ src = im->data + src_y * Bpl + src_x * Bpp; ++ dst = im->data + y * Bpl + x * Bpp; + for (i = 0; i < height; i++) { + memmove(dst, src, Bpp * width); + src += Bpl; + dst += Bpl; + } + } else { -+ src = image->data + (src_y + height - 1) * Bpl + src_x * Bpp; -+ dst = image->data + (y + height - 1) * Bpl + x * Bpp; ++ src = im->data + (src_y + height - 1) * Bpl + src_x * Bpp; ++ dst = im->data + (y + height - 1) * Bpl + x * Bpp; + for (i = 0; i < height; i++) { + memmove(dst, src, Bpp * width); + src -= Bpl; + dst -= Bpl; + } + } ++ ++ if (image_scale && !did2) { ++ im = image; ++ Bpp = im->bits_per_pixel / 8; ++ Bpl = im->bytes_per_line; ++ ++ x *= scale_factor_x; ++ y *= scale_factor_y; ++ src_x *= scale_factor_x; ++ src_y *= scale_factor_y; ++ width = scale_round(width, scale_factor_x); ++ height = scale_round(height, scale_factor_y); ++ ++ did2 = 1; ++ goto copyrect2; ++ } } -@@ -359,38 +947,35 @@ +@@ -359,38 +1979,37 @@ void CopyDataToScreen(char *buf, int x, int y, int width, int height) { @@ -3406,6 +5181,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - - usleep(appData.rawDelay * 1000); - } ++ if (appData.chatOnly) { ++ return; ++ } + if (appData.rawDelay != 0) { + XFillRectangle(dpy, desktopWin, gc, x, y, width, height); + XSync(dpy,False); @@ -3436,12 +5214,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + int h; + int widthInBytes = width * myFormat.bitsPerPixel / 8; + int scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8; ++ XImage *im = image_scale ? image_scale : image; + -+ char *scr = (image->data + y * scrWidthInBytes ++ char *scr = (im->data + y * scrWidthInBytes + + x * myFormat.bitsPerPixel / 8); + -+//fprintf(stderr, "CopyDataToScreen %dx%d+%d+%d\n", width, height, x, y); -+ + for (h = 0; h < height; h++) { + memcpy(scr, buf, widthInBytes); + buf += widthInBytes; @@ -3456,12 +5233,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview - } -#endif - XPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height); -+ put_image(x, y, x, y, width, height); ++ put_image(x, y, x, y, width, height, 0); + maybe_sync(width, height); } -@@ -401,62 +986,228 @@ +@@ -401,62 +2020,295 @@ static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width, int height) { @@ -3478,11 +5255,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + int xoff = 7 - (x & 7); + int xcur; + int fbwb = si.framebufferWidth / 8; -+ CARD8 *scr1 = ((CARD8 *)image->data) + y * fbwb + x / 8; ++ XImage *im = image_scale ? image_scale : image; ++ CARD8 *scr1 = ((CARD8 *)im->data) + y * fbwb + x / 8; + CARD8 *scrt; -+ CARD8 *scr8 = ( (CARD8 *)image->data) + y * si.framebufferWidth + x; -+ CARD16 *scr16 = ((CARD16 *)image->data) + y * si.framebufferWidth + x; -+ CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x; ++ CARD8 *scr8 = ( (CARD8 *)im->data) + y * si.framebufferWidth + x; ++ CARD16 *scr16 = ((CARD16 *)im->data) + y * si.framebufferWidth + x; ++ CARD32 *scr32 = ((CARD32 *)im->data) + y * si.framebufferWidth + x; + int b0, b1, b2; - switch (visbpp) { @@ -3542,7 +5320,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + } else { + b0 = 2; b1 = 1; b2 = 0; + } -+ scr8 = ((CARD8 *)image->data) + (y * si.framebufferWidth + x) * 3; ++ scr8 = ((CARD8 *)im->data) + (y * si.framebufferWidth + x) * 3; + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + CARD32 v = BGR233ToPixel[*(buf++)]; @@ -3583,7 +5361,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview +{ + int p, q; + int b0, b1, b2; -+ unsigned char *scr= (unsigned char *)image->data + (y * si.framebufferWidth + x) * 3; ++ XImage *im = image_scale ? image_scale : image; ++ unsigned char *scr= (unsigned char *)im->data + (y * si.framebufferWidth + x) * 3; + + if (isLSB) { + b0 = 0; b1 = 1; b2 = 2; @@ -3625,7 +5404,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview +CopyBGR565ToScreen(CARD16 *buf, int x, int y, int width, int height) +{ + int p, q; -+ CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x; ++ XImage *im = image_scale ? image_scale : image; ++ CARD32 *scr32 = ((CARD32 *)im->data) + y * si.framebufferWidth + x; + + if (visbpp == 24) { + BGR565_24bpp(buf, x, y, width, height); @@ -3647,22 +5427,37 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + } + if (image && image->data) { + XDestroyImage(image); ++ fprintf(stderr, "reset_image: destroyed 'image'\n"); + } + image = NULL; + if (image_ycrop && image_ycrop->data) { + XDestroyImage(image_ycrop); ++ fprintf(stderr, "reset_image: destroyed 'image_ycrop'\n"); + } + image_ycrop = NULL; ++ if (image_scale && image_scale->data) { ++ XDestroyImage(image_scale); ++ fprintf(stderr, "reset_image: destroyed 'image_scale'\n"); ++ } ++ image_scale = NULL; ++ + create_image(); + XFlush(dpy); +} + +void ReDoDesktop(void) { -+ int w, h, x, y, dw, dh; ++ int w, h, h0, x, y, dw, dh; ++ int fs = 0; ++ int autoscale = 0; ++ ++ if (!appData.fullScreen && appData.scale != NULL && !strcmp(appData.scale, "auto")) { ++ autoscale = 1; ++ } + -+fprintf(stderr, "ReDoDesktop: ycrop: %d\n", appData.yCrop); ++ fprintf(stderr, "ReDoDesktop: ycrop: %d\n", appData.yCrop); + + check_tall(); ++ + if (appData.yCrop) { + if (appData.yCrop < 0 || old_width <= 0) { + appData.yCrop = guessCrop(); @@ -3678,10 +5473,40 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + } + fprintf(stderr, "Using -ycrop: %d\n", appData.yCrop); + } ++ + old_width = si.framebufferWidth; + old_height = si.framebufferHeight; + + if (appData.fullScreen) { ++ if (prev_fb_width != si.framebufferWidth || prev_fb_height != si.framebufferHeight) { ++ int xmax = si.framebufferWidth; ++ int ymax = si.framebufferHeight; ++ if (appData.yCrop > 0) { ++ ymax = appData.yCrop; ++ } ++ if (scale_x > 0) { ++ xmax = scale_round(xmax, scale_factor_x); ++ ymax = scale_round(ymax, scale_factor_y); ++ } ++ if (xmax < dpyWidth || ymax < dpyHeight) { ++ FullScreenOff(); ++ fs = 1; ++ } ++ } ++ } ++ ++ prev_fb_width = si.framebufferWidth; ++ prev_fb_height = si.framebufferHeight; ++ ++ if (appData.fullScreen) { ++ ++ int xmax = si.framebufferWidth; ++ int ymax = si.framebufferHeight; ++ if (scale_x > 0) { ++ xmax = scale_round(xmax, scale_factor_x); ++ ymax = scale_round(ymax, scale_factor_y); ++ } ++ + if (image && image->data) { + int len; + int h = image->height; @@ -3692,7 +5517,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + XPutImage(dpy, XtWindow(desktop), gc, image, 0, 0, 0, 0, w, h); + XFlush(dpy); + } -+ XtResizeWidget(desktop, si.framebufferWidth, si.framebufferHeight, 0); ++ ++ /* XXX scaling?? */ ++ XtResizeWidget(desktop, xmax, ymax, 0); ++ + XSync(dpy, False); + usleep(100*1000); + FullScreenOn(); @@ -3707,11 +5535,14 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + + w = si.framebufferWidth; + h = si.framebufferHeight; ++ h0 = h; + if (appData.yCrop > 0) { + h = appData.yCrop; -+ if (0 && appData.sbWidth <= 6 && appData.sbWidth > 0) { -+ h += appData.sbWidth; -+ } ++ } ++ if (image_scale) { ++ w = scale_round(w, scale_factor_x); ++ h = scale_round(h, scale_factor_y); ++ h0 = scale_round(h0, scale_factor_y); + } + + if (w + dw >= dpyWidth) { @@ -3721,41 +5552,130 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/desktop.c vnc_unixsrc/vncview + h = dpyHeight - dh; + } + -+ XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL); ++ if (!autoscale) { ++ XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL); ++ } else { ++ XtVaSetValues(toplevel, XtNmaxWidth, dpyWidth, XtNmaxHeight, dpyHeight, NULL); ++ } + -+ XtVaSetValues(desktop, XtNwidth, si.framebufferWidth, -+ XtNheight, si.framebufferHeight, NULL); ++ XtVaSetValues(desktop, XtNwidth, w, XtNheight, h0, NULL); + + x = (dpyWidth - w - dw)/2; + y = (dpyHeight - h - dh)/2; + -+ XtResizeWidget(desktop, si.framebufferWidth, si.framebufferHeight, 0); ++ XtResizeWidget(desktop, w, h0, 0); + + if (appData.yCrop > 0) { -+ XtVaSetValues(toplevel, XtNmaxHeight, appData.yCrop, NULL); -+ XtVaSetValues(form, XtNmaxHeight, appData.yCrop, NULL); ++ int ycrop = appData.yCrop; ++ if (image_scale) { ++ ycrop *= scale_factor_y; ++ } ++ XtVaSetValues(toplevel, XtNmaxHeight, ycrop, NULL); ++ XtVaSetValues(form, XtNmaxHeight, ycrop, NULL); + } + -+ XtConfigureWidget(toplevel, x + dw, y + dh, w, h, 0); ++ if (!autoscale) { ++ XtConfigureWidget(toplevel, x + dw, y + dh, w, h, 0); ++ } + + reset_image(); ++ ++ if (fs) { ++ FullScreenOn(); ++ } } diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncviewer/dialogs.c --- vnc_unixsrc.orig/vncviewer/dialogs.c 2000-10-26 15:19:19.000000000 -0400 -+++ vnc_unixsrc/vncviewer/dialogs.c 2008-02-16 19:04:46.000000000 -0500 -@@ -26,6 +26,208 @@ ++++ vnc_unixsrc/vncviewer/dialogs.c 2008-10-10 15:46:43.000000000 -0400 +@@ -26,6 +26,299 @@ static Bool serverDialogDone = False; static Bool passwordDialogDone = False; +static Bool ycropDialogDone = False; -+static Bool scbarDialogDone = False; +static Bool scaleDialogDone = False; ++static Bool scbarDialogDone = False; ++static Bool scaleNDialogDone = False; +static Bool qualityDialogDone = False; +static Bool compressDialogDone = False; + +extern void popupFixer(Widget wid); + +void ++ScaleDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) ++{ ++ scaleDialogDone = True; ++} ++ ++void dialog_over(Widget wid) { ++ if (appData.fullScreen) { ++ if (!net_wm_supported()) { ++ XtVaSetValues(wid, XtNoverrideRedirect, True, NULL); ++ XSync(dpy, True); ++ } ++ } ++} ++ ++extern int XError_ign; ++ ++void dialog_input(Widget wid) { ++ XError_ign = 1; ++ XSetInputFocus(dpy, XtWindow(wid), RevertToParent, CurrentTime); ++ XSync(dpy, False); ++ usleep(30 * 1000); ++ XSync(dpy, False); ++ usleep(20 * 1000); ++ XSync(dpy, False); ++ XError_ign = 0; ++} ++ ++char * ++DoScaleDialog() ++{ ++ Widget pshell, dialog; ++ char *scaleValue; ++ char *valueString; ++ ++ pshell = XtVaCreatePopupShell("scaleDialog", transientShellWidgetClass, ++ toplevel, NULL); ++ dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); ++ ++ dialog_over(pshell); ++ ++ XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, ++ HeightOfScreen(XtScreen(pshell))*2/5); ++ XtPopup(pshell, XtGrabNonexclusive); ++ XtRealizeWidget(pshell); ++ ++ if (appData.scale != NULL) { ++ String label; ++ char tmp[410]; ++ XtVaGetValues(dialog, XtNlabel, &label, NULL); ++ if (strlen(label) + strlen(appData.scale) < 400) { ++ sprintf(tmp, "%s %s", label, appData.scale); ++ XtVaSetValues(dialog, XtNlabel, tmp, NULL); ++ } ++ } ++ ++ ++ if (appData.popupFix) { ++ popupFixer(pshell); ++ } ++ dialog_input(pshell); ++ ++ scaleDialogDone = False; ++ ++ while (!scaleDialogDone) { ++ XtAppProcessEvent(appContext, XtIMAll); ++ } ++ ++ valueString = XawDialogGetValueString(dialog); ++ scaleValue = XtNewString(valueString); ++ ++ XtPopdown(pshell); ++ return scaleValue; ++} ++ ++void +YCropDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + ycropDialogDone = True; @@ -3772,6 +5692,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + ++ dialog_over(pshell); ++ + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); @@ -3780,6 +5702,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + if (appData.popupFix) { + popupFixer(pshell); + } ++ dialog_input(pshell); + + ycropDialogDone = False; + @@ -3811,6 +5734,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + ++ dialog_over(pshell); ++ + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); @@ -3819,6 +5744,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + if (appData.popupFix) { + popupFixer(pshell); + } ++ dialog_input(pshell); + + scbarDialogDone = False; + @@ -3834,22 +5760,24 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview +} + +void -+ScaleDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) ++ScaleNDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ -+ scaleDialogDone = True; ++ scaleNDialogDone = True; +} + +char * -+DoScaleDialog() ++DoScaleNDialog() +{ + Widget pshell, dialog; -+ char *scaleValue; ++ char *scaleNValue; + char *valueString; + -+ pshell = XtVaCreatePopupShell("scaleDialog", transientShellWidgetClass, ++ pshell = XtVaCreatePopupShell("scaleNDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + ++ dialog_over(pshell); ++ + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); @@ -3858,18 +5786,19 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + if (appData.popupFix) { + popupFixer(pshell); + } ++ dialog_input(pshell); + -+ scaleDialogDone = False; ++ scaleNDialogDone = False; + -+ while (!scaleDialogDone) { ++ while (!scaleNDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); -+ scaleValue = XtNewString(valueString); ++ scaleNValue = XtNewString(valueString); + + XtPopdown(pshell); -+ return scaleValue; ++ return scaleNValue; +} + +void @@ -3889,6 +5818,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + ++ dialog_over(pshell); ++ + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); @@ -3897,6 +5828,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + if (appData.popupFix) { + popupFixer(pshell); + } ++ dialog_input(pshell); + + qualityDialogDone = False; + @@ -3928,6 +5860,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + ++ dialog_over(pshell); ++ + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); @@ -3936,6 +5870,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview + if (appData.popupFix) { + popupFixer(pshell); + } ++ dialog_input(pshell); + + compressDialogDone = False; + @@ -3952,31 +5887,47 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncview void ServerDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) -@@ -49,6 +251,10 @@ +@@ -44,11 +337,18 @@ + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + ++ dialog_over(pshell); ++ + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); XtPopup(pshell, XtGrabNonexclusive); XtRealizeWidget(pshell); + if (appData.popupFix) { + popupFixer(pshell); + } ++ dialog_input(pshell); + serverDialogDone = False; while (!serverDialogDone) { -@@ -85,6 +291,10 @@ +@@ -80,11 +380,18 @@ + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + ++ dialog_over(pshell); ++ + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); XtPopup(pshell, XtGrabNonexclusive); XtRealizeWidget(pshell); + if (appData.popupFix) { + popupFixer(pshell); + } ++ dialog_input(pshell); + passwordDialogDone = False; while (!passwordDialogDone) { diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/fullscreen.c vnc_unixsrc/vncviewer/fullscreen.c --- vnc_unixsrc.orig/vncviewer/fullscreen.c 2003-10-09 05:23:49.000000000 -0400 -+++ vnc_unixsrc/vncviewer/fullscreen.c 2008-02-22 09:03:22.000000000 -0500 ++++ vnc_unixsrc/vncviewer/fullscreen.c 2008-10-12 15:12:52.000000000 -0400 @@ -27,7 +27,9 @@ #include <X11/Xaw/Toggle.h> @@ -3987,111 +5938,240 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/fullscreen.c vnc_unixsrc/vncv static XtIntervalId timer; static Bool timerSet = False; static Bool scrollLeft, scrollRight, scrollUp, scrollDown; -@@ -85,10 +87,14 @@ - Dimension oldViewportWidth, oldViewportHeight, clipWidth, clipHeight; - Position viewportX, viewportY; +@@ -36,6 +38,7 @@ + static Dimension scrollbarWidth, scrollbarHeight; -+ Bool fsAlready = appData.fullScreen, toobig = False; -+ - appData.fullScreen = True; - if (si.framebufferWidth > dpyWidth || si.framebufferHeight > dpyHeight) { -+ int eff_height = si.framebufferHeight; ++int scale_round(int len, double fac); -+ toobig = True; - XtVaSetValues(viewport, XtNforceBars, True, NULL); - XtVaGetValues(viewport, XtNwidth, &oldViewportWidth, - XtNheight, &oldViewportHeight, NULL); -@@ -105,16 +111,23 @@ - toplevelWidth = dpyWidth; - } + /* + * FullScreenOn goes into full-screen mode. It makes the toplevel window +@@ -78,112 +81,450 @@ + * variables so that FullScreenOff can use them. + */ +-void +-FullScreenOn() +-{ +- Dimension toplevelWidth, toplevelHeight; +- Dimension oldViewportWidth, oldViewportHeight, clipWidth, clipHeight; +- Position viewportX, viewportY; +- +- appData.fullScreen = True; +- +- if (si.framebufferWidth > dpyWidth || si.framebufferHeight > dpyHeight) { +- +- XtVaSetValues(viewport, XtNforceBars, True, NULL); +- XtVaGetValues(viewport, XtNwidth, &oldViewportWidth, +- XtNheight, &oldViewportHeight, NULL); +- XtVaGetValues(XtNameToWidget(viewport, "clip"), +- XtNwidth, &clipWidth, XtNheight, &clipHeight, NULL); +- +- scrollbarWidth = oldViewportWidth - clipWidth; +- scrollbarHeight = oldViewportHeight - clipHeight; +- +- if (si.framebufferWidth > dpyWidth) { +- viewportWidth = toplevelWidth = dpyWidth + scrollbarWidth; +- } else { +- viewportWidth = si.framebufferWidth + scrollbarWidth; +- toplevelWidth = dpyWidth; +- } +- - if (si.framebufferHeight > dpyHeight) { -+ if (appData.yCrop > 0) { -+ eff_height = appData.yCrop; -+ } -+ -+ if (eff_height > dpyHeight) { - viewportHeight = toplevelHeight = dpyHeight + scrollbarHeight; - } else { +- viewportHeight = toplevelHeight = dpyHeight + scrollbarHeight; +- } else { - viewportHeight = si.framebufferHeight + scrollbarHeight; -+ viewportHeight = eff_height + scrollbarHeight; - toplevelHeight = dpyHeight; - } - - } else { - viewportWidth = si.framebufferWidth; - viewportHeight = si.framebufferHeight; -+ if (appData.yCrop > 0) { -+ viewportHeight = appData.yCrop; +- toplevelHeight = dpyHeight; +- } +- +- } else { +- viewportWidth = si.framebufferWidth; +- viewportHeight = si.framebufferHeight; +- toplevelWidth = dpyWidth; +- toplevelHeight = dpyHeight; +- } ++int net_wm_supported(void) { ++ unsigned char *data; ++ unsigned long items_read, items_left, i; ++ int ret, format; ++ Window wm; ++ Atom type; ++ Atom _NET_SUPPORTING_WM_CHECK; ++ Atom _NET_SUPPORTED; ++ Atom _NET_WM_STATE; ++ Atom _NET_WM_STATE_FULLSCREEN; ++ ++ static time_t last_check = 0; ++ static int fs_supported = -1; ++ ++ if (fs_supported >= 0 && time(NULL) < last_check + 600) { ++ static int first = 1; ++ if (first) { ++ fprintf(stderr, "fs_supported: %d\n", fs_supported); ++ } ++ first = 0; ++ return fs_supported; + } - toplevelWidth = dpyWidth; - toplevelHeight = dpyHeight; - } -@@ -129,7 +142,12 @@ - reparenting our window to the root. The window manager will get a - ReparentNotify and hopefully clean up its frame window. */ - -+if (! fsAlready) { -+ XUnmapWindow(dpy, XtWindow(toplevel)); - XtVaSetValues(toplevel, XtNoverrideRedirect, True, NULL); -+ XtVaSetValues(viewport, XtNoverrideRedirect, True, NULL); -+ XtVaSetValues(desktop, XtNoverrideRedirect, True, NULL); -+ XtVaSetValues(popup, XtNoverrideRedirect, True, NULL); - - XReparentWindow(dpy, XtWindow(toplevel), DefaultRootWindow(dpy), 0, 0); - -@@ -139,6 +157,8 @@ - with XReparentWindow. The last XSync seems to prevent losing - focus, but I don't know why. */ - XSync(dpy, False); -+XMapWindow(dpy, XtWindow(toplevel)); -+XRaiseWindow(dpy, XtWindow(toplevel)); - XMoveWindow(dpy, XtWindow(toplevel), 0, 0); - XSync(dpy, False); - -@@ -164,25 +184,67 @@ ++ last_check = time(NULL); ++ ++ fs_supported = 0; ++ ++ _NET_SUPPORTING_WM_CHECK = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); ++ _NET_SUPPORTED = XInternAtom(dpy, "_NET_SUPPORTED", False); ++ _NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False); ++ _NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); ++ ++ ret = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _NET_SUPPORTING_WM_CHECK, ++ 0L, 1L, False, XA_WINDOW, &type, &format, &items_read, &items_left, &data); ++ ++ if (ret != Success || !items_read) { ++ if (ret == Success) { ++ XFree(data); ++ } ++ return fs_supported; ++ } ++ ++ wm = ((Window*) data)[0]; ++ XFree(data); ++ ++ ret = XGetWindowProperty(dpy, wm, _NET_SUPPORTING_WM_CHECK, ++ 0L, 1L, False, XA_WINDOW, &type, &format, &items_read, &items_left, &data); ++ ++ if (ret != Success || !items_read) { ++ if (ret == Success) { ++ XFree(data); ++ } ++ return fs_supported; ++ } ++ ++ if (wm != ((Window*) data)[0]) { ++ XFree(data); ++ return fs_supported; ++ } ++ ++ ret = XGetWindowProperty(dpy, DefaultRootWindow(dpy), _NET_SUPPORTED, ++ 0L, 8192L, False, XA_ATOM, &type, &format, &items_read, &items_left, &data); ++ ++ if (ret != Success || !items_read) { ++ if (ret == Success) { ++ XFree(data); ++ } ++ return fs_supported; ++ } ++ ++ for (i=0; i < items_read; i++) { ++ if ( ((Atom*) data)[i] == _NET_WM_STATE_FULLSCREEN) { ++ fs_supported = 1; ++ } ++ } ++ XFree(data); - XtManageChild(viewport); +- viewportX = (toplevelWidth - viewportWidth) / 2; +- viewportY = (toplevelHeight - viewportHeight) / 2; ++ return fs_supported; ++} -- /* Now we can set "toplevel" to its proper size. */ -+} else { ++static void net_wm_fullscreen(int to_fs) { ++ ++ int _NET_WM_STATE_REMOVE = 0; ++ int _NET_WM_STATE_ADD = 1; ++ int _NET_WM_STATE_TOGGLE = 2; ++ Atom _NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False); ++ Atom _NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); ++ XEvent xev; ++ ++ if (to_fs == 2) { ++ XChangeProperty(dpy, XtWindow(toplevel), _NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char*)&_NET_WM_STATE_FULLSCREEN, 1); ++ } else { ++ xev.xclient.type = ClientMessage; ++ xev.xclient.window = XtWindow(toplevel); ++ xev.xclient.message_type = _NET_WM_STATE; ++ xev.xclient.serial = 0; ++ xev.xclient.display = dpy; ++ xev.xclient.send_event = True; ++ xev.xclient.format = 32; ++ xev.xclient.data.l[0] = to_fs ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; ++ xev.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN; ++ xev.xclient.data.l[2] = 0; ++ xev.xclient.data.l[3] = 0; ++ xev.xclient.data.l[4] = 0; ++ XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); ++ } + +- /* We want to stop the window manager from managing our toplevel window. +- This is not really a nice thing to do, so may not work properly with every +- window manager. We do this simply by setting overrideRedirect and +- reparenting our window to the root. The window manager will get a +- ReparentNotify and hopefully clean up its frame window. */ + XSync(dpy, False); +} -+ /* Now we can set "toplevel" to its proper size. */ - XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0); +- XtVaSetValues(toplevel, XtNoverrideRedirect, True, NULL); ++time_t main_grab = 0; -- /* Set the popup to overrideRedirect too */ -+if (fsAlready) { -+ XtResizeWidget(viewport, viewportWidth, viewportHeight, 0); -+ if (! toobig) { -+ XtVaSetValues(viewport, XtNforceBars, False, NULL); -+ } -+ XMoveWindow(dpy, XtWindow(viewport), viewportX, viewportY); -+ XSync(dpy, False); +- XReparentWindow(dpy, XtWindow(toplevel), DefaultRootWindow(dpy), 0, 0); ++void fs_ungrab(int check) { ++ if (check) { ++ if (time(NULL) <= main_grab + 2) { ++ return; ++ } ++ if (net_wm_supported()) { ++ return; ++ } ++ } ++ fprintf(stderr, "calling fs_ungrab()\n"); ++ if (appData.grabAll) { /* runge top of FullScreenOff */ ++ fprintf(stderr, "calling XUngrabServer(dpy)\n"); ++ XUngrabServer(dpy); ++ } ++ if (appData.grabKeyboard) { ++ fprintf(stderr, "calling XUngrabKeyboard(dpy)\n"); ++ XtUngrabKeyboard(desktop, CurrentTime); ++ } +} -- XtVaSetValues(popup, XtNoverrideRedirect, True, NULL); -+ /* Set the popup to overrideRedirect too */ - - /* Try to get the input focus. */ - -+#if 0 - XSetInputFocus(dpy, DefaultRootWindow(dpy), RevertToPointerRoot, - CurrentTime); -+#else -+ XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, -+ CurrentTime); -+#endif +- /* Some WMs does not obey x,y values of XReparentWindow; the window +- is not placed in the upper, left corner. The code below fixes +- this: It manually moves the window, after the Xserver is done +- with XReparentWindow. The last XSync seems to prevent losing +- focus, but I don't know why. */ +- XSync(dpy, False); +- XMoveWindow(dpy, XtWindow(toplevel), 0, 0); +- XSync(dpy, False); +- +- /* Now we want to fix the size of "viewport". We shouldn't just change it +- directly. Instead we set "toplevel" to the required size (which should +- propagate through "form" to "viewport"). Then we remove "viewport" from +- being managed by "form", change its resources to position it and make sure +- that "form" won't attempt to resize it, then ask "form" to manage it +- again. */ +- +- XtResizeWidget(toplevel, viewportWidth, viewportHeight, 0); +- +- XtUnmanageChild(viewport); +- +- XtVaSetValues(viewport, +- XtNhorizDistance, viewportX, +- XtNvertDistance, viewportY, +- XtNleft, XtChainLeft, +- XtNright, XtChainLeft, +- XtNtop, XtChainTop, +- XtNbottom, XtChainTop, +- NULL); ++void fs_grab(int check) { ++ if (check) { ++ if (time(NULL) <= main_grab + 2) { ++ return; ++ } ++ if (net_wm_supported()) { ++ return; ++ } ++ } + - - /* Optionally, grab the keyboard. */ - -- if (appData.grabKeyboard && -- XtGrabKeyboard(desktop, True, GrabModeAsync, -- GrabModeAsync, CurrentTime) != GrabSuccess) { -- fprintf(stderr, "XtGrabKeyboard() failed.\n"); ++ main_grab = time(NULL); ++ ++ fprintf(stderr, "calling fs_grab()\n"); ++ +#define FORCE_UP \ + XSync(dpy, False); \ + XUnmapWindow(dpy, XtWindow(toplevel)); \ @@ -4100,73 +6180,640 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/fullscreen.c vnc_unixsrc/vncv + XRaiseWindow(dpy, XtWindow(toplevel)); \ + XSync(dpy, False); + -+ if (appData.grabKeyboard && XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { -+ fprintf(stderr, "XtGrabKeyboard() failed.\n"); -+ XSync(dpy, False); -+ usleep(200 * 1000); -+ FORCE_UP ++ if (appData.grabKeyboard && XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { ++ fprintf(stderr, "XtGrabKeyboard() failed.\n"); ++ XSync(dpy, False); ++ usleep(100 * 1000); ++ FORCE_UP + -+ if (XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { -+ fprintf(stderr, "XtGrabKeyboard() failed again.\n"); -+ usleep(200 * 1000); -+ XSync(dpy, True); -+ if (XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { -+ fprintf(stderr, "XtGrabKeyboard() failed 3rd time.\n"); ++ if (XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { ++ fprintf(stderr, "XtGrabKeyboard() failed again.\n"); ++ usleep(200 * 1000); ++ XSync(dpy, False); ++ if (XtGrabKeyboard(desktop, True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { ++ fprintf(stderr, "XtGrabKeyboard() failed 3rd time.\n"); ++ } else { ++ fprintf(stderr, "XtGrabKeyboard() OK 3rd try.\n"); ++ } ++ } else { ++ fprintf(stderr, "XtGrabKeyboard() OK 2nd try.\n"); ++ } ++ XRaiseWindow(dpy, XtWindow(toplevel)); ++ } ++ ++ if (appData.grabAll) { ++ fprintf(stderr, "calling XGrabServer(dpy)\n"); ++ if (! XGrabServer(dpy)) { ++ XSync(dpy, False); ++ usleep(100 * 1000); ++ fprintf(stderr, "calling XGrabServer(dpy) 2nd time\n"); ++ if (!XGrabServer(dpy)) { ++ XSync(dpy, False); ++ usleep(200 * 1000); ++ fprintf(stderr, "calling XGrabServer(dpy) 3rd time\n"); ++ if (XGrabServer(dpy)) { ++ fprintf(stderr, "XGrabServer(dpy) OK 3rd time\n"); ++ } ++ } else { ++ fprintf(stderr, "XGrabServer(dpy) OK 2nd time\n"); ++ } ++ XSync(dpy, False); ++ } ++ if (getenv("VNCVIEWER_FORCE_UP")) { ++ fprintf(stderr, "FORCE_UP\n"); ++ FORCE_UP ++ } ++ } ++} ++ ++extern int fullscreen_startup; ++extern double last_fullscreen; ++ ++#define set_size_hints() \ ++{ \ ++ long supplied; \ ++ XSizeHints *sizehints = XAllocSizeHints(); \ ++ XGetWMSizeHints(dpy, topwin, sizehints, &supplied, XA_WM_NORMAL_HINTS); \ ++ if (sizehints->base_width < toplevelWidth) { \ ++ sizehints->base_width = toplevelWidth; \ ++ } \ ++ if (sizehints->base_height < toplevelHeight) { \ ++ sizehints->base_height = toplevelHeight; \ ++ } \ ++ if (sizehints->max_width < toplevelWidth) { \ ++ sizehints->max_width = toplevelWidth; \ ++ } \ ++ if (sizehints->max_height < toplevelHeight) { \ ++ sizehints->max_height = toplevelHeight; \ ++ } \ ++ XSetWMSizeHints(dpy, topwin, sizehints, XA_WM_NORMAL_HINTS); \ ++ XFree(sizehints); \ ++} + +- XtManageChild(viewport); ++extern int scale_x, scale_y; ++extern double scale_factor_y; ++ ++void ++FullScreenOn() ++{ ++ Dimension toplevelWidth, toplevelHeight; ++ Dimension oldViewportWidth, oldViewportHeight, clipWidth, clipHeight; ++ Position viewportX, viewportY; ++ int do_net_wm = net_wm_supported(); ++ int fbW = si.framebufferWidth; ++ int fbH = si.framebufferHeight; ++ int eff_height; ++ ++ Bool fsAlready = appData.fullScreen, toobig = False; ++ Window topwin = XtWindow(toplevel); ++ ++ appData.fullScreen = True; ++ ++ last_fullscreen = dnow(); ++ ++ if (scale_x > 0) { ++ fbW = scale_x; ++ fbH = scale_y; ++ } ++ ++ eff_height = fbH; ++ if (appData.yCrop > 0) { ++ eff_height = appData.yCrop; ++ if (scale_y > 0) { ++ eff_height = scale_round(eff_height, scale_factor_y); ++ } ++ } ++ ++ if (fbW > dpyWidth || eff_height > dpyHeight) { ++ ++ toobig = True; ++ ++ /* ++ * This is a crazy thing to have the scrollbars hang ++ * just a bit offscreen to the right and below. the user ++ * will not see them and bumpscroll will work. ++ */ ++ ++ XtVaSetValues(viewport, XtNforceBars, True, NULL); ++ XtVaGetValues(viewport, XtNwidth, &oldViewportWidth, XtNheight, &oldViewportHeight, NULL); ++ XtVaGetValues(XtNameToWidget(viewport, "clip"), XtNwidth, &clipWidth, XtNheight, &clipHeight, NULL); ++ ++ scrollbarWidth = oldViewportWidth - clipWidth; ++ scrollbarHeight = oldViewportHeight - clipHeight; ++ ++ if (fbW > dpyWidth) { ++ viewportWidth = toplevelWidth = dpyWidth + scrollbarWidth; ++ } else { ++ viewportWidth = fbW + scrollbarWidth; ++ toplevelWidth = dpyWidth; ++ } ++ ++ if (eff_height > dpyHeight) { ++ viewportHeight = toplevelHeight = dpyHeight + scrollbarHeight; + } else { -+ fprintf(stderr, "XtGrabKeyboard() OK 3rd try.\n"); ++ viewportHeight = eff_height + scrollbarHeight; ++ toplevelHeight = dpyHeight; + } ++ if (do_net_wm) { ++ /* but for _NET_WM we make toplevel be correct dpy size */ ++ toplevelWidth = dpyWidth; ++ toplevelHeight = dpyHeight; ++ } ++ + } else { -+ fprintf(stderr, "XtGrabKeyboard() OK 2nd try.\n"); ++ viewportWidth = fbW; ++ viewportHeight = eff_height; ++ toplevelWidth = dpyWidth; ++ toplevelHeight = dpyHeight; + } -+ XRaiseWindow(dpy, XtWindow(toplevel)); -+ } else if (appData.grabAll) { /* runge bot of FullScreenOn */ -+ fprintf(stderr, "calling XGrabServer(dpy)\n"); -+ XGrabServer(dpy); - } + +- /* Now we can set "toplevel" to its proper size. */ ++ viewportX = (toplevelWidth - viewportWidth) / 2; ++ viewportY = (toplevelHeight - viewportHeight) / 2; + +- XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0); ++ if (viewportX < 0) viewportX = 0; ++ if (viewportY < 0) viewportY = 0; + +- /* Set the popup to overrideRedirect too */ + +- XtVaSetValues(popup, XtNoverrideRedirect, True, NULL); ++ /* We want to stop the window manager from managing our toplevel window. ++ This is not really a nice thing to do, so may not work properly with every ++ window manager. We do this simply by setting overrideRedirect and ++ reparenting our window to the root. The window manager will get a ++ ReparentNotify and hopefully clean up its frame window. */ + +- /* Try to get the input focus. */ ++ if (! fsAlready) { ++ if (!do_net_wm) { ++ /* added to try to raise it on top for some cirumstances */ ++ XUnmapWindow(dpy, topwin); ++ ++ XtVaSetValues(toplevel, XtNoverrideRedirect, True, NULL); ++ //XtVaSetValues(viewport, XtNoverrideRedirect, True, NULL); ++ //XtVaSetValues(desktop, XtNoverrideRedirect, True, NULL); ++ XtVaSetValues(popup, XtNoverrideRedirect, True, NULL); ++ ++ XReparentWindow(dpy, topwin, DefaultRootWindow(dpy), 0, 0); ++ ++ /* Some WMs does not obey x,y values of XReparentWindow; the window ++ is not placed in the upper, left corner. The code below fixes ++ this: It manually moves the window, after the Xserver is done ++ with XReparentWindow. The last XSync seems to prevent losing ++ focus, but I don't know why. */ ++ ++ XSync(dpy, False); ++ ++ /* added to try to raise it on top for some cirumstances */ ++ XMapRaised(dpy, topwin); ++ ++ XMoveWindow(dpy, topwin, 0, 0); ++ XSync(dpy, False); ++ } ++ ++ /* Now we want to fix the size of "viewport". We shouldn't just change it ++ directly. Instead we set "toplevel" to the required size (which should ++ propagate through "form" to "viewport"). Then we remove "viewport" from ++ being managed by "form", change its resources to position it and make sure ++ that "form" won't attempt to resize it, then ask "form" to manage it ++ again. */ ++ ++ XtResizeWidget(toplevel, viewportWidth, viewportHeight, 0); ++ ++ XtUnmanageChild(viewport); ++ ++ XtVaSetValues(viewport, ++ XtNhorizDistance, viewportX, ++ XtNvertDistance, viewportY, ++ XtNleft, XtChainLeft, ++ XtNright, XtChainLeft, ++ XtNtop, XtChainTop, ++ XtNbottom, XtChainTop, ++ NULL); ++ ++ XtManageChild(viewport); ++ XSync(dpy, False); ++ } else { ++ XSync(dpy, False); ++ } ++ ++ /* Now we can set "toplevel" to its proper size. */ ++ ++// XtVaSetValues(toplevel, XtNwidth, toplevelWidth, XtNheight, toplevelHeight, NULL); ++// XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0); ++ XResizeWindow(dpy, topwin, toplevelWidth, toplevelHeight); ++ ++ if (do_net_wm) { ++ XWindowAttributes attr; ++ int ok = 0, i, delay = 20; ++ ++ usleep(delay * 1000); ++ ++#define GSIZE() \ ++ XGetWindowAttributes(dpy, topwin, &attr); ++ ++#define PSIZE(s) \ ++ XSync(dpy, False); \ ++ XGetWindowAttributes(dpy, topwin, &attr); \ ++ fprintf(stderr, "%s %dx%d+%d+%d\n", s, attr.width, attr.height, attr.x, attr.y); ++ ++ PSIZE("size-A:"); ++ ++ set_size_hints(); ++ ++ net_wm_fullscreen(1); ++ ++ PSIZE("size-B:"); ++ ++ for (i=0; i < 30; i++) { ++ usleep(delay * 1000); ++ GSIZE(); ++ fprintf(stderr, "size[%d] %dx%d+%d+%d\n", i, attr.width, attr.height, attr.x, attr.y); ++ if (attr.width == toplevelWidth && attr.height == toplevelHeight) { ++ ok = 1; ++ fprintf(stderr, "size ok.\n"); ++ XSync(dpy, False); ++ break; ++ } ++ set_size_hints(); ++ XResizeWindow(dpy, topwin, toplevelWidth, toplevelHeight); ++ XMoveWindow(dpy, topwin, 0, 0); ++ XSync(dpy, False); ++ } ++ ++ PSIZE("size-C:"); ++ } ++ ++ fprintf(stderr, "\ntoplevel: %dx%d viewport: %dx%d\n", toplevelWidth, toplevelHeight, viewportWidth, viewportHeight); ++ ++#if defined (__SVR4) && defined (__sun) ++ if (!do_net_wm) { ++ /* CDE */ ++ XSync(dpy, False); ++ usleep(200 * 1000); ++ XMoveWindow(dpy, topwin, 0, 0); ++ XMapRaised(dpy, topwin); ++ XSync(dpy, False); ++ } ++#endif ++ ++ if (fsAlready) { ++ XtResizeWidget(viewport, viewportWidth, viewportHeight, 0); ++ if (! toobig) { ++ XtVaSetValues(viewport, XtNforceBars, False, NULL); ++ } ++ XMoveWindow(dpy, topwin, viewportX, viewportY); ++ XSync(dpy, False); ++ } ++ ++ /* Try to get the input focus. */ + +- XSetInputFocus(dpy, DefaultRootWindow(dpy), RevertToPointerRoot, +- CurrentTime); ++ // original vnc: DefaultRootWindow(dpy) instead of PointerRoot ++ XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + +- /* Optionally, grab the keyboard. */ ++ /* Optionally, grab the keyboard. */ ++ fs_grab(0); + +- if (appData.grabKeyboard && +- XtGrabKeyboard(desktop, True, GrabModeAsync, +- GrabModeAsync, CurrentTime) != GrabSuccess) { +- fprintf(stderr, "XtGrabKeyboard() failed.\n"); +- } ++ /* finally done. */ } -@@ -210,8 +272,14 @@ - appData.fullScreen = False; +@@ -205,28 +546,52 @@ + void + FullScreenOff() + { +- int toplevelWidth = si.framebufferWidth; +- int toplevelHeight = si.framebufferHeight; +- +- appData.fullScreen = False; ++ int toplevelWidth, toplevelHeight; ++ int do_net_wm = net_wm_supported(); ++ int fbW = si.framebufferWidth; ++ int fbH = si.framebufferHeight; ++ int eff_height; ++ ++ appData.fullScreen = False; ++ ++ last_fullscreen = dnow(); ++ ++ if (scale_x > 0) { ++ fbW = scale_x; ++ fbH = scale_y; ++ } ++ ++ eff_height = fbH; ++ if (appData.yCrop > 0) { ++ eff_height = appData.yCrop; ++ if (scale_y > 0) { ++ eff_height = scale_round(eff_height, scale_factor_y); ++ } ++ } ++ ++ toplevelWidth = fbW; ++ toplevelHeight = eff_height; ++ ++ fs_ungrab(0); ++ ++ if (do_net_wm) { ++ net_wm_fullscreen(0); ++ } else { ++ XtUnmapWidget(toplevel); ++ } - if (appData.grabKeyboard) - XtUngrabKeyboard(desktop, CurrentTime); +- +- XtUnmapWidget(toplevel); +- +- XtResizeWidget(toplevel, ++ XtResizeWidget(toplevel, + viewportWidth - scrollbarWidth, + viewportHeight - scrollbarHeight, 0); +- XtResizeWidget(viewport, ++ XtResizeWidget(viewport, + viewportWidth - scrollbarWidth, + viewportHeight - scrollbarHeight, 0); + +- XtVaSetValues(viewport, XtNforceBars, False, NULL); ++ XtVaSetValues(viewport, XtNforceBars, False, NULL); + +- XtUnmanageChild(viewport); ++ XtUnmanageChild(viewport); + +- XtVaSetValues(viewport, ++ XtVaSetValues(viewport, + XtNhorizDistance, 0, + XtNvertDistance, 0, + XtNleft, XtChainLeft, +@@ -235,24 +600,40 @@ + XtNbottom, XtChainBottom, + NULL); + +- XtManageChild(viewport); +- +- XtVaSetValues(toplevel, XtNoverrideRedirect, False, NULL); +- +- if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) +- toplevelWidth = dpyWidth - appData.wmDecorationWidth; +- +- if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) +- toplevelHeight = dpyHeight - appData.wmDecorationHeight; +- +- XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0); +- +- XtMapWidget(toplevel); +- XSync(dpy, False); ++ XtManageChild(viewport); + +- /* Set the popup back to non-overrideRedirect */ +- +- XtVaSetValues(popup, XtNoverrideRedirect, False, NULL); ++ if (!do_net_wm) { ++ XtVaSetValues(toplevel, XtNoverrideRedirect, False, NULL); ++ //XtVaSetValues(viewport, XtNoverrideRedirect, False, NULL); ++ //XtVaSetValues(desktop, XtNoverrideRedirect, False, NULL); ++ XtVaSetValues(popup, XtNoverrideRedirect, False, NULL); ++ } + -+ if (appData.grabAll) { /* runge top of FullScreenOff */ -+ fprintf(stderr, "calling XUngrabServer(dpy)\n"); -+ XUngrabServer(dpy); -+ } -+ if (appData.grabKeyboard) { -+ XtUngrabKeyboard(desktop, CurrentTime); -+ } ++ if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) ++ toplevelWidth = dpyWidth - appData.wmDecorationWidth; ++ ++ if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) ++ toplevelHeight = dpyHeight - appData.wmDecorationHeight; ++ ++ XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0); ++ ++ if (!do_net_wm) { ++ XtMapWidget(toplevel); ++ } ++ XSync(dpy, False); ++ ++ /* Set the popup back to non-overrideRedirect */ ++ ++ XtVaSetValues(popup, XtNoverrideRedirect, False, NULL); ++ ++ if (!do_net_wm) { ++ int x = (dpyWidth - toplevelWidth) / 2; ++ int y = (dpyHeight - toplevelHeight) / 2; ++ if (x > 0 && y > 0) { ++ XSync(dpy, False); ++ XMoveWindow(dpy, XtWindow(toplevel), x, y); ++ } ++ } + } + - XtUnmapWidget(toplevel); +@@ -264,10 +645,11 @@ + void + SetFullScreenState(Widget w, XEvent *ev, String *params, Cardinal *num_params) + { +- if (appData.fullScreen) +- XtVaSetValues(w, XtNstate, True, NULL); +- else +- XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.fullScreen) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } + } -@@ -238,6 +306,9 @@ - XtManageChild(viewport); - XtVaSetValues(toplevel, XtNoverrideRedirect, False, NULL); -+ XtVaSetValues(viewport, XtNoverrideRedirect, False, NULL); -+ XtVaSetValues(desktop, XtNoverrideRedirect, False, NULL); -+ XtVaSetValues(popup, XtNoverrideRedirect, False, NULL); +@@ -278,11 +660,11 @@ + void + ToggleFullScreen(Widget w, XEvent *ev, String *params, Cardinal *num_params) + { +- if (appData.fullScreen) { +- FullScreenOff(); +- } else { +- FullScreenOn(); +- } ++ if (appData.fullScreen) { ++ FullScreenOff(); ++ } else { ++ FullScreenOn(); ++ } + } - if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) - toplevelWidth = dpyWidth - appData.wmDecorationWidth; -@@ -345,7 +416,9 @@ - } - if (scrollDown) { -- if (desktopY < si.framebufferHeight - dpyHeight) { -+ if (appData.yCrop > 0 && desktopY + dpyHeight >= appData.yCrop) { -+ ; -+ } else if (desktopY < si.framebufferHeight - dpyHeight) { - desktopY += appData.bumpScrollPixels; - if (desktopY > si.framebufferHeight - dpyHeight) - desktopY = si.framebufferHeight - dpyHeight; -@@ -375,3 +448,115 @@ +@@ -294,84 +676,220 @@ + Bool + BumpScroll(XEvent *ev) { - DoBumpScroll(); +- scrollLeft = scrollRight = scrollUp = scrollDown = False; ++ scrollLeft = scrollRight = scrollUp = scrollDown = False; + +- if (ev->xmotion.x_root >= dpyWidth - 3) +- scrollRight = True; +- else if (ev->xmotion.x_root <= 2) +- scrollLeft = True; +- +- if (ev->xmotion.y_root >= dpyHeight - 3) +- scrollDown = True; +- else if (ev->xmotion.y_root <= 2) +- scrollUp = True; +- +- if (scrollLeft || scrollRight || scrollUp || scrollDown) { +- if (timerSet) +- return True; +- +- XtVaGetValues(desktop, XtNx, &desktopX, XtNy, &desktopY, NULL); +- desktopX = -desktopX; +- desktopY = -desktopY; +- +- return DoBumpScroll(); +- } +- +- if (timerSet) { +- XtRemoveTimeOut(timer); +- timerSet = False; +- } ++ if (ev->xmotion.x_root >= dpyWidth - 3) ++ scrollRight = True; ++ else if (ev->xmotion.x_root <= 2) ++ scrollLeft = True; ++ ++ if (ev->xmotion.y_root >= dpyHeight - 3) ++ scrollDown = True; ++ else if (ev->xmotion.y_root <= 2) ++ scrollUp = True; ++ ++ if (scrollLeft || scrollRight || scrollUp || scrollDown) { ++ if (timerSet) ++ return True; ++ ++ XtVaGetValues(desktop, XtNx, &desktopX, XtNy, &desktopY, NULL); ++ desktopX = -desktopX; ++ desktopY = -desktopY; ++ ++ return DoBumpScroll(); ++ } ++ ++ if (timerSet) { ++ XtRemoveTimeOut(timer); ++ timerSet = False; ++ } + +- return False; ++ return False; } + + static Bool + DoBumpScroll() + { +- int oldx = desktopX, oldy = desktopY; +- +- if (scrollRight) { +- if (desktopX < si.framebufferWidth - dpyWidth) { +- desktopX += appData.bumpScrollPixels; +- if (desktopX > si.framebufferWidth - dpyWidth) +- desktopX = si.framebufferWidth - dpyWidth; +- } +- } else if (scrollLeft) { +- if (desktopX > 0) { +- desktopX -= appData.bumpScrollPixels; +- if (desktopX < 0) +- desktopX = 0; +- } +- } +- +- if (scrollDown) { +- if (desktopY < si.framebufferHeight - dpyHeight) { +- desktopY += appData.bumpScrollPixels; +- if (desktopY > si.framebufferHeight - dpyHeight) +- desktopY = si.framebufferHeight - dpyHeight; +- } +- } else if (scrollUp) { +- if (desktopY > 0) { +- desktopY -= appData.bumpScrollPixels; +- if (desktopY < 0) +- desktopY = 0; +- } +- } +- +- if (oldx != desktopX || oldy != desktopY) { +- XawViewportSetCoordinates(viewport, desktopX, desktopY); +- timer = XtAppAddTimeOut(appContext, appData.bumpScrollTime, +- BumpScrollTimerCallback, NULL); +- timerSet = True; +- return True; +- } ++ int oldx = desktopX, oldy = desktopY; ++ int fbW = si.framebufferWidth; ++ int fbH = si.framebufferHeight; ++ ++ if (scale_x > 0) { ++ fbW = scale_x; ++ fbH = scale_y; ++ } ++ ++ if (scrollRight) { ++ if (desktopX < fbW - dpyWidth) { ++ desktopX += appData.bumpScrollPixels; ++ if (desktopX > fbW - dpyWidth) { ++ desktopX = fbW - dpyWidth; ++ } ++ } ++ } else if (scrollLeft) { ++ if (desktopX > 0) { ++ desktopX -= appData.bumpScrollPixels; ++ if (desktopX < 0) { ++ desktopX = 0; ++ } ++ } ++ } ++ ++ if (scrollDown) { ++ int ycrop = appData.yCrop; ++ if (scale_y > 0) { ++ ycrop = scale_round(ycrop, scale_factor_y); ++ } ++ if (ycrop > 0 && desktopY + dpyHeight >= ycrop) { ++ ; ++ } else if (desktopY < fbH - dpyHeight) { ++ desktopY += appData.bumpScrollPixels; ++ if (desktopY > fbH - dpyHeight) { ++ desktopY = fbH - dpyHeight; ++ } ++ } ++ } else if (scrollUp) { ++ if (desktopY > 0) { ++ desktopY -= appData.bumpScrollPixels; ++ if (desktopY < 0) { ++ desktopY = 0; ++ } ++ } ++ } ++ ++ if (oldx != desktopX || oldy != desktopY) { ++ XawViewportSetCoordinates(viewport, desktopX, desktopY); ++ timer = XtAppAddTimeOut(appContext, appData.bumpScrollTime, BumpScrollTimerCallback, NULL); ++ timerSet = True; ++ return True; ++ } + +- timerSet = False; +- return False; ++ timerSet = False; ++ return False; + } + + static void + BumpScrollTimerCallback(XtPointer clientData, XtIntervalId *id) + { +- DoBumpScroll(); ++ DoBumpScroll(); ++} + +/* not working: */ + @@ -4216,14 +6863,22 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/fullscreen.c vnc_unixsrc/vncv +static Bool +DoJumpScroll() { + int oldx = desktopX, oldy = desktopY; -+ int jumpH = si.framebufferWidth / 4; -+ int jumpV = si.framebufferHeight / 4; ++ int jumpH, jumpV; ++ int fbW = si.framebufferWidth; ++ int fbH = si.framebufferHeight; ++ ++ if (scale_x > 0) { ++ fbW = scale_x; ++ fbH = scale_y; ++ } ++ jumpH = fbW / 4; ++ jumpV = fbH / 4; + + if (scrollRight) { -+ if (desktopX < si.framebufferWidth - dpyWidth) { ++ if (desktopX < fbW - dpyWidth) { + desktopX += jumpH; -+ if (desktopX > si.framebufferWidth - dpyWidth) -+ desktopX = si.framebufferWidth - dpyWidth; ++ if (desktopX > fbW - dpyWidth) ++ desktopX = fbW - dpyWidth; + } + } else if (scrollLeft) { + if (desktopX > 0) { @@ -4236,10 +6891,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/fullscreen.c vnc_unixsrc/vncv + if (scrollDown) { + if (appData.yCrop > 0 && desktopY + dpyHeight >= appData.yCrop) { + ; -+ } else if (desktopY < si.framebufferHeight - dpyHeight) { ++ } else if (desktopY < fbH - dpyHeight) { + desktopY += jumpV; -+ if (desktopY > si.framebufferHeight - dpyHeight) -+ desktopY = si.framebufferHeight - dpyHeight; ++ if (desktopY > fbH - dpyHeight) ++ desktopY = fbH - dpyHeight; + } + } else if (scrollUp) { + if (desktopY > 0) { @@ -4273,7 +6928,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/fullscreen.c vnc_unixsrc/vncv +} +void JumpUp(Widget w, XEvent *ev, String *params, Cardinal *num_params) { + JumpScroll(1, 1); -+} + } +void JumpDown(Widget w, XEvent *ev, String *params, Cardinal *num_params) { + JumpScroll(0, 1); +} @@ -4295,7 +6950,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/h2html.pl vnc_unixsrc/vncview +} diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/hextile.c vnc_unixsrc/vncviewer/hextile.c --- vnc_unixsrc.orig/vncviewer/hextile.c 2007-02-17 22:33:46.000000000 -0500 -+++ vnc_unixsrc/vncviewer/hextile.c 2007-02-17 22:48:39.000000000 -0500 ++++ vnc_unixsrc/vncviewer/hextile.c 2008-10-05 15:16:24.000000000 -0400 @@ -30,6 +30,18 @@ #define CARDBPP CONCAT2E(CARD,BPP) #define GET_PIXEL CONCAT2E(GET_PIXEL,BPP) @@ -4304,7 +6959,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/hextile.c vnc_unixsrc/vncview + { \ + XGCValues _gcv; \ + _gcv.foreground = color; \ -+ if (!appData.useBackingstore) { \ ++ if (!appData.useXserverBackingStore) { \ + FillScreen(x, y, w, h, _gcv.foreground); \ + } else { \ + XChangeGC(dpy, gc, GCForeground, &_gcv); \ @@ -4420,8 +7075,16 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/hextile.c vnc_unixsrc/vncview +#undef FillRectangle diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewer/listen.c --- vnc_unixsrc.orig/vncviewer/listen.c 2001-01-16 03:07:57.000000000 -0500 -+++ vnc_unixsrc/vncviewer/listen.c 2008-09-07 11:23:30.000000000 -0400 -@@ -58,6 +58,8 @@ ++++ vnc_unixsrc/vncviewer/listen.c 2008-09-26 15:43:23.000000000 -0400 +@@ -32,6 +32,7 @@ + #define FLASHDELAY 1 /* seconds */ + + Bool listenSpecified = False; ++pid_t listenParent = 0; + int listenPort = 0, flashPort = 0; + + static Font flashFont; +@@ -58,8 +59,11 @@ int n; int i; char *displayname = NULL; @@ -4429,12 +7092,20 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewe + int totalconn = 0, maxconn = 0; listenSpecified = True; ++ listenParent = getpid(); + + for (i = 1; i < *argc; i++) { + if (strcmp(argv[i], "-display") == 0 && i+1 < *argc) { +@@ -108,23 +112,40 @@ + exit(1); + } -@@ -111,20 +113,36 @@ - getFlashFont(d); +- getFlashFont(d); ++//getFlashFont(d); listenSocket = ListenAtTcpPort(listenPort); - flashSocket = ListenAtTcpPort(flashPort); ++ +//flashSocket = ListenAtTcpPort(flashPort); + flashSocket = 1234; @@ -4472,7 +7143,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewe /* discard any X events */ while (XCheckIfEvent(d, &ev, AllXEventsPredicate, NULL)) -@@ -132,12 +150,24 @@ +@@ -132,12 +153,24 @@ FD_ZERO(&fds); @@ -4498,7 +7169,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewe if (FD_ISSET(flashSocket, &fds)) { sock = AcceptTcpConnection(flashSocket); -@@ -151,11 +181,48 @@ +@@ -151,11 +184,48 @@ } close(sock); } @@ -4550,7 +7221,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewe XCloseDisplay(d); -@@ -175,6 +242,7 @@ +@@ -170,18 +240,23 @@ + case 0: + /* child - return to caller */ + close(listenSocket); +- close(flashSocket); ++// close(flashSocket); + return; default: /* parent - go round and listen again */ @@ -4558,10 +7235,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewe close(rfbsock); if (!(d = XOpenDisplay(displayname))) { fprintf(stderr,"%s: unable to open display %s\n", -@@ -182,6 +250,10 @@ + programName, XDisplayName(displayname)); exit(1); } - getFlashFont(d); +- getFlashFont(d); ++// getFlashFont(d); + fprintf(stderr,"\n\n%s -listen: Listening on port %d\n", + programName,listenPort); + fprintf(stderr,"%s -listen: Cmdline errors are not reported until " @@ -4569,21 +7247,451 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewe break; } } +@@ -200,6 +275,13 @@ + char **fontNames; + int nFontNames; + ++#if 1 ++ ++ /* no longer used */ ++ return; ++ ++#else ++ + sprintf(fontName,"-*-courier-bold-r-*-*-%d-*-*-*-*-*-iso8859-1", + FLASHWIDTH); + fontNames = XListFonts(d, fontName, 1, &nFontNames); +@@ -209,6 +291,9 @@ + sprintf(fontName,"fixed"); + } + flashFont = XLoadFont(d, fontName); ++ ++#endif ++ + } + + +@@ -222,6 +307,11 @@ + Window w1, w2, w3, w4; + XSetWindowAttributes attr; + ++#if 1 ++ /* no longer used */ ++ return; ++#else ++ + XBell(d, 0); + + XForceScreenSaver(d, ScreenSaverReset); +@@ -284,6 +374,9 @@ + XDestroyWindow(d, w3); + XDestroyWindow(d, w4); + XFlush(d); ++ ++#endif ++ + } + + /* diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/misc.c vnc_unixsrc/vncviewer/misc.c --- vnc_unixsrc.orig/vncviewer/misc.c 2003-01-15 02:58:32.000000000 -0500 -+++ vnc_unixsrc/vncviewer/misc.c 2007-05-26 13:29:19.000000000 -0400 -@@ -287,6 +287,7 @@ - if (appData.useShm) - ShmCleanup(); ++++ vnc_unixsrc/vncviewer/misc.c 2008-10-14 22:32:04.000000000 -0400 +@@ -33,12 +33,14 @@ + + Dimension dpyWidth, dpyHeight; + Atom wmDeleteWindow, wmState; ++int fullscreen_startup = 0; + + static Bool xloginIconified = False; + static XErrorHandler defaultXErrorHandler; + static XIOErrorHandler defaultXIOErrorHandler; + static XtErrorHandler defaultXtErrorHandler; + ++int XError_ign = 0; + + /* + * ToplevelInitBeforeRealization sets the title, geometry and other resources +@@ -48,87 +50,103 @@ + void + ToplevelInitBeforeRealization() + { +- char *titleFormat; +- char *title; +- char *geometry; +- +- XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL); +- title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1); +- sprintf(title, titleFormat, desktopName); +- XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL); +- +- XtVaSetValues(toplevel, XtNmaxWidth, si.framebufferWidth, +- XtNmaxHeight, si.framebufferHeight, NULL); +- +- dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); +- dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); +- +- if (appData.fullScreen) { +- +- /* full screen - set position to 0,0, but defer size calculation until +- widgets are realized */ +- +- XtVaSetValues(toplevel, XtNoverrideRedirect, True, +- XtNgeometry, "+0+0", NULL); +- +- } else { +- +- /* not full screen - work out geometry for middle of screen unless +- specified by user */ +- +- XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL); +- +- if (geometry == NULL) { +- Dimension toplevelX, toplevelY; +- Dimension toplevelWidth = si.framebufferWidth; +- Dimension toplevelHeight = si.framebufferHeight; +- +- if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) +- toplevelWidth = dpyWidth - appData.wmDecorationWidth; +- +- if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) +- toplevelHeight = dpyHeight - appData.wmDecorationHeight; +- +- toplevelX = (dpyWidth - toplevelWidth - appData.wmDecorationWidth) / 2; +- +- toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2; +- +- /* set position via "geometry" so that window manager thinks it's a +- user-specified position and therefore honours it */ +- +- geometry = XtMalloc(256); +- +- sprintf(geometry, "%dx%d+%d+%d", +- toplevelWidth, toplevelHeight, toplevelX, toplevelY); +- XtVaSetValues(toplevel, XtNgeometry, geometry, NULL); +- } +- } ++ char *titleFormat; ++ char *title; ++ char *geometry; ++ int h = si.framebufferHeight; ++ int w = si.framebufferWidth; ++ ++ check_tall(); ++ if (appData.yCrop < 0) { ++ appData.yCrop = guessCrop(); ++ fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop); ++ if (appData.yCrop > 0) { ++ h = appData.yCrop; ++ } ++ } ++ ++ XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL); ++ title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1); ++ sprintf(title, titleFormat, desktopName); ++ XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL); ++ ++ if (appData.scale != NULL) { ++ /* switched to not scaled */ ++ double frac_x, frac_y; ++ get_scale_values(&frac_x, &frac_y); ++ if (frac_x > 0.0) { ++ w = scale_round(w, frac_x); ++ h = scale_round(h, frac_y); ++ } ++ } ++ XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL); ++ ++ dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); ++ dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); ++ ++ if (appData.fullScreen) { ++ /* full screen - set position to 0,0, but defer size calculation until widgets are realized */ ++ ++ if (!net_wm_supported()) { ++ XtVaSetValues(toplevel, XtNoverrideRedirect, True, XtNgeometry, "+0+0", NULL); ++ } else { ++ fullscreen_startup = 1; ++ } ++ ++ } else { ++ ++ /* not full screen - work out geometry for middle of screen unless specified by user */ ++ ++ XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL); ++ ++ if (geometry == NULL) { ++ Dimension toplevelX, toplevelY; ++ Dimension toplevelWidth = w; ++ Dimension toplevelHeight = h; ++ ++ if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) { ++ toplevelWidth = dpyWidth - appData.wmDecorationWidth; ++ } ++ ++ if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) { ++ toplevelHeight = dpyHeight - appData.wmDecorationHeight; ++ } ++ ++ toplevelX = (dpyWidth - toplevelWidth - appData.wmDecorationWidth) / 2; ++ toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2; ++ ++ /* set position via "geometry" so that window manager thinks it's a ++ user-specified position and therefore honours it */ ++ ++ geometry = XtMalloc(256); ++ ++ sprintf(geometry, "%dx%d+%d+%d", toplevelWidth, toplevelHeight, toplevelX, toplevelY); ++ fprintf(stderr, "geometry: %s ycrop: %d\n", geometry, appData.yCrop); ++ XtVaSetValues(toplevel, XtNgeometry, geometry, NULL); ++ } ++ } + + /* Test if the keyboard is grabbed. If so, it's probably because the + XDM login window is up, so try iconifying it to release the grab */ + +- if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync, +- GrabModeSync, CurrentTime) == GrabSuccess) { +- XUngrabKeyboard(dpy, CurrentTime); +- } else { +- wmState = XInternAtom(dpy, "WM_STATE", False); +- +- if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) { +- xloginIconified = True; +- XSync(dpy, False); +- sleep(1); +- } +- } +- +- /* Set handlers for signals and X errors to perform cleanup */ +- +- signal(SIGHUP, CleanupSignalHandler); +- signal(SIGINT, CleanupSignalHandler); +- signal(SIGTERM, CleanupSignalHandler); +- defaultXErrorHandler = XSetErrorHandler(CleanupXErrorHandler); +- defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler); +- defaultXtErrorHandler = XtAppSetErrorHandler(appContext, +- CleanupXtErrorHandler); ++ if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync, GrabModeSync, CurrentTime) == GrabSuccess) { ++ XUngrabKeyboard(dpy, CurrentTime); ++ } else { ++ wmState = XInternAtom(dpy, "WM_STATE", False); ++ if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) { ++ xloginIconified = True; ++ XSync(dpy, False); ++ sleep(1); ++ } ++ } ++ ++ /* Set handlers for signals and X errors to perform cleanup */ ++ signal(SIGHUP, CleanupSignalHandler); ++ signal(SIGINT, CleanupSignalHandler); ++ signal(SIGTERM, CleanupSignalHandler); ++ defaultXErrorHandler = XSetErrorHandler(CleanupXErrorHandler); ++ defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler); ++ defaultXtErrorHandler = XtAppSetErrorHandler(appContext, CleanupXtErrorHandler); + } + + +@@ -141,14 +159,22 @@ + void + ToplevelInitAfterRealization() + { +- if (appData.fullScreen) { +- FullScreenOn(); +- } +- +- wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); +- XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1); +- XtOverrideTranslations +- (toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); ++ if (appData.fullScreen) { ++ FullScreenOn(); ++ if (net_wm_supported()) { ++ /* problem with scroll bars sticking: */ ++ XSync(dpy, False); ++ usleep(50 * 1000); ++ FullScreenOff(); ++ XSync(dpy, False); ++ usleep(50 * 1000); ++ FullScreenOn(); ++ } ++ } ++ ++ wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); ++ XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1); ++ XtOverrideTranslations(toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); + } + + +@@ -157,9 +183,7 @@ + * CurrentTime if the event has no time field. + */ + +-Time +-TimeFromEvent(XEvent *ev) +-{ ++Time TimeFromEvent(XEvent *ev) { + switch (ev->type) { + case KeyPress: + case KeyRelease: +@@ -192,18 +216,15 @@ + * generated by SendRFBEvent. + */ + +-void +-Pause(Widget w, XEvent *event, String *params, Cardinal *num_params) +-{ +- int msec; ++void Pause(Widget w, XEvent *event, String *params, Cardinal *num_params) { ++ int msec; + +- if (*num_params == 0) { +- msec = 100; +- } else { +- msec = atoi(params[0]); +- } +- +- usleep(msec * 1000); ++ if (*num_params == 0) { ++ msec = 100; ++ } else { ++ msec = atoi(params[0]); ++ } ++ usleep(msec * 1000); + } + + +@@ -264,11 +285,9 @@ + * Quit action - called when we get a "delete window" message. + */ + +-void +-Quit(Widget w, XEvent *event, String *params, Cardinal *num_params) +-{ +- Cleanup(); +- exit(0); ++void Quit(Widget w, XEvent *event, String *params, Cardinal *num_params) { ++ Cleanup(); ++ exit(0); + } + + +@@ -276,49 +295,90 @@ + * Cleanup - perform any cleanup operations prior to exiting. + */ + +-void +-Cleanup() +-{ +- if (xloginIconified) { +- IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True); +- XFlush(dpy); +- } ++void Cleanup() { ++ ++ if (appData.chatActive) { ++ appData.chatActive = False; ++ fprintf(stderr,"Sending SendTextChatClose()\n"); ++ SendTextChatClose(); ++ SendTextChatFinished(); ++ } ++ ++ if (xloginIconified) { ++ IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True); ++ XFlush(dpy); ++ } + #ifdef MITSHM +- if (appData.useShm) +- ShmCleanup(); ++ if (appData.useShm) { ++ ShmCleanup(); ++ } #endif -+ fprintf(stderr,"\nVNC Viewer exiting.\n\n"); ++ ++ releaseAllPressedModifiers(); ++ ++ fprintf(stderr,"\nVNC Viewer exiting.\n\n"); ++ if (listenSpecified) { ++ if (listenParent != 0 && getenv("SSVNC_LISTEN_ONCE") && listenParent != getpid()) { ++ fprintf(stderr, "SSVNC_LISTEN_ONCE: Trying to kill Listening Parent: %d\n", (int) listenParent); ++ fprintf(stderr, "SSVNC_LISTEN_ONCE: Press Ctrl-C if it continues to Listen.\n\n"); ++ kill(listenParent, SIGTERM); ++ } else { ++ fprintf(stderr,"(NOTE: You may need to Press Ctrl-C to make the Viewer Stop Listening.)\n\n"); ++ } ++ } ++} ++ ++static void check_dbg(void) { ++ if (getenv("SSVNC_EXIT_DEBUG")) { ++ fprintf(stderr, "Press any key to continue: "); ++ getc(stdin); ++ } + } + + static int + CleanupXErrorHandler(Display *dpy, XErrorEvent *error) + { +- fprintf(stderr,"CleanupXErrorHandler called\n"); +- Cleanup(); +- return (*defaultXErrorHandler)(dpy, error); ++ if (XError_ign) { ++ char str[4096]; ++ XError_ign++; ++ fprintf(stderr,"XError_ign called.\n"); ++ str[0] = '\0'; ++ if (XGetErrorText(dpy, error->error_code, str, 4096)) { ++ fprintf(stderr, "%s", str); ++ } ++ return; ++ } ++ fprintf(stderr,"CleanupXErrorHandler called\n"); ++ check_dbg(); ++ Cleanup(); ++ return (*defaultXErrorHandler)(dpy, error); } static int + CleanupXIOErrorHandler(Display *dpy) + { +- fprintf(stderr,"CleanupXIOErrorHandler called\n"); +- Cleanup(); +- return (*defaultXIOErrorHandler)(dpy); ++ fprintf(stderr,"CleanupXIOErrorHandler called\n"); ++ check_dbg(); ++ Cleanup(); ++ return (*defaultXIOErrorHandler)(dpy); + } + + static void + CleanupXtErrorHandler(String message) + { +- fprintf(stderr,"CleanupXtErrorHandler called\n"); +- Cleanup(); +- (*defaultXtErrorHandler)(message); ++ fprintf(stderr,"CleanupXtErrorHandler called\n"); ++ check_dbg(); ++ Cleanup(); ++ (*defaultXtErrorHandler)(message); + } + + static void + CleanupSignalHandler(int sig) + { +- fprintf(stderr,"CleanupSignalHandler called\n"); +- Cleanup(); +- exit(1); ++ fprintf(stderr,"CleanupSignalHandler called\n"); ++ check_dbg(); ++ Cleanup(); ++ exit(1); + } + + diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup.c vnc_unixsrc/vncviewer/popup.c --- vnc_unixsrc.orig/vncviewer/popup.c 2000-06-11 08:00:53.000000000 -0400 -+++ vnc_unixsrc/vncviewer/popup.c 2008-09-14 10:34:39.000000000 -0400 -@@ -25,15 +25,44 @@ ++++ vnc_unixsrc/vncviewer/popup.c 2008-10-15 08:26:28.000000000 -0400 +@@ -25,22 +25,55 @@ #include <X11/Xaw/Form.h> #include <X11/Xaw/Command.h> @@ -4613,24 +7721,39 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup.c vnc_unixsrc/vncviewer + XtMoveWidget(wid, x0, y0); +} + ++void Noop(Widget w, XEvent *event, String *params, Cardinal *num_params) { ++ //fprintf(stderr, "No-op\n"); ++} ++ void ShowPopup(Widget w, XEvent *event, String *params, Cardinal *num_params) { - XtMoveWidget(popup, event->xbutton.x_root, event->xbutton.y_root); - XtPopup(popup, XtGrabNone); -+ if (appData.popupFix) { -+ popupFixer(popup); -+ } else { -+ XtMoveWidget(popup, event->xbutton.x_root, event->xbutton.y_root); -+ XtPopup(popup, XtGrabNone); -+ } -+ if (appData.grabAll) { -+ XRaiseWindow(dpy, XtWindow(popup)); -+ } - XSetWMProtocols(dpy, XtWindow(popup), &wmDeleteWindow, 1); +- XSetWMProtocols(dpy, XtWindow(popup), &wmDeleteWindow, 1); ++ if (appData.popupFix) { ++ popupFixer(popup); ++ } else { ++ XtMoveWidget(popup, event->xbutton.x_root, event->xbutton.y_root); ++ XtPopup(popup, XtGrabNone); ++ } ++ if (appData.grabAll) { ++ XSync(dpy, False); ++ XRaiseWindow(dpy, XtWindow(popup)); ++ } ++ XSetWMProtocols(dpy, XtWindow(popup), &wmDeleteWindow, 1); } -@@ -52,42 +81,464 @@ + void +-HidePopup(Widget w, XEvent *event, String *params, Cardinal *num_params) +-{ +- XtPopdown(popup); ++HidePopup(Widget w, XEvent *event, String *params, Cardinal *num_params) { ++ XtPopdown(popup); + } + + +@@ -52,42 +85,541 @@ }; void @@ -4952,13 +8075,20 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup.c vnc_unixsrc/vncviewer + if (! chat_visible) { + XtPopup(chat, XtGrabNone); + chat_visible = 1; ++ wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + XSetWMProtocols(dpy, XtWindow(chat), &wmDeleteWindow, 1); ++ if (appData.chatOnly) { ++ XtOverrideTranslations(chat, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); ++ } else { ++ XtOverrideTranslations(chat, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideChat()")); ++ } + XSync(dpy, False); + usleep(200 * 1000); + } +} + +void hidechat(void) { ++ appData.chatActive = False; + if (appData.termChat) { + return; + } @@ -4968,46 +8098,116 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup.c vnc_unixsrc/vncviewer + XSync(dpy, False); + usleep(200 * 1000); + } ++ if (appData.chatOnly) { ++ Quit(0, NULL, NULL, NULL); ++ } +} + +void HideChat(Widget w, XEvent *event, String *params, Cardinal *num_params) { + SendTextChatClose(); ++ SendTextChatFinished(); + hidechat(); +} + +void dismiss_proc(Widget w, XtPointer client_data, XtPointer call_data) { + SendTextChatClose(); ++ SendTextChatFinished(); + hidechat(); +} + +extern void printChat(char *, Bool); + ++static void ChatTextCallback(XtPointer clientData, XtIntervalId *id); ++static XtIntervalId timer; ++static Bool timerSet = False; ++ ++void CheckTextInput(void); ++extern double start_time; ++ ++static void ChatTextCallback(XtPointer clientData, XtIntervalId *id) { ++ static int db = -1; ++ if (db < 0) { ++ if (getenv("SSVNC_DEBUG_CHAT")) { ++ db = 1; ++ } else { ++ db = 0; ++ } ++ } ++ if (db) fprintf(stderr, "ChatTextCallback: %.4f\n", dnow() - start_time); ++ CheckTextInput(); ++} ++ +void CheckTextInput(void) { + Arg args[2]; + String str; + int len; ++ static int db = -1; ++ ++ if (timerSet) { ++ XtRemoveTimeOut(timer); ++ timerSet = False; ++ } ++ if (appData.chatActive) { ++ timer = XtAppAddTimeOut(appContext, 333, ChatTextCallback, NULL); ++ timerSet = True; ++ } ++ if (appData.chatOnly && !appData.chatActive) { ++ Quit(0, NULL, NULL, NULL); ++ } + + if (appData.termChat) { + return; + } ++#if 0 ++ if (!appData.chatActive) { ++ return; ++ } ++#endif ++ ++ if (db < 0) { ++ if (getenv("SSVNC_DEBUG_CHAT")) { ++ db = 1; ++ } else { ++ db = 0; ++ } ++ } + + XtSetArg(args[0], XtNstring, &str); + XtGetValues(entry, args, 1); ++ ++ if (db) fprintf(stderr, "CheckTextInput\n"); ++ + if (str == NULL || str[0] == '\0') { + return; + } else { ++ char *q; + len = strlen(str); ++ if (db) fprintf(stderr, "CheckTextInput: len: %d '%s'\n", len, str); + if (len <= 0) { + return; + } -+ if (str[len-1] == '\n') { -+ char *s = strdup(str); -+ if (s) { -+ SendTextChat(s); ++ q = strrchr(str, '\n'); ++ if (q) { ++ char *send, save[2]; ++ save[0] = *(q+1); ++ *(q+1) = '\0'; ++ send = strdup(str); ++ *(q+1) = save[0]; ++ if (send) { ++ SendTextChat(send); + printChat("Send: ", True); -+ printChat(s, True); -+ XtVaSetValues(entry, XtNtype, XawAsciiString, XtNstring, "", NULL); -+ free(s); ++ printChat(send, True); ++ free(send); ++ if (save[0] == '\0') { ++ XtVaSetValues(entry, XtNtype, XawAsciiString, XtNstring, "", NULL); ++ } else { ++ char *leak = strdup(q+1); ++ XtVaSetValues(entry, XtNtype, XawAsciiString, XtNstring, leak, NULL); ++ if (strlen(leak) > 0) { ++ XSync(dpy, False); ++ XtVaSetValues(entry, XtNinsertPosition, strlen(leak), NULL); ++ } ++ } + } + } + } @@ -5099,7 +8299,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup.c vnc_unixsrc/vncviewer + XtNuseStringInPlace, False, NULL); + + entry = XtVaCreateManagedWidget("entry", asciiTextWidgetClass, myform, -+ XtNresize, XawtextResizeWidth, XtNresizable, True, XtNwrap, XawtextWrapWord, ++ XtNresize, XawtextResizeWidth, XtNresizable, True, XtNwrap, XawtextWrapNever, + XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollNever, + XtNheight, 20, XtNwidth, 400, XtNfromVert, text, XtNeditType, XawtextEdit, + XtNdisplayCaret, True, XtNeditType, XawtextEdit, NULL); @@ -5138,7 +8338,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup_ad vnc_unixsrc/vncviewe +} diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncviewer/rfbproto.c --- vnc_unixsrc.orig/vncviewer/rfbproto.c 2008-09-05 19:51:24.000000000 -0400 -+++ vnc_unixsrc/vncviewer/rfbproto.c 2008-09-13 18:00:27.000000000 -0400 ++++ vnc_unixsrc/vncviewer/rfbproto.c 2008-10-15 08:00:20.000000000 -0400 @@ -23,6 +23,7 @@ * rfbproto.c - functions to deal with client side of RFB protocol. */ @@ -5192,11 +8392,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie static void ReadConnFailedReason(void); static long ReadCompactLen (void); -@@ -67,6 +106,11 @@ +@@ -67,6 +106,13 @@ static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, int compressedLen); +extern int currentMsg; ++extern double scale_factor_x; ++extern double scale_factor_y; + +int sent_FBU = 0; +int skip_XtUpdate = 0; @@ -5204,7 +8406,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie int rfbsock; char *desktopName; -@@ -177,6 +221,9 @@ +@@ -177,6 +223,9 @@ sig_rfbEncodingPointerPos, "Pointer position update"); CapsAdd(encodingCaps, rfbEncodingLastRect, rfbTightVncVendor, sig_rfbEncodingLastRect, "LastRect protocol extension"); @@ -5214,7 +8416,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -187,21 +234,104 @@ +@@ -187,21 +236,117 @@ Bool ConnectToRFBServer(const char *hostname, int port) { @@ -5256,9 +8458,20 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - } + if (cmd != NULL) { + int sfd[2]; ++ char *q, *cmd2 = strdup(cmd); + pid_t pid; + -+ fprintf(stderr, "exec-cmd: %s\n", cmd); ++ q = strstr(cmd2, "pw="); ++ if (q) { ++ q += strlen("pw="); ++ while (*q != '\0' && !isspace(*q)) { ++ *q = '*'; ++ q++; ++ } ++ } ++ ++ fprintf(stderr, "exec-cmd: %s\n", cmd2); ++ free(cmd2); + + if (! SocketPair(sfd)) { + return False; @@ -5300,6 +8513,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + fprintf(stderr,"Unable to connect to exec'd command: %s\n", cmd); + return False; + } ++ } else if (strstr(hostname, "fd=") == hostname) { ++ rfbsock = atoi(hostname + strlen("fd=")); + } else if (strchr(hostname, '/') && stat(hostname, &sb) == 0) { + /* assume unix domain socket */ + char *thost = strdup(hostname); @@ -5332,7 +8547,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -212,211 +342,301 @@ +@@ -212,211 +357,307 @@ Bool InitialiseRFBConnection(void) { @@ -5411,7 +8626,6 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + fprintf(stderr, "***************************************************************\n"); + fprintf(stderr, "To work around UltraVNC SC III SSL dropping after a few minutes\n"); + fprintf(stderr, "you may need to set STUNNEL_EXTRA_OPTS_USER='options = ALL'.\n"); -+ fprintf(stderr, "Or select 'UltraVNC Single Click III Bug' in the SSVNC GUI.\n"); + fprintf(stderr, "***************************************************************\n"); + fprintf(stderr, "\n"); + } @@ -5463,6 +8677,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - return False; + if (appData.rfbVersion != NULL && sscanf(appData.rfbVersion, "%d.%d", &viewer_major, &viewer_minor) == 2) { + fprintf(stderr,"Setting RFB version to %d.%d from -rfbversion.\n", viewer_major, viewer_minor); ++ } else if (getenv("SSVNC_RFB_VERSION") != NULL && sscanf(getenv("SSVNC_RFB_VERSION"), "%d.%d", &viewer_major, &viewer_minor) == 2) { ++ fprintf(stderr,"Setting RFB version to %d.%d from SSVNC_RFB_VERSION.\n", viewer_major, viewer_minor); + } else if (server_major == 3 && (server_minor == 14 || server_minor == 16)) { + /* hack for UltraVNC Single Click. They misuse rfb proto version */ + fprintf(stderr,"Setting RFB version to 3.3 for UltraVNC Single Click.\n"); @@ -5584,6 +8800,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + si.format.blueMax = Swap16IfLE(si.format.blueMax); + si.nameLength = Swap32IfLE(si.nameLength); + ++ if (appData.chatOnly) { ++ si.framebufferWidth = 32; ++ si.framebufferHeight = 32; ++ } + +- fprintf(stderr,"VNC server default format:\n"); +- PrintPixelFormat(&si.format); + /* FIXME: Check arguments to malloc() calls. */ + desktopName = malloc(si.nameLength + 1); + if (!desktopName) { @@ -5592,20 +8815,18 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + return False; + } -- fprintf(stderr,"VNC server default format:\n"); -- PrintPixelFormat(&si.format); -+ if (!ReadFromRFBServer(desktopName, si.nameLength)) { -+ return False; -+ } - - if (tightVncProtocol) { - /* Read interaction capabilities (protocol 3.7t) */ - if (!ReadInteractionCaps()) - return False; - } -+ desktopName[si.nameLength] = 0; ++ if (!ReadFromRFBServer(desktopName, si.nameLength)) { ++ return False; ++ } - return True; ++ desktopName[si.nameLength] = 0; ++ + fprintf(stderr,"Desktop name \"%s\"\n\n", desktopName); + + fprintf(stderr,"VNC server default format:\n"); @@ -5757,8 +8978,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + return rfbSecTypeTight; + } + } - -- free(secTypes); ++ + /* Find first supported security type */ + for (j = 0; j < (int)nSecTypes; j++) { + for (i = 0; i < nKnownSecTypes; i++) { @@ -5775,7 +8995,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + break; + } + } -+ + +- free(secTypes); + free(secTypes); - if (secType == rfbSecTypeInvalid) @@ -5789,7 +9010,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -451,6 +671,9 @@ +@@ -451,6 +692,9 @@ return True; } @@ -5799,7 +9020,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie /* * Negotiate authentication scheme (protocol version 3.7t) -@@ -459,56 +682,61 @@ +@@ -459,56 +703,61 @@ static Bool PerformAuthenticationTight(void) { @@ -5903,7 +9124,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -519,80 +747,97 @@ +@@ -519,80 +768,100 @@ static Bool AuthenticateVNC(void) { @@ -5975,6 +9196,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + buffer[len - 1] = '\0'; + } + } ++ } else if (getenv("VNCVIEWER_PASSWORD")) { ++ passwd = strdup(getenv("VNCVIEWER_PASSWORD")); ++ putenv("VNCVIEWER_PASSWORD=none"); + } else if (appData.passwordDialog) { + passwd = DoPasswordDialog(); + } else { @@ -6064,7 +9288,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } /* -@@ -602,68 +847,71 @@ +@@ -602,68 +871,71 @@ static Bool AuthenticateUnixLogin(void) { @@ -6188,7 +9412,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -675,19 +923,20 @@ +@@ -675,19 +947,20 @@ static Bool ReadInteractionCaps(void) { @@ -6221,7 +9445,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -700,17 +949,18 @@ +@@ -700,17 +973,18 @@ static Bool ReadCapabilityList(CapsContainer *caps, int count) { @@ -6249,7 +9473,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -729,6 +979,11 @@ +@@ -729,6 +1003,11 @@ Bool requestCompressLevel = False; Bool requestQualityLevel = False; Bool requestLastRectEncoding = False; @@ -6261,7 +9485,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie spf.type = rfbSetPixelFormat; spf.format = myFormat; -@@ -736,12 +991,18 @@ +@@ -736,12 +1015,18 @@ spf.format.greenMax = Swap16IfLE(spf.format.greenMax); spf.format.blueMax = Swap16IfLE(spf.format.blueMax); @@ -6280,7 +9504,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie if (appData.encodingsString) { char *encStr = appData.encodingsString; int encStrLen; -@@ -754,11 +1015,17 @@ +@@ -754,11 +1039,17 @@ encStrLen = strlen(encStr); } @@ -6299,7 +9523,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); requestLastRectEncoding = True; if (appData.compressLevel >= 0 && appData.compressLevel <= 9) -@@ -767,16 +1034,33 @@ +@@ -767,16 +1058,33 @@ requestQualityLevel = True; } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile); @@ -6335,7 +9559,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } encStr = nextEncStr; -@@ -797,7 +1081,7 @@ +@@ -797,7 +1105,7 @@ if (appData.useRemoteCursor) { if (se->nEncodings < MAX_ENCODINGS) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor); @@ -6344,7 +9568,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor); if (se->nEncodings < MAX_ENCODINGS) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos); -@@ -806,10 +1090,14 @@ +@@ -806,10 +1114,14 @@ if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect); } @@ -6360,7 +9584,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie fprintf(stderr,"Same machine: preferring raw encoding\n"); encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw); } else { -@@ -818,13 +1106,15 @@ +@@ -818,13 +1130,15 @@ } encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect); @@ -6380,7 +9604,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0); } else if (!tunnelSpecified) { -@@ -835,7 +1125,7 @@ +@@ -835,7 +1149,7 @@ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCompressLevel1); } @@ -6389,7 +9613,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie if (appData.qualityLevel < 0 || appData.qualityLevel > 9) appData.qualityLevel = 5; encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + -@@ -844,18 +1134,35 @@ +@@ -844,18 +1158,35 @@ if (appData.useRemoteCursor) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor); @@ -6428,7 +9652,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie return True; } -@@ -868,31 +1175,110 @@ +@@ -868,31 +1199,86 @@ Bool SendIncrementalFramebufferUpdateRequest() { @@ -6436,38 +9660,14 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - si.framebufferHeight, True); + return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, + si.framebufferHeight, True); -+} -+ + } + +time_t last_filexfer = 0; +int delay_filexfer = 3; +extern void CheckFileXfer(void); +extern int rfbsock_is_ready(void); + + -+// fprintf(stderr, "skip SendFramebufferUpdateRequest: %d - %d\n", last_filexfer, time(NULL)); -+#if 0 -+int ready; -+if (0) { -+ ready = rfbsock_is_ready(); -+ if (db) fprintf(stderr, "rsir: %d\n", ready); -+ if (ready) { -+ int r = (int) HandleRFBServerMessage(); -+ if (db) fprintf(stderr, "hrsm: %d\n", r); -+ -+ } -+ if (db) fprintf(stderr, "CFX: C ****\n"); -+ CheckFileXfer(); -+ return True; -+} -+if (db) { -+ ready = rfbsock_is_ready(); -+ fprintf(stderr, "rsir: %d\n", ready); - } -+#endif -+// x = y = 0; -+// w = h = 1; -+ - +static int dyn = -1; +extern int filexfer_sock; +extern int filexfer_listen; @@ -6552,7 +9752,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -903,19 +1289,28 @@ +@@ -903,19 +1289,36 @@ Bool SendPointerEvent(int x, int y, int buttonMask) { @@ -6565,6 +9765,23 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + return True; + } + } ++ ++ pe.type = rfbPointerEvent; ++ pe.buttonMask = buttonMask; ++ ++ if (scale_factor_x > 0.0 && scale_factor_x != 1.0) { ++ x /= scale_factor_x; ++ } ++ if (scale_factor_y > 0.0 && scale_factor_y != 1.0) { ++ y /= scale_factor_y; ++ } ++ ++ if (x < 0) x = 0; ++ if (y < 0) y = 0; ++ ++ if (!appData.useX11Cursor) { ++ SoftCursorMove(x, y); ++ } - pe.type = rfbPointerEvent; - pe.buttonMask = buttonMask; @@ -6577,15 +9794,6 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - pe.x = Swap16IfLE(x); - pe.y = Swap16IfLE(y); - return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg); -+ pe.type = rfbPointerEvent; -+ pe.buttonMask = buttonMask; -+ if (x < 0) x = 0; -+ if (y < 0) y = 0; -+ -+ if (!appData.useX11Cursor) { -+ SoftCursorMove(x, y); -+ } -+ + pe.x = Swap16IfLE(x); + pe.y = Swap16IfLE(y); + currentMsg = rfbPointerEvent; @@ -6593,7 +9801,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -926,12 +1321,20 @@ +@@ -926,12 +1329,20 @@ Bool SendKeyEvent(CARD32 key, Bool down) { @@ -6619,7 +9827,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -942,281 +1345,860 @@ +@@ -942,281 +1353,943 @@ Bool SendClientCutText(char *str, int len) { @@ -6737,19 +9945,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie +Bool +SendTextChat(char *str) +{ ++ static int db = -1; + rfbTextChatMsg chat; -+ chat.type = rfbTextChat; -+ chat.pad1 = 0; -+ chat.pad2 = 0; -+ chat.length = (unsigned int) strlen(str); -+ //fprintf(stderr, "SendTextChat: %d '%s'\n", chat.length, str); -+ chat.length = Swap32IfLE(chat.length); -+ if (!WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg)) { -+ return False; -+ } -+ currentMsg = rfbTextChat; -+ return WriteExact(rfbsock, str, strlen(str)); -+} - for (i = 0; i < msg.scme.nColours; i++) { - if (!ReadFromRFBServer((char *)rgb, 6)) @@ -6761,20 +9958,31 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - xc.flags = DoRed|DoGreen|DoBlue; - XStoreColor(dpy, cmap, &xc); - } -+extern void raiseme(int force); ++ if (db < 0) { ++ if (getenv("SSVNC_DEBUG_CHAT")) { ++ db = 1; ++ } else { ++ db = 0; ++ } ++ } ++ if (!appData.chatActive) { ++ SendTextChatOpen(); ++ appData.chatActive = True; ++ } - break; - } -+Bool -+SendTextChatOpen(void) -+{ -+ raiseme(0); -+ rfbTextChatMsg chat; + chat.type = rfbTextChat; + chat.pad1 = 0; + chat.pad2 = 0; -+ chat.length = Swap32IfLE(rfbTextChatOpen); -+ return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg); ++ chat.length = (unsigned int) strlen(str); ++ if (db) fprintf(stderr, "SendTextChat: %d '%s'\n", chat.length, str); ++ chat.length = Swap32IfLE(chat.length); ++ if (!WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg)) { ++ return False; ++ } ++ currentMsg = rfbTextChat; ++ return WriteExact(rfbsock, str, strlen(str)); +} - case rfbFramebufferUpdate: @@ -6784,6 +9992,24 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - int bytesPerLine; - int i; - int usecs; ++extern void raiseme(int force); + +- if (!ReadFromRFBServer(((char *)&msg.fu) + 1, +- sz_rfbFramebufferUpdateMsg - 1)) +- return False; ++Bool ++SendTextChatOpen(void) ++{ ++ raiseme(0); ++ rfbTextChatMsg chat; ++ chat.type = rfbTextChat; ++ chat.pad1 = 0; ++ chat.pad2 = 0; ++ chat.length = Swap32IfLE(rfbTextChatOpen); ++ return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg); ++} + +- msg.fu.nRects = Swap16IfLE(msg.fu.nRects); +Bool +SendTextChatClose(void) +{ @@ -6792,12 +10018,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + chat.pad1 = 0; + chat.pad2 = 0; + chat.length = Swap32IfLE(rfbTextChatClose); ++ appData.chatActive = False; + return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg); +} -- if (!ReadFromRFBServer(((char *)&msg.fu) + 1, -- sz_rfbFramebufferUpdateMsg - 1)) -- return False; +- for (i = 0; i < msg.fu.nRects; i++) { +- if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) +- return False; +Bool +SendTextChatFinished(void) +{ @@ -6806,6 +10033,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + chat.pad1 = 0; + chat.pad2 = 0; + chat.length = Swap32IfLE(rfbTextChatFinished); ++ appData.chatActive = False; + return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg); +} + @@ -6880,9 +10108,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + int rfbCFileDelete = 4; // Request the server to delete the given file + + int rfbRErrorUnknownCmd = 1; // Unknown FileTransfer command. -+ int rfbRErrorCmd = 0xFFFFFFFF; ++#define rfbRErrorCmd 0xFFFFFFFF + -+ int db = 0; ++ static int db = -1; ++ static int guess_x11vnc = 0; + +#if 0 + if (filexfer_sock < 0) { @@ -6891,20 +10120,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + // instead, we read and discard the ft msg data. +#endif -- msg.fu.nRects = Swap16IfLE(msg.fu.nRects); -+//fprintf(stderr, "In HandleFileXfer\n"); - -- for (i = 0; i < msg.fu.nRects; i++) { -- if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) -- return False; -+ last_filexfer = time(NULL); -+ //fprintf(stderr, "last_filexfer-1: %d\n", last_filexfer); - - rect.encoding = Swap32IfLE(rect.encoding); - if (rect.encoding == rfbEncodingLastRect) - break; -+ // load first byte to send to Java be the FT msg number: -+ hdr[0] = rfbFileTransfer; ++//fprintf(stderr, "In HandleFileXfer\n"); - rect.r.x = Swap16IfLE(rect.r.x); - rect.r.y = Swap16IfLE(rect.r.y); @@ -6916,6 +10135,25 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, - rect.encoding)) { - return False; ++ if (db < 0) { ++ if (getenv("DEBUG_HandleFileXfer")) { ++ db = 1; ++ } else { ++ db = 0; ++ } + } +- continue; +- } + +- if (rect.encoding == rfbEncodingPointerPos) { +- if (!HandleCursorPos(rect.r.x, rect.r.y)) { +- return False; ++ last_filexfer = time(NULL); ++ //fprintf(stderr, "last_filexfer-1: %d\n", last_filexfer); ++ ++ // load first byte to send to Java be the FT msg number: ++ hdr[0] = rfbFileTransfer; ++ + // this is to avoid XtAppProcessEvent() calls induce by our ReadFromRFBServer calls below: + skip_XtUpdateAll = 1; + if (!ReadFromRFBServer(&hdr[1], 11)) { @@ -6942,23 +10180,29 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - continue; - } -- if (rect.encoding == rfbEncodingPointerPos) { -- if (!HandleCursorPos(rect.r.x, rect.r.y)) { +- if ((rect.r.x + rect.r.w > si.framebufferWidth) || +- (rect.r.y + rect.r.h > si.framebufferHeight)) +- { +- fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n", +- rect.r.w, rect.r.h, rect.r.x, rect.r.y); - return False; + if (hdr[1] == rfbEndOfFile) { + goto read_no_more; + } else if (hdr[1] == rfbAbortFileTransfer) { + goto read_no_more; } + +- if (rect.r.h * rect.r.w == 0) { +- fprintf(stderr,"Zero size rect - ignoring\n"); - continue; - } ++ if (hdr[1] == rfbDirPacket && hdr[3] == rfbADirectory) { ++ ++ } -- if ((rect.r.x + rect.r.w > si.framebufferWidth) || -- (rect.r.y + rect.r.h > si.framebufferHeight)) -- { -- fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n", -- rect.r.w, rect.r.h, rect.r.x, rect.r.y); -- return False; +- /* If RichCursor encoding is used, we should prevent collisions +- between framebuffer updates and cursor drawing operations. */ +- SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h); + len = (hdr[8] << 24) | (hdr[9] << 16) | (hdr[10] << 8) | hdr[11]; + if (db) fprintf(stderr, "Got rfbFileTransfer: len1 %u\n", len); + if (len > 0) { @@ -6967,24 +10211,64 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + return False; + } + if (db > 1) write(2, fxfer, len); ++ if (len >= 12 && hdr[1] == rfbDirPacket) { ++ /* try to guess if x11vnc or not... */ ++ if (db) { ++ int i; ++ fprintf(stderr, "HFX DIR PKT (attr, timeL, timeH):"); ++ for (i=0; i < 12; i++) { ++ fprintf(stderr, " %d", (unsigned char) fxfer[i]); ++ } ++ fprintf(stderr, "\n"); ++ } ++ if (hdr[2] == 1) { ++ int dattr = (unsigned char) fxfer[0]; ++ int timeL1 = (unsigned char) fxfer[4]; ++ int timeL2 = (unsigned char) fxfer[5]; ++ int timeL3 = (unsigned char) fxfer[6]; ++ int timeL4 = (unsigned char) fxfer[7]; ++ int timeH1 = (unsigned char) fxfer[8]; ++ int timeH2 = (unsigned char) fxfer[9]; ++ int timeH3 = (unsigned char) fxfer[10]; ++ int timeH4 = (unsigned char) fxfer[11]; ++ if (dattr != 0) { ++ if (timeH1 == 0 && timeH2 == 0 && timeH3 == 0 && timeH4 == 0) { ++ if (timeL1 != 0 || timeL2 != 0 && timeL3 != 0 && timeL4 != 0) { ++ if (!guess_x11vnc) fprintf(stderr, "guessed x11vnc server\n"); ++ guess_x11vnc = 1; ++ } ++ } ++ } ++ } ++ } + if (db && 0) fprintf(stderr, "\n"); + if (filexfer_sock >= 0) { + write(filexfer_sock, fxfer, len); + } else { + fprintf(stderr, "filexfer_sock closed, discarding %d bytes\n", len); + } - } ++ } -- if (rect.r.h * rect.r.w == 0) { -- fprintf(stderr,"Zero size rect - ignoring\n"); -- continue; -- } -+ /* not used! */ +- switch (rect.encoding) { + len = (hdr[4] << 24) | (hdr[5] << 16) | (hdr[6] << 8) | hdr[7]; + if (db) fprintf(stderr, "Got rfbFileTransfer: len2 %u\n", len); -+ -+ if (hdr[1] == rfbFileHeader && len != rfbRErrorCmd) { + +- case rfbEncodingRaw: ++#if 0 ++ if (hdr[1] == rfbFileHeader && len != rfbRErrorCmd) ++#else ++ // the extra 4 bytes get send on rfbRErrorCmd as well. ++ if (hdr[1] == rfbFileHeader) { ++#endif ++ int is_err = 0; ++ if (len == rfbRErrorCmd) { ++ is_err = 1; ++ } + if (db) fprintf(stderr, "Got rfbFileTransfer: rfbFileHeader\n"); ++ if (is_err && guess_x11vnc) { ++ fprintf(stderr, "rfbRErrorCmd x11vnc skip read 4 bytes.\n"); ++ goto read_no_more; ++ } + len = 4; + if (!ReadFromRFBServer(fxfer, len)) { + skip_XtUpdateAll = 0; @@ -6992,6 +10276,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + } + if (db > 1) write(2, fxfer, len); + if (db && 0) fprintf(stderr, "\n"); ++ if (is_err) { ++ fprintf(stderr, "rfbRErrorCmd skip write 4 bytes.\n"); ++ goto read_no_more; ++ } + if (filexfer_sock >= 0) { + write(filexfer_sock, fxfer, len); + } else { @@ -6999,12 +10287,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + } + } -- /* If RichCursor encoding is used, we should prevent collisions -- between framebuffer updates and cursor drawing operations. */ -- SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h); +- bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; +- linesToRead = BUFFER_SIZE / bytesPerLine; + read_no_more: -- switch (rect.encoding) { +- while (rect.r.h > 0) { +- if (linesToRead > rect.r.h) +- linesToRead = rect.r.h; + if (filexfer_sock < 0) { + int stop = 0; + static time_t last_stop = 0; @@ -7028,58 +10317,34 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + } + } -- case rfbEncodingRaw: +- if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) +- return False; + if (db) fprintf(stderr, "Got rfbFileTransfer done.\n"); + skip_XtUpdateAll = 0; -- bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; -- linesToRead = BUFFER_SIZE / bytesPerLine; +- CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, +- linesToRead); + if (db) fprintf(stderr, "CFX: B\n"); + CheckFileXfer(); +//fprintf(stderr, "Out HandleFileXfer\n"); + return True; +} - -- while (rect.r.h > 0) { -- if (linesToRead > rect.r.h) -- linesToRead = rect.r.h; ++ +/* + * HandleRFBServerMessage. + */ -- if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) -- return False; +- rect.r.h -= linesToRead; +- rect.r.y += linesToRead; -- CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, -- linesToRead); +- } +- break; +Bool +HandleRFBServerMessage() +{ + static int db = -1; + rfbServerToClientMsg msg; -- rect.r.h -= linesToRead; -- rect.r.y += linesToRead; -+ if (db < 0) { -+ if (getenv("DEBUG_RFB_SMSG")) { -+ db = 1; -+ } else { -+ db = 0; -+ } -+ } - -+ if (!ReadFromRFBServer((char *)&msg, 1)) { -+ return False; - } -- break; -+ if (appData.ultraDSM) { -+ if (!ReadFromRFBServer((char *)&msg, 1)) { -+ return False; -+ } -+ } -+ -+//fprintf(stderr, "msg.type: %d\n", msg.type); - - case rfbEncodingCopyRect: - { - rfbCopyRect cr; @@ -7106,21 +10371,28 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - rect.r.w, rect.r.h); - XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, - rect.r.w, rect.r.h); -+ if (msg.type == rfbFileTransfer) { -+ return HandleFileXfer(); ++ if (db < 0) { ++ if (getenv("DEBUG_RFB_SMSG")) { ++ db = 1; ++ } else { ++ db = 0; ++ } } - XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY, - rect.r.w, rect.r.h, rect.r.x, rect.r.y); -+ switch (msg.type) { ++ if (!ReadFromRFBServer((char *)&msg, 1)) { ++ return False; ++ } ++ if (appData.ultraDSM) { ++ if (!ReadFromRFBServer((char *)&msg, 1)) { ++ return False; ++ } ++ } - break; - } -+ case rfbSetColourMapEntries: -+ { -+ int i; -+ CARD16 rgb[3]; -+ XColor xc; ++//fprintf(stderr, "msg.type: %d\n", msg.type); - case rfbEncodingRRE: - { @@ -7137,8 +10409,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; -+ if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbSetColourMapEntriesMsg - 1)) { -+ return False; ++ if (msg.type == rfbFileTransfer) { ++ return HandleFileXfer(); } - break; - } @@ -7158,11 +10430,19 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; -- } ++ switch (msg.type) { ++ ++ case rfbSetColourMapEntries: ++ { ++ int i; ++ CARD16 rgb[3]; ++ XColor xc; ++ ++ if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbSetColourMapEntriesMsg - 1)) { ++ return False; + } - break; - } -+ msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour); -+ msg.scme.nColours = Swap16IfLE(msg.scme.nColours); - case rfbEncodingHextile: - { @@ -7179,6 +10459,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie - if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; ++ msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour); ++ msg.scme.nColours = Swap16IfLE(msg.scme.nColours); ++ + for (i = 0; i < msg.scme.nColours; i++) { + if (!ReadFromRFBServer((char *)rgb, 6)) { + return False; @@ -7317,6 +10600,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + continue; + } + if (rect.encoding == rfbEncodingNewFBSize) { ++ if (appData.chatOnly) { ++ continue; ++ } + fprintf(stderr,"New Size: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); + si.framebufferWidth = rect.r.w; + si.framebufferHeight = rect.r.h; @@ -7357,9 +10643,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + + if ((rect.r.x + rect.r.w > si.framebufferWidth) || + (rect.r.y + rect.r.h > si.framebufferHeight)) { -+ fprintf(stderr,"Rect too large: %dx%d at (%d, %d) encoding=%d\n", -+ rect.r.w, rect.r.h, rect.r.x, rect.r.y, rect.encoding); -+ return False; ++ if (!appData.chatOnly) { ++ fprintf(stderr,"Rect too large: %dx%d at (%d, %d) encoding=%d\n", ++ rect.r.w, rect.r.h, rect.r.x, rect.r.y, rect.encoding); ++ return False; ++ } + } + + if (rect.r.h * rect.r.w == 0) { @@ -7409,6 +10697,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) { + return False; + } ++ if (appData.chatOnly) { ++ break; ++ } + + cr.srcX = Swap16IfLE(cr.srcX); + cr.srcY = Swap16IfLE(cr.srcY); @@ -7436,9 +10727,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie + } + + if (db) fprintf(stderr, "FBU-CPA1 %.6f\n", dnow()); -+ if (!appData.useBackingstore) { ++ if (!appData.useXserverBackingStore) { + copy_rect(rect.r.x, rect.r.y, rect.r.w, rect.r.h, cr.srcX, cr.srcY); -+ put_image(rect.r.x, rect.r.y, rect.r.x, rect.r.y, rect.r.w, rect.r.h); ++ put_image(rect.r.x, rect.r.y, rect.r.x, rect.r.y, rect.r.w, rect.r.h, 0); + XSync(dpy, False); + } else { + XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY, @@ -7703,7 +10994,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie #ifdef MITSHM /* if using shared memory PutImage, make sure that the X server has -@@ -1224,59 +2206,165 @@ +@@ -1224,59 +2297,165 @@ mainly to avoid copyrect using invalid screen contents - not sure if we'd need it otherwise. */ @@ -7902,7 +11193,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie } -@@ -1296,26 +2384,47 @@ +@@ -1296,26 +2475,47 @@ #define CONCAT2(a,b) a##b #define CONCAT2E(a,b) CONCAT2(a,b) @@ -7950,7 +11241,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie #undef BPP /* -@@ -1358,9 +2467,9 @@ +@@ -1358,9 +2558,9 @@ " %s significant bit in each byte is leftmost on the screen.\n", (format->bigEndian ? "Most" : "Least")); } else { @@ -7962,14 +11253,14 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rfbproto.c vnc_unixsrc/vncvie (format->bigEndian ? "Most" : "Least")); } if (format->trueColour) { -@@ -1462,4 +2571,3 @@ +@@ -1462,4 +2662,3 @@ cinfo->src = &jpegSrcManager; } - diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rre.c vnc_unixsrc/vncviewer/rre.c --- vnc_unixsrc.orig/vncviewer/rre.c 2000-06-11 08:00:53.000000000 -0400 -+++ vnc_unixsrc/vncviewer/rre.c 2007-02-17 22:52:24.000000000 -0500 ++++ vnc_unixsrc/vncviewer/rre.c 2008-10-05 15:16:30.000000000 -0400 @@ -29,6 +29,18 @@ #define HandleRREBPP CONCAT2E(HandleRRE,BPP) #define CARDBPP CONCAT2E(CARD,BPP) @@ -7978,7 +11269,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rre.c vnc_unixsrc/vncviewer/r + { \ + XGCValues _gcv; \ + _gcv.foreground = color; \ -+ if (!appData.useBackingstore) { \ ++ if (!appData.useXserverBackingStore) { \ + FillScreen(x, y, w, h, _gcv.foreground); \ + } else { \ + XChangeGC(dpy, gc, GCForeground, &_gcv); \ @@ -8035,8 +11326,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rre.c vnc_unixsrc/vncviewer/r +#undef FillRectangle diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/shm.c --- vnc_unixsrc.orig/vncviewer/shm.c 2000-06-11 08:00:53.000000000 -0400 -+++ vnc_unixsrc/vncviewer/shm.c 2007-03-23 22:20:35.000000000 -0400 -@@ -33,68 +33,80 @@ ++++ vnc_unixsrc/vncviewer/shm.c 2008-10-10 12:26:07.000000000 -0400 +@@ -33,68 +33,97 @@ void ShmCleanup() { @@ -8067,6 +11358,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/s + return 0; } ++int scale_round(int len, double fac); ++extern int scale_x, scale_y; ++extern double scale_factor_x, scale_factor_y; ++ XImage * -CreateShmImage() +CreateShmImage(int do_ycrop) @@ -8114,6 +11409,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/s + XImage *image; + XErrorHandler oldXErrorHandler; + int ymax = si.framebufferHeight; ++ int xmax = si.framebufferWidth; + + if (!XShmQueryExtension(dpy)) { + return NULL; @@ -8121,12 +11417,21 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/s + if (!appData.useShm) { + return NULL; + } ++ if (do_ycrop == -1) { ++ /* kludge to test for shm prescence */ ++ return (XImage *) 0x1; ++ } ++ + if (do_ycrop) { + ymax = appData.yCrop; + } + -+ image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo, -+ si.framebufferWidth, ymax); ++ if (scale_x > 0) { ++ xmax = scale_round(xmax, scale_factor_x); ++ ymax = scale_round(ymax, scale_factor_y); ++ } ++ ++ image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo, xmax, ymax); + if (!image) { + return NULL; + } @@ -8135,6 +11440,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/s + + if (shminfo.shmid == -1) { + XDestroyImage(image); ++ //fprintf(stderr, "CreateShmImage: destroyed 'image' (1)\n"); + return NULL; + } + @@ -8142,6 +11448,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/s + + if (shminfo.shmaddr == (char *)-1) { + XDestroyImage(image); ++ //fprintf(stderr, "CreateShmImage: destroyed 'image' (2)\n"); + shmctl(shminfo.shmid, IPC_RMID, 0); + return NULL; + } @@ -8155,6 +11462,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/s + + if (caughtShmError) { + XDestroyImage(image); ++ //fprintf(stderr, "CreateShmImage: destroyed 'image' (3)\n"); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + return NULL; @@ -8164,7 +11472,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/shm.c vnc_unixsrc/vncviewer/s + needShmCleanup = True; - fprintf(stderr,"Using shared memory PutImage\n"); -+ fprintf(stderr,"Using shared memory (PutImage ycrop=%d)\n", do_ycrop); ++ fprintf(stderr,"Using shared memory (PutImage ycrop=%d, Size %dx%d)\n", do_ycrop, xmax, ymax); - return image; + return image; @@ -8186,7 +11494,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/smake vnc_unixsrc/vncviewer/s +fi diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncviewer/sockets.c --- vnc_unixsrc.orig/vncviewer/sockets.c 2001-01-14 22:54:18.000000000 -0500 -+++ vnc_unixsrc/vncviewer/sockets.c 2008-09-14 10:28:56.000000000 -0400 ++++ vnc_unixsrc/vncviewer/sockets.c 2008-10-15 08:30:41.000000000 -0400 @@ -27,6 +27,7 @@ #include <netinet/in.h> #include <netinet/tcp.h> @@ -8195,7 +11503,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview #include <netdb.h> #include <fcntl.h> #include <assert.h> -@@ -56,22 +57,339 @@ +@@ -56,22 +57,366 @@ */ static Bool rfbsockReady = False; @@ -8323,7 +11631,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview + fprintf(stderr, " %d", (int) fxfer[i]); + } + fprintf(stderr, " ?\n"); - } ++} + if (0 || db) fprintf(stderr, "filexfer read[%d] %d.\n", icnt, rn); + if (rn < 0) { + fprintf(stderr, "filexfer bad read: %d\n", errno); @@ -8421,12 +11729,52 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview + } +//fprintf(stderr, "Out CheckFileXfer\n"); + return; + } + ++static void check_term_chat(void) { ++ fd_set fds; ++ struct timeval tv; ++ int i, igot = -1, n = fileno(stdin); ++ char strs[100][512]; ++ char buf[rfbTextMaxSize]; ++ ++ for (i=0; i < 100; i++) { ++ FD_ZERO(&fds); ++ FD_SET(n,&fds); ++ tv.tv_sec = 0; ++ tv.tv_usec = 0; ++ if (select(n+1, &fds, NULL, NULL, &tv) > 0) { ++ if (FD_ISSET(n, &fds)) { ++ fgets(strs[i], 512, stdin); ++ igot = i; ++ } else { ++ break; ++ } ++ } else { ++ break; ++ } ++ } ++ buf[0] = '\0'; ++ for (i=0; i <= igot; i++) { ++ if (strlen(buf) + strlen(strs[i]) < rfbTextMaxSize) { ++ strcat(buf, strs[i]); ++ } else { ++ SendTextChat(buf); ++ buf[0] = '0'; ++ } ++ } ++ if (buf[0] != '\0') { ++ SendTextChat(buf); ++ } ++ if (igot >= 0) printChat("Send: "); +} + +static time_t time_mark; +extern int delay_filexfer; +#include <sys/stat.h> - ++ ++extern double start_time; ++ static void ProcessXtEvents() { @@ -8438,6 +11786,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview - } + int y, db = 0; + static int dyn = -1; ++ static int chat_was_active = 0; ++ int check_chat = 0; + + if (dyn < 0) { + struct stat sb; @@ -8454,50 +11804,35 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview + } + } + ++ //if (0) fprintf(stderr, "ProcessXtEvents: %d %.4f\n", skip_XtUpdateAll, dnow() - start_time); ++ + if (skip_XtUpdateAll) { + return; + } -+ if (appData.chatActive) { -+ fd_set fds; -+ struct timeval tv; -+ int i, igot = -1, n = fileno(stdin); -+ char strs[100][512]; -+ char buf[rfbTextMaxSize]; + -+ if (appData.termChat) { -+ for (i=0; i < 100; i++) { -+ FD_ZERO(&fds); -+ FD_SET(n,&fds); -+ tv.tv_sec = 0; -+ tv.tv_usec = 0; -+ if (select(n+1, &fds, NULL, NULL, &tv) > 0) { -+ if (FD_ISSET(n, &fds)) { -+ fgets(strs[i], 512, stdin); -+ igot = i; -+ } else { -+ break; -+ } -+ } else { -+ break; -+ } -+ } -+ buf[0] = '\0'; -+ for (i=0; i <= igot; i++) { -+ if (strlen(buf) + strlen(strs[i]) < rfbTextMaxSize) { -+ strcat(buf, strs[i]); -+ } else { -+ SendTextChat(buf); -+ buf[0] = '0'; -+ } -+ } -+ if (buf[0] != '\0') { -+ SendTextChat(buf); -+ } -+ if (igot >= 0) printChat("Send: "); -+ } else { ++ /* text chat */ ++ if (appData.chatActive ) { ++ check_chat = 1; ++ } else if (chat_was_active) { ++ static double last_check = 0.0; ++ double now = dnow(); ++ if (now > last_check + 0.75) { ++ //fprintf(stderr, "cwa\n"); ++ check_chat = 1; ++ last_check = now; ++ } ++ } ++ if (check_chat) { ++ if (appData.chatActive) { ++ chat_was_active = 1; ++ } ++ if (!appData.termChat) { + CheckTextInput(); ++ } else { ++ check_term_chat(); + } + } ++ + if (skip_XtUpdate) { + return; + } @@ -8543,7 +11878,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview } Bool -@@ -151,6 +469,8 @@ +@@ -151,6 +496,8 @@ } @@ -8552,7 +11887,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview /* * Write an exact number of bytes, and don't return until you've sent them. */ -@@ -158,37 +478,81 @@ +@@ -158,37 +505,81 @@ Bool WriteExact(int sock, char *buf, int n) { @@ -8663,7 +11998,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview } -@@ -203,6 +567,8 @@ +@@ -203,6 +594,8 @@ struct sockaddr_in addr; int one = 1; @@ -8672,12 +12007,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = host; -@@ -232,7 +598,22 @@ +@@ -232,7 +625,22 @@ return sock; } +Bool SocketPair(int fd[2]) { -+ if (socketpair(PF_UNIX, SOCK_STREAM, AF_UNIX, fd) == -1) { ++ if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) == -1) { + perror("socketpair"); + return False; + } @@ -8695,7 +12030,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview /* * FindFreeTcpPort tries to find unused TCP port in the range -@@ -245,6 +626,8 @@ +@@ -245,6 +653,8 @@ int sock, port; struct sockaddr_in addr; @@ -8704,7 +12039,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; -@@ -272,6 +655,8 @@ +@@ -272,6 +682,8 @@ * ListenAtTcpPort starts listening at the given TCP port. */ @@ -8713,7 +12048,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview int ListenAtTcpPort(int port) { -@@ -279,10 +664,16 @@ +@@ -279,10 +691,16 @@ struct sockaddr_in addr; int one = 1; @@ -8732,7 +12067,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/sockets.c vnc_unixsrc/vncview fprintf(stderr,programName); diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tight.c vnc_unixsrc/vncviewer/tight.c --- vnc_unixsrc.orig/vncviewer/tight.c 2002-04-30 09:07:31.000000000 -0400 -+++ vnc_unixsrc/vncviewer/tight.c 2007-02-17 22:08:20.000000000 -0500 ++++ vnc_unixsrc/vncviewer/tight.c 2008-10-05 15:16:35.000000000 -0400 @@ -129,14 +129,21 @@ #endif @@ -8750,7 +12085,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tight.c vnc_unixsrc/vncviewer - XChangeGC(dpy, gc, GCForeground, &gcv); - XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); -+ if (!appData.useBackingstore) { ++ if (!appData.useXserverBackingStore) { + FillScreen(rx, ry, rw, rh, gcv.foreground); + } else { + XChangeGC(dpy, gc, GCForeground, &gcv); @@ -8787,7 +12122,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tunnel.c vnc_unixsrc/vncviewe sprintf(lastArgv, "localhost::%d", localPort); diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncviewer/vncviewer.c --- vnc_unixsrc.orig/vncviewer/vncviewer.c 2004-01-13 09:22:05.000000000 -0500 -+++ vnc_unixsrc/vncviewer/vncviewer.c 2008-09-09 00:08:07.000000000 -0400 ++++ vnc_unixsrc/vncviewer/vncviewer.c 2008-10-17 20:36:47.000000000 -0400 @@ -22,6 +22,7 @@ */ @@ -8796,7 +12131,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi char *programName; XtAppContext appContext; -@@ -29,11 +30,179 @@ +@@ -29,11 +30,190 @@ Widget toplevel; @@ -8957,12 +12292,23 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + SendKeyEvent(XK_Return, 0); +} + ++static void chat_window_only(void) { ++ if (appData.chatOnly) { ++ static double last_time = 0.0; ++ if (dnow() > last_time + 1.5) { ++ XSync(dpy, False); ++ XUnmapWindow(dpy, XtWindow(toplevel)); ++ } ++ } ++} ++ int main(int argc, char **argv) { - int i; - programName = argv[0]; + int i, save_sbw; ++ char *pw_loc = NULL; + programName = argv[0]; + + for (i = 1; i < argc; i++) { @@ -8978,7 +12324,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi /* The -listen option is used to make us a daemon process which listens for incoming connections from servers, rather than actively connecting to a -@@ -45,89 +214,1235 @@ +@@ -45,89 +225,1363 @@ listenForIncomingConnections() returns, setting the listenSpecified flag. */ @@ -8994,6 +12340,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi - } - } + for (i = 1; i < argc; i++) { ++ if (strstr(argv[i], " pw=") != NULL) { ++ pw_loc = strstr(argv[i], " pw=") + 1; ++ } ++ } ++ ++ for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-listen") == 0) { + listenForIncomingConnections(&argc, argv, i); + break; @@ -9085,6 +12437,18 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + if (save_sbw) { + appData.sbWidth = save_sbw; + } ++ ++ if (appData.chatOnly) { ++ appData.encodingsString = "raw hextile"; ++ } ++ ++ if (pw_loc != NULL) { ++ char *q = pw_loc; ++ while (*q != '\0' && !isspace(*q)) { ++ *q = ' '; ++ q++; ++ } ++ } /* Unless we accepted an incoming connection, make a TCP connection to the given VNC server */ @@ -9136,6 +12500,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi - if (!InitialiseRFBConnection()) exit(1); + if (!InitialiseRFBConnection()) { ++ Cleanup(); + exit(1); + } + if (appData.unixPW != NULL) { @@ -9189,6 +12554,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi - SetFormatAndEncodings(); + SetFormatAndEncodings(); ++ ++ if (appData.chatOnly) { ++ chat_window_only(); ++ ToggleTextChat(0, NULL, NULL, NULL); ++ } /* Now enter the main loop, processing VNC messages. X events will automatically be processed whenever the VNC connection is idle. */ @@ -9201,6 +12571,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + if (!HandleRFBServerMessage()) { + break; + } ++ if (appData.chatOnly) { ++ chat_window_only(); ++ } + } + + Cleanup(); @@ -9324,6 +12697,21 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + schedule_format_change(); +} + ++void ++ToggleXGrab(Widget w, XEvent *ev, String *params, Cardinal *num_params) ++{ ++ if (getenv("SSVNC_DEBUG_GRAB")) { ++ fprintf(stderr, "ToggleXGrab, current=%d\n", appData.grabAll); ++ } ++ if (appData.grabAll) { ++ appData.grabAll = False; ++ } else { ++ appData.grabAll = True; ++ } ++ /* always ungrab to be sure, fullscreen will handle the rest */ ++ XUngrabServer(dpy); ++} ++ +/* + * ToggleNColors + */ @@ -9641,7 +13029,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + if (appData.chatActive) { + printChat("\n*SentClose*\n\n", False); + SendTextChatClose(); -+ HideChat(); ++ SendTextChatFinished(); ++ HideChat(0, NULL, NULL, NULL); + appData.chatActive= False; + } else { + ShowChat(); @@ -9731,7 +13120,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + char str[100], *s, *q; + int n; + if (1) { -+ s = DoScaleDialog(); ++ s = DoScaleNDialog(); + } else { + raiseme(1); + fprintf(stderr, "\n\n\a\nEnter integer n for 1/n server scaling: "); @@ -9815,8 +13204,41 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + } +} + - -- Cleanup(); ++extern void rescale_image(void); ++ ++void ++SetScale(Widget w, XEvent *ev, String *params, Cardinal *num_params) ++{ ++ char *s; ++ s = DoScaleDialog(); ++ if (s[0] != '\0') { ++ int w = si.framebufferWidth; ++ int h = si.framebufferHeight; ++ int fs = 0; ++ if (appData.scale != NULL && !strcmp(s, appData.scale)) { ++ return; ++ } ++ if (!strcasecmp(s, "none")) { ++ appData.scale = NULL; ++ } else if (!strcmp(s, "1.0")) { ++ appData.scale = NULL; ++ } else if (!strcmp(s, "1")) { ++ appData.scale = NULL; ++ } else { ++ appData.scale = strdup(s); ++ } ++ if (appData.fullScreen) { ++ fs = 1; ++ FullScreenOff(); ++ } ++ rescale_image(); ++ if (fs) { ++ FullScreenOn(); ++ } ++ } ++} ++ ++ +void set_ycrop(int n) { + if (n >= 1) { + int w = si.framebufferWidth; @@ -9849,8 +13271,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + set_ycrop(n); + } +} - -- return 0; ++ +void set_scbar(int n) { + if (n >= 1) { + int w = si.framebufferWidth; @@ -9911,13 +13332,14 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + set_server_compress(n); + } +} -+ + +- Cleanup(); +void +GotChatText(char *str, int len) +{ + static char *b = NULL; + static int blen = -1; -+ int i; ++ int i, k; + if (appData.termChat) { + printChat("\nChat: ", True); + } else { @@ -9932,9 +13354,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + b = (char *) malloc(blen); + } + ++ k = 0; + for (i=0; i < len; i++) { -+ b[i] = str[i]; ++ if (str[i] != '\r') { ++ b[k++] = str[i]; ++ } + } ++ b[k] = '\0'; + b[len] = '\0'; + printChat(b, True); + @@ -9946,23 +13372,26 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + } + } +} -+ + +- return 0; +void +SetViewOnlyState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.viewOnly) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.viewOnly) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetNOJPEGState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.enableJPEG) -+ XtVaSetValues(w, XtNstate, False, NULL); -+ else -+ XtVaSetValues(w, XtNstate, True, NULL); ++ if (appData.enableJPEG) { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } +} + +void @@ -10009,8 +13438,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi +{ + if (appData.useBGR233) { + XtVaSetValues(w, XtNstate, True, NULL); -+ if (b16 != NULL) XtVaSetValues(b16, XtNstate, False, NULL); -+ if (bfull != NULL) XtVaSetValues(bfull, XtNstate, False, NULL); ++ if (b16 != NULL) { ++ XtVaSetValues(b16, XtNstate, False, NULL); ++ } ++ if (bfull != NULL) { ++ XtVaSetValues(bfull, XtNstate, False, NULL); ++ } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } @@ -10021,8 +13454,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi +{ + if (appData.useBGR565) { + XtVaSetValues(w, XtNstate, True, NULL); -+ if (b8 != NULL) XtVaSetValues(b8, XtNstate, False, NULL); -+ if (bfull != NULL) XtVaSetValues(bfull, XtNstate, False, NULL); ++ if (b8 != NULL) { ++ XtVaSetValues(b8, XtNstate, False, NULL); ++ } ++ if (bfull != NULL) { ++ XtVaSetValues(bfull, XtNstate, False, NULL); ++ } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } @@ -10035,8 +13472,22 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + XtVaSetValues(w, XtNstate, False, NULL); + } else { + XtVaSetValues(w, XtNstate, True, NULL); -+ if (b8 != NULL) XtVaSetValues(b8, XtNstate, False, NULL); -+ if (b16 != NULL) XtVaSetValues(b16, XtNstate, False, NULL); ++ if (b8 != NULL) { ++ XtVaSetValues(b8, XtNstate, False, NULL); ++ } ++ if (b16 != NULL) { ++ XtVaSetValues(b16, XtNstate, False, NULL); ++ } ++ } ++} ++ ++void ++SetXGrabState(Widget w, XEvent *ev, String *params, Cardinal *num_params) ++{ ++ if (appData.grabAll) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); + } +} + @@ -10045,8 +13496,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi +{ + if (appData.useBGR233 == 256) { + XtVaSetValues(w, XtNstate, True, NULL); -+ if (w64 != NULL) XtVaSetValues(w64 , XtNstate, False, NULL); -+ if (w8 != NULL) XtVaSetValues(w8 , XtNstate, False, NULL); ++ if (w64 != NULL) { ++ XtVaSetValues(w64 , XtNstate, False, NULL); ++ } ++ if (w8 != NULL) { ++ XtVaSetValues(w8 , XtNstate, False, NULL); ++ } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } @@ -10057,8 +13512,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi +{ + if (appData.useBGR233 == 64) { + XtVaSetValues(w, XtNstate, True, NULL); -+ if (w256 != NULL) XtVaSetValues(w256, XtNstate, False, NULL); -+ if (w8 != NULL) XtVaSetValues(w8 , XtNstate, False, NULL); ++ if (w256 != NULL) { ++ XtVaSetValues(w256, XtNstate, False, NULL); ++ } ++ if (w8 != NULL) { ++ XtVaSetValues(w8 , XtNstate, False, NULL); ++ } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } @@ -10069,8 +13528,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi +{ + if (appData.useBGR233 == 8) { + XtVaSetValues(w, XtNstate, True, NULL); -+ if (w256 != NULL) XtVaSetValues(w256, XtNstate, False, NULL); -+ if (w64 != NULL) XtVaSetValues(w64 , XtNstate, False, NULL); ++ if (w256 != NULL) { ++ XtVaSetValues(w256, XtNstate, False, NULL); ++ } ++ if (w64 != NULL) { ++ XtVaSetValues(w64 , XtNstate, False, NULL); ++ } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } @@ -10155,104 +13618,115 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.c vnc_unixsrc/vncvi + } + first = 0; + -+ if (usingZRLE) ++ if (usingZRLE) { + XtVaSetValues(w, XtNstate, True, NULL); -+ else ++ } else { + XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetZYWRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (usingZYWRLE) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (usingZYWRLE) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetCursorShapeState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.useRemoteCursor) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.useRemoteCursor) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetCursorAlphaState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.useCursorAlpha) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.useCursorAlpha) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetX11CursorState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.useX11Cursor) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.useX11Cursor) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetBellState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.useBell) -+ XtVaSetValues(w, XtNstate, False, NULL); -+ else -+ XtVaSetValues(w, XtNstate, True, NULL); ++ if (appData.useBell) { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } +} + +void +SetRawLocalState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.useRawLocal) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.useRawLocal) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetServerInputState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (!appData.serverInput) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (!appData.serverInput) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetSingleWindowState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.singleWindow) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.singleWindow) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.chatActive) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.chatActive) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } +} + +void +SetFileXferState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ -+ if (appData.fileActive) -+ XtVaSetValues(w, XtNstate, True, NULL); -+ else -+ XtVaSetValues(w, XtNstate, False, NULL); ++ if (appData.fileActive) { ++ XtVaSetValues(w, XtNstate, True, NULL); ++ } else { ++ XtVaSetValues(w, XtNstate, False, NULL); ++ } } diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncviewer/vncviewer.h --- vnc_unixsrc.orig/vncviewer/vncviewer.h 2004-03-11 13:14:40.000000000 -0500 -+++ vnc_unixsrc/vncviewer/vncviewer.h 2008-09-13 13:54:01.000000000 -0400 ++++ vnc_unixsrc/vncviewer/vncviewer.h 2008-10-17 20:31:48.000000000 -0400 @@ -51,7 +51,7 @@ (((l) & 0x0000ff00) << 8) | \ (((l) & 0x000000ff) << 24)) : (l)) @@ -10262,10 +13736,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi #define FLASH_PORT_OFFSET 5400 #define LISTEN_PORT_OFFSET 5500 -@@ -68,51 +68,77 @@ - /* argsresources.c */ +@@ -65,59 +65,93 @@ + (DEFAULT_SSH_CMD " -f -L %L:%H:%R %G sleep 20") - typedef struct { + +-/* argsresources.c */ +- +-typedef struct { - Bool shareDesktop; - Bool viewOnly; - Bool fullScreen; @@ -10293,20 +13770,17 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi - - int rawDelay; - int copyRectDelay; -- ++/* for debugging width, height, etc */ ++//#define XtVaSetValues printf("%s:%d\n", __FILE__, __LINE__); XtVaSetValues + - Bool debug; -- + - int popupButtonCount; -- ++/* argsresources.c */ + - int bumpScrollTime; - int bumpScrollPixels; -- -- int compressLevel; -- int qualityLevel; -- Bool enableJPEG; -- Bool useRemoteCursor; -- Bool useX11Cursor; -- Bool autoPass; ++typedef struct { + Bool shareDesktop; + Bool viewOnly; + Bool fullScreen; @@ -10325,7 +13799,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi + Bool useGreyScale; + + Bool grabAll; -+ Bool useBackingstore; ++ Bool useXserverBackingStore; + Bool overrideRedir; + Bool popupFix; + @@ -10372,8 +13846,17 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi + Bool singleWindow; + int serverScale; + Bool chatActive; ++ Bool chatOnly; + Bool fileActive; +- int compressLevel; +- int qualityLevel; +- Bool enableJPEG; +- Bool useRemoteCursor; +- Bool useX11Cursor; +- Bool autoPass; ++ char *scale; + } AppData; extern AppData appData; @@ -10381,7 +13864,13 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi extern char *fallback_resources[]; extern char vncServerHost[]; -@@ -130,10 +156,11 @@ + extern int vncServerPort; + extern Bool listenSpecified; ++extern pid_t listenParent; + extern int listenPort, flashPort; + + extern XrmOptionDescRec cmdLineOptions[]; +@@ -130,10 +164,11 @@ /* colour.c */ extern unsigned long BGR233ToPixel[]; @@ -10394,7 +13883,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi extern void SetVisualAndCmap(); -@@ -157,13 +184,40 @@ +@@ -157,13 +192,48 @@ extern void DesktopInitBeforeRealization(); extern void DesktopInitAfterRealization(); @@ -10407,11 +13896,19 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi +extern void ReDoDesktop(); +extern void DesktopCursorOff(); -+extern void put_image(int x1, int y1, int x2, int y2, int width, int height); ++extern void put_image(int x1, int y1, int x2, int y2, int width, int height, int solid); +extern void copy_rect(int x, int y, int width, int height, int src_x, int src_y); + ++extern void releaseAllPressedModifiers(void); ++extern void fs_grab(int check); ++extern void fs_ungrab(int check); ++ /* dialogs.c */ ++extern void ScaleDialogDone(Widget w, XEvent *event, String *params, ++ Cardinal *num_params); ++extern char *DoScaleDialog(); ++ +extern void YCropDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoYCropDialog(); @@ -10420,9 +13917,9 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi + Cardinal *num_params); +extern char *DoScbarDialog(); + -+extern void ScaleDialogDone(Widget w, XEvent *event, String *params, ++extern void ScaleNDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); -+extern char *DoScaleDialog(); ++extern char *DoScaleNDialog(); + +extern void QualityDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); @@ -10435,10 +13932,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi extern void ServerDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params); extern char *DoServerDialog(); -@@ -181,6 +235,11 @@ +@@ -181,6 +251,13 @@ extern void FullScreenOn(); extern void FullScreenOff(); ++extern int net_wm_supported(void); ++ +extern void JumpLeft(Widget w, XEvent *event, String *params, Cardinal *num_params); +extern void JumpRight(Widget w, XEvent *event, String *params, Cardinal *num_params); +extern void JumpUp(Widget w, XEvent *event, String *params, Cardinal *num_params); @@ -10447,7 +13946,16 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi /* listen.c */ extern void listenForIncomingConnections(); -@@ -207,6 +266,18 @@ +@@ -196,6 +273,8 @@ + Cardinal *num_params); + extern void Quit(Widget w, XEvent *event, String *params, + Cardinal *num_params); ++extern void HideChat(Widget w, XEvent *event, String *params, ++ Cardinal *num_params); + extern void Cleanup(); + + /* popup.c */ +@@ -207,6 +286,20 @@ Cardinal *num_params); extern void CreatePopup(); @@ -10463,10 +13971,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi + Cardinal *num_params); +extern void CreateCompress(); + ++extern void Noop(Widget w, XEvent *event, String *params, ++ Cardinal *num_params); /* rfbproto.c */ extern int rfbsock; -@@ -229,6 +300,15 @@ +@@ -229,8 +322,19 @@ extern Bool SendClientCutText(char *str, int len); extern Bool HandleRFBServerMessage(); @@ -10481,8 +13991,12 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi + extern void PrintPixelFormat(rfbPixelFormat *format); ++extern double dnow(void); ++ /* selection.c */ -@@ -241,8 +321,9 @@ + + extern void InitialiseSelection(); +@@ -241,8 +345,9 @@ /* shm.c */ @@ -10493,7 +14007,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi /* sockets.c */ -@@ -253,8 +334,11 @@ +@@ -253,8 +358,11 @@ extern int FindFreeTcpPort(void); extern int ListenAtTcpPort(int port); extern int ConnectToTcpAddr(unsigned int host, int port); @@ -10505,7 +14019,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi extern int StringToIPAddr(const char *str, unsigned int *addr); extern Bool SameMachine(int sock); -@@ -271,3 +355,63 @@ +@@ -271,3 +379,66 @@ extern XtAppContext appContext; extern Display* dpy; extern Widget toplevel; @@ -10530,9 +14044,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi +extern void ToggleRawLocal(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleServerInput(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleSingleWindow(Widget w, XEvent *ev, String *params, Cardinal *num_params); ++extern void ToggleXGrab(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void DoServerScale(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void DoServerQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void DoServerCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params); ++extern void SetScale(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetYCrop(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetScbar(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ShowScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params); @@ -10569,9 +14085,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.h vnc_unixsrc/vncvi +extern void SetTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetTermTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetFileXferState(Widget w, XEvent *ev, String *params, Cardinal *num_params); ++extern void SetXGrabState(Widget w, XEvent *ev, String *params, Cardinal *num_params); diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vncviewer/vncviewer.man --- vnc_unixsrc.orig/vncviewer/vncviewer.man 2004-03-11 13:14:40.000000000 -0500 -+++ vnc_unixsrc/vncviewer/vncviewer.man 2008-09-14 14:32:53.000000000 -0400 ++++ vnc_unixsrc/vncviewer/vncviewer.man 2008-10-17 22:04:57.000000000 -0400 @@ -5,38 +5,51 @@ .\" Copyright (C) 1998 Marcus.Brinkmann@ruhr-uni-bochum.de .\" Copyright (C) 2000,2001 Red Hat, Inc. @@ -10583,7 +14100,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc .\" TightVNC distribution. .\" -.TH vncviewer 1 "January 2003" "" "TightVNC" -+.TH ssvncviewer 1 "August 2008" "" "SSVNC" ++.TH ssvncviewer 1 "October 2008" "" "SSVNC" .SH NAME -vncviewer \- an X viewer client for VNC +ssvncviewer \- an X viewer client for VNC @@ -10632,7 +14149,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc You can use F8 to display a pop\-up utility menu. Press F8 twice to pass single F8 to the remote side. .SH OPTIONS -@@ -168,6 +181,227 @@ +@@ -168,6 +181,244 @@ \fB\-autopass\fR Read a plain-text password from stdin. This option affects only the standard VNC authentication. @@ -10701,6 +14218,16 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc +requires: x11vnc server, both client and server +must be 32bpp and same endianness. +.TP ++\fB\-scale\fR \fIstr\fR ++Scale the desktop locally. The string "str" can ++a floating point ratio, e.g. "0.9", or a fraction, ++e.g. "3/4", or WxH, e.g. 1280x1024. Use "fit" ++to fit in the current screen size. ++Use "auto" to fit in the window size. ++Note that scaling is done in software and can be slow ++and requires more memory. "str" can also be set by ++the env. var. SSVNC_SCALE. ++.TP +\fB\-ycrop\fR n +Only show the top n rows of the framebuffer. For +use with x11vnc \fB\-ncache\fR client caching option @@ -10811,6 +14338,11 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc +data sent so as to work with the UltraVNC Server. For some +reason, each RFB msg type must be sent twice under DSM. +.TP ++\fB\-chatonly\fR ++Try to be a client that only does UltraVNC text chat. This ++mode is used by x11vnc to present a chat window on the physical ++X11 console (i.e. to chat with the person at the display). ++.TP +\fB-env\fR \fIVAR=VALUE\fR +To save writing a shell script to set environment +variables, specify as many as you need on the command line. For example, @@ -10841,8 +14373,10 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc + 256 colors ~ -bgr233 default # of colors. + 64 colors ~ -bgr222 / -use64 + 8 colors ~ -bgr111 / -use8 ++ Scale Viewer ~ -scale + Set Y Crop (y-max) ~ -ycrop + Set Scrollbar Width ~ -sbwidth ++ XGrabServer ~ -graball + + UltraVNC Extensions: + @@ -10860,7 +14394,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc .SH ENCODINGS The server supplies information in whatever format is desired by the client, in order to make the client as easy as possible to implement. -@@ -238,6 +472,15 @@ +@@ -238,6 +489,15 @@ \-quality and \-nojpeg options above). Tight encoding is usually the best choice for low\-bandwidth network environments (e.g. slow modem connections). @@ -10876,7 +14410,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc .SH RESOURCES X resources that \fBvncviewer\fR knows about, aside from the normal Xt resources, are as follows: -@@ -364,8 +607,8 @@ +@@ -364,8 +624,8 @@ .B %R remote TCP port number. .SH SEE ALSO @@ -10887,7 +14421,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc .SH AUTHORS Original VNC was developed in AT&T Laboratories Cambridge. TightVNC additions was implemented by Constantin Kaplinsky. Many other people -@@ -380,3 +623,5 @@ +@@ -380,3 +640,5 @@ Tim Waugh <twaugh@redhat.com>, .br Constantin Kaplinsky <const@ce.cctpu.edu.ru> @@ -10895,8 +14429,8 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vnc +Karl Runge <runge@karlrunge.com> diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrle.c vnc_unixsrc/vncviewer/zrle.c --- vnc_unixsrc.orig/vncviewer/zrle.c 2007-02-04 18:59:50.000000000 -0500 -+++ vnc_unixsrc/vncviewer/zrle.c 2008-02-17 10:34:45.000000000 -0500 -@@ -0,0 +1,616 @@ ++++ vnc_unixsrc/vncviewer/zrle.c 2008-10-08 00:04:43.000000000 -0400 +@@ -0,0 +1,618 @@ +/* + * Copyright (C) 2005 Johannes E. Schindelin. All Rights Reserved. + * @@ -10948,7 +14482,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrle.c vnc_unixsrc/vncviewer/ + { \ + XGCValues _gcv; \ + _gcv.foreground = color; \ -+ if (!appData.useBackingstore) { \ ++ if (!appData.useXserverBackingStore) { \ + FillScreen(x, y, w, h, _gcv.foreground); \ + } else { \ + XChangeGC(dpy, gc, GCForeground, &_gcv); \ @@ -11163,6 +14697,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrle.c vnc_unixsrc/vncviewer/ +#endif + +extern XImage *image; ++extern XImage *image_scale; +extern int skip_maybe_sync; + +static int HandleZRLETile( @@ -11409,6 +14944,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrle.c vnc_unixsrc/vncviewer/ + char *scr, *buf; + static CARDBPP *ptmp = NULL; + static int ptmp_len = 0; ++ XImage *im = image_scale ? image_scale : image; + + if (w * h > ptmp_len) { + ptmp_len = w * h; @@ -11426,7 +14962,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrle.c vnc_unixsrc/vncviewer/ + // make this CopyDataFromScreen() or something. + if (!appData.useBGR565) { + scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8; -+ scr = image->data + y * scrWidthInBytes + x * myFormat.bitsPerPixel / 8; ++ scr = im->data + y * scrWidthInBytes + x * myFormat.bitsPerPixel / 8; + buf = (char *) ptmp; + + for (th = 0; th < h; th++) { @@ -11436,7 +14972,7 @@ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrle.c vnc_unixsrc/vncviewer/ + } + } else { + scrWidthInBytes = si.framebufferWidth * 4; -+ scr = image->data + y * scrWidthInBytes + x * 4; ++ scr = im->data + y * scrWidthInBytes + x * 4; + buf = (char *) ptmp; + + for (th = 0; th < h; th++) { |