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/misc/enhanced_tightvnc_viewer/src/patches/tight-vncviewer-full.patch | |
| parent | 73f19d71e0dbdf4f5237e89bd431b971dacbca99 (diff) | |
| download | libtdevnc-8938cda1.tar.gz libtdevnc-8938cda1.zip | |
Sync SSVNC changes: fullscreen fixes, local scaling, -chatonly, iso-8859-1/utf8 etc., etc.
Diffstat (limited to 'x11vnc/misc/enhanced_tightvnc_viewer/src/patches/tight-vncviewer-full.patch')
| -rw-r--r-- | x11vnc/misc/enhanced_tightvnc_viewer/src/patches/tight-vncviewer-full.patch | 5474 | 
1 files changed, 4505 insertions, 969 deletions
| 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++) { | 
