diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/Vncviewer vnc_unixsrc/vncviewer/Vncviewer --- vnc_unixsrc.orig/vncviewer/Vncviewer 2003-02-07 05:30:57.000000000 -0500 +++ vnc_unixsrc/vncviewer/Vncviewer 2008-08-24 16:26:01.000000000 -0400 @@ -1,20 +1,22 @@ ! -! Application defaults file for vncviewer. +! Application defaults file for SSVNC vncviewer. +! +! N.B.: You will need to rename this file to be "Ssvnc" instead of "Vncviewer" ! ! ! The title of the main window. "%s" will be replaced by the desktop name. -! +! -Vncviewer.title: TightVNC: %s +Ssvnc.title: SSVNC: %s Press F8 for Menu ! ! Translations on the main window. ! -Vncviewer.translations:\ +Ssvnc.translations:\ : SelectionToVNC()\n\ : SelectionFromVNC() @@ -23,7 +25,7 @@ ! Uncomment to grab the keyboard in full-screen mode. ! -! Vncviewer.grabKeyboard: True +! Ssvnc.grabKeyboard: True ! @@ -43,6 +45,9 @@ *viewport.useRight: True *viewport*Scrollbar*thumb: None +*viewport.horizontal.height: 6 +*viewport.vertical.width: 6 + ! ! Default translations on desktop window. @@ -50,89 +55,591 @@ *desktop.baseTranslations:\ F8: ShowPopup()\n\ + F9: ToggleFullScreen()\n\ : SendRFBEvent()\n\ : SendRFBEvent()\n\ : SendRFBEvent()\n\ : SendRFBEvent()\n\ : SendRFBEvent() +*viewport.horizontal.translations: #override\n\ + Right: StartScroll(Forward)\n\ + Right: NotifyScroll(FullLength) EndScroll()\n\ + Left: StartScroll(Backward)\n\ + Left: NotifyScroll(FullLength) EndScroll()\n\ + Next: StartScroll(Forward)\n\ + Next: NotifyScroll(FullLength) EndScroll()\n\ + Prior: StartScroll(Backward)\n\ + Prior: NotifyScroll(FullLength) EndScroll()\n\ + z: StartScroll(Forward)\n\ + z: NotifyScroll(FullLength) EndScroll()\n\ + a: StartScroll(Backward)\n\ + a: NotifyScroll(FullLength) EndScroll()\n\ + f: StartScroll(Forward)\n\ + f: NotifyScroll(FullLength) EndScroll()\n\ + b: StartScroll(Backward)\n\ + b: NotifyScroll(FullLength) EndScroll()\n\ + Down: StartScroll(Forward)\n\ + Down: NotifyScroll(FullLength) EndScroll()\n\ + Up: StartScroll(Backward)\n\ + Up: NotifyScroll(FullLength) EndScroll() + +*viewport.vertical.translations: #override\n\ + Down: StartScroll(Forward)\n\ + Down: NotifyScroll(FullLength) EndScroll()\n\ + Up: StartScroll(Backward)\n\ + Up: NotifyScroll(FullLength) EndScroll()\n\ + Next: StartScroll(Forward)\n\ + Next: NotifyScroll(FullLength) EndScroll()\n\ + Prior: StartScroll(Backward)\n\ + Prior: NotifyScroll(FullLength) EndScroll()\n\ + z: StartScroll(Forward)\n\ + z: NotifyScroll(FullLength) EndScroll()\n\ + a: StartScroll(Backward)\n\ + a: NotifyScroll(FullLength) EndScroll()\n\ + f: StartScroll(Forward)\n\ + f: NotifyScroll(FullLength) EndScroll()\n\ + b: StartScroll(Backward)\n\ + b: NotifyScroll(FullLength) EndScroll()\n\ + Right: StartScroll(Forward)\n\ + Right: NotifyScroll(FullLength) EndScroll()\n\ + Left: StartScroll(Backward)\n\ + Left: NotifyScroll(FullLength) EndScroll() + ! ! Dialog boxes ! *serverDialog.dialog.label: VNC server: + *serverDialog.dialog.value: + *serverDialog.dialog.value.translations: #override\n\ - Return: ServerDialogDone() + Return: ServerDialogDone() + +*ycropDialog.dialog.label: Y Crop (max-height in pixels): + +*ycropDialog.dialog.value: + +*ycropDialog.dialog.value.translations: #override\n\ + Return: YCropDialogDone() + +*scbarDialog.dialog.label: Scroll Bars width: + +*scbarDialog.dialog.value: + +*scbarDialog.dialog.value.translations: #override\n\ + Return: ScbarDialogDone() + +*scaleDialog.dialog.label: Integer n for 1/n server scaling: + +*scaleDialog.dialog.value: + +*scaleDialog.dialog.value.translations: #override\n\ + Return: ScaleDialogDone() *passwordDialog.dialog.label: Password: + *passwordDialog.dialog.value: + *passwordDialog.dialog.value.AsciiSink.echo: False + *passwordDialog.dialog.value.translations: #override\n\ - Return: PasswordDialogDone() + Return: PasswordDialogDone() ! ! Popup window appearance ! -*popup.title: TightVNC popup +*popup.title: SSVNC popup + *popup*background: grey -*popup*font: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-* -*popup.buttonForm.Command.borderWidth: 0 -*popup.buttonForm.Toggle.borderWidth: 0 + +*popup*font_old: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-* + +*popup*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-* + +*popup.buttonForm*.Command.borderWidth: 0 + +*popup.buttonForm*.Toggle.borderWidth: 0 + +*scaleN.title: 1/n scale + +*scaleN*background: grey + +*scaleN*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-* + +*scaleN.buttonForm.Command.borderWidth: 0 + +*scaleN.buttonForm.Toggle.borderWidth: 0 + +*quality.title: quality + +*quality*background: grey + +*quality*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-* + +*quality.buttonForm.Command.borderWidth: 0 + +*quality.buttonForm.Toggle.borderWidth: 0 + +*compress.title: compress + +*compress*background: grey + +*compress*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-* + +*compress.buttonForm.Command.borderWidth: 0 + +*compress.buttonForm.Toggle.borderWidth: 0 + ! ! Translations on popup window - send key presses through ! *popup.translations: #override WM_PROTOCOLS: HidePopup() + *popup.buttonForm.translations: #override\n\ - : SendRFBEvent() HidePopup() + : SendRFBEvent() HidePopup() ! ! Popup buttons ! -*popupButtonCount: 8 +*popupButtonCount: 38 + +*popupButtonBreak: 19 *popup*button1.label: Dismiss popup + *popup*button1.translations: #override\n\ - ,: HidePopup() + ,: HidePopup() *popup*button2.label: Quit viewer + *popup*button2.translations: #override\n\ - ,: Quit() + ,: Quit() + +*popup*button3.label: Full screen (also F9) -*popup*button3.label: Full screen *popup*button3.type: toggle + *popup*button3.translations: #override\n\ - : SetFullScreenState()\n\ - ,: toggle() HidePopup() ToggleFullScreen() + : SetFullScreenState()\n\ + ,: toggle() ToggleFullScreen() HidePopup() *popup*button4.label: Clipboard: local -> remote + *popup*button4.translations: #override\n\ - ,: SelectionToVNC(always) HidePopup() + ,: SelectionToVNC(always) HidePopup() *popup*button5.label: Clipboard: local <- remote + *popup*button5.translations: #override\n\ - ,: SelectionFromVNC(always) HidePopup() + ,: SelectionFromVNC(always) HidePopup() *popup*button6.label: Request refresh + *popup*button6.translations: #override\n\ - ,: SendRFBEvent(fbupdate) HidePopup() + ,: SendRFBEvent(fbupdate) HidePopup() *popup*button7.label: Send ctrl-alt-del + *popup*button7.translations: #override\n\ - ,: SendRFBEvent(keydown,Control_L)\ - SendRFBEvent(keydown,Alt_L)\ - SendRFBEvent(key,Delete)\ - SendRFBEvent(keyup,Alt_L)\ - SendRFBEvent(keyup,Control_L)\ - HidePopup() + ,: SendRFBEvent(keydown,Control_L) SendRFBEvent(keydown,Alt_L) SendRFBEvent(key,Delete) SendRFBEvent(keyup,Alt_L) SendRFBEvent(keyup,Control_L) HidePopup() *popup*button8.label: Send F8 + *popup*button8.translations: #override\n\ - ,: SendRFBEvent(key,F8) HidePopup() + ,: SendRFBEvent(key,F8) HidePopup() + +*popup*button9.label: Send F9 + +*popup*button9.translations: #override\n\ + ,: SendRFBEvent(key,F9) HidePopup() + +*popup*button10.label: ViewOnly + +*popup*button10.type: toggle + +*popup*button10.translations: #override\n\ + : SetViewOnlyState()\n\ + ,: toggle() ToggleViewOnly() HidePopup() + +*popup*button11.label: Disable Bell + +*popup*button11.type: toggle + +*popup*button11.translations: #override\n\ + : SetBellState()\n\ + ,: toggle() ToggleBell() HidePopup() + +*popup*button12.label: Cursor Shape + +*popup*button12.type: toggle + +*popup*button12.translations: #override\n\ + : SetCursorShapeState()\n\ + ,: toggle() ToggleCursorShape() HidePopup() + +*popup*button13.label: X11 Cursor + +*popup*button13.type: toggle + +*popup*button13.translations: #override\n\ + : SetX11CursorState()\n\ + ,: toggle() ToggleX11Cursor() HidePopup() + +*popup*button14.label: Cursor Alphablend + +*popup*button14.type: toggle + +*popup*button14.translations: #override\n\ + : SetCursorAlphaState()\n\ + ,: toggle() ToggleCursorAlpha() HidePopup() + +*popup*button15.label: Toggle Tight/ZRLE + +*popup*button15.type: toggle + +*popup*button15.translations: #override\n\ + : SetZRLEState()\n\ + ,: toggle() ToggleTightZRLE() HidePopup() + +*popup*button16.label: Toggle ZRLE/ZYWRLE + +*popup*button16.type: toggle + +*popup*button16.translations: #override\n\ + : SetZYWRLEState()\n\ + ,: toggle() ToggleZRLEZYWRLE() HidePopup() + +*popup*button17.label: Quality Level + +*popup*button17.translations: #override\n\ + ,: HidePopup() ShowQuality() + +*popup*button18.label: Compress Level + +*popup*button18.translations: #override\n\ + ,: HidePopup() ShowCompress() + +*popup*button19.label: Disable JPEG + +*popup*button19.type: toggle + +*popup*button19.translations: #override\n\ + : SetNOJPEGState()\n\ + ,: toggle() ToggleJPEG() HidePopup() + +*popup*button20.label: Full Color + +*popup*button20.type: toggle + +*popup*button20.translations: #override\n\ + : SetFullColorState()\n\ + ,: toggle() ToggleFullColor() HidePopup() + +*popup*button21.label: Grey Scale (16 & 8-bpp) + +*popup*button21.type: toggle + +*popup*button21.translations: #override\n\ + : SetGreyScaleState()\n\ + ,: toggle() ToggleGreyScale() HidePopup() + +*popup*button22.label: 16 bit color (BGR565) + +*popup*button22.type: toggle + +*popup*button22.translations: #override\n\ + : Set16bppState()\n\ + ,: toggle() Toggle16bpp() HidePopup() + +*popup*button23.label: 8 bit color (BGR233) + +*popup*button23.type: toggle + +*popup*button23.translations: #override\n\ + : Set8bppState()\n\ + ,: toggle() Toggle8bpp() HidePopup() + +*popup*button24.label: - 256 colors + +*popup*button24.type: toggle + +*popup*button24.translations: #override\n\ + : Set256ColorsState()\n\ + ,: toggle() Toggle256Colors() HidePopup() + +*popup*button25.label: - 64 colors + +*popup*button25.type: toggle + +*popup*button25.translations: #override\n\ + : Set64ColorsState()\n\ + ,: toggle() Toggle64Colors() HidePopup() + +*popup*button26.label: - 8 colors + +*popup*button26.type: toggle + +*popup*button26.translations: #override\n\ + : Set8ColorsState()\n\ + ,: toggle() Toggle8Colors() HidePopup() + +*popup*button27.label: Set Y Crop (y-max) + +*popup*button27.translations: #override\n\ + ,: HidePopup() SetYCrop() + +*popup*button28.label: Set Scrollbar Width + +*popup*button28.translations: #override\n\ + ,: HidePopup() SetScbar() + +*popup*button29.label: UltraVNC Extensions: + +*popup*button29.translations: #override\n\ + ,: HidePopup() + +*popup*button30.label: - Set 1/n Server Scale + +*popup*button30.translations: #override\n\ + ,: HidePopup() ShowScaleN() + +*popup*button31.label: - Text Chat + +*popup*button31.type: toggle + +*popup*button31.translations: #override\n\ + : SetTextChatState()\n\ + ,: toggle() ToggleTextChat() HidePopup() + +*popup*button32.label: - File Transfer + +*popup*button32.type: toggle + +*popup*button32.translations: #override\n\ + : SetFileXferState()\n\ + ,: toggle() ToggleFileXfer() HidePopup() + +*popup*button33.label: - Single Window + +*popup*button33.type: toggle + +*popup*button33.translations: #override\n\ + : SetSingleWindowState()\n\ + ,: toggle() ToggleSingleWindow() HidePopup() + +*popup*button34.label: - Disable Remote Input + +*popup*button34.type: toggle + +*popup*button34.translations: #override\n\ + : SetServerInputState()\n\ + ,: toggle() ToggleServerInput() HidePopup() + +*popup*button35.label: + +*popup*button36.label: + +*popup*button37.label: + +*popup*button38.label: + +*scaleN*button0.label: Dismiss + +*scaleN*button0.translations: #override\n\ + ,: HideScaleN() + +*scaleN*button1.label: 1/1 + +*scaleN*button1.translations: #override\n\ + : SetScaleNState(1)\n\ + ,: SetScaleN(1) HideScaleN() + +*scaleN*button2.label: 1/2 + +*scaleN*button2.translations: #override\n\ + : SetScaleNState(2)\n\ + ,: SetScaleN(2) HideScaleN() + +*scaleN*button3.label: 1/3 + +*scaleN*button3.translations: #override\n\ + : SetScaleNState(3)\n\ + ,: SetScaleN(3) HideScaleN() + +*scaleN*button4.label: 1/4 + +*scaleN*button4.translations: #override\n\ + : SetScaleNState(4)\n\ + ,: SetScaleN(4) HideScaleN() + +*scaleN*button5.label: 1/5 + +*scaleN*button5.translations: #override\n\ + : SetScaleNState(5)\n\ + ,: SetScaleN(5) HideScaleN() + +*scaleN*button6.label: Other + +*scaleN*button6.translations: #override\n\ + : SetScaleNState(6)\n\ + ,: HideScaleN() DoServerScale() + +*quality*buttonD.label: Dismiss + +*quality*buttonD.translations: #override\n\ + ,: HideQuality() + +*quality*button0.label: 0 + +*quality*button0.type: toggle + +*quality*button0.translations: #override\n\ + : SetQualityState(0)\n\ + ,: SetQuality(0) HideQuality() + +*quality*button1.label: 1 + +*quality*button1.type: toggle + +*quality*button1.translations: #override\n\ + : SetQualityState(1)\n\ + ,: SetQuality(1) HideQuality() + +*quality*button2.label: 2 + +*quality*button2.type: toggle + +*quality*button2.translations: #override\n\ + : SetQualityState(2)\n\ + ,: SetQuality(2) HideQuality() + +*quality*button3.label: 3 + +*quality*button3.type: toggle + +*quality*button3.translations: #override\n\ + : SetQualityState(3)\n\ + ,: SetQuality(3) HideQuality() + +*quality*button4.label: 4 + +*quality*button4.type: toggle + +*quality*button4.translations: #override\n\ + : SetQualityState(4)\n\ + ,: SetQuality(4) HideQuality() + +*quality*button5.label: 5 + +*quality*button5.type: toggle + +*quality*button5.translations: #override\n\ + : SetQualityState(5)\n\ + ,: SetQuality(5) HideQuality() + +*quality*button6.label: 6 + +*quality*button6.type: toggle + +*quality*button6.translations: #override\n\ + : SetQualityState(6)\n\ + ,: SetQuality(6) HideQuality() + +*quality*button7.label: 7 + +*quality*button7.type: toggle + +*quality*button7.translations: #override\n\ + : SetQualityState(7)\n\ + ,: SetQuality(7) HideQuality() + +*quality*button8.label: 8 + +*quality*button8.type: toggle + +*quality*button8.translations: #override\n\ + : SetQualityState(8)\n\ + ,: SetQuality(8) HideQuality() + +*quality*button9.label: 9 + +*quality*button9.type: toggle + +*quality*button9.translations: #override\n\ + : SetQualityState(9)\n\ + ,: SetQuality(9) HideQuality() + +*compress*buttonD.label: Dismiss + +*compress*buttonD.translations: #override\n\ + ,: HideCompress() + +*compress*button0.label: 0 + +*compress*button0.translations: #override\n\ + : SetCompressState(0)\n\ + ,: SetCompress(0) HideCompress() + +*compress*button1.label: 1 + +*compress*button1.translations: #override\n\ + : SetCompressState(1)\n\ + ,: SetCompress(1) HideCompress() + +*compress*button2.label: 2 + +*compress*button2.translations: #override\n\ + : SetCompressState(2)\n\ + ,: SetCompress(2) HideCompress() + +*compress*button3.label: 3 + +*compress*button3.translations: #override\n\ + : SetCompressState(3)\n\ + ,: SetCompress(3) HideCompress() + +*compress*button4.label: 4 + +*compress*button4.translations: #override\n\ + : SetCompressState(4)\n\ + ,: SetCompress(4) HideCompress() + +*compress*button5.label: 5 + +*compress*button5.translations: #override\n\ + : SetCompressState(5)\n\ + ,: SetCompress(5) HideCompress() + +*compress*button6.label: 6 + +*compress*button6.translations: #override\n\ + : SetCompressState(6)\n\ + ,: SetCompress(6) HideCompress() + +*compress*button7.label: 7 + +*compress*button7.translations: #override\n\ + : SetCompressState(7)\n\ + ,: SetCompress(7) HideCompress() + +*compress*button8.label: 8 + +*compress*button8.translations: #override\n\ + : SetCompressState(8)\n\ + ,: SetCompress(8) HideCompress() + +*compress*button9.label: 9 + +*compress*button9.translations: #override\n\ + : SetCompressState(9)\n\ + ,: SetCompress(9) HideCompress() + 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 2009-11-25 00:02:42.000000000 -0500 @@ -31,9 +31,9 @@ char *fallback_resources[] = { - "Vncviewer.title: TightVNC: %s", + "Ssvnc.title: SSVNC: %s - Press F8 for Menu", - "Vncviewer.translations:\ + "Ssvnc.translations:\ : SelectionToVNC()\\n\ : SelectionFromVNC()", @@ -45,8 +45,60 @@ "*viewport.useRight: True", "*viewport*Scrollbar*thumb: None", + "*viewport.horizontal.height: 6 ", + "*viewport.vertical.width: 6 ", + "ssvnc*viewport.horizontal.height: 6 ", + "ssvnc*viewport.vertical.width: 6 ", + + "*viewport.horizontal.translations: #override\\n\ + Right: StartScroll(Forward)\\n\ + Right: NotifyScroll(FullLength) EndScroll()\\n\ + Left: StartScroll(Backward)\\n\ + Left: NotifyScroll(FullLength) EndScroll()\\n\ + Next: StartScroll(Forward)\\n\ + Next: NotifyScroll(FullLength) EndScroll()\\n\ + Prior: StartScroll(Backward)\\n\ + Prior: NotifyScroll(FullLength) EndScroll()\\n\ + z: StartScroll(Forward)\\n\ + z: NotifyScroll(FullLength) EndScroll()\\n\ + a: StartScroll(Backward)\\n\ + a: NotifyScroll(FullLength) EndScroll()\\n\ + f: StartScroll(Forward)\\n\ + f: NotifyScroll(FullLength) EndScroll()\\n\ + b: StartScroll(Backward)\\n\ + b: NotifyScroll(FullLength) EndScroll()\\n\ + Down: StartScroll(Forward)\\n\ + Down: NotifyScroll(FullLength) EndScroll()\\n\ + Up: StartScroll(Backward)\\n\ + Up: NotifyScroll(FullLength) EndScroll()", + + "*viewport.vertical.translations: #override\\n\ + Down: StartScroll(Forward)\\n\ + Down: NotifyScroll(FullLength) EndScroll()\\n\ + Up: StartScroll(Backward)\\n\ + Up: NotifyScroll(FullLength) EndScroll()\\n\ + Next: StartScroll(Forward)\\n\ + Next: NotifyScroll(FullLength) EndScroll()\\n\ + Prior: StartScroll(Backward)\\n\ + Prior: NotifyScroll(FullLength) EndScroll()\\n\ + z: StartScroll(Forward)\\n\ + z: NotifyScroll(FullLength) EndScroll()\\n\ + a: StartScroll(Backward)\\n\ + a: NotifyScroll(FullLength) EndScroll()\\n\ + f: StartScroll(Forward)\\n\ + f: NotifyScroll(FullLength) EndScroll()\\n\ + b: StartScroll(Backward)\\n\ + b: NotifyScroll(FullLength) EndScroll()\\n\ + Right: StartScroll(Forward)\\n\ + Right: NotifyScroll(FullLength) EndScroll()\\n\ + Left: StartScroll(Backward)\\n\ + Left: NotifyScroll(FullLength) EndScroll()", + "*desktop.baseTranslations:\ - F8: ShowPopup()\\n\ + F8: ShowPopup()\\n\ + F8: Noop()\\n\ + F9: ToggleFullScreen()\\n\ + F9: Noop()\\n\ : SendRFBEvent()\\n\ : SendRFBEvent()\\n\ : SendRFBEvent()\\n\ @@ -55,26 +107,137 @@ "*serverDialog.dialog.label: VNC server:", "*serverDialog.dialog.value:", + "*serverDialog.dialog.value.width: 150", "*serverDialog.dialog.value.translations: #override\\n\ Return: ServerDialogDone()", - "*passwordDialog.dialog.label: Password:", + "*userDialog.dialog.label: SSVNC: Enter Username", + "*userDialog.dialog.value:", + "*userDialog.dialog.value.width: 150", + "*userDialog.dialog.value.translations: #override\\n\ + Return: UserDialogDone()", + + "*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\ + Return: ScaleDialogDone()", + + "*escapeDialog.dialog.label: Escape Keys: Enter a comma separated list of modifier keys to be the\\n" + "'escape sequence'. When these keys are held down, the next keystroke is\\n" + "interpreted locally to invoke a special action instead of being sent to\\n" + "the remote VNC server. In other words, a set of 'Hot Keys'.\\n" + "\\n" + "To enable or disable this, click on 'Escape Keys: Toggle' in the Popup.\\n" + "\\n" + "Here is the list of hot-key mappings to special actions:\\n" + "\\n" + " r: refresh desktop b: toggle bell c: toggle full-color\\n" + " f: file transfer x: x11cursor z: toggle Tight/ZRLE\\n" + " l: full screen g: graball e: escape keys dialog\\n" + " s: scale dialog +: scale up (=) -: scale down (_)\\n" + " t: text chat a: alphablend cursor\\n" + " V: toggle viewonly Q: quit viewer 1 2 3 4 5 6: UltraVNC scale 1/n\\n" + "\\n" + " Arrow keys: pan the viewport about 10% for each keypress.\\n" + " PageUp / PageDown: pan the viewport by a screenful vertically.\\n" + " Home / End: pan the viewport by a screenful horizontally.\\n" + " KeyPad Arrow keys: pan the viewport by 1 pixel for each keypress.\\n" + " Dragging the Mouse with Button1 pressed also pans the viewport.\\n" + " Clicking Mouse Button3 brings up the Popup Menu.\\n" + "\\n" + "The above mappings are *always* active in ViewOnly mode, unless you set the\\n" + "Escape Keys value to 'never'.\\n" + "\\n" + "x11vnc -appshare hot-keys: x11vnc has a simple application sharing mode\\n" + "that enables the viewer-side to move, resize, or raise the remote toplevel\\n" + "windows. To enable it, hold down Shift + the Escape Keys and press these:\\n" + "\\n" + " Arrow keys: move the remote window around in its desktop.\\n" + " PageUp/PageDn/Home/End: resize the remote window.\\n" + " +/- raise or lower the remote window.\\n" + " M or Button1 move win to local position; D or Button3: delete remote win.\\n" + "\\n" + "If the Escape Keys value below is set to 'default' then a fixed list of\\n" + "modifier keys is used. For Unix it is: Alt_L,Super_L and for MacOSX it is\\n" + "Control_L,Meta_L. Note: the Super_L key usually has a Windows(TM) Flag.\\n" + "Also note the _L and _R mean the key is on the LEFT or RIGHT side of keyboard.\\n" + "\\n" + "On Unix the default is Alt and Windows keys on Left side of keyboard.\\n" + "On MacOSX the default is Control and Command keys on Left side of keyboard.\\n" + "\\n" + "Example: Press and hold the Alt and Windows keys on the LEFT side of the\\n" + "keyboard and then press 'c' to toggle the full-color state. Or press 't'\\n" + "to toggle the ultravnc Text Chat window, etc.\\n" + "\\n" + "To use something besides the default, supply a comma separated list (or a\\n" + "single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L\\n" + "Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch.\\n" + "\\n" + "Current Escape Keys Value:", + "*escapeDialog.dialog.value:", + "*escapeDialog.dialog.value.width: 280", + "*escapeDialog.dialog.value.translations: #override\\n\ + Return: EscapeDialogDone()", + + "*ycropDialog.dialog.label: Y Crop (max-height in pixels):", + "*ycropDialog.dialog.value:", + "*ycropDialog.dialog.value.translations: #override\\n\ + Return: YCropDialogDone()", + + "*scbarDialog.dialog.label: Scroll Bars width:", + "*scbarDialog.dialog.value:", + "*scbarDialog.dialog.value.translations: #override\\n\ + Return: ScbarDialogDone()", + + "*scaleNDialog.dialog.label: Integer n for 1/n server scaling:", + "*scaleNDialog.dialog.value:", + "*scaleNDialog.dialog.value.translations: #override\\n\ + Return: ScaleNDialogDone()", + + "*passwordDialog.dialog.label: SSVNC: Enter Password", "*passwordDialog.dialog.value:", + "*passwordDialog.dialog.value.width: 150", "*passwordDialog.dialog.value.AsciiSink.echo: False", "*passwordDialog.dialog.value.translations: #override\\n\ Return: PasswordDialogDone()", - "*popup.title: TightVNC popup", + "*popup.title: SSVNC popup", "*popup*background: grey", - "*popup*font: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-*", - "*popup.buttonForm.Command.borderWidth: 0", - "*popup.buttonForm.Toggle.borderWidth: 0", + "*popup*font_old: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-*", + "*popup*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", + "*popup.buttonForm*.Command.borderWidth: 0", + "*popup.buttonForm*.Toggle.borderWidth: 0", + + "*scaleN.title: 1/n scale", + "*scaleN*background: grey", + "*scaleN*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", + "*scaleN.buttonForm.Command.borderWidth: 0", + "*scaleN.buttonForm.Toggle.borderWidth: 0", + + "*turboVNC.title: TurboVNC", + "*turboVNC*background: grey", + "*turboVNC*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", + "*turboVNC.buttonForm.Command.borderWidth: 0", + "*turboVNC.buttonForm.Toggle.borderWidth: 0", + + "*quality.title: quality", + "*quality*background: grey", + "*quality*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", + "*quality.buttonForm.Command.borderWidth: 0", + "*quality.buttonForm.Toggle.borderWidth: 0", + + "*compress.title: compress", + "*compress*background: grey", + "*compress*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", + "*compress.buttonForm.Command.borderWidth: 0", + "*compress.buttonForm.Toggle.borderWidth: 0", "*popup.translations: #override WM_PROTOCOLS: HidePopup()", "*popup.buttonForm.translations: #override\\n\ : SendRFBEvent() HidePopup()", - "*popupButtonCount: 8", + "*popupButtonCount: 44", + "*popupButtonBreak: 22", "*popup*button1.label: Dismiss popup", "*popup*button1.translations: #override\\n\ @@ -84,7 +247,7 @@ "*popup*button2.translations: #override\\n\ ,: Quit()", - "*popup*button3.label: Full screen", + "*popup*button3.label: Full screen (also F9)", "*popup*button3.type: toggle", "*popup*button3.translations: #override\\n\ : SetFullScreenState()\\n\ @@ -105,16 +268,426 @@ "*popup*button7.label: Send ctrl-alt-del", "*popup*button7.translations: #override\\n\ ,: SendRFBEvent(keydown,Control_L)\ - SendRFBEvent(keydown,Alt_L)\ - SendRFBEvent(key,Delete)\ - SendRFBEvent(keyup,Alt_L)\ - SendRFBEvent(keyup,Control_L)\ - HidePopup()", + SendRFBEvent(keydown,Alt_L)\ + SendRFBEvent(key,Delete)\ + SendRFBEvent(keyup,Alt_L)\ + SendRFBEvent(keyup,Control_L)\ + HidePopup()", "*popup*button8.label: Send F8", "*popup*button8.translations: #override\\n\ ,: SendRFBEvent(key,F8) HidePopup()", + "*popup*button9.label: Send F9", + "*popup*button9.translations: #override\\n\ + ,: SendRFBEvent(key,F9) HidePopup()", + + "*popup*button10.label: ViewOnly", + "*popup*button10.type: toggle", + "*popup*button10.translations: #override\\n\ + : SetViewOnlyState()\\n\ + ,: toggle() ToggleViewOnly() HidePopup()", + + "*popup*button11.label: Disable Bell", + "*popup*button11.type: toggle", + "*popup*button11.translations: #override\\n\ + : SetBellState()\\n\ + ,: toggle() ToggleBell() HidePopup()", + + "*popup*button12.label: Cursor Shape", + "*popup*button12.type: toggle", + "*popup*button12.translations: #override\\n\ + : SetCursorShapeState()\\n\ + ,: toggle() ToggleCursorShape() HidePopup()", + + "*popup*button13.label: X11 Cursor", + "*popup*button13.type: toggle", + "*popup*button13.translations: #override\\n\ + : SetX11CursorState()\\n\ + ,: toggle() ToggleX11Cursor() HidePopup()", + + "*popup*button14.label: Cursor Alphablend", + "*popup*button14.type: toggle", + "*popup*button14.translations: #override\\n\ + : SetCursorAlphaState()\\n\ + ,: toggle() ToggleCursorAlpha() HidePopup()", + + "*popup*button15.label: Toggle Tight/Hextile", + "*popup*button15.type: toggle", + "*popup*button15.translations: #override\\n\ + : SetHextileState()\\n\ + ,: toggle() ToggleTightHextile() HidePopup()", + + "*popup*button16.label: Toggle Tight/ZRLE", + "*popup*button16.type: toggle", + "*popup*button16.translations: #override\\n\ + : SetZRLEState()\\n\ + ,: toggle() ToggleTightZRLE() HidePopup()", + + "*popup*button17.label: Toggle ZRLE/ZYWRLE", + "*popup*button17.type: toggle", + "*popup*button17.translations: #override\\n\ + : SetZYWRLEState()\\n\ + ,: toggle() ToggleZRLEZYWRLE() HidePopup()", + + "*popup*button18.label: Quality Level", + "*popup*button18.translations: #override\\n\ + ,: HidePopup() ShowQuality()", + + "*popup*button19.label: Compress Level", + "*popup*button19.translations: #override\\n\ + ,: HidePopup() ShowCompress()", + + "*popup*button20.label: Disable JPEG", + "*popup*button20.type: toggle", + "*popup*button20.translations: #override\\n\ + : SetNOJPEGState()\\n\ + ,: toggle() ToggleJPEG() HidePopup()", + + "*popup*button21.label: TurboVNC Settings", + "*popup*button21.translations: #override\\n\ + ,: HidePopup() ShowTurboVNC()", + + "*popup*button22.label: Pipeline Updates", + "*popup*button22.type: toggle", + "*popup*button22.translations: #override\\n\ + : SetPipelineUpdates()\\n\ + ,: toggle() TogglePipelineUpdates() HidePopup()", + + "*popup*button23.label: Full Color", + "*popup*button23.type: toggle", + "*popup*button23.translations: #override\\n\ + : SetFullColorState()\\n\ + ,: toggle() ToggleFullColor() HidePopup()", + + "*popup*button24.label: Grey Scale (16 & 8-bpp)", + "*popup*button24.type: toggle", + "*popup*button24.translations: #override\\n\ + : SetGreyScaleState()\\n\ + ,: toggle() ToggleGreyScale() HidePopup()", + + "*popup*button25.label: 16 bit color (BGR565)", + "*popup*button25.type: toggle", + "*popup*button25.translations: #override\\n\ + : Set16bppState()\\n\ + ,: toggle() Toggle16bpp() HidePopup()", + + "*popup*button26.label: 8 bit color (BGR233)", + "*popup*button26.type: toggle", + "*popup*button26.translations: #override\\n\ + : Set8bppState()\\n\ + ,: toggle() Toggle8bpp() HidePopup()", + + "*popup*button27.label: - 256 colors", + "*popup*button27.type: toggle", + "*popup*button27.translations: #override\\n\ + : Set256ColorsState()\\n\ + ,: toggle() Toggle256Colors() HidePopup()", + + "*popup*button28.label: - 64 colors", + "*popup*button28.type: toggle", + "*popup*button28.translations: #override\\n\ + : Set64ColorsState()\\n\ + ,: toggle() Toggle64Colors() HidePopup()", + + "*popup*button29.label: - 8 colors", + "*popup*button29.type: toggle", + "*popup*button29.translations: #override\\n\ + : Set8ColorsState()\\n\ + ,: toggle() Toggle8Colors() HidePopup()", + + "*popup*button30.label: Scale Viewer", + "*popup*button30.translations: #override\\n\ + ,: HidePopup() SetScale()", + + "*popup*button31.label: Escape Keys: Toggle", + "*popup*button31.type: toggle", + "*popup*button31.translations: #override\\n\ + : SetEscapeKeysState()\\n\ + , : toggle() ToggleEscapeActive() HidePopup()", + + "*popup*button32.label: Escape Keys: Help+Set", + "*popup*button32.translations: #override\\n\ + , : HidePopup() SetEscapeKeys()", + + "*popup*button33.label: Set Y Crop (y-max)", + "*popup*button33.translations: #override\\n\ + ,: HidePopup() SetYCrop()", + + "*popup*button34.label: Set Scrollbar Width", + "*popup*button34.translations: #override\\n\ + ,: HidePopup() SetScbar()", + + "*popup*button35.label: XGrabServer", + "*popup*button35.type: toggle", + "*popup*button35.translations: #override\\n\ + : SetXGrabState()\\n\ + ,: toggle() ToggleXGrab() HidePopup()", + + "*popup*button36.label: UltraVNC Extensions:", + "*popup*button36.translations: #override\\n\ + ,: HidePopup()", + + "*popup*button37.label: - Set 1/n Server Scale", + "*popup*button37.translations: #override\\n\ + ,: HidePopup() ShowScaleN()", + + "*popup*button38.label: - Text Chat", + "*popup*button38.type: toggle", + "*popup*button38.translations: #override\\n\ + : SetTextChatState()\\n\ + ,: toggle() ToggleTextChat() HidePopup()", + + "*popup*button39.label: - File Transfer", + "*popup*button39.type: toggle", + "*popup*button39.translations: #override\\n\ + : SetFileXferState()\\n\ + ,: toggle() ToggleFileXfer() HidePopup()", + + "*popup*button40.label: - Single Window", + "*popup*button40.type: toggle", + "*popup*button40.translations: #override\\n\ + : SetSingleWindowState()\\n\ + ,: toggle() ToggleSingleWindow() HidePopup()", + + "*popup*button41.label: - Disable Remote Input", + "*popup*button41.type: toggle", + "*popup*button41.translations: #override\\n\ + : SetServerInputState()\\n\ + ,: toggle() ToggleServerInput() HidePopup()", + + "*popup*button42.label: Send Clipboard not Primary", + "*popup*button42.type: toggle", + "*popup*button42.translations: #override\\n\ + : SetSendClipboard()\\n\ + ,: toggle() ToggleSendClipboard() HidePopup()", + + "*popup*button43.label: Send Selection Every time", + "*popup*button43.type: toggle", + "*popup*button43.translations: #override\\n\ + : SetSendAlways()\\n\ + ,: toggle() ToggleSendAlways() HidePopup()", + + "*popup*button44.label: ", + + "*turboVNC*button0.label: Dismiss", + "*turboVNC*button0.translations: #override\\n\ + ,: HideTurboVNC()", + + "*turboVNC*button1.label: High Quality (LAN)", + "*turboVNC*button1.translations: #override\\n\ + ,: SetTurboVNC(1)", + + "*turboVNC*button2.label: Medium Quality", + "*turboVNC*button2.translations: #override\\n\ + ,: SetTurboVNC(2)", + + "*turboVNC*button3.label: Low Quality (WAN)", + "*turboVNC*button3.translations: #override\\n\ + ,: SetTurboVNC(3)", + + "*turboVNC*button4.label: Lossless (Gigabit)", + "*turboVNC*button4.translations: #override\\n\ + ,: SetTurboVNC(4)", + + "*turboVNC*button5.label: Lossless Zlib (WAN)", + "*turboVNC*button5.translations: #override\\n\ + ,: SetTurboVNC(5)", + + "*turboVNC*button6.label: Subsampling:", + + "*turboVNC*button7.label: - None", + "*turboVNC*button7.translations: #override\\n\ + ,: SetTurboVNC(6)", + + "*turboVNC*button8.label: - 2X", + "*turboVNC*button8.translations: #override\\n\ + ,: SetTurboVNC(7)", + + "*turboVNC*button9.label: - 4X", + "*turboVNC*button9.translations: #override\\n\ + ,: SetTurboVNC(8)", + + "*turboVNC*button10.label: - Gray", + "*turboVNC*button10.translations: #override\\n\ + ,: SetTurboVNC(9)", + + "*turboVNC*button11.label: Lossless Refresh", + "*turboVNC*button11.translations: #override\\n\ + ,: SetTurboVNC(10)", + + "*turboVNC*button12.label: Lossy Refresh", + "*turboVNC*button12.translations: #override\\n\ + ,: SendRFBEvent(fbupdate)", + + "*turboVNC*buttonNone.label: Not Compiled with\\nTurboVNC Support.", + "*turboVNC*buttonNone.translations: #override\\n\ + ,: HideTurboVNC()", + + "*qualLabel.label: JPEG Image Quality:", + "*qualBar.length: 100", + "*qualBar.width: 130", + "*qualBar.orientation: horizontal", + "*qualBar.translations: #override\\n\ + : StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ + : MoveThumb() NotifyThumb()\\n\ + : StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ + : MoveThumb() NotifyThumb()", + + "*qualText.label: 000", + + "*scaleN*button0.label: Dismiss", + "*scaleN*button0.translations: #override\\n\ + ,: HideScaleN()", + + "*scaleN*button1.label: 1/1", + "*scaleN*button1.translations: #override\\n\ + : SetScaleNState(1)\\n\ + ,: SetScaleN(1) HideScaleN()", + + "*scaleN*button2.label: 1/2", + "*scaleN*button2.translations: #override\\n\ + : SetScaleNState(2)\\n\ + ,: SetScaleN(2) HideScaleN()", + + "*scaleN*button3.label: 1/3", + "*scaleN*button3.translations: #override\\n\ + : SetScaleNState(3)\\n\ + ,: SetScaleN(3) HideScaleN()", + + "*scaleN*button4.label: 1/4", + "*scaleN*button4.translations: #override\\n\ + : SetScaleNState(4)\\n\ + ,: SetScaleN(4) HideScaleN()", + + "*scaleN*button5.label: 1/5", + "*scaleN*button5.translations: #override\\n\ + : SetScaleNState(5)\\n\ + ,: SetScaleN(5) HideScaleN()", + + "*scaleN*button6.label: Other", + "*scaleN*button6.translations: #override\\n\ + : SetScaleNState(6)\\n\ + ,: HideScaleN() DoServerScale()", + + "*quality*buttonD.label: Dismiss", + "*quality*buttonD.translations: #override\\n\ + ,: HideQuality()", + + "*quality*button0.label: 0", + "*quality*button0.type: toggle", + "*quality*button0.translations: #override\\n\ + : SetQualityState(0)\\n\ + ,: SetQuality(0) HideQuality()", + + "*quality*button1.label: 1", + "*quality*button1.type: toggle", + "*quality*button1.translations: #override\\n\ + : SetQualityState(1)\\n\ + ,: SetQuality(1) HideQuality()", + + "*quality*button2.label: 2", + "*quality*button2.type: toggle", + "*quality*button2.translations: #override\\n\ + : SetQualityState(2)\\n\ + ,: SetQuality(2) HideQuality()", + + "*quality*button3.label: 3", + "*quality*button3.type: toggle", + "*quality*button3.translations: #override\\n\ + : SetQualityState(3)\\n\ + ,: SetQuality(3) HideQuality()", + + "*quality*button4.label: 4", + "*quality*button4.type: toggle", + "*quality*button4.translations: #override\\n\ + : SetQualityState(4)\\n\ + ,: SetQuality(4) HideQuality()", + + "*quality*button5.label: 5", + "*quality*button5.type: toggle", + "*quality*button5.translations: #override\\n\ + : SetQualityState(5)\\n\ + ,: SetQuality(5) HideQuality()", + + "*quality*button6.label: 6", + "*quality*button6.type: toggle", + "*quality*button6.translations: #override\\n\ + : SetQualityState(6)\\n\ + ,: SetQuality(6) HideQuality()", + + "*quality*button7.label: 7", + "*quality*button7.type: toggle", + "*quality*button7.translations: #override\\n\ + : SetQualityState(7)\\n\ + ,: SetQuality(7) HideQuality()", + + "*quality*button8.label: 8", + "*quality*button8.type: toggle", + "*quality*button8.translations: #override\\n\ + : SetQualityState(8)\\n\ + ,: SetQuality(8) HideQuality()", + + "*quality*button9.label: 9", + "*quality*button9.type: toggle", + "*quality*button9.translations: #override\\n\ + : SetQualityState(9)\\n\ + ,: SetQuality(9) HideQuality()", + + "*compress*buttonD.label: Dismiss", + "*compress*buttonD.translations: #override\\n\ + ,: HideCompress()", + + "*compress*button0.label: 0", + "*compress*button0.translations: #override\\n\ + : SetCompressState(0)\\n\ + ,: SetCompress(0) HideCompress()", + + "*compress*button1.label: 1", + "*compress*button1.translations: #override\\n\ + : SetCompressState(1)\\n\ + ,: SetCompress(1) HideCompress()", + + "*compress*button2.label: 2", + "*compress*button2.translations: #override\\n\ + : SetCompressState(2)\\n\ + ,: SetCompress(2) HideCompress()", + + "*compress*button3.label: 3", + "*compress*button3.translations: #override\\n\ + : SetCompressState(3)\\n\ + ,: SetCompress(3) HideCompress()", + + "*compress*button4.label: 4", + "*compress*button4.translations: #override\\n\ + : SetCompressState(4)\\n\ + ,: SetCompress(4) HideCompress()", + + "*compress*button5.label: 5", + "*compress*button5.translations: #override\\n\ + : SetCompressState(5)\\n\ + ,: SetCompress(5) HideCompress()", + + "*compress*button6.label: 6", + "*compress*button6.translations: #override\\n\ + : SetCompressState(6)\\n\ + ,: SetCompress(6) HideCompress()", + + "*compress*button7.label: 7", + "*compress*button7.translations: #override\\n\ + : SetCompressState(7)\\n\ + ,: SetCompress(7) HideCompress()", + + "*compress*button8.label: 8", + "*compress*button8.translations: #override\\n\ + : SetCompressState(8)\\n\ + ,: SetCompress(8) HideCompress()", + + "*compress*button9.label: 9", + "*compress*button9.translations: #override\\n\ + : SetCompressState(9)\\n\ + ,: SetCompress(9) HideCompress()", + NULL }; @@ -124,7 +697,7 @@ * from a dialog box. */ -char vncServerHost[256]; +char vncServerHost[1024]; int vncServerPort = 0; @@ -135,6 +708,7 @@ */ AppData appData; +AppData appDataNew; static XtResource appDataResourceList[] = { {"shareDesktop", "ShareDesktop", XtRBool, sizeof(Bool), @@ -155,14 +729,44 @@ {"userLogin", "UserLogin", XtRString, sizeof(String), XtOffsetOf(AppData, userLogin), XtRImmediate, (XtPointer) 0}, + {"unixPW", "UnixPW", XtRString, sizeof(String), + XtOffsetOf(AppData, unixPW), XtRImmediate, (XtPointer) 0}, + + {"msLogon", "MSLogon", XtRString, sizeof(String), + XtOffsetOf(AppData, msLogon), XtRImmediate, (XtPointer) 0}, + + {"repeaterUltra", "RepeaterUltra", XtRString, sizeof(String), + XtOffsetOf(AppData, repeaterUltra), XtRImmediate, (XtPointer) 0}, + + {"ultraDSM", "UltraDSM", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, ultraDSM), XtRImmediate, (XtPointer) False}, + + {"acceptPopup", "AcceptPopup", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, acceptPopup), XtRImmediate, (XtPointer) False}, + + {"rfbVersion", "RfbVersion", XtRString, sizeof(String), + XtOffsetOf(AppData, rfbVersion), XtRImmediate, (XtPointer) 0}, + {"passwordDialog", "PasswordDialog", XtRBool, sizeof(Bool), XtOffsetOf(AppData, passwordDialog), XtRImmediate, (XtPointer) False}, {"encodings", "Encodings", XtRString, sizeof(String), XtOffsetOf(AppData, encodingsString), XtRImmediate, (XtPointer) 0}, - {"useBGR233", "UseBGR233", XtRBool, sizeof(Bool), - XtOffsetOf(AppData, useBGR233), XtRImmediate, (XtPointer) False}, + {"useBGR233", "UseBGR233", XtRInt, sizeof(int), + XtOffsetOf(AppData, useBGR233), XtRImmediate, (XtPointer) 0}, + + {"useBGR565", "UseBGR565", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, useBGR565), XtRImmediate, (XtPointer) False}, + + {"useGreyScale", "UseGreyScale", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, useGreyScale), XtRImmediate, (XtPointer) False}, + + {"yCrop", "yCrop", XtRInt, sizeof(int), + XtOffsetOf(AppData, yCrop), XtRImmediate, (XtPointer) 0}, + + {"sbWidth", "sbWidth", XtRInt, sizeof(int), + XtOffsetOf(AppData, sbWidth), XtRImmediate, (XtPointer) 2}, {"nColours", "NColours", XtRInt, sizeof(int), XtOffsetOf(AppData, nColours), XtRImmediate, (XtPointer) 256}, @@ -179,9 +783,12 @@ {"requestedDepth", "RequestedDepth", XtRInt, sizeof(int), XtOffsetOf(AppData, requestedDepth), XtRImmediate, (XtPointer) 0}, - {"useSharedMemory", "UseSharedMemory", XtRBool, sizeof(Bool), + {"useShm", "UseShm", XtRBool, sizeof(Bool), XtOffsetOf(AppData, useShm), XtRImmediate, (XtPointer) True}, + {"termChat", "TermChat", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, termChat), XtRImmediate, (XtPointer) False}, + {"wmDecorationWidth", "WmDecorationWidth", XtRInt, sizeof(int), XtOffsetOf(AppData, wmDecorationWidth), XtRImmediate, (XtPointer) 4}, @@ -191,6 +798,9 @@ {"popupButtonCount", "PopupButtonCount", XtRInt, sizeof(int), XtOffsetOf(AppData, popupButtonCount), XtRImmediate, (XtPointer) 0}, + {"popupButtonBreak", "PopupButtonBreak", XtRInt, sizeof(int), + XtOffsetOf(AppData, popupButtonBreak), XtRImmediate, (XtPointer) 0}, + {"debug", "Debug", XtRBool, sizeof(Bool), XtOffsetOf(AppData, debug), XtRImmediate, (XtPointer) False}, @@ -206,11 +816,13 @@ {"bumpScrollPixels", "BumpScrollPixels", XtRInt, sizeof(int), XtOffsetOf(AppData, bumpScrollPixels), XtRImmediate, (XtPointer) 20}, + /* hardwired compress -1 vs . 7 */ {"compressLevel", "CompressionLevel", XtRInt, sizeof(int), XtOffsetOf(AppData, compressLevel), XtRImmediate, (XtPointer) -1}, + /* hardwired quality was 6 */ {"qualityLevel", "QualityLevel", XtRInt, sizeof(int), - XtOffsetOf(AppData, qualityLevel), XtRImmediate, (XtPointer) 6}, + XtOffsetOf(AppData, qualityLevel), XtRImmediate, (XtPointer) -1}, {"enableJPEG", "EnableJPEG", XtRBool, sizeof(Bool), XtOffsetOf(AppData, enableJPEG), XtRImmediate, (XtPointer) True}, @@ -218,14 +830,91 @@ {"useRemoteCursor", "UseRemoteCursor", XtRBool, sizeof(Bool), XtOffsetOf(AppData, useRemoteCursor), XtRImmediate, (XtPointer) True}, + {"useCursorAlpha", "UseCursorAlpha", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, useCursorAlpha), XtRImmediate, (XtPointer) False}, + + {"useRawLocal", "UseRawLocal", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, useRawLocal), XtRImmediate, (XtPointer) False}, + + {"notty", "NoTty", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, notty), XtRImmediate, (XtPointer) False}, + {"useX11Cursor", "UseX11Cursor", XtRBool, sizeof(Bool), XtOffsetOf(AppData, useX11Cursor), XtRImmediate, (XtPointer) False}, + {"useBell", "UseBell", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, useBell), XtRImmediate, (XtPointer) True}, + {"grabKeyboard", "GrabKeyboard", XtRBool, sizeof(Bool), - XtOffsetOf(AppData, grabKeyboard), XtRImmediate, (XtPointer) False}, + XtOffsetOf(AppData, grabKeyboard), XtRImmediate, (XtPointer) True}, {"autoPass", "AutoPass", XtRBool, sizeof(Bool), - XtOffsetOf(AppData, autoPass), XtRImmediate, (XtPointer) False} + XtOffsetOf(AppData, autoPass), XtRImmediate, (XtPointer) False}, + + {"grabAll", "GrabAll", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, grabAll), XtRImmediate, (XtPointer) False}, + + {"useXserverBackingStore", "UseXserverBackingStore", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, useXserverBackingStore), XtRImmediate, (XtPointer) False}, + + {"overrideRedir", "OverrideRedir", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, overrideRedir), XtRImmediate, (XtPointer) True}, + + {"serverInput", "ServerInput", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, serverInput), XtRImmediate, (XtPointer) True}, + + {"singleWindow", "SingleWindow", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, singleWindow), XtRImmediate, (XtPointer) False}, + + {"serverScale", "ServerScale", XtRInt, sizeof(int), + XtOffsetOf(AppData, serverScale), XtRImmediate, (XtPointer) 1}, + + {"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}, + + {"scale", "Scale", XtRString, sizeof(String), + XtOffsetOf(AppData, scale), XtRImmediate, (XtPointer) 0}, + + {"pipelineUpdates", "PipelineUpdates", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, pipelineUpdates), XtRImmediate, (XtPointer) +#ifdef TURBOVNC + True}, +#else +#if 0 + False}, +#else + True}, +#endif +#endif + + {"sendClipboard", "SendClipboard", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, sendClipboard), XtRImmediate, (XtPointer) False}, + + {"sendAlways", "SendAlways", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, sendAlways), XtRImmediate, (XtPointer) False}, + + {"recvText", "RecvText", XtRString, sizeof(String), + XtOffsetOf(AppData, recvText), XtRImmediate, (XtPointer) 0}, + + {"appShare", "AppShare", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, appShare), XtRImmediate, (XtPointer) False}, + + {"escapeKeys", "EscapeKeys", XtRString, sizeof(String), + XtOffsetOf(AppData, escapeKeys), XtRImmediate, (XtPointer) 0}, + + {"escapeActive", "EscapeActive", XtRBool, sizeof(Bool), + XtOffsetOf(AppData, escapeActive), XtRImmediate, (XtPointer) False} + + /* check commas */ }; @@ -242,8 +931,29 @@ {"-noraiseonbeep", "*raiseOnBeep", XrmoptionNoArg, "False"}, {"-passwd", "*passwordFile", XrmoptionSepArg, 0}, {"-user", "*userLogin", XrmoptionSepArg, 0}, + {"-unixpw", "*unixPW", XrmoptionSepArg, 0}, + {"-mslogon", "*msLogon", XrmoptionSepArg, 0}, + {"-repeater", "*repeaterUltra", XrmoptionSepArg, 0}, + {"-ultradsm", "*ultraDSM", XrmoptionNoArg, "True"}, + {"-acceptpopup", "*acceptPopup", XrmoptionNoArg, "True"}, + {"-acceptpopupsc", "*acceptPopup", XrmoptionNoArg, "True"}, + {"-rfbversion", "*rfbVersion", XrmoptionSepArg, 0}, {"-encodings", "*encodings", XrmoptionSepArg, 0}, - {"-bgr233", "*useBGR233", XrmoptionNoArg, "True"}, + {"-bgr233", "*useBGR233", XrmoptionNoArg, "256"}, + {"-use64", "*useBGR233", XrmoptionNoArg, "64"}, + {"-bgr222", "*useBGR233", XrmoptionNoArg, "64"}, + {"-use8", "*useBGR233", XrmoptionNoArg, "8"}, + {"-bgr111", "*useBGR233", XrmoptionNoArg, "8"}, + {"-16bpp", "*useBGR565", XrmoptionNoArg, "True"}, + {"-bgr565", "*useBGR565", XrmoptionNoArg, "True"}, + {"-grey", "*useGreyScale", XrmoptionNoArg, "True"}, + {"-gray", "*useGreyScale", XrmoptionNoArg, "True"}, + {"-sbwidth", "*sbwidth", XrmoptionSepArg, 0}, + {"-env", "*envDummy", XrmoptionSepArg, 0}, + {"-ycrop", "*yCrop", XrmoptionSepArg, 0}, + {"-rawlocal", "*useRawLocal", XrmoptionNoArg, "True"}, + {"-notty", "*notty", XrmoptionNoArg, "True"}, + {"-alpha", "*useCursorAlpha", XrmoptionNoArg, "True"}, {"-owncmap", "*forceOwnCmap", XrmoptionNoArg, "True"}, {"-truecolor", "*forceTrueColour", XrmoptionNoArg, "True"}, {"-truecolour", "*forceTrueColour", XrmoptionNoArg, "True"}, @@ -253,8 +963,28 @@ {"-nojpeg", "*enableJPEG", XrmoptionNoArg, "False"}, {"-nocursorshape", "*useRemoteCursor", XrmoptionNoArg, "False"}, {"-x11cursor", "*useX11Cursor", XrmoptionNoArg, "True"}, - {"-autopass", "*autoPass", XrmoptionNoArg, "True"} - + {"-nobell", "*useBell", XrmoptionNoArg, "False"}, + {"-autopass", "*autoPass", XrmoptionNoArg, "True"}, + {"-graball", "*grabAll", XrmoptionNoArg, "True"}, + {"-grabkbd", "*grabKeyboard", XrmoptionNoArg, "True"}, + {"-nograbkbd", "*grabKeyboard", XrmoptionNoArg, "False"}, + {"-grabkeyboard", "*grabKeyboard", XrmoptionNoArg, "True"}, + {"-nograbkeyboard","*grabKeyboard", XrmoptionNoArg, "False"}, + {"-nooverride", "*overrideRedir", XrmoptionNoArg, "False"}, + {"-bs", "*useXserverBackingStore", XrmoptionNoArg, "True"}, + {"-nobs", "*useXserverBackingStore", XrmoptionNoArg, "False"}, + {"-popupfix", "*popupFix", XrmoptionNoArg, "True"}, + {"-noshm", "*useShm", XrmoptionNoArg, "False"}, + {"-termchat", "*termChat", XrmoptionNoArg, "True"}, + {"-chatonly", "*chatOnly", XrmoptionNoArg, "True"}, + {"-scale", "*scale", XrmoptionSepArg, 0}, + {"-appshare", "*appShare", XrmoptionNoArg, "True"}, + {"-escape", "*escapeKeys", XrmoptionSepArg, 0}, + {"-sendclipboard", "*sendClipboard", XrmoptionNoArg, "True"}, + {"-sendalways", "*sendAlways", XrmoptionNoArg, "True"}, + {"-recvtext", "*recvText", XrmoptionSepArg, 0}, + {"-pipeline", "*pipelineUpdates", XrmoptionNoArg, "True"}, + {"-nopipeline", "*pipelineUpdates", XrmoptionNoArg, "False"} }; int numCmdLineOptions = XtNumber(cmdLineOptions); @@ -267,16 +997,100 @@ static XtActionsRec actions[] = { {"SendRFBEvent", SendRFBEvent}, {"ShowPopup", ShowPopup}, + {"Noop", Noop}, {"HidePopup", HidePopup}, + {"HideScaleN", HideScaleN}, + {"HideTurboVNC", HideTurboVNC}, + {"HideQuality", HideQuality}, + {"HideCompress", HideCompress}, {"ToggleFullScreen", ToggleFullScreen}, + {"JumpLeft", JumpLeft}, + {"JumpRight", JumpRight}, + {"JumpUp", JumpUp}, + {"JumpDown", JumpDown}, {"SetFullScreenState", SetFullScreenState}, {"SelectionFromVNC", SelectionFromVNC}, {"SelectionToVNC", SelectionToVNC}, {"ServerDialogDone", ServerDialogDone}, + {"UserDialogDone", UserDialogDone}, + {"YCropDialogDone", YCropDialogDone}, + {"ScbarDialogDone", ScbarDialogDone}, + {"ScaleNDialogDone", ScaleNDialogDone}, + {"ScaleDialogDone", ScaleDialogDone}, {"PasswordDialogDone", PasswordDialogDone}, {"Pause", Pause}, {"RunCommand", RunCommand}, {"Quit", Quit}, + {"HideChat", HideChat}, + {"Toggle8bpp", Toggle8bpp}, + {"Toggle16bpp", Toggle16bpp}, + {"ToggleFullColor", ToggleFullColor}, + {"Toggle256Colors", Toggle256Colors}, + {"Toggle64Colors", Toggle64Colors}, + {"Toggle8Colors", Toggle8Colors}, + {"ToggleGreyScale", ToggleGreyScale}, + {"ToggleTightZRLE", ToggleTightZRLE}, + {"ToggleTightHextile", ToggleTightHextile}, + {"ToggleZRLEZYWRLE", ToggleZRLEZYWRLE}, + {"ToggleViewOnly", ToggleViewOnly}, + {"ToggleJPEG", ToggleJPEG}, + {"ToggleCursorShape", ToggleCursorShape}, + {"ToggleCursorAlpha", ToggleCursorAlpha}, + {"ToggleX11Cursor", ToggleX11Cursor}, + {"ToggleBell", ToggleBell}, + {"ToggleRawLocal", ToggleRawLocal}, + {"ToggleServerInput", ToggleServerInput}, + {"TogglePipelineUpdates", TogglePipelineUpdates}, + {"ToggleSendClipboard", ToggleSendClipboard}, + {"ToggleSendAlways", ToggleSendAlways}, + {"ToggleSingleWindow", ToggleSingleWindow}, + {"ToggleTextChat", ToggleTextChat}, + {"ToggleFileXfer", ToggleFileXfer}, + {"ToggleXGrab", ToggleXGrab}, + {"DoServerScale", DoServerScale}, + {"SetScale", SetScale}, + {"SetYCrop", SetYCrop}, + {"SetScbar", SetScbar}, + {"ShowScaleN", ShowScaleN}, + {"ShowTurboVNC", ShowTurboVNC}, + {"ShowQuality", ShowQuality}, + {"ShowCompress", ShowCompress}, + {"SetScaleN", SetScaleN}, + {"SetTurboVNC", SetTurboVNC}, + {"SetQuality", SetQuality}, + {"SetCompress", SetCompress}, + {"Set8bppState", Set8bppState}, + {"Set16bppState", Set16bppState}, + {"SetFullColorState", SetFullColorState}, + {"Set256ColorsState", Set256ColorsState}, + {"Set64ColorsState", Set64ColorsState}, + {"Set8ColorsState", Set8ColorsState}, + {"SetGreyScaleState", SetGreyScaleState}, + {"SetZRLEState", SetZRLEState}, + {"SetHextileState", SetHextileState}, + {"SetZYWRLEState", SetZYWRLEState}, + {"SetNOJPEGState", SetNOJPEGState}, + {"SetScaleNState", SetScaleNState}, + {"SetQualityState", SetQualityState}, + {"SetCompressState", SetCompressState}, + {"SetViewOnlyState", SetViewOnlyState}, + {"SetCursorShapeState", SetCursorShapeState}, + {"SetCursorAlphaState", SetCursorAlphaState}, + {"SetX11CursorState", SetX11CursorState}, + {"SetBellState", SetBellState}, + {"SetRawLocalState", SetRawLocalState}, + {"SetServerInputState", SetServerInputState}, + {"SetPipelineUpdates", SetPipelineUpdates}, + {"SetSendClipboard", SetSendClipboard}, + {"SetSendAlways", SetSendAlways}, + {"SetSingleWindowState", SetSingleWindowState}, + {"SetTextChatState", SetTextChatState}, + {"SetFileXferState", SetFileXferState}, + {"SetXGrabState", SetXGrabState}, + {"SetEscapeKeysState", SetEscapeKeysState}, + {"ToggleEscapeActive", ToggleEscapeActive}, + {"EscapeDialogDone", EscapeDialogDone}, + {"SetEscapeKeys", SetEscapeKeys} }; @@ -302,11 +1116,14 @@ void usage(void) { - fprintf(stderr, - "TightVNC viewer version 1.3dev7\n" + fprintf(stdout, + "SSVNC Viewer (based on TightVNC viewer version 1.3.9)\n" "\n" "Usage: %s [] [][:]\n" " %s [] [][::]\n" + " %s [] exec=[CMD ARGS...]\n" + " %s [] fd=n\n" + " %s [] /path/to/unix/socket\n" " %s [] -listen []\n" " %s -help\n" "\n" @@ -319,7 +1136,7 @@ " -noraiseonbeep\n" " -passwd (standard VNC authentication)\n" " -user (Unix login authentication)\n" - " -encodings (e.g. \"tight copyrect\")\n" + " -encodings (e.g. \"tight,copyrect\")\n" " -bgr233\n" " -owncmap\n" " -truecolour\n" @@ -332,10 +1149,386 @@ " -autopass\n" "\n" "Option names may be abbreviated, e.g. -bgr instead of -bgr233.\n" - "See the manual page for more information." - "\n", programName, programName, programName, programName); + "See the manual page for more information.\n" + "\n" + "\n" + "Enhanced TightVNC viewer (SSVNC) options:\n" + "\n" + " URL http://www.karlrunge.com/x11vnc/ssvnc.html\n" + "\n" + " Note: ZRLE and ZYWRLE encodings are now supported.\n" + "\n" + " Note: F9 is shortcut to Toggle FullScreen mode.\n" + "\n" + " Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1\n" + " to allow more than one incoming VNC server at a time.\n" + " This is the same as -multilisten described below. Set\n" + " SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than \"n\"\n" + " simultaneous reverse connections.\n" + "\n" + " Note: If the host:port is specified as \"exec=command args...\"\n" + " then instead of making a TCP/IP socket connection to the\n" + " remote VNC server, \"command args...\" is executed and the\n" + " viewer is attached to its stdio. This enables tunnelling\n" + " established via an external command, e.g. an stunnel(8)\n" + " that does not involve a listening socket. This mode does\n" + " not work for -listen reverse connections.\n" + "\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" + " allow more than one incoming VNC server to be connected\n" + " at a time. The default for -listen of only one at a\n" + " time tries to play it safe by not allowing anyone on\n" + " the network to put (many) desktops on your screen over\n" + " a long window of time. Use -multilisten for no limit.\n" + "\n" + " -acceptpopup In -listen (reverse connection listening) mode when\n" + " a reverse VNC connection comes in show a popup asking\n" + " whether to Accept or Reject the connection. The IP\n" + " address of the connecting host is shown. Same as\n" + " setting the env. var. SSVNC_ACCEPT_POPUP=1.\n" + "\n" + " -acceptpopupsc As in -acceptpopup except assume UltraVNC Single\n" + " Click (SC) server. Retrieve User and ComputerName\n" + " info from UltraVNC Server and display in the Popup.\n" + "\n" + " -use64 In -bgr233 mode, use 64 colors instead of 256.\n" + " -bgr222 Same as -use64.\n" + "\n" + " -use8 In -bgr233 mode, use 8 colors instead of 256.\n" + " -bgr111 Same as -use8.\n" + "\n" + " -16bpp If the vnc viewer X display is depth 24 at 32bpp\n" + " request a 16bpp format from the VNC server to cut\n" + " network traffic by up to 2X, then tranlate the\n" + " pixels to 32bpp locally.\n" + " -bgr565 Same as -16bpp.\n" + "\n" + " -grey Use a grey scale for the 16- and 8-bpp modes.\n" + "\n" + " -alpha Use alphablending transparency for local cursors\n" + " 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. \"str\" can also be set by\n" + " the env. var. SSVNC_SCALE.\n" + "\n" + " If you observe mouse trail painting errors, enable\n" + " X11 Cursor mode (either via Popup or -x11cursor.)\n" + "\n" + " Note that scaling is done in software and so can be\n" + " slow and requires more memory. Some speedup Tips:\n" + "\n" + " ZRLE is faster than Tight in this mode. When\n" + " scaling is first detected, the encoding will\n" + " be automatically switched to ZRLE. Use the\n" + " Popup menu if you want to go back to Tight.\n" + " Set SSVNC_PRESERVE_ENCODING=1 to disable this.\n" + "\n" + " Use a solid background on the remote side.\n" + " (e.g. manually or via x11vnc -solid ...)\n" + "\n" + " If the remote server is x11vnc, try client\n" + " side caching: x11vnc -ncache 10 ...\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" + " Use a negative value (e.g. -1) for autodetection.\n" + " Autodetection will always take place if the remote\n" + " fb height is more than 2 times the width.\n" + "\n" + " -sbwidth n Scrollbar width for x11vnc -ncache mode (-ycrop),\n" + " default is very narrow: 2 pixels, it is narrow to\n" + " avoid distraction in -ycrop mode.\n" + "\n" + " -nobell Disable bell.\n" + "\n" + " -rawlocal Prefer raw encoding for localhost, default is\n" + " no, i.e. assumes you have a SSH tunnel instead.\n" + "\n" + " -notty Try to avoid using the terminal for interactive\n" + " responses: use windows for messages and prompting\n" + " instead. Messages will also be printed to terminal.\n" + "\n" + " -sendclipboard Send the X CLIPBOARD selection (i.e. Ctrl+C,\n" + " Ctrl+V) instead of the X PRIMARY selection (mouse\n" + " select and middle button paste.)\n" + "\n" + " -sendalways Whenever the mouse enters the VNC viewer main\n" + " window, send the selection to the VNC server even if\n" + " it has not changed. This is like the Xt resource\n" + " translation SelectionToVNC(always)\n" + "\n" + " -recvtext str When cut text is received from the VNC server,\n" + " ssvncviewer will set both the X PRIMARY and the\n" + " X CLIPBOARD local selections. To control which\n" + " is set, specify 'str' as 'primary', 'clipboard',\n" + " or 'both' (the default.)\n" + "\n" + " -graball Grab the entire X server when in fullscreen mode,\n" + " needed by some old window managers like fvwm2.\n" + "\n" + " -popupfix Warp the popup back to the pointer position,\n" + " needed by some old window managers like fvwm2.\n" + " -sendclipboard Send the X CLIPBOARD selection (i.e. Ctrl+C,\n" + " Ctrl+V) instead of the X PRIMARY selection (mouse\n" + " select and middle button paste.)\n" + "\n" + " -sendalways Whenever the mouse enters the VNC viewer main\n" + " window, send the selection to the VNC server even if\n" + " it has not changed. This is like the Xt resource\n" + " translation SelectionToVNC(always)\n" + "\n" + " -recvtext str When cut text is received from the VNC server,\n" + " ssvncviewer will set both the X PRIMARY and the\n" + " X CLIPBOARD local selections. To control which\n" + " is set, specify 'str' as 'primary', 'clipboard',\n" + " or 'both' (the default.)\n" + "\n" + " -graball Grab the entire X server when in fullscreen mode,\n" + " needed by some old window managers like fvwm2.\n" + "\n" + " -popupfix Warp the popup back to the pointer position,\n" + " needed by some old window managers like fvwm2.\n" + "\n" + " -grabkbd Grab the X keyboard when in fullscreen mode,\n" + " needed by some window managers. Same as -grabkeyboard.\n" + " -grabkbd is the default, use -nograbkbd to disable.\n" + "\n" + " -bs, -nobs Whether or not to use X server Backingstore for the\n" + " main viewer window. The default is to not, mainly\n" + " because most Linux, etc, systems X servers disable\n" + " *all* Backingstore by default. To re-enable it put\n" + "\n" + " Option \"Backingstore\"\n" + "\n" + " in the Device section of /etc/X11/xorg.conf.\n" + " In -bs mode with no X server backingstore, whenever an\n" + " area of the screen is re-exposed it must go out to the\n" + " VNC server to retrieve the pixels. This is too slow.\n" + "\n" + " In -nobs mode, memory is allocated by the viewer to\n" + " provide its own backing of the main viewer window. This\n" + " actually makes some activities faster (changes in large\n" + " regions) but can appear to \"flash\" too much.\n" + "\n" + " -noshm Disable use of MIT shared memory extension (not recommended)\n" + "\n" + " -termchat Do the UltraVNC chat in the terminal vncviewer is in\n" + " instead of in an independent window.\n" + "\n" + " -unixpw str Useful for logging into x11vnc in -unixpw mode. \"str\" is a\n" + " string that allows many ways to enter the Unix Username\n" + " and Unix Password. These characters: username, newline,\n" + " password, newline are sent to the VNC server after any VNC\n" + " authentication has taken place. Under x11vnc they are\n" + " used for the -unixpw login. Other VNC servers could do\n" + " something similar.\n" + "\n" + " You can also indicate \"str\" via the environment\n" + " variable SSVNC_UNIXPW.\n" + "\n" + " Note that the Escape key is actually sent first to tell\n" + " x11vnc to not echo the Unix Username back to the VNC\n" + " viewer. Set SSVNC_UNIXPW_NOESC=1 to override this.\n" + "\n" + " If str is \".\", then you are prompted at the command line\n" + " for the username and password in the normal way. If str is\n" + " \"-\" the stdin is read via getpass(3) for username@password.\n" + " Otherwise if str is a file, it is opened and the first line\n" + " read is taken as the Unix username and the 2nd as the\n" + " password. If str prefixed by \"rm:\" the file is removed\n" + " after reading. Otherwise, if str has a \"@\" character,\n" + " it is taken as username@password. Otherwise, the program\n" + " exits with an error. Got all that?\n" + "\n" + " -repeater str This is for use with UltraVNC repeater proxy described\n" + " here: http://www.uvnc.com/addons/repeater.html. The \"str\"\n" + " is the ID string to be sent to the repeater. E.g. ID:1234\n" + " It can also be the hostname and port or display of the VNC\n" + " server, e.g. 12.34.56.78:0 or snoopy.com:1. Note that when\n" + " using -repeater, the host:dpy on the cmdline is the repeater\n" + " server, NOT the VNC server. The repeater will connect you.\n" + "\n" + " Example: vncviewer ... -repeater ID:3333 repeat.host:5900\n" + " Example: vncviewer ... -repeater vhost:0 repeat.host:5900\n" + "\n" + " Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a\n" + " Single Click III (SSL) repeater (repeater_SSL.exe) and you\n" + " are passing the SSL part of the connection through stunnel,\n" + " socat, etc. This way the magic UltraVNC string 'testB'\n" + " needed to work with the repeater is sent to it.\n" + "\n" + " -rfbversion str Set the advertised RFB version. E.g.: -rfbversion 3.6\n" + " For some servers, e.g. UltraVNC this needs to be done.\n" + "\n" + " -ultradsm UltraVNC has symmetric private key encryption DSM plugins:\n" + " http://www.uvnc.com/features/encryption.html. It is assumed\n" + " you are using a unix program (e.g. our ultravnc_dsm_helper)\n" + " to encrypt and decrypt the UltraVNC DSM stream. IN ADDITION\n" + " TO THAT supply -ultradsm to tell THIS viewer to modify the\n" + " 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" + " -mslogon user Use Windows MS Logon to an UltraVNC server. Supply the\n" + " username or \"1\" to be prompted. The default is to\n" + " autodetect the UltraVNC MS Logon server and prompt for\n" + " the username and password.\n" + "\n" + " IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman\n" + " exchange is very weak and can be brute forced to recover\n" + " your username and password in a few seconds of CPU time.\n" + " To be safe, be sure to use an additional encrypted tunnel\n" + " (e.g. SSL or SSH) for the entire VNC session.\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" + "\n" + " -printres Print out the Ssvnc X resources (appdefaults) and then exit\n" + " You can save them to a file and customize them (e.g. the\n" + " keybindings and Popup menu) Then point to the file via\n" + " XENVIRONMENT or XAPPLRESDIR.\n" + "\n" + " -pipeline Like TurboVNC, request the next framebuffer update as soon\n" + " as possible instead of waiting until the end of the current\n" + " framebuffer update coming in. Helps 'pipeline' the updates.\n" + " This is currently the default, use -nopipeline to disable.\n" + "\n" + " -appshare Enable features for use with x11vnc's -appshare mode where\n" + " instead of sharing the full desktop only the application's\n" + " windows are shared. Viewer multilisten mode is used to\n" + " create the multiple windows: -multilisten is implied.\n" + " See 'x11vnc -appshare -help' more information on the mode.\n" + "\n" + " Features enabled in the viewer under -appshare are:\n" + " Minimum extra text in the title, auto -ycrop is disabled,\n" + " x11vnc -remote_prefix X11VNC_APPSHARE_CMD: message channel,\n" + " x11vnc initial window position hints. See also Escape Keys\n" + " below for additional key and mouse bindings.\n" + "\n" + " -escape str This sets the 'Escape Keys' modifier sequence and enables\n" + " escape keys mode. When the modifier keys escape sequence\n" + " is held down, the next keystroke is interpreted locally\n" + " to perform a special action instead of being sent to the\n" + " remote VNC server.\n" + "\n" + " Use '-escape default' for the default modifier sequence.\n" + " (Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L)\n" + "\n" + " Here are the 'Escape Keys: Help+Set' instructions from the Popup Menu:\n" + "\n" + " Escape Keys: Enter a comma separated list of modifier keys to be the\n" + " 'escape sequence'. When these keys are held down, the next keystroke is\n" + " interpreted locally to invoke a special action instead of being sent to\n" + " the remote VNC server. In other words, a set of 'Hot Keys'.\n" + " \n" + " To enable or disable this, click on 'Escape Keys: Toggle' in the Popup.\n" + " \n" + " Here is the list of hot-key mappings to special actions:\n" + " \n" + " r: refresh desktop b: toggle bell c: toggle full-color\n" + " f: file transfer x: x11cursor z: toggle Tight/ZRLE\n" + " l: full screen g: graball e: escape keys dialog\n" + " s: scale dialog +: scale up (=) -: scale down (_)\n" + " t: text chat a: alphablend cursor\n" + " V: toggle viewonly Q: quit viewer 1 2 3 4 5 6: UltraVNC scale 1/n\n" + " \n" + " Arrow keys: pan the viewport about 10%% for each keypress.\n" + " PageUp / PageDown: pan the viewport by a screenful vertically.\n" + " Home / End: pan the viewport by a screenful horizontally.\n" + " KeyPad Arrow keys: pan the viewport by 1 pixel for each keypress.\n" + " Dragging the Mouse with Button1 pressed also pans the viewport.\n" + " Clicking Mouse Button3 brings up the Popup Menu.\n" + " \n" + " The above mappings are *always* active in ViewOnly mode, unless you set the\n" + " Escape Keys value to 'never'.\n" + " \n" + " If the Escape Keys value below is set to 'default' then a default list of\n" + " of modifier keys is used. For Unix it is: Alt_L,Super_L and for MacOSX it\n" + " is Control_L,Meta_L. Note: the Super_L key usually has a Windows(TM) Flag\n" + " on it. Also note the _L and _R mean the key is on the LEFT or RIGHT side\n" + " of the keyboard.\n" + " \n" + " On Unix the default is Alt and Windows keys on Left side of keyboard.\n" + " On MacOSX the default is Control and Command keys on Left side of keyboard.\n" + " \n" + " Example: Press and hold the Alt and Windows keys on the LEFT side of the\n" + " keyboard and then press 'c' to toggle the full-color state. Or press 't'\n" + " to toggle the ultravnc Text Chat window, etc.\n" + " \n" + " To use something besides the default, supply a comma separated list (or a\n" + " single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L\n" + " Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch.\n" + "\n" + "\n" + " New Popup actions:\n" + "\n" + " ViewOnly: ~ -viewonly\n" + " Disable Bell: ~ -nobell\n" + " Cursor Shape: ~ -nocursorshape\n" + " X11 Cursor: ~ -x11cursor\n" + " Cursor Alphablend: ~ -alpha\n" + " Toggle Tight/Hextile: ~ -encodings hextile...\n" + " Toggle Tight/ZRLE: ~ -encodings zrle...\n" + " Toggle ZRLE/ZYWRLE: ~ -encodings zywrle...\n" + " Quality Level ~ -quality (both Tight and ZYWRLE)\n" + " Compress Level ~ -compresslevel\n" + " Disable JPEG: ~ -nojpeg (Tight)\n" + " Pipeline Updates ~ -pipeline\n" + "\n" + " Full Color as many colors as local screen allows.\n" + " Grey scale (16 & 8-bpp) ~ -grey, for low colors 16/8bpp modes only.\n" + " 16 bit color (BGR565) ~ -16bpp / -bgr565\n" + " 8 bit color (BGR233) ~ -bgr233\n" + " 256 colors ~ -bgr233 default # of colors.\n" + " 64 colors ~ -bgr222 / -use64\n" + " 8 colors ~ -bgr111 / -use8\n" + " Scale Viewer ~ -scale\n" + " Escape Keys: Toggle ~ -escape\n" + " Escape Keys: Help+Set ~ -escape\n" + " Set Y Crop (y-max) ~ -ycrop\n" + " Set Scrollbar Width ~ -sbwidth\n" + " XGrabServer ~ -graball\n" + "\n" + " UltraVNC Extensions:\n" + "\n" + " Set 1/n Server Scale Ultravnc ext. Scale desktop by 1/n.\n" + " Text Chat Ultravnc ext. Do Text Chat.\n" + " File Transfer Ultravnc ext. File xfer via Java helper.\n" + " Single Window Ultravnc ext. Grab and view a single window.\n" + " (select then click on the window you want).\n" + " Disable Remote Input Ultravnc ext. Try to prevent input and\n" + " viewing of monitor at physical display.\n" + "\n" + " Note: the Ultravnc extensions only apply to servers that support\n" + " them. x11vnc/libvncserver supports some of them.\n" + "\n" + " Send Clipboard not Primary ~ -sendclipboard\n" + " Send Selection Every time ~ -sendalways\n" + "\n" + "\n", programName, programName, programName, programName, programName, programName, programName); exit(1); } +#if 0 + " -nooverride Do not apply OverrideRedirect in fullscreen mode.\n" +#endif /* @@ -343,77 +1536,234 @@ * not already processed by XtVaAppInitialize(). It sets vncServerHost and * vncServerPort and all the fields in appData. */ +extern int saw_appshare; 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 */ - 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; + } + if (getenv("VNCVIEWER_POPUP_FIX")) { + if (getenv("NOPOPUPFIX")) { + ; + } else if (!strcmp(getenv("VNCVIEWER_POPUP_FIX"), "0")) { + ; + } else { + appData.popupFix = True; + } + } + if (getenv("VNCVIEWER_GRAB_SERVER")) { + appData.grabAll = True; + } + if (getenv("VNCVIEWER_YCROP")) { + int n = atoi(getenv("VNCVIEWER_YCROP")); + if (n != 0) { + 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_NOTTY") || getenv("SSVNC_VNCVIEWER_NOTTY")) { + appData.notty = 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")); + } + } + if (getenv("VNCVIEWER_ESCAPE") && strcmp(getenv("VNCVIEWER_ESCAPE"), "")) { + if (appData.escapeKeys == NULL) { + appData.escapeKeys = strdup(getenv("VNCVIEWER_ESCAPE")); + } + } + if (saw_appshare) { + appData.appShare = True; + } + if (appData.appShare && appData.escapeKeys == NULL) { + appData.escapeKeys = strdup("default"); + } + if (appData.escapeKeys != NULL) { + appData.escapeActive = True; + } + if (getenv("VNCVIEWER_SEND_CLIPBOARD")) { + appData.sendClipboard = True; + } + if (getenv("VNCVIEWER_SEND_ALWAYS")) { + appData.sendAlways = True; + } + if (getenv("VNCVIEWER_RECV_TEXT")) { + char *s = getenv("VNCVIEWER_RECV_TEXT"); + if (!strcasecmp(s, "clipboard")) { + appData.recvText = strdup("clipboard"); + } else if (!strcasecmp(s, "primary")) { + appData.recvText = strdup("primary"); + } else if (!strcasecmp(s, "both")) { + appData.recvText = strdup("both"); + } + } + if (getenv("VNCVIEWER_PIPELINE_UPDATES")) { + appData.pipelineUpdates = True; + } else if (getenv("VNCVIEWER_NO_PIPELINE_UPDATES")) { + appData.pipelineUpdates = False; + } + + if (appData.useBGR233 && appData.useBGR565) { + appData.useBGR233 = 0; + } + + if (getenv("SSVNC_ULTRA_FTP_JAR") == NULL && programName != NULL) { + int len = strlen(programName) + 200; + char *q, *jar = (char *) malloc(len); + + sprintf(jar, "%s", programName); + q = strrchr(jar, '/'); + if (q) { + struct stat sb; + *(q+1) = '\0'; + strcat(jar, "../lib/ssvnc/util/ultraftp.jar"); + if (stat(jar, &sb) == 0) { + char *put = (char *) malloc(len); + sprintf(put, "SSVNC_ULTRA_FTP_JAR=%s", jar); + fprintf(stderr, "Setting: %s\n\n", put); + putenv(put); + } else { + sprintf(jar, "%s", programName); + q = strrchr(jar, '/'); + *(q+1) = '\0'; + strcat(jar, "util/ultraftp.jar"); + if (stat(jar, &sb) == 0) { + char *put = (char *) malloc(len); + sprintf(put, "SSVNC_ULTRA_FTP_JAR=%s", jar); + fprintf(stderr, "Setting: %s\n\n", put); + putenv(put); + } + } + } + free(jar); + } + /* Add our actions to the actions table so they can be used in widget resource specs */ - 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 (argc == 1) { + vncServerName = DoServerDialog(); + if (!use_tty()) { + appData.passwordDialog = True; + } + } else if (argc != 2) { + usage(); + } else { + vncServerName = argv[1]; + + if (!use_tty()) { + 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; +#else + 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 +++ vnc_unixsrc/vncviewer/colour.c 2009-11-29 22:31:14.000000000 -0500 @@ -31,9 +31,12 @@ #define BGR233_SIZE 256 unsigned long BGR233ToPixel[BGR233_SIZE]; +#define BGR565_SIZE 65536 +unsigned long BGR565ToPixel[BGR565_SIZE]; + Colormap cmap; Visual *vis; -unsigned int visdepth, visbpp; +unsigned int visdepth, visbpp, isLSB; Bool allocColorFailed = False; static int nBGR233ColoursAllocated; @@ -45,6 +48,8 @@ static void AllocateExactBGR233Colours(); static Bool AllocateBGR233Colour(int r, int g, int b); +static void SetupBGR565Map(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask); + /* * SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are @@ -97,6 +102,44 @@ visbpp = GetBPPForDepth(visdepth); cmap = DefaultColormap(dpy,DefaultScreen(dpy)); + if (ImageByteOrder(dpy) == LSBFirst) { + isLSB = 1; + } else { + isLSB = 0; + } + if (visbpp == 24) { + if (!appData.useBGR233) { + fprintf(stderr, "Warning: for 24bpp enabling -bgr565 -- Don't use FullColor!\n"); + appData.useBGR565 = True; + } else { + fprintf(stderr, "Warning: for 24bpp using -bgr233 -- Don't use FullColor!\n"); + } + } + + if (appData.useBGR565) { + if (visdepth < 24 || visbpp < 24 || vis->class != TrueColor) { + fprintf(stderr, "disabling -16bpp BGR565 on non-depth 24 machine\n"); + appData.useBGR565 = False; + } else { + myFormat.bitsPerPixel = 16; + myFormat.depth = 16; + myFormat.trueColour = 1; + myFormat.bigEndian = 0; + myFormat.redMax = 31; + myFormat.greenMax = 63; + myFormat.blueMax = 31; + myFormat.redShift = 11; + myFormat.greenShift = 5; + myFormat.blueShift = 0; + + fprintf(stderr, "Using default colormap and translating from BGR565 (65536 colors). Pixel format:\n"); + PrintPixelFormat(&myFormat); + + SetupBGR565Map(vis->red_mask, vis->green_mask, vis->blue_mask); + return; + } + } + if (!appData.useBGR233 && (vis->class == TrueColor)) { myFormat.bitsPerPixel = visbpp; @@ -116,21 +159,42 @@ return; } - appData.useBGR233 = True; + if (appData.useBGR233 == 0) { + appData.useBGR233 = 256; + } myFormat.bitsPerPixel = 8; myFormat.depth = 8; myFormat.trueColour = 1; myFormat.bigEndian = 0; - myFormat.redMax = 7; + myFormat.redMax = 7; myFormat.greenMax = 7; - myFormat.blueMax = 3; - myFormat.redShift = 0; + myFormat.blueMax = 3; + myFormat.redShift = 0; myFormat.greenShift = 3; - myFormat.blueShift = 6; + myFormat.blueShift = 6; + + if (appData.useBGR233 == 64) { + /* BGR222 */ + myFormat.redMax = 3; + myFormat.greenMax = 3; + myFormat.blueMax = 3; + myFormat.redShift = 0; + myFormat.greenShift = 2; + myFormat.blueShift = 4; + } + if (appData.useBGR233 == 8) { + /* BGR111 */ + myFormat.redMax = 2; + myFormat.greenMax = 2; + myFormat.blueMax = 2; + myFormat.redShift = 0; + myFormat.greenShift = 1; + myFormat.blueShift = 2; + } fprintf(stderr, - "Using default colormap and translating from BGR233. Pixel format:\n"); + "Using default colormap and translating from BGR233 (%d colors). Pixel format:\n", appData.useBGR233); PrintPixelFormat(&myFormat); SetupBGR233Map(); @@ -282,8 +346,12 @@ XFree(format); if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32) { - fprintf(stderr,"Can't cope with %d bits-per-pixel. Sorry.\n", bpp); - exit(1); + if (bpp == 24) { + fprintf(stderr,"Warning: 24 bits-per-pixel may have problems...\n"); + } else { + fprintf(stderr,"Can't cope with %d bits-per-pixel. Sorry.\n", bpp); + exit(1); + } } return bpp; @@ -394,16 +462,43 @@ for (r = 0; r < 8; r++) { for (g = 0; g < 8; g++) { for (b = 0; b < 4; b++) { - if (BGR233ToPixel[(b<<6) | (g<<3) | r] == INVALID_PIXEL) { + int bs = 6, gs = 3, rs = 0; + int bm = 3, gm = 7, rm = 7; + if (appData.useBGR233 == 64) { + bs = 4; gs = 2; rs = 0; + bm = 3; gm = 3; rm = 3; + } + if (appData.useBGR233 == 8) { + bs = 2; gs = 1; rs = 0; + bm = 1; gm = 1; rm = 1; + } + if ((b > bm || g > gm || r > rm)) { + continue; + } + if (BGR233ToPixel[(b< bm || g > gm || r > rm)) { + continue; + } + r2 = (255 * r) / rm; + g2 = (255 * g) / gm; + b2 = (255 * b) / bm; + + pixel = (r2 << 16) | (g2 << 8) | (b2 << 0); + if (appData.useGreyScale) { + int ave; + int r1, g1, b1; + ave = (2*r + g + 2*b)/3; + r1 = ave/2; + g1 = ave; + b1 = ave/2; + + r2 = (255 * r1) / rm; + g2 = (255 * g1) / gm; + b2 = (255 * b1) / bm; + + pixel = (r2 << 16) | (g2 << 8) | (b2 << 0); + } + + if (red_mask == 0xff) { + idx = (r< 3 || gv[gi] > 3 || rv[ri] > 3)) { + nBGR233ColoursAllocated++; + } else if (appData.useBGR233 == 8 && (bv[bi] > 1 || gv[gi] > 1 || rv[ri] > 1)) { + nBGR233ColoursAllocated++; + } else if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi])) { + return; + } } } rn++; @@ -496,8 +647,13 @@ gi = gn; for (ri = 0; ri < rn; ri++) { for (bi = 0; bi < bn; bi++) { - if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi])) - return; + if (appData.useBGR233 == 64 && (bv[bi] > 3 || gv[gi] > 3 || rv[ri] > 3)) { + nBGR233ColoursAllocated++; + } else if (appData.useBGR233 == 8 && (bv[bi] > 1 || gv[gi] > 1 || rv[ri] > 1)) { + nBGR233ColoursAllocated++; + } else if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi])) { + return; + } } } gn++; @@ -507,8 +663,13 @@ bi = bn; for (ri = 0; ri < rn; ri++) { for (gi = 0; gi < gn; gi++) { - if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi])) - return; + if (appData.useBGR233 == 64 && (bv[bi] > 3 || gv[gi] > 3 || rv[ri] > 3)) { + nBGR233ColoursAllocated++; + } else if (appData.useBGR233 == 8 && (bv[bi] > 1 || gv[gi] > 1 || rv[ri] > 1)) { + nBGR233ColoursAllocated++; + } else if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi])) { + return; + } } } bn++; @@ -529,18 +690,36 @@ AllocateBGR233Colour(int r, int g, int b) { XColor c; + int bs = 6, gs = 3, rs = 0; + int bm = 3, gm = 7, rm = 7; if (nBGR233ColoursAllocated >= appData.nColours) return False; - c.red = r * 65535 / 7; - c.green = g * 65535 / 7; - c.blue = b * 65535 / 3; + if (appData.useBGR233 == 64) { + bs = 4; gs = 2, rs = 0; + bm = 3; gm = 3; rm = 3; + } + if (appData.useBGR233 == 8) { + bs = 2; gs = 1, rs = 0; + bm = 1; gm = 1; rm = 1; + } + + c.red = r * 65535 / rm; + c.green = g * 65535 / gm; + c.blue = b * 65535 / bm; + if (appData.useGreyScale) { + int ave; + ave = (c.red + c.green + c.blue)/3; + c.red = ave; + c.green = ave; + c.blue = ave; + } if (!XAllocColor(dpy, cmap, &c)) return False; - BGR233ToPixel[(b<<6) | (g<<3) | r] = c.pixel; + BGR233ToPixel[(b< $dest +touch -r ./vncviewer $dest +yy=/dist/src/apps/VNC/etc/libvncserver_cvs/expts/etv/ssvnc/bin/Linux.i686/vncviewer +mv $yy $yy.unlink +cp -p ./vncviewer $yy +mv $yy.turbovnc $yy.unlink.turbovnc +cp -p ./vncviewer $HOME/etv_col/Linux.i686 +cp -p ./vncviewer.turbovnc $yy.turbovnc +cp -p ./vncviewer.turbovnc $HOME/etv_col/Linux.i686/vncviewer.turbovnc +chmod 755 $yy* + +rm -f $yy.unlink* +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 2008-10-18 09:35:02.000000000 -0400 @@ -38,8 +38,11 @@ static Bool prevSoftCursorSet = False; -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 +51,13 @@ static Bool SoftCursorInLockedArea(void); static void SoftCursorCopyArea(int oper); static void SoftCursorDraw(void); -static void FreeSoftCursor(void); -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] = { @@ -91,6 +99,8 @@ static Bool prevXCursorSet = False; static Cursor prevXCursor; +extern double scale_factor_x; +extern double scale_factor_y; Bool HandleXCursor(int xhot, int yhot, int width, int height) { @@ -167,148 +177,179 @@ 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; } /********************************************************************* @@ -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; + } + + 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; +void new_pixmap(int w, int h) { - x = rcCursorX - rcHotX; - y = rcCursorY - rcHotY; - if (x >= si.framebufferWidth || y >= si.framebufferHeight) - return; - - w = rcWidth; - h = rcHeight; - if (x < 0) { - w += x; - x = 0; - } else if (x + w > si.framebufferWidth) { - w = si.framebufferWidth - x; - } - if (y < 0) { - h += y; - y = 0; - } 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) { + w += x; + x = 0; + } else if (x + w > si.framebufferWidth) { + w = si.framebufferWidth - x; + } + if (y < 0) { + h += y; + y = 0; + } else if (y + h > si.framebufferHeight) { + h = si.framebufferHeight - y; + } + + 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. */ + scale_saved = 0; + if (appData.useXserverBackingStore) { + XSync(dpy, False); + XCopyArea(dpy, desktopWin, rcSavedArea, gc, x, y, w, h, 0, 0); + } else { + 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 { + +#define XE(s) if (XError_ign > 1) {fprintf(stderr, "X-%d\n", (s)); db = 1;} + + /* Restore screen area. */ + 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 { + 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,43 +651,182 @@ int offset, bytesPerPixel; char *pos; +#define alphahack +#ifdef alphahack + /* hack to have cursor transparency at 32bpp */ + int alphablend = 0; + + if (!rcSource) { + return; + } + + if (appData.useCursorAlpha) { + alphablend = 1; + } + 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 = 192; + + if (! alpha_image) { + /* watch out for tiny fb (rare) */ + if (iwidth > si.framebufferWidth) { + iwidth = si.framebufferWidth; + } + if (iwidth > si.framebufferHeight) { + iwidth = si.framebufferHeight; + } + + /* 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++) { + for (x = 0; x < rcWidth; x++) { + int alpha; + + offset = y * rcWidth + x; + pos = (char *)&rcSource[offset * bytesPerPixel]; + + upos = (unsigned long *) pos; + alpha = (*upos & 0xff000000) >> 24; + if (alpha) { + got_alpha = 1; + break; + } + } + if (got_alpha) { + break; + } + } + + if (!got_alpha) { + /* no alpha channel data, fallback to the old way */ + goto oldway; + } + + /* 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 */ + rsW = rcWidth; + rsX = 0; /* used to denote a shift from the left side */ + x = rcCursorX - rcHotX; + if (x < 0) { + rsW += x; + rsX = -x; + } else if (x + rsW > si.framebufferWidth) { + rsW = si.framebufferWidth - x; + } + rsH = rcHeight; + rsY = 0; /* used to denote a shift from the top side */ + y = rcCursorY - rcHotY; + if (y < 0) { + rsH += y; + rsY = -y; + } else if (y + rsH > si.framebufferHeight) { + rsH = si.framebufferHeight - y; + } + + /* + * now loop over the cursor data, blend in the fb values, + * and then overwrite the fb (CopyDataToScreen()) + */ + for (y = 0; y < rcHeight; y++) { + y0 = rcCursorY - rcHotY + y; + if (y0 < 0 || y0 >= si.framebufferHeight) { + continue; /* clipped */ + } + for (x = 0; x < rcWidth; x++) { + int alpha, color_curs, color_fb, i; + + x0 = rcCursorX - rcHotX + x; + if (x0 < 0 || x0 >= si.framebufferWidth) { + continue; /* clipped */ + } + + offset = y * rcWidth + x; + pos = (char *)&rcSource[offset * bytesPerPixel]; + + /* extract secret alpha byte from rich cursor: */ + upos = (unsigned long *) pos; + alpha = (*upos & 0xff000000) >> 24; /* XXX MSB? */ + + /* extract the pixel from the fb: */ + pixel = *(upix + (y-rsY)*iwidth + (x-rsX)); + + put = 0; + /* for simplicity, blend all 4 bytes */ + for (i = 0; i < 4; i++) { + int sh = i*8; + color_curs = ((0xff << sh) & *upos) >> sh; + color_fb = ((0xff << sh) & pixel) >> sh; + + /* XXX assumes pre-multipled color_curs */ + color_fb = color_curs + + ((0xff - alpha) * color_fb)/0xff; + put |= color_fb << sh; + } + /* place in the fb: */ + CopyDataToScreen((char *)&put, x0, y0, 1, 1); + } + } + return; } +oldway: +#endif + + 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); } -static void FreeSoftCursor(void) +void FreeSoftCursor(void) { - if (prevSoftCursorSet) { - SoftCursorCopyArea(OPER_RESTORE); - XFreePixmap(dpy, rcSavedArea); - free(rcSource); - free(rcMask); - prevSoftCursorSet = False; - } + if (prevSoftCursorSet) { + SoftCursorCopyArea(OPER_RESTORE); + XFreePixmap(dpy, rcSavedArea); + XFreePixmap(dpy, rcSavedArea_0); + free(rcSource); + rcSource = NULL; + free(rcMask); + prevSoftCursorSet = False; + } } -static void FreeX11Cursor() +void FreeX11Cursor() { - if (prevXCursorSet) { - XFreeCursor(dpy, prevXCursor); - prevXCursorSet = False; - } + if (prevXCursorSet) { + XFreeCursor(dpy, prevXCursor); + prevXCursorSet = False; + } } - 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 2009-11-29 22:05:55.000000000 -0500 @@ -28,28 +28,498 @@ #include #endif +#include + GC gc; GC srcGC, dstGC; /* used for debugging copyrect */ Window desktopWin; -Cursor dotCursor; +Cursor dotCursor3 = None; +Cursor dotCursor4 = None; +Cursor bogoCursor = None; +Cursor waitCursor = None; Widget form, viewport, desktop; +int appshare_0_hint = -10000; +int appshare_x_hint = -10000; +int appshare_y_hint = -10000; + static Bool modifierPressed[256]; -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(); static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width,int height); static void HandleBasicDesktopEvent(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont); +static void CopyBGR565ToScreen(CARD16 *buf, int x, int y, int width,int height); + static XtResource desktopBackingStoreResources[] = { { - XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0, - XtRImmediate, (XtPointer) Always, + XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0, + XtRImmediate, (XtPointer) Always, }, }; +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); + +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; + } + + if (sscanf(s, "%d/%d", &n, &m) == 2) { + if (m == 0) { + frac_x = 1.0; + } else { + frac_x = ((double) n) / ((double) m); + } + } + 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); + } + } + if (frac_x < 0.0 && sscanf(s, "%lf", &f) == 1) { + if (f > 0.0) { + frac_x = f; + } + } + + if (frac_y < 0.0) { + frac_y = frac_x; + } + + if (frac_y > 0.0 && frac_x > 0.0) { + if (fx != NULL) { + *fx = frac_x; + } + if (fy != NULL) { + *fy = frac_y; + } + } else { + if (appData.scale) { + fprintf(stderr, "Invalid scale string: '%s'\n", appData.scale); + } else { + fprintf(stderr, "Invalid scale string.\n"); + } + appData.scale = 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(); + +// 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; + + 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 || frac_y < 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()) { + ShmDetach(); + } + XDestroyImage(image); + fprintf(stderr, "rescale_image: destroyed 'image'\n"); + if (UsingShm()) { + ShmCleanup(); + } + 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) { + if (appData.scale != NULL && scale_x > 0) { + ; + } else { + 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) { + 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, "try_create_image: malloc failed\n"); + exit(1); + } else { + fprintf(stderr, "try_create_image: created *non-shm* image: %dx%d\n", image->width, image->height); + } + } + fprintf(stderr, "try_create_image: image->bytes_per_line: %d\n", image->bytes_per_line); +} + +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; + + get_scale_values(&frac_x, &frac_y); + + if (frac_x < 0.0 || frac_y < 0.0) { + fprintf(stderr, "Cannot figure out scale factor!\n"); + goto bork; + } + + scale_factor_x = 0.0; + scale_factor_y = 0.0; + scale_x = 0; + scale_y = 0; + + + if (1) { + 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); + } + } + } + bork: + try_create_image(); +} + +int old_width = 0; +int old_height = 0; + +int guessCrop(void) { + int w = si.framebufferWidth; + + if (w == 320) { + return 240; + } else if (w == 400) { + return 300; + } else if (w == 640) { + return 480; + } else if (w == 800) { + return 600; + } else if (w == 1024) { + return 768; + } else if (w == 1152) { + 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 { + int h = (3 * w) / 4; + return h; + } +} + +void check_tall(void) { + if (appData.appShare) { + return; + } + if (! appData.yCrop) { + int w = si.framebufferWidth; + int h = si.framebufferHeight; + if (h > 2 * w) { + fprintf(stderr, "Tall display (%dx%d) suspect 'x11vnc -ncache' mode,\n", w, h); + fprintf(stderr, " setting auto -ycrop detection.\n", w, h); + appData.yCrop = -1; + } + } +} /* * DesktopInitBeforeRealization creates the "desktop" widget and the viewport @@ -59,92 +529,1017 @@ 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); + if (frac_x > 0.0 && frac_y > 0.0) { + w = scale_round(w, frac_x); + h = scale_round(h, frac_y); + } else { + appData.scale = NULL; + } + } - form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel, - XtNborderWidth, 0, - XtNdefaultDistance, 0, NULL); + form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel, + XtNborderWidth, 0, XtNdefaultDistance, 0, NULL); - viewport = XtVaCreateManagedWidget("viewport", viewportWidgetClass, form, - XtNborderWidth, 0, - NULL); + viewport = XtVaCreateManagedWidget("viewport", viewportWidgetClass, form, + XtNborderWidth, 0, NULL); - desktop = XtVaCreateManagedWidget("desktop", coreWidgetClass, viewport, - XtNborderWidth, 0, - NULL); + desktop = XtVaCreateManagedWidget("desktop", coreWidgetClass, viewport, + XtNborderWidth, 0, NULL); - XtVaSetValues(desktop, XtNwidth, si.framebufferWidth, - XtNheight, si.framebufferHeight, NULL); + XtVaSetValues(desktop, XtNwidth, w, XtNheight, h, NULL); - XtAddEventHandler(desktop, LeaveWindowMask|ExposureMask, - True, HandleBasicDesktopEvent, NULL); + XtAddEventHandler(desktop, LeaveWindowMask|EnterWindowMask|ExposureMask, + True, HandleBasicDesktopEvent, NULL); - for (i = 0; i < 256; i++) - modifierPressed[i] = False; + 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; + fprintf(stderr, "ycrop h: %d -> %d\n", hm, (int) (hm*frac_y)); -#ifdef MITSHM - if (appData.useShm) { - image = CreateShmImage(); - if (!image) - appData.useShm = False; - } -#endif + hm *= frac_y; - if (!image) { - 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"); - 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 + +static XtCallbackProc Scrolled(Widget w, XtPointer closure, XtPointer call_data) { + Position x, y; + XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL); + if (0) fprintf(stderr, "scrolled by %d pixels x=%d y=%d\n", (int) call_data, x, y); + if (xsst == 2) { + x = 0; + y = 0; + XtVaSetValues(desktop, XtNx, x, XtNy, y, NULL); + } else if (xsst) { + XawScrollbarSetThumb(w, 0.0, 0.0); + } else { + 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; + XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL); + if (0) fprintf(stderr, "thumb value: %.4f x=%d y=%d\n", top, x, y); + if (top > 0.01) { + if (xsst == 2) { + x = 0; + y = 0; + XtVaSetValues(desktop, XtNx, x, XtNy, y, NULL); + } else if (xsst) { + XawScrollbarSetThumb(w, 0.0, 0.0); + } else { + float t = 0.0, s = 1.0; + XtVaSetValues(w, XtNtopOfThumb, *(XtArgVal*)&t, XtNshown, *(XtArgVal*)&s, NULL); + } + } +} + +extern double dnow(void); + +void check_things() { + static int installed_callback = 0; + static int first = 1; + static double last_scrollbar = 0.0; + int w = si.framebufferWidth; + 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 * fac < dpyHeight && h > 2*w && now > last_scrollbar + 0.25) { + Widget wv, wh, wc; + Position x0, y0; + Position x1, y1; + Dimension w0, h0, b0; + Dimension w1, h1, b1; + Dimension w2, h2, b2; + + wc = XtNameToWidget(viewport, "clip"); + wv = XtNameToWidget(viewport, "vertical"); + wh = XtNameToWidget(viewport, "horizontal"); + if (wc && wv && wh) { + int doit = 1; + int sb = appData.sbWidth; + XtVaGetValues(wv, XtNwidth, &w0, XtNheight, &h0, XtNborderWidth, &b0, XtNx, &x0, XtNy, &y0, NULL); + XtVaGetValues(wh, XtNwidth, &w1, XtNheight, &h1, XtNborderWidth, &b1, XtNx, &x1, XtNy, &y1, NULL); + XtVaGetValues(wc, XtNwidth, &w2, XtNheight, &h2, XtNborderWidth, &b2, NULL); + if (!sb) { + sb = 2; + } + if (w0 != sb || h1 != 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(wh, XtNheight, sb, XtNy, y1 + (h1 - sb), NULL); + w2 = w2 + (w0 - sb); + h2 = h2 + (h1 - sb); + if (w2 > 10 && h2 > 10) { + XtVaSetValues(wc, XtNwidth, w2, XtNheight, h2, NULL); + } + + XtManageChild(wv); + XtManageChild(wh); + XtManageChild(wc); + + appData.sbWidth = sb; + } + } + last_scrollbar = dnow(); + } + + if (now <= last + 0.25) { + return; + } + + if (image_scale) { + scale_check_zrle(); + } + + /* 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(); +} /* * DesktopInitAfterRealization does things which require the X windows to * exist. It creates some GCs and sets the dot cursor. */ +void Xcursors(int set) { + if (dotCursor3 == None) { + dotCursor3 = CreateDotCursor(3); + } + if (dotCursor4 == None) { + dotCursor4 = CreateDotCursor(4); + } + if (set) { + XSetWindowAttributes attr; + unsigned long valuemask = 0; + + if (!appData.useX11Cursor) { + if (appData.viewOnly) { + attr.cursor = dotCursor4; + } else { + attr.cursor = dotCursor3; + } + valuemask |= CWCursor; + XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); + } + } +} + void DesktopInitAfterRealization() { - XGCValues gcv; - XSetWindowAttributes attr; - unsigned long valuemask; - - desktopWin = XtWindow(desktop); - - gc = XCreateGC(dpy,desktopWin,0,NULL); - - gcv.function = GXxor; - gcv.foreground = 0x0f0f0f0f; - srcGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv); - gcv.foreground = 0xf0f0f0f0; - dstGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv); - - XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore, - NULL, 0); - - XtVaGetApplicationResources(desktop, (XtPointer)&attr.backing_store, - desktopBackingStoreResources, 1, NULL); - valuemask = CWBackingStore; - - if (!appData.useX11Cursor) { - dotCursor = CreateDotCursor(); - attr.cursor = dotCursor; - valuemask |= CWCursor; - } + XGCValues gcv; + XSetWindowAttributes attr; + XWindowAttributes gattr; + unsigned long valuemask = 0; + + desktopWin = XtWindow(desktop); + + gc = XCreateGC(dpy,desktopWin,0,NULL); + + gcv.function = GXxor; + gcv.foreground = 0x0f0f0f0f; + srcGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv); + gcv.foreground = 0xf0f0f0f0; + dstGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv); + + XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore, + NULL, 0); + + if (appData.useXserverBackingStore) { + Screen *s = DefaultScreenOfDisplay(dpy); + if (DoesBackingStore(s) != Always) { + fprintf(stderr, "X server does not do backingstore, disabling it.\n"); + appData.useXserverBackingStore = False; + } + } - XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); + if (appData.useXserverBackingStore) { + XtVaGetApplicationResources(desktop, (XtPointer)&attr.backing_store, + desktopBackingStoreResources, 1, NULL); + valuemask |= CWBackingStore; + } else { + attr.background_pixel = BlackPixel(dpy, DefaultScreen(dpy)); + valuemask |= CWBackPixel; + } + + Xcursors(0); + if (!appData.useX11Cursor) { + if (appData.viewOnly) { + attr.cursor = dotCursor4; + } else { + attr.cursor = dotCursor3; + } + valuemask |= CWCursor; + } + bogoCursor = XCreateFontCursor(dpy, XC_bogosity); + waitCursor = XCreateFontCursor(dpy, XC_watch); + + XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); + + if (XGetWindowAttributes(dpy, desktopWin, &gattr)) { +#if 0 + fprintf(stderr, "desktopWin backingstore: %d save_under: %d\n", gattr.backing_store, gattr.save_under); +#endif + } + fprintf(stderr, "\n"); +} + +extern void FreeX11Cursor(void); +extern void FreeSoftCursor(void); + +void +DesktopCursorOff() +{ + XSetWindowAttributes attr; + unsigned long valuemask; + + if (dotCursor3 == None) { + dotCursor3 = CreateDotCursor(3); + dotCursor4 = CreateDotCursor(4); + } + if (appData.viewOnly) { + XDefineCursor(dpy, desktopWin, dotCursor4); + } else { + XDefineCursor(dpy, desktopWin, dotCursor3); + } + 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; + + 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; + } + } + 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 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 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 last + 4.0) { + double cnt = calls; + if (cnt <= 0.0) cnt = 1.0; + var /= cnt; + sum /= cnt; + var = var - sum * sum; + if (sum > 0.0) { + var = var / (sum*sum); + } + fprintf(stderr, "scale_rect stats: %10d %10.1f ave: %10.3f var-rat: %10.3f\n", (int) calls, sum * cnt, sum, var); + + calls = 0.0; + sum = 0.0; + var = 0.0; + last = dnow(); + } +} + +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; + static int scale_stats = -1; + + 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); + + if (scale_stats < 0) { + if (getenv("SSVNC_SCALE_STATS")) { + scale_stats = 1; + } else { + scale_stats = 0; + } + } + if (scale_stats) { + do_scale_stats(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) { + 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 { + char *src, *dst; + int Bpp = image->bits_per_pixel / 8; + int Bpl = image->bytes_per_line, h; + int Bpl2 = image_ycrop->bytes_per_line; + src = image->data + src_y * Bpl + src_x * Bpp; + dst = image_ycrop->data; + for (h = 0; h < height; h++) { + memcpy(dst, src, width * Bpp); + src += Bpl; + dst += Bpl2; + } + XShmPutImage(dpy, desktopWin, gc, image_ycrop, 0, 0, + dst_x, dst_y, width, height, False); + } + } else +#endif + { + 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); + /* * HandleBasicDesktopEvent - deal with expose and leave events. */ @@ -152,42 +1547,528 @@ 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(); + + if (0) { + PR_EXPOSE; + } - switch (ev->type) { + switch (ev->type) { case Expose: case GraphicsExpose: /* sometimes due to scrollbars being added/removed we get an expose outside the actual desktop area. Make sure we don't pass it on to the RFB server. */ + x = ev->xexpose.x; + y = ev->xexpose.y; + width = ev->xexpose.width; + height = ev->xexpose.height; + + 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++; + } + } - if (ev->xexpose.x + ev->xexpose.width > si.framebufferWidth) { - ev->xexpose.width = si.framebufferWidth - ev->xexpose.x; - if (ev->xexpose.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; - } - - SendFramebufferUpdateRequest(ev->xexpose.x, ev->xexpose.y, - ev->xexpose.width, ev->xexpose.height, False); - break; + if (x + width > si.framebufferWidth) { + width = si.framebufferWidth - x; + if (width <= 0) { + break; + } + } + + if (y + height > si.framebufferHeight) { + height = si.framebufferHeight - y; + if (height <= 0) { + break; + } + } + + if (appData.useXserverBackingStore) { + SendFramebufferUpdateRequest(x, y, width, height, False); + } else { + 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; case LeaveNotify: - for (i = 0; i < 256; i++) { - if (modifierPressed[i]) { - SendKeyEvent(XKeycodeToKeysym(dpy, i, 0), False); - modifierPressed[i] = False; - } - } - break; + releaseAllPressedModifiers(); + if (appData.fullScreen) { + fs_ungrab(1); + } + break; + case EnterNotify: + if (appData.fullScreen) { + fs_grab(1); + } + break; + case ClientMessage: + if (ev->xclient.window == XtWindow(desktop) && ev->xclient.message_type == XA_INTEGER && + ev->xclient.format == 8 && !strcmp(ev->xclient.data.b, "SendRFBUpdate")) { + SendIncrementalFramebufferUpdateRequest(); + } + break; } + check_things(); } +extern Position desktopX, desktopY; + +void x11vnc_appshare(char *cmd) { + char send[200], str[100]; + char *id = "cmd=id_cmd"; + int m_big = 80, m_fine = 15; + int resize = 100, db = 0; + + if (getenv("X11VNC_APPSHARE_DEBUG")) { + db = atoi(getenv("X11VNC_APPSHARE_DEBUG")); + } + + if (db) fprintf(stderr, "x11vnc_appshare: cmd=%s\n", cmd); + + str[0] = '\0'; + + if (!strcmp(cmd, "left")) { + sprintf(str, "%s:move:-%d+0", id, m_big); + } else if (!strcmp(cmd, "right")) { + sprintf(str, "%s:move:+%d+0", id, m_big); + } else if (!strcmp(cmd, "up")) { + sprintf(str, "%s:move:+0-%d", id, m_big); + } else if (!strcmp(cmd, "down")) { + sprintf(str, "%s:move:+0+%d", id, m_big); + } else if (!strcmp(cmd, "left-fine")) { + sprintf(str, "%s:move:-%d+0", id, m_fine); + } else if (!strcmp(cmd, "right-fine")) { + sprintf(str, "%s:move:+%d+0", id, m_fine); + } else if (!strcmp(cmd, "up-fine")) { + sprintf(str, "%s:move:+0-%d", id, m_fine); + } else if (!strcmp(cmd, "down-fine")) { + sprintf(str, "%s:move:+0+%d", id, m_fine); + } else if (!strcmp(cmd, "taller")) { + sprintf(str, "%s:resize:+0+%d", id, resize); + } else if (!strcmp(cmd, "shorter")) { + sprintf(str, "%s:resize:+0-%d", id, resize); + } else if (!strcmp(cmd, "wider")) { + sprintf(str, "%s:resize:+%d+0", id, resize); + } else if (!strcmp(cmd, "narrower")) { + sprintf(str, "%s:resize:-%d+0", id, resize); + } else if (!strcmp(cmd, "lower")) { + sprintf(str, "%s:lower", id); + } else if (!strcmp(cmd, "raise")) { + sprintf(str, "%s:raise", id); + } else if (!strcmp(cmd, "delete")) { + sprintf(str, "%s:wm_delete", id); + } else if (!strcmp(cmd, "position")) { + Position x, y; + int xi, yi; + + XtVaGetValues(toplevel, XtNx, &x, XtNy, &y, NULL); + xi = (int) x; + yi = (int) y; + if (appData.scale) { + double fx = 1.0, fy = 1.0; + get_scale_values(&fx, &fy); + if (fx > 0.0 && fy > 0.0) { + xi /= fx; + yi /= fx; + } + } + sprintf(str, "%s:geom:0x0+%d+%d", id, xi, yi); + fprintf(stderr, "str=%s\n", str); + } + if (strcmp(str, "")) { + Bool vo = appData.viewOnly; + strcpy(send, "X11VNC_APPSHARE_CMD:"); + strcat(send, str); + if (db) fprintf(stderr, "x11vnc_appshare: send=%s\n", send); + if (vo) appData.viewOnly = False; + SendClientCutText(send, strlen(send)); + if (vo) appData.viewOnly = True; + } +} + +void scroll_desktop(int horiz, int vert, double amount) { + Dimension h, w; + Position x, y; + Position x2, y2; + static int db = -1; + + if (db < 0) { + if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) { + db = 1; + } else { + db = 0; + } + } + + XtVaGetValues(form, XtNheight, &h, XtNwidth, &w, NULL); + XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL); + + x2 = -x; + y2 = -y; + if (amount == -1.0) { + int dx = horiz; + int dy = vert; + if (dx == 0 && dy == 0) { + return; + } + x2 -= dx; + y2 -= dy; + } else { + if (horiz) { + int dx = (int) (amount * w); + if (dx < 0) dx = -dx; + if (amount == 0.0) dx = 1; + if (horiz > 0) { + x2 += dx; + } else { + x2 -= dx; + } + if (x2 < 0) x2 = 0; + } + if (vert) { + int dy = (int) (amount * h); + if (amount == 0.0) dy = 1; + if (dy < 0) dy = -dy; + if (vert < 0) { + y2 += dy; + } else { + y2 -= dy; + } + if (y2 < 0) y2 = 0; + } + } + + if (db) fprintf(stderr, "%d %d %f viewport(%dx%d): %d %d -> %d %d\n", horiz, vert, amount, w, h, -x, -y, x2, y2); + XawViewportSetCoordinates(viewport, x2, y2); + + if (appData.fullScreen) { + XSync(dpy, False); + XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL); + desktopX = -x; + desktopY = -y; + } else if (amount == -1.0) { + XSync(dpy, False); + } +} + +void scale_desktop(int bigger, double frac) { + double current, new; + char tmp[100]; + char *s; + int fs; + + if (appData.scale == NULL) { + s = "1.0"; + } else { + s = appData.scale; + } + if (!strcmp(s, "auto")) { + fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s); + return; + } else if (!strcmp(s, "fit")) { + fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s); + return; + } else if (strstr(s, "x")) { + fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s); + return; + } else if (!strcmp(s, "none")) { + s = "1.0"; + } + + if (sscanf(s, "%lf", ¤t) != 1) { + fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s); + return; + } + if (bigger) { + new = current * (1.0 + frac); + } else { + new = current / (1.0 + frac); + } + if (0.99 < new && new < 1.01) { + new = 1.0; + } + + if (new > 5.0) { + fprintf(stderr, "scale_desktop: not scaling > 5.0: %f\n", new); + return; + } else if (new < 0.05) { + fprintf(stderr, "scale_desktop: not scaling < 0.05: %f\n", new); + return; + } + sprintf(tmp, "%.16f", new); + appData.scale = strdup(tmp); + + fs = 0; + if (appData.fullScreen) { + fs = 1; + FullScreenOff(); + } + if (1) { + double fx, fy; + get_scale_values(&fx, &fy); + if (fx > 0.0 && fy > 0.0) { + rescale_image(); + } + } + if (fs) { + FullScreenOn(); + } +} + +static int escape_mods[8]; +static int escape_drag_in_progress = 0, last_x = 0, last_y = 0; +static double last_drag = 0.0; +static double last_key = 0.0; + +static int escape_sequence_pressed(void) { + static char *prev = NULL; + char *str = "default"; + int sum, i, init = 0, pressed; + static int db = -1; + + if (db < 0) { + if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) { + db = 1; + } else { + db = 0; + } + } + + if (appData.escapeKeys != NULL) { + str = appData.escapeKeys; + } + if (prev == NULL) { + init = 1; + prev = strdup(str); + } else { + if (strcmp(prev, str)) { + init = 1; + free(prev); + prev = strdup(str); + } + } + if (db) fprintf(stderr, "str: %s\n", str); + + if (init) { + char *p, *s; + KeySym ks; + int k = 0, failed = 0; + + for (i = 0; i < 8; i++) { + escape_mods[i] = -1; + } + + if (!strcasecmp(str, "default")) { +#if (defined(__MACH__) && defined(__APPLE__)) + s = strdup("Control_L,Meta_L"); +#else + s = strdup("Alt_L,Super_L"); +#endif + } else { + s = strdup(str); + } + + p = strtok(s, ",+ "); + while (p) { + ks = XStringToKeysym(p); + if (ks == XK_Shift_L || ks == XK_Shift_R) { + putenv("NO_X11VNC_APPSHARE=1"); + } + if (k >= 8) { + fprintf(stderr, "EscapeKeys: more than 8 modifier keys.\n"); + failed = 1; + break; + } + if (ks == NoSymbol) { + fprintf(stderr, "EscapeKeys: failed lookup for '%s'\n", p); + failed = 1; + break; + } else if (!IsModifierKey(ks)) { + fprintf(stderr, "EscapeKeys: not a modifier key '%s'\n", p); + failed = 1; + break; + } else { + KeyCode kc = XKeysymToKeycode(dpy, ks); + if (kc == NoSymbol) { + fprintf(stderr, "EscapeKeys: no keycode for modifier key '%s'\n", p); + failed = 1; + break; + } + if (db) fprintf(stderr, "set: %d %d\n", k, kc); + escape_mods[k++] = kc; + } + + p = strtok(NULL, ",+ "); + } + free(s); + + if (failed) { + for (i = 0; i < 8; i++) { + escape_mods[i] = -1; + } + } + } + + pressed = 1; + sum = 0; + for (i = 0; i < 8; i++) { + int kc = escape_mods[i]; + if (kc != -1 && kc < 256) { + if (db) fprintf(stderr, "try1: %d %d = %d\n", i, kc, modifierPressed[kc]); + if (!modifierPressed[kc]) { + pressed = 0; + break; + } else { + sum++; + } + } + } + if (sum == 0) pressed = 0; + + if (!pressed) { + /* user may have dragged mouse outside of toplevel window */ + int i, k; + int keystate[256]; + char keys[32]; + + /* so query server instead of modifierPressed[] */ + XQueryKeymap(dpy, keys); + for (i=0; i<32; i++) { + char c = keys[i]; + + for (k=0; k < 8; k++) { + if (c & 0x1) { + keystate[8*i + k] = 1; + } else { + keystate[8*i + k] = 0; + } + c = c >> 1; + } + } + + /* check again using keystate[] */ + pressed = 2; + sum = 0; + for (i = 0; i < 8; i++) { + int kc = escape_mods[i]; + if (kc != -1 && kc < 256) { + if (db) fprintf(stderr, "try2: %d %d = %d\n", i, kc, keystate[kc]); + if (!keystate[kc]) { + pressed = 0; + break; + } else { + sum++; + } + } + } + if (sum == 0) pressed = 0; + } + + return pressed; +} + +static int shift_is_down(void) { + int shift_down = 0; + KeyCode kc; + + if (appData.viewOnly) { + int i, k; + char keys[32]; + int keystate[256]; + + XQueryKeymap(dpy, keys); + for (i=0; i<32; i++) { + char c = keys[i]; + + for (k=0; k < 8; k++) { + if (c & 0x1) { + keystate[8*i + k] = 1; + } else { + keystate[8*i + k] = 0; + } + c = c >> 1; + } + } + + kc = XKeysymToKeycode(dpy, XK_Shift_L); + if (kc != NoSymbol && keystate[kc]) { + shift_down = 1; + } else { + kc = XKeysymToKeycode(dpy, XK_Shift_R); + if (kc != NoSymbol && keystate[kc]) { + shift_down = 1; + } + } + return shift_down; + } else { + kc = XKeysymToKeycode(dpy, XK_Shift_L); + if (kc != NoSymbol && modifierPressed[kc]) { + shift_down = 1; + } else { + kc = XKeysymToKeycode(dpy, XK_Shift_R); + if (kc != NoSymbol && modifierPressed[kc]) { + shift_down = 1; + } + } + return shift_down; + } +} + /* * SendRFBEvent is an action which sends an RFB event. It can be used in two * ways. Without any parameters it simply sends an RFB event corresponding to @@ -201,127 +2082,406 @@ * button2 down, 3 for both, etc). */ +extern Bool selectingSingleWindow; + +extern Cursor dotCursor3; +extern Cursor dotCursor4; + +extern void set_server_scale(int); + void SendRFBEvent(Widget w, XEvent *ev, String *params, Cardinal *num_params) { - KeySym ks; - char keyname[256]; - int buttonMask, x, y; - - if (appData.fullScreen && ev->type == MotionNotify) { - if (BumpScroll(ev)) - return; - } + KeySym ks; + char keyname[256]; + int buttonMask, x, y; + int do_escape; + static int db = -1; + char *ek = appData.escapeKeys; + + if (db < 0) { + if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) { + db = 1; + } else { + db = 0; + } + } + + 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 (selectingSingleWindow && ev->type == ButtonPress) { + selectingSingleWindow = False; + SendSingleWindow(ev->xbutton.x, ev->xbutton.y); + if (appData.viewOnly) { + XDefineCursor(dpy, desktopWin, dotCursor4); + } else { + XDefineCursor(dpy, desktopWin, dotCursor3); + } + return; + } + + if (appData.fullScreen && ev->type == MotionNotify && !escape_drag_in_progress) { + if (BumpScroll(ev)) { + return; + } + } + + do_escape = 0; + if (ek != NULL && (ek[0] == 'n' || ek[0] == 'N') && !strcasecmp(ek, "never")) { + ; + } else if (appData.viewOnly) { + do_escape = 1; + } else if (appData.escapeActive) { + int skip = 0, is_key = 0; + + if (ev->type == KeyPress || ev->type == KeyRelease) { + is_key = 1; + XLookupString(&ev->xkey, keyname, 256, &ks, NULL); + if (IsModifierKey(ks)) { + skip = 1; + } + } + if (!skip) { + int es = escape_sequence_pressed(); + if (es == 1) { + do_escape = 1; + } else if (es == 2) { + if (is_key) { + if (dnow() < last_key + 5.0) { + do_escape = 1; + } + } else { + if (dnow() < last_drag + 5.0) { + do_escape = 1; + } + } + } + } + } + if (!do_escape) { + escape_drag_in_progress = 0; + } + if (db) fprintf(stderr, "do_escape: %d\n", do_escape); + + if (do_escape) { + int W = si.framebufferWidth; + int H = si.framebufferHeight; + int shift_down = 0; + + if (!getenv("NO_X11VNC_APPSHARE")) { + shift_down = shift_is_down(); + } + if (db) fprintf(stderr, "shift_down: %d\n", shift_down); + + if (*num_params != 0) { + if (strcasecmp(params[0],"fbupdate") == 0) { + SendFramebufferUpdateRequest(0, 0, W, H, False); + } + } + if (ev->type == ButtonRelease) { + XButtonEvent *b = (XButtonEvent *) ev; + if (db) fprintf(stderr, "ButtonRelease: %d %d %d\n", b->x_root, b->y_root, b->state); + if (b->button == 3) { + if (shift_down) { + x11vnc_appshare("delete"); + } else { + ShowPopup(w, ev, params, num_params); + } + } else if (escape_drag_in_progress && b->button == 1) { + escape_drag_in_progress = 0; + } + } else if (ev->type == ButtonPress) { + XButtonEvent *b = (XButtonEvent *) ev; + if (db) fprintf(stderr, "ButtonPress: %d %d %d\n", b->x_root, b->y_root, b->state); + if (b->button == 1) { + if (shift_down) { + x11vnc_appshare("position"); + } else { + escape_drag_in_progress = 1; + last_x = b->x_root; + last_y = b->y_root; + } + } else { + escape_drag_in_progress = 0; + } + } else if (ev->type == MotionNotify) { + XMotionEvent *m = (XMotionEvent *) ev; + if (escape_drag_in_progress) { + if (db) fprintf(stderr, "MotionNotify: %d %d %d\n", m->x_root, m->y_root, m->state); + scroll_desktop(m->x_root - last_x, m->y_root - last_y, -1.0); + last_x = m->x_root; + last_y = m->y_root; + } + } else if (ev->type == KeyRelease) { + int did = 1; + + XLookupString(&ev->xkey, keyname, 256, &ks, NULL); + if (ks == XK_1 || ks == XK_KP_1) { + set_server_scale(1); + } else if (ks == XK_2 || ks == XK_KP_2) { + set_server_scale(2); + } else if (ks == XK_3 || ks == XK_KP_3) { + set_server_scale(3); + } else if (ks == XK_4 || ks == XK_KP_4) { + set_server_scale(4); + } else if (ks == XK_5 || ks == XK_KP_5) { + set_server_scale(5); + } else if (ks == XK_6 || ks == XK_KP_6) { + set_server_scale(6); + } else if (ks == XK_r || ks == XK_R) { + SendFramebufferUpdateRequest(0, 0, W, H, False); + } else if (ks == XK_b || ks == XK_B) { + ToggleBell(w, ev, params, num_params); + } else if (ks == XK_c || ks == XK_C) { + Toggle8bpp(w, ev, params, num_params); + } else if (ks == XK_x || ks == XK_X) { + ToggleX11Cursor(w, ev, params, num_params); + } else if (ks == XK_z || ks == XK_Z) { + ToggleTightZRLE(w, ev, params, num_params); + } else if (ks == XK_h || ks == XK_H) { + ToggleTightHextile(w, ev, params, num_params); + } else if (ks == XK_f || ks == XK_F) { + ToggleFileXfer(w, ev, params, num_params); + } else if (ks == XK_V) { + ToggleViewOnly(w, ev, params, num_params); + } else if (ks == XK_Q) { + Quit(w, ev, params, num_params); + } else if (ks == XK_l || ks == XK_L) { + ToggleFullScreen(w, ev, params, num_params); + } else if (ks == XK_a || ks == XK_A) { + ToggleCursorAlpha(w, ev, params, num_params); + } else if (ks == XK_s || ks == XK_S) { + SetScale(w, ev, params, num_params); + } else if (ks == XK_t || ks == XK_T) { + ToggleTextChat(w, ev, params, num_params); + } else if (ks == XK_e || ks == XK_E) { + SetEscapeKeys(w, ev, params, num_params); + } else if (ks == XK_g || ks == XK_G) { + ToggleXGrab(w, ev, params, num_params); + } else if (ks == XK_D) { + if (shift_down || appData.appShare) { + x11vnc_appshare("delete"); + } + } else if (ks == XK_M) { + if (shift_down || appData.appShare) { + x11vnc_appshare("position"); + } + } else if (ks == XK_Left) { + if (shift_down) { + x11vnc_appshare("left"); + } else { + scroll_desktop(-1, 0, 0.1); + } + } else if (ks == XK_Right) { + if (shift_down) { + x11vnc_appshare("right"); + } else { + scroll_desktop(+1, 0, 0.1); + } + } else if (ks == XK_Up) { + if (shift_down) { + x11vnc_appshare("up"); + } else { + scroll_desktop(0, +1, 0.1); + } + } else if (ks == XK_Down) { + if (shift_down) { + x11vnc_appshare("down"); + } else { + scroll_desktop(0, -1, 0.1); + } + } else if (ks == XK_KP_Left) { + if (shift_down) { + x11vnc_appshare("left-fine"); + } else { + scroll_desktop(-1, 0, 0.0); + } + } else if (ks == XK_KP_Right) { + if (shift_down) { + x11vnc_appshare("right-fine"); + } else { + scroll_desktop(+1, 0, 0.0); + } + } else if (ks == XK_KP_Up) { + if (shift_down) { + x11vnc_appshare("up-fine"); + } else { + scroll_desktop(0, +1, 0.0); + } + } else if (ks == XK_KP_Down) { + if (shift_down) { + x11vnc_appshare("down-fine"); + } else { + scroll_desktop(0, -1, 0.0); + } + } else if (ks == XK_Next || ks == XK_KP_Next) { + if (shift_down && ks == XK_Next) { + x11vnc_appshare("shorter"); + } else { + scroll_desktop(0, -1, 1.0); + } + } else if (ks == XK_Prior || ks == XK_KP_Prior) { + if (shift_down && ks == XK_Prior) { + x11vnc_appshare("taller"); + } else { + scroll_desktop(0, +1, 1.0); + } + } else if (ks == XK_End || ks == XK_KP_End) { + if (shift_down && ks == XK_End) { + x11vnc_appshare("narrower"); + } else { + scroll_desktop(+1, 0, 1.0); + } + } else if (ks == XK_Home || ks == XK_KP_Home) { + if (shift_down && ks == XK_Home) { + x11vnc_appshare("wider"); + } else { + scroll_desktop(-1, 0, 1.0); + } + } else if (ks == XK_equal || ks == XK_plus) { + if (shift_down) { + x11vnc_appshare("raise"); + } else { + scale_desktop(1, 0.1); + } + } else if (ks == XK_underscore || ks == XK_minus) { + if (shift_down) { + x11vnc_appshare("lower"); + } else { + scale_desktop(0, 0.1); + } + } else { + did = 0; + } + if (did) { + last_key = dnow(); + } + } + if (escape_drag_in_progress) { + last_drag = dnow(); + } + return; + } + if (appData.viewOnly) { + return; + } - if (appData.viewOnly) return; + if (*num_params != 0) { + if (strncasecmp(params[0],"key",3) == 0) { + if (*num_params != 2) { + fprintf(stderr, "Invalid params: " + "SendRFBEvent(key|keydown|keyup,)\n"); + return; + } + ks = XStringToKeysym(params[1]); + if (ks == NoSymbol) { + fprintf(stderr,"Invalid keysym '%s' passed to " + "SendRFBEvent\n", params[1]); + return; + } + if (strcasecmp(params[0],"keydown") == 0) { + SendKeyEvent(ks, 1); + } else if (strcasecmp(params[0],"keyup") == 0) { + SendKeyEvent(ks, 0); + } else if (strcasecmp(params[0],"key") == 0) { + SendKeyEvent(ks, 1); + SendKeyEvent(ks, 0); + } else { + fprintf(stderr,"Invalid event '%s' passed to " + "SendRFBEvent\n", params[0]); + return; + } + } else if (strcasecmp(params[0],"fbupdate") == 0) { + if (*num_params != 1) { + fprintf(stderr, "Invalid params: " + "SendRFBEvent(fbupdate)\n"); + return; + } + SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, + si.framebufferHeight, False); + + } else if (strcasecmp(params[0],"ptr") == 0) { + if (*num_params == 4) { + x = atoi(params[1]); + y = atoi(params[2]); + buttonMask = atoi(params[3]); + SendPointerEvent(x, y, buttonMask); + } else if (*num_params == 2) { + switch (ev->type) { + case ButtonPress: + case ButtonRelease: + x = ev->xbutton.x; + y = ev->xbutton.y; + break; + case KeyPress: + case KeyRelease: + x = ev->xkey.x; + y = ev->xkey.y; + break; + default: + fprintf(stderr, "Invalid event caused " + "SendRFBEvent(ptr,)\n"); + return; + } + buttonMask = atoi(params[1]); + SendPointerEvent(x, y, buttonMask); + } else { + fprintf(stderr, "Invalid params: " + "SendRFBEvent(ptr,,,)\n" + " or SendRFBEvent(ptr,)\n"); + return; + } + } else { + fprintf(stderr,"Invalid event '%s' passed to " + "SendRFBEvent\n", params[0]); + } + return; + } - if (*num_params != 0) { - if (strncasecmp(params[0],"key",3) == 0) { - if (*num_params != 2) { - fprintf(stderr, - "Invalid params: SendRFBEvent(key|keydown|keyup,)\n"); - return; - } - ks = XStringToKeysym(params[1]); - if (ks == NoSymbol) { - fprintf(stderr,"Invalid keysym '%s' passed to SendRFBEvent\n", - params[1]); - return; - } - if (strcasecmp(params[0],"keydown") == 0) { - SendKeyEvent(ks, 1); - } else if (strcasecmp(params[0],"keyup") == 0) { - SendKeyEvent(ks, 0); - } else if (strcasecmp(params[0],"key") == 0) { - SendKeyEvent(ks, 1); - SendKeyEvent(ks, 0); - } else { - fprintf(stderr,"Invalid event '%s' passed to SendRFBEvent\n", - params[0]); - return; - } - } else if (strcasecmp(params[0],"fbupdate") == 0) { - if (*num_params != 1) { - fprintf(stderr, "Invalid params: SendRFBEvent(fbupdate)\n"); - return; - } - SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, - si.framebufferHeight, False); - } else if (strcasecmp(params[0],"ptr") == 0) { - if (*num_params == 4) { - x = atoi(params[1]); - y = atoi(params[2]); - buttonMask = atoi(params[3]); - SendPointerEvent(x, y, buttonMask); - } else if (*num_params == 2) { switch (ev->type) { + case MotionNotify: + while (XCheckTypedWindowEvent(dpy, desktopWin, MotionNotify, ev)) { + ; /* discard all queued motion notify events */ + } + + SendPointerEvent(ev->xmotion.x, ev->xmotion.y, + (ev->xmotion.state & 0x1f00) >> 8); + return; + case ButtonPress: + SendPointerEvent(ev->xbutton.x, ev->xbutton.y, + (((ev->xbutton.state & 0x1f00) >> 8) | + (1 << (ev->xbutton.button - 1)))); + return; + case ButtonRelease: - x = ev->xbutton.x; - y = ev->xbutton.y; - break; + SendPointerEvent(ev->xbutton.x, ev->xbutton.y, + (((ev->xbutton.state & 0x1f00) >> 8) & + ~(1 << (ev->xbutton.button - 1)))); + return; + case KeyPress: case KeyRelease: - x = ev->xkey.x; - y = ev->xkey.y; - break; - default: - fprintf(stderr, - "Invalid event caused SendRFBEvent(ptr,)\n"); - return; - } - buttonMask = atoi(params[1]); - SendPointerEvent(x, y, buttonMask); - } else { - fprintf(stderr, - "Invalid params: SendRFBEvent(ptr,,,)\n" - " or SendRFBEvent(ptr,)\n"); - return; - } - - } else { - fprintf(stderr,"Invalid event '%s' passed to SendRFBEvent\n", params[0]); - } - return; - } - - switch (ev->type) { + XLookupString(&ev->xkey, keyname, 256, &ks, NULL); - case MotionNotify: - while (XCheckTypedWindowEvent(dpy, desktopWin, MotionNotify, ev)) - ; /* discard all queued motion notify events */ - - SendPointerEvent(ev->xmotion.x, ev->xmotion.y, - (ev->xmotion.state & 0x1f00) >> 8); - return; - - case ButtonPress: - SendPointerEvent(ev->xbutton.x, ev->xbutton.y, - (((ev->xbutton.state & 0x1f00) >> 8) | - (1 << (ev->xbutton.button - 1)))); - return; - - case ButtonRelease: - SendPointerEvent(ev->xbutton.x, ev->xbutton.y, - (((ev->xbutton.state & 0x1f00) >> 8) & - ~(1 << (ev->xbutton.button - 1)))); - return; - - case KeyPress: - case KeyRelease: - XLookupString(&ev->xkey, keyname, 256, &ks, NULL); - - if (IsModifierKey(ks)) { - ks = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0); - modifierPressed[ev->xkey.keycode] = (ev->type == KeyPress); - } + if (IsModifierKey(ks)) { + ks = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0); + modifierPressed[ev->xkey.keycode] = (ev->type == KeyPress); + } - SendKeyEvent(ks, (ev->type == KeyPress)); - return; + SendKeyEvent(ks, (ev->type == KeyPress)); + return; - default: - fprintf(stderr,"Invalid event passed to SendRFBEvent\n"); - } + default: + fprintf(stderr,"Invalid event passed to SendRFBEvent\n"); + } } @@ -329,26 +2489,207 @@ * CreateDotCursor. */ +#ifndef very_small_dot_cursor +static Cursor +CreateDotCursor(int which) +{ + Cursor cursor; + Pixmap src, msk; + static char srcBits3[] = { 0x00, 0x02, 0x00 }; + static char mskBits3[] = { 0x02, 0x07, 0x02 }; + static char srcBits4[] = { 0x00, 0x06, 0x06, 0x00 }; + static char mskBits4[] = { 0x06, 0x0f, 0x0f, 0x06 }; + XColor fg, bg; + + if (which == 3) { + src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits3, 3, 3); + msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits3, 3, 3); + } else { + src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits4, 4, 4); + msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits4, 4, 4); + } + XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "black", + &fg, &fg); + XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "white", + &bg, &bg); + cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 1, 1); + XFreePixmap(dpy, src); + XFreePixmap(dpy, msk); + + return cursor; +} +#else static Cursor CreateDotCursor() { - Cursor cursor; - Pixmap src, msk; - static char srcBits[] = { 0, 14,14,14, 0 }; - static char mskBits[] = { 14,31,31,31,14 }; - XColor fg, bg; - - src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits, 5, 5); - msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits, 5, 5); - XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "black", - &fg, &fg); - XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "white", - &bg, &bg); - cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 2, 2); - XFreePixmap(dpy, src); - XFreePixmap(dpy, msk); + Cursor cursor; + Pixmap src, msk; + static char srcBits[] = { 0, 14, 0 }; + static char mskBits[] = { 14,31,14 }; + XColor fg, bg; + + src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits, 3, 3); + msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits, 3, 3); + XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "black", + &fg, &fg); + XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "white", + &bg, &bg); + cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 1, 1); + XFreePixmap(dpy, src); + XFreePixmap(dpy, msk); + + return cursor; +} +#endif + +int skip_maybe_sync = 0; +void maybe_sync(int width, int height) { + static int singles = 0, always_skip = -1; + int singles_max = 64; + + if (always_skip < 0) { + if (getenv("SSVNC_NO_MAYBE_SYNC")) { + always_skip = 1; + } else { + always_skip = 0; + } + } + if (skip_maybe_sync || always_skip) { + return; + } +#if 0 + if (width > 1 || height > 1) { + XSync(dpy, False); + singles = 0; + } else { + if (++singles >= singles_max) { + singles = 0; + XSync(dpy, False); + } + } +#else + if (width * height >= singles_max) { + XSync(dpy, False); + singles = 0; + } else { + singles += width * height; + if (singles >= singles_max) { + XSync(dpy, False); + singles = 0; + } + } +#endif +} +/* + * FillImage. + */ + +void +FillScreen(int x, int y, int width, int height, unsigned long fill) +{ + 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; + unsigned char *ucp; + unsigned short *usp; + unsigned int *uip; + char *scr; + 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; + } - return cursor; + if (widthInBytes > buflen || !buf) { + if (buf) { + free(buf); + } + buflen = widthInBytes * 2; + buf = (char *)malloc(buflen); + } + ucp = (unsigned char*) buf; + usp = (unsigned short*) buf; + uip = (unsigned int*) buf; + + if (isLSB) { + b0 = 0; b1 = 1; b2 = 2; + } else { + b0 = 2; b1 = 1; b2 = 0; + } + + for (h = 0; h < width; h++) { + if (bpp == 8) { + *(ucp+h) = (unsigned char) fill; + } else if (bpp == 16) { + *(usp+h) = (unsigned short) fill; + } else if (bpp == 24) { + *(ucp + 3*h + b0) = (unsigned char) ((fill & 0x0000ff) >> 0); + *(ucp + 3*h + b1) = (unsigned char) ((fill & 0x00ff00) >> 8); + *(ucp + 3*h + b2) = (unsigned char) ((fill & 0xff0000) >> 16); + } else if (bpp == 32) { + *(uip+h) = (unsigned int) fill; + } + } + + 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, 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; + 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 = 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 = 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 +2700,39 @@ void CopyDataToScreen(char *buf, int x, int y, int width, int height) { - if (appData.rawDelay != 0) { - XFillRectangle(dpy, desktopWin, gc, x, y, width, height); - - XSync(dpy,False); - - usleep(appData.rawDelay * 1000); - } + if (appData.chatOnly) { + return; + } + if (appData.rawDelay != 0) { + XFillRectangle(dpy, desktopWin, gc, x, y, width, height); + XSync(dpy,False); + usleep(appData.rawDelay * 1000); + } - if (!appData.useBGR233) { - int h; - int widthInBytes = width * myFormat.bitsPerPixel / 8; - int scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8; - - char *scr = (image->data + y * scrWidthInBytes - + x * myFormat.bitsPerPixel / 8); - - for (h = 0; h < height; h++) { - memcpy(scr, buf, widthInBytes); - buf += widthInBytes; - scr += scrWidthInBytes; - } - } else { - CopyBGR233ToScreen((CARD8 *)buf, x, y, width, height); - } + if (appData.useBGR233) { + CopyBGR233ToScreen((CARD8 *)buf, x, y, width, height); + } else if (appData.useBGR565) { + CopyBGR565ToScreen((CARD16 *)buf, x, y, width, height); + } else { + int h; + int widthInBytes = width * myFormat.bitsPerPixel / 8; + int scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8; + XImage *im = image_scale ? image_scale : image; + + if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line; + + char *scr = (im->data + y * scrWidthInBytes + + x * myFormat.bitsPerPixel / 8); + + for (h = 0; h < height; h++) { + memcpy(scr, buf, widthInBytes); + buf += widthInBytes; + scr += scrWidthInBytes; + } + } -#ifdef MITSHM - if (appData.useShm) { - XShmPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height, False); - return; - } -#endif - XPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height); + put_image(x, y, x, y, width, height, 0); + maybe_sync(width, height); } @@ -401,62 +2743,339 @@ static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width, int height) { - int p, q; - int xoff = 7 - (x & 7); - int xcur; - int fbwb = si.framebufferWidth / 8; - CARD8 *scr1 = ((CARD8 *)image->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; + XImage *im = image_scale ? image_scale : image; + int p, q; + int xoff = 7 - (x & 7); + int xcur; + int fbwb = si.framebufferWidth / 8; + int src_width8 = im->bytes_per_line/1; + int src_width16 = im->bytes_per_line/2; + int src_width32 = im->bytes_per_line/4; + CARD8 *src1 = ((CARD8 *)im->data) + y * fbwb + x / 8; + CARD8 *srct; + CARD8 *src8 = ( (CARD8 *)im->data) + y * src_width8 + x; + CARD16 *src16 = ((CARD16 *)im->data) + y * src_width16 + x; + CARD32 *src32 = ((CARD32 *)im->data) + y * src_width32 + x; + int b0, b1, b2; - switch (visbpp) { + switch (visbpp) { /* thanks to Chris Hooper for single bpp support */ - case 1: - for (q = 0; q < height; q++) { - xcur = xoff; - scrt = scr1; - for (p = 0; p < width; p++) { - *scrt = ((*scrt & ~(1 << xcur)) - | (BGR233ToPixel[*(buf++)] << xcur)); - - if (xcur-- == 0) { - xcur = 7; - scrt++; - } - } - scr1 += fbwb; - } - break; - - case 8: - for (q = 0; q < height; q++) { - for (p = 0; p < width; p++) { - *(scr8++) = BGR233ToPixel[*(buf++)]; - } - scr8 += si.framebufferWidth - width; - } - break; - - case 16: - for (q = 0; q < height; q++) { - for (p = 0; p < width; p++) { - *(scr16++) = BGR233ToPixel[*(buf++)]; - } - scr16 += si.framebufferWidth - width; - } - break; - - case 32: - for (q = 0; q < height; q++) { - for (p = 0; p < width; p++) { - *(scr32++) = BGR233ToPixel[*(buf++)]; - } - scr32 += si.framebufferWidth - width; - } - break; - } + case 1: + for (q = 0; q < height; q++) { + xcur = xoff; + srct = src1; + for (p = 0; p < width; p++) { + *srct = ((*srct & ~(1 << xcur)) + | (BGR233ToPixel[*(buf++)] << xcur)); + + if (xcur-- == 0) { + xcur = 7; + srct++; + } + } + src1 += fbwb; + } + break; + + case 8: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(src8++) = BGR233ToPixel[*(buf++)]; + } + src8 += src_width8 - width; + } + break; + + case 16: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(src16++) = BGR233ToPixel[*(buf++)]; + } + src16 += src_width16 - width; + } + break; + + case 24: + if (isLSB) { + b0 = 0; b1 = 1; b2 = 2; + } else { + b0 = 2; b1 = 1; b2 = 0; + } + src8 = ((CARD8 *)im->data) + (y * si.framebufferWidth + x) * 3; + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + CARD32 v = BGR233ToPixel[*(buf++)]; + *(src8 + b0) = (unsigned char) ((v & 0x0000ff) >> 0); + *(src8 + b1) = (unsigned char) ((v & 0x00ff00) >> 8); + *(src8 + b2) = (unsigned char) ((v & 0xff0000) >> 16); + src8 += 3; + } + src8 += (si.framebufferWidth - width) * 3; + } + break; + + case 32: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(src32++) = BGR233ToPixel[*(buf++)]; + } + src32 += src_width32 - width; + } + break; + } +} + +static void +BGR565_24bpp(CARD16 *buf, int x, int y, int width, int height) +{ + int p, q; + int b0, b1, b2; + XImage *im = image_scale ? image_scale : image; + unsigned char *src= (unsigned char *)im->data + (y * si.framebufferWidth + x) * 3; + + if (isLSB) { + b0 = 0; b1 = 1; b2 = 2; + } else { + b0 = 2; b1 = 1; b2 = 0; + } + + /* case 24: */ + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + CARD32 v = BGR565ToPixel[*(buf++)]; + *(src + b0) = (unsigned char) ((v & 0x0000ff) >> 0); + *(src + b1) = (unsigned char) ((v & 0x00ff00) >> 8); + *(src + b2) = (unsigned char) ((v & 0xff0000) >> 16); + src += 3; + } + src += (si.framebufferWidth - width) * 3; + } +} + +static void +CopyBGR565ToScreen(CARD16 *buf, int x, int y, int width, int height) +{ + int p, q; + XImage *im = image_scale ? image_scale : image; + int src_width32 = im->bytes_per_line/4; + CARD32 *src32 = ((CARD32 *)im->data) + y * src_width32 + x; + + if (visbpp == 24) { + BGR565_24bpp(buf, x, y, width, height); + return; + } + + /* case 32: */ + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(src32++) = BGR565ToPixel[*(buf++)]; + } + src32 += src_width32 - width; + } +} + +static void reset_image(void) { + if (UsingShm()) { + ShmDetach(); + } + 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; + + if (UsingShm()) { + ShmCleanup(); + } + create_image(); + XFlush(dpy); +} + +void ReDoDesktop(void) { + int w, w0, h, h0, x, y, dw, dh; + int fs = 0; + int autoscale = 0; + Position x_orig, y_orig; + Dimension w_orig, h_orig; + + if (!appData.fullScreen && appData.scale != NULL && !strcmp(appData.scale, "auto")) { + autoscale = 1; + } + + fprintf(stderr, "ReDoDesktop: ycrop: %d\n", appData.yCrop); + + XtVaGetValues(toplevel, XtNx, &x_orig, XtNy, &y_orig, NULL); + XtVaGetValues(toplevel, XtNheight, &h_orig, XtNwidth, &w_orig, NULL); + + check_tall(); + + if (appData.yCrop) { + if (appData.yCrop < 0 || old_width <= 0) { + appData.yCrop = guessCrop(); + fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop); + } else { + int w1 = si.framebufferWidth; + int w0 = old_width; + appData.yCrop = (w1 * appData.yCrop) / old_width; + if (appData.yCrop <= 100) { + appData.yCrop = guessCrop(); + fprintf(stderr, "Set small -ycrop to: %d\n", appData.yCrop); + } + } + 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; + int w = image->width; + len = image->bytes_per_line * image->height; + /* black out window first: */ + memset(image->data, 0, len); + XPutImage(dpy, XtWindow(desktop), gc, image, 0, 0, 0, 0, w, h); + XFlush(dpy); + } + + /* XXX scaling?? */ + XtResizeWidget(desktop, xmax, ymax, 0); + + XSync(dpy, False); + usleep(100*1000); + FullScreenOn(); + XSync(dpy, False); + usleep(100*1000); + reset_image(); + return; + } + + dw = appData.wmDecorationWidth; + dh = appData.wmDecorationHeight; + + w = si.framebufferWidth; + h = si.framebufferHeight; + w0 = w; + h0 = h; + if (appData.yCrop > 0) { + h = appData.yCrop; + } + if (image_scale) { + w = scale_round(w, scale_factor_x); + h = scale_round(h, scale_factor_y); + w0 = scale_round(w0, scale_factor_x); + h0 = scale_round(h0, scale_factor_y); + } + + if (w + dw >= dpyWidth) { + w = dpyWidth - dw; + } + if (h + dh >= dpyHeight) { + h = dpyHeight - dh; + } + + if (!autoscale) { + XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL); + } else { + XtVaSetValues(toplevel, XtNmaxWidth, dpyWidth, XtNmaxHeight, dpyHeight, NULL); + } + + XtVaSetValues(desktop, XtNwidth, w0, XtNheight, h0, NULL); + + XtResizeWidget(desktop, w0, h0, 0); + + if (appData.yCrop > 0) { + int ycrop = appData.yCrop; + if (image_scale) { + ycrop *= scale_factor_y; + } + XtVaSetValues(toplevel, XtNmaxHeight, ycrop, NULL); + XtVaSetValues(form, XtNmaxHeight, ycrop, NULL); + } + + x = (dpyWidth - w - dw)/2; + y = (dpyHeight - h - dh)/2; + + if (!autoscale) { + + if (!getenv("VNCVIEWER_ALWAYS_RECENTER")) { + int x_cm_old, y_cm_old; + int x_cm_new, y_cm_new; + int x_try, y_try; + + x_cm_old = (int) x_orig + ((int) w_orig)/2; + y_cm_old = (int) y_orig + ((int) h_orig)/2; + + x_cm_new = dpyWidth/2; + y_cm_new = dpyHeight/2; + + x_try = x + (x_cm_old - x_cm_new); + y_try = y + (y_cm_old - y_cm_new); + if (x_try < 0) { + x_try = 0; + } + if (y_try < 0) { + y_try = 0; + } + if (x_try + w + dw > dpyWidth) { + x_try = dpyWidth - w - dw; + } + if (y_try + h + dh > dpyHeight) { + y_try = dpyHeight - h - dh; + } + x = x_try; + y = y_try; + } + + 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 2009-10-27 00:14:05.000000000 -0400 @@ -25,75 +25,549 @@ #include static Bool serverDialogDone = False; +static Bool userDialogDone = False; static Bool passwordDialogDone = False; +static Bool ycropDialogDone = False; +static Bool scaleDialogDone = False; +static Bool escapeDialogDone = False; +static Bool scbarDialogDone = False; +static Bool scaleNDialogDone = False; +static Bool qualityDialogDone = False; +static Bool compressDialogDone = False; + +extern void popupFixer(Widget wid); + +int use_tty(void) { + if (appData.notty) { + return 0; + } else if (!isatty(0)) { + return 0; + } + return 1; +} + +void +ScaleDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + scaleDialogDone = True; +} + +void +EscapeDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + escapeDialogDone = 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; +} + +static void rmNL(char *s) { + int len; + if (s == NULL) { + return; + } + len = strlen(s); + if (len > 0 && s[len-1] == '\n') { + s[len-1] = '\0'; + } +} + +static void wm_delete(Widget w, char *func) { + char str[1024]; + Atom wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + XSetWMProtocols(dpy, XtWindow(w), &wmDeleteWindow, 1); + if (func) { + sprintf(str, "WM_PROTOCOLS: %s", func); + XtOverrideTranslations(w, XtParseTranslationTable (str)); + } +} + +static void xtmove(Widget w) { + XtMoveWidget(w, WidthOfScreen(XtScreen(w))*2/5, HeightOfScreen(XtScreen(w))*2/5); +} + +char * +DoScaleDialog() +{ + Widget pshell, dialog; + char *scaleValue; + char *valueString; + + pshell = XtVaCreatePopupShell("scaleDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + + if (0) 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 (1 && appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "ScaleDialogDone()"); + + scaleDialogDone = False; + + while (!scaleDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + scaleValue = XtNewString(valueString); + + XtPopdown(pshell); + return scaleValue; +} + +char * +DoEscapeKeysDialog() +{ + Widget pshell, dialog; + char *escapeValue; + char *valueString; + char *curr = appData.escapeKeys ? appData.escapeKeys : "default"; + + pshell = XtVaCreatePopupShell("escapeDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (curr != NULL) { + String label; + char tmp[3010]; + XtVaGetValues(dialog, XtNlabel, &label, NULL); + if (strlen(label) + strlen(curr) < 3000) { + sprintf(tmp, "%s %s", label, curr); + XtVaSetValues(dialog, XtNlabel, tmp, NULL); + } + } + + if (appData.popupFix) { + popupFixer(pshell); + } else { + /* too big */ + if (0) xtmove(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "EscapeDialogDone()"); + + escapeDialogDone = False; + + while (!escapeDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + escapeValue = XtNewString(valueString); + + XtPopdown(pshell); + return escapeValue; +} + +void +YCropDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + ycropDialogDone = True; +} + +char * +DoYCropDialog() +{ + Widget pshell, dialog; + char *ycropValue; + char *valueString; + + pshell = XtVaCreatePopupShell("ycropDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (1 && appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "YCropDialogDone()"); + + ycropDialogDone = False; + + while (!ycropDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + ycropValue = XtNewString(valueString); + + XtPopdown(pshell); + return ycropValue; +} + +void +ScbarDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + scbarDialogDone = True; +} + +char * +DoScbarDialog() +{ + Widget pshell, dialog; + char *scbarValue; + char *valueString; + + pshell = XtVaCreatePopupShell("scbarDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (1 && appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "ScbarDialogDone()"); + + scbarDialogDone = False; + + while (!scbarDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + scbarValue = XtNewString(valueString); + + XtPopdown(pshell); + return scbarValue; +} + +void +ScaleNDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + scaleNDialogDone = True; +} + +char * +DoScaleNDialog() +{ + Widget pshell, dialog; + char *scaleNValue; + char *valueString; + + pshell = XtVaCreatePopupShell("scaleNDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + wm_delete(pshell, "ScaleNDialogDone()"); + + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "ScaleNDialogDone()"); + + scaleNDialogDone = False; + + while (!scaleNDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + scaleNValue = XtNewString(valueString); + + XtPopdown(pshell); + return scaleNValue; +} + +void +QualityDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + qualityDialogDone = True; +} + +char * +DoQualityDialog() +{ + Widget pshell, dialog; + char *qualityValue; + char *valueString; + + pshell = XtVaCreatePopupShell("qualityDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (1 && appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "QualityDialogDone() HideQuality()"); + + qualityDialogDone = False; + + while (!qualityDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + qualityValue = XtNewString(valueString); + + XtPopdown(pshell); + return qualityValue; +} + +void +CompressDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + compressDialogDone = True; +} + +char * +DoCompressDialog() +{ + Widget pshell, dialog; + char *compressValue; + char *valueString; + + fprintf(stderr, "compress start:\n"); + + pshell = XtVaCreatePopupShell("compressDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (1 && appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "CompressDialogDone() HideCompress()"); + + compressDialogDone = False; + + while (!compressDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + compressValue = XtNewString(valueString); + + fprintf(stderr, "compress done: %s\n", compressValue); + + XtPopdown(pshell); + return compressValue; +} void ServerDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) { - serverDialogDone = True; + serverDialogDone = True; } char * DoServerDialog() { - Widget pshell, dialog; - char *vncServerName; - char *valueString; + Widget pshell, dialog; + char *vncServerName; + char *valueString; - pshell = XtVaCreatePopupShell("serverDialog", transientShellWidgetClass, + pshell = XtVaCreatePopupShell("serverDialog", transientShellWidgetClass, toplevel, NULL); - dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); - XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, - HeightOfScreen(XtScreen(pshell))*2/5); - XtPopup(pshell, XtGrabNonexclusive); - XtRealizeWidget(pshell); + dialog_over(pshell); - serverDialogDone = False; + if (0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (0 && appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + //dialog_input(pshell); + wm_delete(pshell, "ServerDialogDone()"); + + serverDialogDone = False; + + while (!serverDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + vncServerName = XtNewString(valueString); - while (!serverDialogDone) { - XtAppProcessEvent(appContext, XtIMAll); - } + XtPopdown(pshell); + return vncServerName; +} - valueString = XawDialogGetValueString(dialog); - vncServerName = XtNewString(valueString); +void +UserDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + userDialogDone = True; +} - XtPopdown(pshell); - return vncServerName; +char * +DoUserDialog() +{ + Widget pshell, dialog; + char *userName; + char *valueString; + + pshell = XtVaCreatePopupShell("userDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (0 && appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + //dialog_input(pshell); + wm_delete(pshell, "UserDialogDone()"); + + userDialogDone = False; + + while (!userDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + userName = XtNewString(valueString); + + XtPopdown(pshell); + return userName; } void PasswordDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) { - passwordDialogDone = True; + passwordDialogDone = True; } char * DoPasswordDialog() { - Widget pshell, dialog; - char *password; - char *valueString; + Widget pshell, dialog; + char *password; + char *valueString; - pshell = XtVaCreatePopupShell("passwordDialog", transientShellWidgetClass, + pshell = XtVaCreatePopupShell("passwordDialog", transientShellWidgetClass, toplevel, NULL); - dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); - - XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, - HeightOfScreen(XtScreen(pshell))*2/5); - XtPopup(pshell, XtGrabNonexclusive); - XtRealizeWidget(pshell); - - passwordDialogDone = False; + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); - while (!passwordDialogDone) { - XtAppProcessEvent(appContext, XtIMAll); - } + dialog_over(pshell); - valueString = XawDialogGetValueString(dialog); - password = XtNewString(valueString); + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (0 && appData.popupFix) { + popupFixer(pshell); + } else { + xtmove(pshell); + } + //dialog_input(pshell); + wm_delete(pshell, "PasswordDialogDone()"); + + passwordDialogDone = False; + + while (!passwordDialogDone) { + XtAppProcessEvent(appContext, XtIMAll); + } + + valueString = XawDialogGetValueString(dialog); + rmNL(valueString); + password = XtNewString(valueString); - XtPopdown(pshell); - return password; + XtPopdown(pshell); + return password; } 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-10-25 18:22:14.000000000 -0400 @@ -27,15 +27,18 @@ #include static Bool DoBumpScroll(); +static Bool DoJumpScroll(); static void BumpScrollTimerCallback(XtPointer clientData, XtIntervalId *id); +static void JumpScrollTimerCallback(XtPointer clientData, XtIntervalId *id); static XtIntervalId timer; static Bool timerSet = False; static Bool scrollLeft, scrollRight, scrollUp, scrollDown; -static Position desktopX, desktopY; +Position desktopX, desktopY; static Dimension viewportWidth, viewportHeight; static Dimension scrollbarWidth, scrollbarHeight; +int scale_round(int len, double fac); /* * 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) { - viewportHeight = toplevelHeight = dpyHeight + scrollbarHeight; - } else { - viewportHeight = si.framebufferHeight + scrollbarHeight; - 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; + } + 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); - viewportX = (toplevelWidth - viewportWidth) / 2; - viewportY = (toplevelHeight - viewportHeight) / 2; + return fs_supported; +} +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); +} - XtVaSetValues(toplevel, XtNoverrideRedirect, True, NULL); +time_t main_grab = 0; - 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); + } +} - /* 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; + } + } + + main_grab = time(NULL); + + fprintf(stderr, "calling fs_grab()\n"); + +#define FORCE_UP \ + XSync(dpy, False); \ + XUnmapWindow(dpy, XtWindow(toplevel)); \ + XSync(dpy, False); \ + XMapWindow(dpy, XtWindow(toplevel)); \ + 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(100 * 1000); + FORCE_UP + + 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 { + 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 { + viewportWidth = fbW; + viewportHeight = eff_height; + toplevelWidth = dpyWidth; + toplevelHeight = dpyHeight; + } - /* 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. */ } @@ -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 ((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); + } + } } @@ -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); + } } @@ -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(); + } } @@ -294,84 +676,220 @@ Bool BumpScroll(XEvent *ev) { - 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: */ + +Bool +JumpScroll(int up, int vert) { + scrollLeft = scrollRight = scrollUp = scrollDown = False; + + + if (appData.fullScreen) { + return True; + } + fprintf(stderr, "JumpScroll(%d, %d)\n", up, vert); + + if (vert) { + if (up) { + scrollUp = True; + } else { + scrollDown = True; + } + } else { + if (up) { + scrollRight = True; + } else { + scrollLeft = True; + } + } + + if (scrollLeft || scrollRight || scrollUp || scrollDown) { + if (timerSet) { + return True; + } + + XtVaGetValues(desktop, XtNx, &desktopX, XtNy, &desktopY, NULL); + desktopX = -desktopX; + desktopY = -desktopY; + return DoJumpScroll(); + } + + if (timerSet) { + XtRemoveTimeOut(timer); + timerSet = False; + } + + return False; +} + +static Bool +DoJumpScroll() { + int oldx = desktopX, oldy = desktopY; + 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 < fbW - dpyWidth) { + desktopX += jumpH; + if (desktopX > fbW - dpyWidth) + desktopX = fbW - dpyWidth; + } + } else if (scrollLeft) { + if (desktopX > 0) { + desktopX -= jumpH; + if (desktopX < 0) + desktopX = 0; + } + } + + if (scrollDown) { + if (appData.yCrop > 0 && desktopY + dpyHeight >= appData.yCrop) { + ; + } else if (desktopY < fbH - dpyHeight) { + desktopY += jumpV; + if (desktopY > fbH - dpyHeight) + desktopY = fbH - dpyHeight; + } + } else if (scrollUp) { + if (desktopY > 0) { + desktopY -= jumpV; + if (desktopY < 0) + desktopY = 0; + } + } + + if (oldx != desktopX || oldy != desktopY) { + XawViewportSetCoordinates(viewport, desktopX, desktopY); + timer = XtAppAddTimeOut(appContext, appData.bumpScrollTime, + JumpScrollTimerCallback, NULL); + timerSet = True; + return True; + } + + timerSet = False; + return False; +} + +static void +JumpScrollTimerCallback(XtPointer clientData, XtIntervalId *id) { + DoJumpScroll(); +} +void JumpRight(Widget w, XEvent *ev, String *params, Cardinal *num_params) { + JumpScroll(1, 0); +} +void JumpLeft(Widget w, XEvent *ev, String *params, Cardinal *num_params) { + JumpScroll(0, 0); +} +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); +} + + diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/h2html.pl vnc_unixsrc/vncviewer/h2html.pl --- vnc_unixsrc.orig/vncviewer/h2html.pl 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/h2html.pl 2008-08-30 20:34:45.000000000 -0400 @@ -0,0 +1,10 @@ +#!/usr/bin/perl + +open(HELP, "./vncviewer -help|"); + +while () { + $_ =~ s/&/&/g; + $_ =~ s//>/g; + print; +} 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 2009-10-16 22:54:40.000000000 -0400 @@ -30,6 +30,21 @@ #define CARDBPP CONCAT2E(CARD,BPP) #define GET_PIXEL CONCAT2E(GET_PIXEL,BPP) +#define FillRectangle(x, y, w, h, color) \ + { \ + XGCValues _gcv; \ + _gcv.foreground = color; \ + if (!appData.useXserverBackingStore) { \ + FillScreen(x, y, w, h, _gcv.foreground); \ + } else { \ + XChangeGC(dpy, gc, GCForeground, &_gcv); \ + XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \ + } \ + } + +extern int skip_maybe_sync; +extern void maybe_sync(int w, int h); + static Bool HandleHextileBPP (int rx, int ry, int rw, int rh) { @@ -41,21 +56,43 @@ int sx, sy, sw, sh; CARD8 subencoding; CARD8 nSubrects; + int irect = 0, nrects = (rw * rh) / (16 * 16); + static int nosync_ycrop = -1; + + if (nosync_ycrop < 0) { + nosync_ycrop = 0; + if (getenv("HEXTILE_YCROP_TOO")) { + nosync_ycrop = 1; + } + } for (y = ry; y < ry+rh; y += 16) { for (x = rx; x < rx+rw; x += 16) { w = h = 16; - if (rx+rw - x < 16) + if (rx+rw - x < 16) { w = rx+rw - x; - if (ry+rh - y < 16) + } + if (ry+rh - y < 16) { h = ry+rh - y; + } + + if (nrects > 400 && (appData.yCrop == 0 || nosync_ycrop)) { + skip_maybe_sync = 0; + if (irect++ % 2000 != 0) { + if (x < rx+rw-16 || y < ry+rh-16) { + skip_maybe_sync = 1; + } + } + } - if (!ReadFromRFBServer((char *)&subencoding, 1)) + if (!ReadFromRFBServer((char *)&subencoding, 1)) { return False; + } if (subencoding & rfbHextileRaw) { - if (!ReadFromRFBServer(buffer, w * h * (BPP / 8))) + if (!ReadFromRFBServer(buffer, w * h * (BPP / 8))) { return False; + } CopyDataToScreen(buffer, x, y, w, h); continue; @@ -66,14 +103,25 @@ return False; #if (BPP == 8) - if (appData.useBGR233) + if (appData.useBGR233) { gcv.foreground = BGR233ToPixel[bg]; - else + } else +#endif +#if (BPP == 16) + if (appData.useBGR565) { + gcv.foreground = BGR565ToPixel[bg]; + } else #endif + { gcv.foreground = bg; + } - XChangeGC(dpy, gc, GCForeground, &gcv); - XFillRectangle(dpy, desktopWin, gc, x, y, w, h); +#if 0 + XChangeGC(dpy, gc, GCForeground, &gcv); + XFillRectangle(dpy, desktopWin, gc, x, y, w, h); +#else + FillRectangle(x, y, w, h, gcv.foreground); +#endif if (subencoding & rfbHextileForegroundSpecified) if (!ReadFromRFBServer((char *)&fg, sizeof(fg))) @@ -101,14 +149,25 @@ sh = rfbHextileExtractH(*ptr); ptr++; #if (BPP == 8) - if (appData.useBGR233) + if (appData.useBGR233) { gcv.foreground = BGR233ToPixel[fg]; - else + } else #endif +#if (BPP == 16) + if (appData.useBGR565) { + gcv.foreground = BGR565ToPixel[fg]; + } else +#endif + { gcv.foreground = fg; + } - XChangeGC(dpy, gc, GCForeground, &gcv); - XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh); +#if 0 + XChangeGC(dpy, gc, GCForeground, &gcv); + XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh); +#else + FillRectangle(x+sx, y+sy, sw, sh, gcv.foreground); +#endif } } else { @@ -116,13 +175,22 @@ return False; #if (BPP == 8) - if (appData.useBGR233) + if (appData.useBGR233) { gcv.foreground = BGR233ToPixel[fg]; - else + } else #endif +#if (BPP == 16) + if (appData.useBGR565) { + gcv.foreground = BGR565ToPixel[fg]; + } else +#endif + { gcv.foreground = fg; + } +#if 0 XChangeGC(dpy, gc, GCForeground, &gcv); +#endif for (i = 0; i < nSubrects; i++) { sx = rfbHextileExtractX(*ptr); @@ -131,7 +199,11 @@ sw = rfbHextileExtractW(*ptr); sh = rfbHextileExtractH(*ptr); ptr++; +#if 0 XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh); +#else + FillRectangle(x+sx, y+sy, sw, sh, gcv.foreground); +#endif } } } @@ -139,3 +211,5 @@ return True; } + +#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 2009-11-24 18:26:13.000000000 -0500 @@ -32,6 +32,7 @@ #define FLASHDELAY 1 /* seconds */ Bool listenSpecified = False; +pid_t listenParent = 0; int listenPort = 0, flashPort = 0; static Font flashFont; @@ -40,6 +41,77 @@ static void flashDisplay(Display *d, char *user); static Bool AllXEventsPredicate(Display *d, XEvent *ev, char *arg); +void raiseme(int force); + +static int accept_popup_check(int *argc, char **argv, char *sip, char *sih) { + char line[16]; + char msg[1000]; + int dopopup = 1; + + if (!getenv("SSVNC_ACCEPT_POPUP")) { + return 1; + } + + if (!dopopup && use_tty()) { + raiseme(1); + fprintf(stderr, "Accept VNC connection? y/[n] "); + fgets(line, sizeof(line), stdin); + if (!strchr(line, 'y') && !strchr(line, 'Y')) { + fprintf(stderr, "Refusing connection.\n"); + return 0; + } else { + fprintf(stderr, "Accepting connection.\n"); + return 1; + } + } else { + int pid, pid2, accept_it = 0; + + pid = fork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + if (pid == 0) { + char *geometry = "2x2+0+0"; + String fb[] = { "*message.Scroll: whenNeeded", NULL}; + close(rfbsock); + + toplevel = XtAppInitialize(&appContext, "Ssvnc", cmdLineOptions, numCmdLineOptions, + argc, argv, fb, NULL, 0); + XtVaSetValues(toplevel, XtNmaxWidth, 2, XtNmaxHeight, 2, NULL); + XtVaSetValues(toplevel, XtNgeometry, geometry, NULL); + XtRealizeWidget(toplevel); + dpy = XtDisplay(toplevel); + sprintf(msg, "\n(LISTEN) Reverse VNC connection from IP: %s\n Hostname: %s\n\n", sip, sih); + strcat(msg, "Accept or Reject VNC connection?"); + if (CreateMsg(msg, 2)) { + XCloseDisplay(dpy); + exit(0); + } else { + XCloseDisplay(dpy); + exit(1); + } + } else { + int status; + pid2 = waitpid(pid, &status, 0); + fprintf(stderr, "waitpid: %d/%d status: %d\n", pid, pid2, status); + if (pid2 == pid) { + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + accept_it = 1; + } + } + } + if (accept_it) { + fprintf(stderr, "Accepting connection.\n"); + return 1; + } else { + fprintf(stderr, "Refusing connection.\n"); + return 0; + } + } + return 0; +} + /* * listenForIncomingConnections() - listen for incoming connections from * servers, and fork a new process to deal with each connection. We must do @@ -58,8 +130,11 @@ int n; int i; char *displayname = NULL; + int children = 0; + 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 +183,40 @@ exit(1); } - getFlashFont(d); +//getFlashFont(d); listenSocket = ListenAtTcpPort(listenPort); - flashSocket = ListenAtTcpPort(flashPort); + +//flashSocket = ListenAtTcpPort(flashPort); + flashSocket = 1234; if ((listenSocket < 0) || (flashSocket < 0)) exit(1); - fprintf(stderr,"%s -listen: Listening on port %d (flash port %d)\n", - programName,listenPort,flashPort); - fprintf(stderr,"%s -listen: Command line errors are not reported until " + fprintf(stderr,"%s -listen: Listening on port %d\n", + programName,listenPort); + fprintf(stderr,"%s -listen: Cmdline errors are not reported until " "a connection comes in.\n", programName); + /* this will only work if X events drives this loop -- they don't */ + if (getenv("SSVNC_MAX_LISTEN")) { + maxconn = atoi(getenv("SSVNC_MAX_LISTEN")); + } + while (True) { /* reap any zombies */ int status, pid; - while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0); + while ((pid = wait3(&status, WNOHANG, (struct rusage *)0))>0) { + if (pid > 0 && children > 0) { + children--; + /* this will only work if X events drives this loop -- they don't */ + if (maxconn > 0 && totalconn >= maxconn) { + fprintf(stderr,"%s -listen: Finished final connection %d\n", + programName, maxconn); + exit(0); + } + } + } /* discard any X events */ while (XCheckIfEvent(d, &ev, AllXEventsPredicate, NULL)) @@ -132,12 +224,24 @@ FD_ZERO(&fds); - FD_SET(flashSocket, &fds); +// FD_SET(flashSocket, &fds); FD_SET(listenSocket, &fds); FD_SET(ConnectionNumber(d), &fds); select(FD_SETSIZE, &fds, NULL, NULL, NULL); + while ((pid = wait3(&status, WNOHANG, (struct rusage *)0))>0) { + if (pid > 0 && children > 0) { + children--; + if (maxconn > 0 && totalconn >= maxconn) { + fprintf(stderr,"%s -listen: Finished final connection %d\n", + programName, maxconn); + exit(0); + } + } + } + +#if 0 if (FD_ISSET(flashSocket, &fds)) { sock = AcceptTcpConnection(flashSocket); @@ -151,11 +255,66 @@ } close(sock); } +#endif if (FD_ISSET(listenSocket, &fds)) { - rfbsock = AcceptTcpConnection(listenSocket); - if (rfbsock < 0) exit(1); - if (!SetNonBlocking(rfbsock)) exit(1); + int multi_ok = 0; + char *sml = getenv("SSVNC_MULTIPLE_LISTEN"); + char *sip = NULL; + char *sih = NULL; + + rfbsock = AcceptTcpConnection(listenSocket); + + if (sml != NULL) { + if (strstr(sml, "MAX:") == sml || strstr(sml, "max:") == sml) { + char *q = strchr(sml, ':'); + int maxc = atoi(q+1); + if (maxc == 0 && strcmp(q+1, "0")) { + maxc = -99; + } + if (maxc < 0) { + fprintf(stderr, "invalid SSVNC_MULTIPLE_LISTEN=MAX:n, %s, must be 0 or positive, using 1\n", sml); + } else if (maxc == 0) { + multi_ok = 1; + } else if (children < maxc) { + multi_ok = 1; + } + } else if (strcmp(sml, "") && strcmp(sml, "0")) { + multi_ok = 1; + } + } + + if (rfbsock < 0) exit(1); + if (!SetNonBlocking(rfbsock)) exit(1); + + if (children > 0 && !multi_ok) { + fprintf(stderr,"\n"); + fprintf(stderr,"%s: denying extra incoming connection (%d already)\n", + programName, children); + fprintf(stderr,"%s: to override: use '-multilisten' or set SSVNC_MULTIPLE_LISTEN=1\n", + programName); + fprintf(stderr,"\n"); + close(rfbsock); + rfbsock = -1; + continue; + } + + sip = get_peer_ip(rfbsock); + if (strlen(sip) > 100) sip = "0.0.0.0"; + sih = ip2host(sip); + if (strlen(sih) > 300) sih = "unknown"; + + fprintf(stderr, "\n"); + fprintf(stderr, "(LISTEN) Reverse VNC connection from IP: %s\n", sip); + fprintf(stderr, " Hostname: %s\n\n", sih); + + if (sml == NULL && !accept_popup_check(argc, argv, sip, sih)) { + close(rfbsock); + rfbsock = -1; + continue; + } + + totalconn++; XCloseDisplay(d); @@ -170,18 +329,28 @@ case 0: /* child - return to caller */ close(listenSocket); - close(flashSocket); +// close(flashSocket); + if (sml != NULL && !accept_popup_check(argc, argv, sip, sih)) { + close(rfbsock); + rfbsock = -1; + exit(0); + } return; default: /* parent - go round and listen again */ + children++; close(rfbsock); if (!(d = XOpenDisplay(displayname))) { fprintf(stderr,"%s: unable to open display %s\n", programName, XDisplayName(displayname)); exit(1); } - 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 " + "a connection comes in.\n\n", programName); break; } } @@ -200,6 +369,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 +385,9 @@ sprintf(fontName,"fixed"); } flashFont = XLoadFont(d, fontName); + +#endif + } @@ -222,6 +401,11 @@ Window w1, w2, w3, w4; XSetWindowAttributes attr; +#if 1 + /* no longer used */ + return; +#else + XBell(d, 0); XForceScreenSaver(d, ScreenSaverReset); @@ -284,6 +468,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 2009-11-28 00:44:24.000000000 -0500 @@ -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,122 @@ 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 && frac_y > 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; + + if (appData.appShare) { + int X = appshare_x_hint; + int Y = appshare_y_hint; + if (appData.scale) { + double fx = 1.0, fy = 1.0; + get_scale_values(&fx, &fy); + if (fx > 0.0 && fy > 0.0) { + X *= fx; + Y *= fy; + } + } + if (appshare_x_hint != appshare_0_hint) { + toplevelX = X; + } + if (appshare_y_hint != appshare_0_hint) { + toplevelY = Y; + } + } + + /* 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 +178,22 @@ void ToplevelInitAfterRealization() { - if (appData.fullScreen) { - FullScreenOn(); - } - - wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1); - XtOverrideTranslations - (toplevel, XtParseTranslationTable ("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 ("WM_PROTOCOLS: Quit()")); } @@ -157,9 +202,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 +235,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 +304,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 +314,93 @@ * 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) { + if (UsingShm()) { + ShmDetach(); + } + ShmCleanup(); + } #endif + + 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 2009-10-27 00:14:17.000000000 -0400 @@ -25,22 +25,59 @@ #include #include +#include #include +#include +#include + Widget popup, fullScreenToggle; +void popupFixer(Widget wid) { + Window rr, cr; + unsigned int m; + int x0 = 500, y0 = 500; + int xr, yr, wxr, wyr; + Dimension ph; + if (XQueryPointer(dpy, DefaultRootWindow(dpy), &rr, &cr, &xr, &yr, &wxr, &wyr, &m)) { + x0 = xr; + y0 = yr; + } + XtPopup(wid, XtGrabNone); + XtVaGetValues(wid, XtNheight, &ph, NULL); + if (y0 + (int) ph > dpyHeight) { + y0 = dpyHeight - (int) ph; + if (y0 < 0) { + y0 = 0; + } + } + 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); - 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); + XtOverrideTranslations(popup, XtParseTranslationTable ("WM_PROTOCOLS: HidePopup()")); } 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 +89,786 @@ }; void -CreatePopup() +CreatePopup() { + Widget buttonForm1, buttonForm2, twoForm, button, prevButton = NULL; + int i; + char buttonName[12]; + String buttonType; + + popup = XtVaCreatePopupShell("popup", transientShellWidgetClass, toplevel, NULL); + + twoForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, popup, NULL); + buttonForm1 = XtVaCreateManagedWidget("buttonForm", formWidgetClass, twoForm, NULL); + buttonForm2 = XtVaCreateManagedWidget("buttonForm", formWidgetClass, twoForm, XtNfromHoriz, (XtArgVal) buttonForm1, NULL); + + if (appData.popupButtonCount > 100) { + fprintf(stderr,"Too many popup buttons\n"); + exit(1); + } + + for (i = 1; i <= appData.popupButtonCount; i++) { + Widget bform; + sprintf(buttonName, "button%d", i); + + if (i <= appData.popupButtonBreak) { + bform = buttonForm1; + } else { + if (i == appData.popupButtonBreak+1) { + prevButton = NULL; + } + bform = buttonForm2; + } + XtVaGetSubresources(bform, (XtPointer)&buttonType, buttonName, "Button", resources, 1, NULL); + + if (strcmp(buttonType, "command") == 0) { + button = XtVaCreateManagedWidget(buttonName, commandWidgetClass, bform, NULL); + XtVaSetValues(button, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); + } else if (strcmp(buttonType, "toggle") == 0) { + button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, bform, NULL); + XtVaSetValues(button, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); + } else { + fprintf(stderr,"unknown button type '%s'\n", buttonType); + } + prevButton = button; + } +} + + +Widget scaleN; + +void +ShowScaleN(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + if (appData.popupFix) { + popupFixer(scaleN); + } else { + XtMoveWidget(scaleN, event->xbutton.x_root, event->xbutton.y_root); + XtPopup(scaleN, XtGrabNone); + } + if (appData.grabAll) { + XRaiseWindow(dpy, XtWindow(scaleN)); + } + XSetWMProtocols(dpy, XtWindow(scaleN), &wmDeleteWindow, 1); + XtOverrideTranslations(scaleN, XtParseTranslationTable ("WM_PROTOCOLS: HideScaleN()")); +} + +void +HideScaleN(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + XtPopdown(scaleN); +} + + +void +CreateScaleN() { Widget buttonForm, button, prevButton = NULL; int i; - char buttonName[12]; + char buttonName[32]; String buttonType; - popup = XtVaCreatePopupShell("popup", transientShellWidgetClass, toplevel, + scaleN = XtVaCreatePopupShell("scaleN", transientShellWidgetClass, toplevel, NULL); - buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, popup, + buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, scaleN, NULL); - if (appData.popupButtonCount > 100) { - fprintf(stderr,"Too many popup buttons\n"); - exit(1); - } - - for (i = 1; i <= appData.popupButtonCount; i++) { + for (i = 0; i <= 6; i++) { sprintf(buttonName, "button%d", i); XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName, "Button", resources, 1, NULL); - if (strcmp(buttonType, "command") == 0) { - button = XtVaCreateManagedWidget(buttonName, commandWidgetClass, + button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, buttonForm, NULL); - XtVaSetValues(button, XtNfromVert, prevButton, + XtVaSetValues(button, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); - } else if (strcmp(buttonType, "toggle") == 0) { - button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, + prevButton = button; + } +} + +Widget turbovncW; + +static Widget turboButtons[32]; + +Widget qualtext, qualslider; + +void UpdateQualSlider(void) { +#ifdef TURBOVNC + char text[16]; + XawScrollbarSetThumb(qualslider, (float)appData.qualityLevel/100., 0.); + sprintf(text, "%3d", appData.qualityLevel); + XtVaSetValues(qualtext, XtNlabel, text, NULL); +#endif +} + +void qualScrollProc(Widget w, XtPointer client, XtPointer p) { +#ifdef TURBOVNC + float size, val; int qual, pos=(int)p; + XtVaGetValues(w, XtNshown, &size, XtNtopOfThumb, &val, 0); + if(pos<0) val-=.1; else val+=.1; + qual=(int)(val*100.); if(qual<1) qual=1; if(qual>100) qual=100; + XawScrollbarSetThumb(w, val, 0.); + appData.qualityLevel=qual; + UpdateQual(); +#endif +} + +void qualJumpProc(Widget w, XtPointer client, XtPointer p) { +#ifdef TURBOVNC + float val=*(float *)p; int qual; + qual=(int)(val*100.); if(qual<1) qual=1; if(qual>100) qual=100; + appData.qualityLevel=qual; + UpdateQual(); +#endif +} + +void UpdateSubsampButtons(void) { +#ifdef TURBOVNC + int i; + for (i=7; i <= 10; i++) { + XtVaSetValues(turboButtons[i], XtNstate, 0, NULL); + } + if (appData.subsampLevel==TVNC_1X) { + i = 7; + } else if (appData.subsampLevel==TVNC_2X) { + i = 8; + } else if (appData.subsampLevel==TVNC_4X) { + i = 9; + } else if (appData.subsampLevel==TVNC_GRAY) { + i = 10; + } else { + return; + } + XtVaSetValues(turboButtons[i], XtNstate, 1, NULL); +#endif +} + +void +ShowTurboVNC(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + UpdateSubsampButtons(); + UpdateQualSlider(); + if (appData.popupFix) { + popupFixer(turbovncW); + } else { + XtMoveWidget(turbovncW, event->xbutton.x_root, event->xbutton.y_root); + XtPopup(turbovncW, XtGrabNone); + } + if (appData.grabAll) { + XRaiseWindow(dpy, XtWindow(turbovncW)); + } + XSetWMProtocols(dpy, XtWindow(turbovncW), &wmDeleteWindow, 1); + XtOverrideTranslations(turbovncW, XtParseTranslationTable ("WM_PROTOCOLS: HideTurboVNC()")); +} + +void +HideTurboVNC(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + XtPopdown(turbovncW); +} + +void +CreateTurboVNC() { + Widget buttonForm, button, prevButton = NULL; + Widget label; + int i; + char buttonName[32]; + String buttonType; + + turbovncW = XtVaCreatePopupShell("turboVNC", transientShellWidgetClass, toplevel, NULL); + + buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, turbovncW, NULL); + + for (i = 0; i <= 12; i++) { + sprintf(buttonName, "button%d", i); +#ifndef TURBOVNC + if (i == 0) { + sprintf(buttonName, "buttonNone"); + } else if (i > 0) { + return; + } +#endif + XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName, + "Button", resources, 1, NULL); + + button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, + buttonForm, NULL); + turboButtons[i] = button; + XtVaSetValues(button, XtNfromVert, prevButton, + XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); + prevButton = button; + } + + label = XtCreateManagedWidget("qualLabel", toggleWidgetClass, buttonForm, NULL, 0); + XtVaSetValues(label, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); + + qualslider = XtCreateManagedWidget("qualBar", scrollbarWidgetClass, buttonForm, NULL, 0); + XtVaSetValues(qualslider, XtNfromVert, label, XtNleft, XawChainLeft, NULL); + XtAddCallback(qualslider, XtNscrollProc, qualScrollProc, NULL) ; + XtAddCallback(qualslider, XtNjumpProc, qualJumpProc, NULL) ; + + qualtext = XtCreateManagedWidget("qualText", labelWidgetClass, buttonForm, NULL, 0); + XtVaSetValues(qualtext, XtNfromVert, label, XtNfromHoriz, qualslider, XtNright, XawChainRight, NULL); +} + +Widget qualityW; + +void +ShowQuality(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + if (appData.popupFix) { + popupFixer(qualityW); + } else { + XtMoveWidget(qualityW, event->xbutton.x_root, event->xbutton.y_root); + XtPopup(qualityW, XtGrabNone); + } + if (appData.grabAll) { + XRaiseWindow(dpy, XtWindow(qualityW)); + } + XSetWMProtocols(dpy, XtWindow(qualityW), &wmDeleteWindow, 1); + XtOverrideTranslations(qualityW, XtParseTranslationTable ("WM_PROTOCOLS: HideQuality()")); +} + +void +HideQuality(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + XtPopdown(qualityW); +} + + +void +CreateQuality() +{ + Widget buttonForm, button, prevButton = NULL; + int i; + char buttonName[32]; + String buttonType; + + qualityW = XtVaCreatePopupShell("quality", transientShellWidgetClass, toplevel, + NULL); + + buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, qualityW, + NULL); + + for (i = -1; i <= 9; i++) { + if (i < 0) { + sprintf(buttonName, "buttonD"); + } else { + sprintf(buttonName, "button%d", i); + } + XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName, + "Button", resources, 1, NULL); + + button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, buttonForm, NULL); - XtVaSetValues(button, XtNfromVert, prevButton, + XtVaSetValues(button, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); + prevButton = button; + } +} + +Widget compressW; + +void +ShowCompress(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + if (appData.popupFix) { + popupFixer(compressW); + } else { + XtMoveWidget(compressW, event->xbutton.x_root, event->xbutton.y_root); + XtPopup(compressW, XtGrabNone); + } + if (appData.grabAll) { + XRaiseWindow(dpy, XtWindow(compressW)); + } + XSetWMProtocols(dpy, XtWindow(compressW), &wmDeleteWindow, 1); + XtOverrideTranslations(compressW, XtParseTranslationTable ("WM_PROTOCOLS: HideCompress()")); +} + +void +HideCompress(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + XtPopdown(compressW); +} + + +void +CreateCompress() +{ + Widget buttonForm, button, prevButton = NULL; + int i; + char buttonName[32]; + String buttonType; + + compressW = XtVaCreatePopupShell("compress", transientShellWidgetClass, toplevel, + NULL); + + buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, compressW, + NULL); + + for (i = -1; i <= 9; i++) { + if (i < 0) { + sprintf(buttonName, "buttonD"); } else { - fprintf(stderr,"unknown button type '%s'\n",buttonType); + sprintf(buttonName, "button%d", i); } + XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName, + "Button", resources, 1, NULL); + + button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, + buttonForm, NULL); + XtVaSetValues(button, XtNfromVert, prevButton, + XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); prevButton = button; } } + + +int filexfer_sock = -1; +int filexfer_listen = -1; + +void HideFile(Widget w, XEvent *event, String *params, Cardinal *num_params) { + if (filexfer_sock >= 0) { + close(filexfer_sock); + filexfer_sock = -1; + } + if (filexfer_listen >= 0) { + close(filexfer_listen); + filexfer_listen = -1; + } +} + +extern int use_loopback; +time_t start_listen = 0; +pid_t java_helper = 0; + +void ShowFile(Widget w, XEvent *event, String *params, Cardinal *num_params) { + int i, port0 = 7200, port, sock = -1; + char *cmd, *jar; + char fmt[] = "java -cp '%s' VncViewer HOST localhost PORT %d delayAuthPanel yes ignoreMSLogonCheck yes disableSSL yes ftpOnly yes graftFtp yes dsmActive no &"; + + if (getenv("SSVNC_ULTRA_FTP_JAR")) { + jar = getenv("SSVNC_ULTRA_FTP_JAR"); + cmd = (char *) malloc(strlen(fmt) + strlen(jar) + 100); + } else { + fprintf(stderr, "Cannot find UltraVNC FTP jar file.\n"); + return; + } + + use_loopback = 1; + for (i = 0; i < 100; i++) { + port = port0 + i; + sock = ListenAtTcpPort(port); + if (sock >= 0) { + fprintf(stderr, "listening for filexfer on port: %d sock: %d\n", port, sock); + break; + } + } + use_loopback = 0; + + if (sock >= 0) { + int st; + pid_t pid = fork(); + if (pid < 0) { + free(cmd); + return; + } else if (pid == 0) { + int i; + sprintf(cmd, fmt, jar, port); + if (appData.ultraDSM) { + char *q = strstr(cmd, "dsmActive"); + if (q) { + q = strstr(q, "no "); + if (q) { + q[0] = 'y'; + q[1] = 'e'; + q[2] = 's'; + } + } + } + for (i = 3; i < 100; i++) { + close(i); + } + fprintf(stderr, "\n-- Experimental UltraVNC File Transfer --\n\nRunning cmd:\n\n %s\n\n", cmd); + system(cmd); + exit(0); + } + fprintf(stderr, "java helper pid is: %d\n", (int) pid); + waitpid(pid, &st, 0); + java_helper = pid; + start_listen = time(NULL); + } + free(cmd); + filexfer_listen = sock; +} + +Widget chat, entry, text; + +static int chat_visible = 0; + +void +ShowChat(Widget w, XEvent *event, String *params, Cardinal *num_params) +{ + if (appData.termChat) { + return; + } + 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 ("WM_PROTOCOLS: Quit()")); + } else { + XtOverrideTranslations(chat, XtParseTranslationTable ("WM_PROTOCOLS: HideChat()")); + } + XSync(dpy, False); + usleep(200 * 1000); + } +} + +void hidechat(void) { + appData.chatActive = False; + if (appData.termChat) { + return; + } + if (chat_visible) { + XtPopdown(chat); + chat_visible = 0; + 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; + } + 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(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); + } + } + } + } + } +} + +void AppendChatInput0(char *in) { + Arg args[10]; + int n; + String str; + int len; + static char *s = NULL; + static int slen = -1; + XawTextPosition pos; + + fprintf(stderr, "AppendChatInput: in= '%s'\n", in); + + XtSetArg(args[0], XtNstring, &str); + XtGetValues(text, args, 1); + fprintf(stderr, "AppendChatInput: str='%s'\n", str); + + len = strlen(str) + strlen(in); + + if (slen <= len) { + slen = 2 * (len + 10); + if (s) free(s); + s = (char *) malloc(slen+1); + } + + s[0] = '\0'; + strcat(s, str); + strcat(s, in); + fprintf(stderr, "AppendChatInput s= '%s'\n", s); + pos = (XawTextPosition) (len-1); + n = 0; + XtSetArg(args[n], XtNtype, XawAsciiString); n++; + XtSetArg(args[n], XtNstring, s); n++; + XtSetArg(args[n], XtNdisplayPosition, pos); n++; + XtSetArg(args[n], XtNinsertPosition, pos); n++; + XtSetValues(text, args, n); + fprintf(stderr, "AppendChatInput done\n"); +} + +void AppendChatInput(char *in) { + int len; + XawTextPosition beg, end; + static XawTextPosition pos = 0; + XawTextBlock txt; + + if (appData.termChat) { + return; + } + + XawTextSetInsertionPoint(text, pos); + beg = XawTextGetInsertionPoint(text); + end = beg; + //fprintf(stderr, "AppendChatInput: pos=%d in= '%s'\n", beg, in); + + txt.firstPos = 0; + txt.length = strlen(in); + txt.ptr = in; + txt.format = FMT8BIT; + + XawTextReplace(text, beg, end, &txt); + XawTextSetInsertionPoint(text, beg + txt.length); + + pos = XawTextGetInsertionPoint(text); + //fprintf(stderr, "AppendChatInput done pos=%d\n", pos); +} + +static char errorbuf[1] = {0}; + +void CreateChat(void) { + + Widget myform, dismiss; + int i, n; + Dimension w = 400, h = 300; + Dimension x = 33, y = 33; + Arg args[10]; + + chat = XtVaCreatePopupShell("chat", topLevelShellWidgetClass, toplevel, XtNmappedWhenManaged, False, NULL); + + myform = XtVaCreateManagedWidget("myform", formWidgetClass, chat, NULL); + + text = XtVaCreateManagedWidget("text", asciiTextWidgetClass, myform, + XtNresize, XawtextResizeBoth, XtNresizable, True, XtNwrap, XawtextWrapWord, + XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollAlways, + XtNwidth, w, XtNheight, h, XtNdisplayCaret, False, + XtNeditType, XawtextAppend, XtNtype, XawAsciiString, + XtNuseStringInPlace, False, NULL); + + entry = XtVaCreateManagedWidget("entry", asciiTextWidgetClass, myform, + XtNresize, XawtextResizeWidth, XtNresizable, True, XtNwrap, XawtextWrapNever, + XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollNever, + XtNheight, 20, XtNwidth, 400, XtNfromVert, text, XtNeditType, XawtextEdit, + XtNdisplayCaret, True, XtNeditType, XawtextEdit, NULL); + + dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "Close Chat", XtNfromVert, entry, NULL); + + AppendChatInput(""); + + XtAddCallback(dismiss, XtNcallback, dismiss_proc, NULL); + + XtRealizeWidget(chat); + + XtSetKeyboardFocus(chat, entry); +} + +Widget msgwin, msgtext; + +void AppendMsg(char *in) { + int len; + XawTextPosition beg, end; + static XawTextPosition pos = 0; + XawTextBlock txt; + + XawTextSetInsertionPoint(msgtext, pos); + beg = XawTextGetInsertionPoint(msgtext); + end = beg; + + txt.firstPos = 0; + txt.length = strlen(in); + txt.ptr = in; + txt.format = FMT8BIT; + + XawTextReplace(msgtext, beg, end, &txt); + XawTextSetInsertionPoint(msgtext, beg + txt.length); + + pos = XawTextGetInsertionPoint(msgtext); +} + +static int msg_visible = 0; +static int msg_NO_clicked = 0; + +void msg_dismiss_proc(Widget w, XtPointer client_data, XtPointer call_data) { + XtPopdown(msgwin); + msg_visible = 0; + XSync(dpy, False); + usleep(200 * 1000); +} + +void msg_NO_proc(Widget w, XtPointer client_data, XtPointer call_data) { + XtPopdown(msgwin); + msg_visible = 0; + msg_NO_clicked = 1; + XSync(dpy, False); + usleep(200 * 1000); +} + +int CreateMsg(char *msg, int wait) { + + Widget myform, dismiss, reject; + char *p; + int i, n, run, wmax = 0; + int ret = 1; + Dimension w, h; + + + n = 0; + run = 0; + p = msg; + while (*p != '\0') { + if (*p == '\n') { + run = 0; + n++; + } + run++; + if (run > wmax) wmax = run; + p++; + } + if (wmax > 80) { + if (wmax > 120) n++; + if (wmax > 80) n++; + wmax = 80; + } + h = (Dimension) (n+2) * 14; + w = (Dimension) (wmax+10) * 8; + + msgwin = XtVaCreatePopupShell("Message", topLevelShellWidgetClass, toplevel, XtNmappedWhenManaged, False, NULL); + + myform = XtVaCreateManagedWidget("myform", formWidgetClass, msgwin, NULL); + + msgtext = XtVaCreateManagedWidget("msgtext", asciiTextWidgetClass, myform, + XtNresize, XawtextResizeBoth, XtNresizable, True, XtNwrap, XawtextWrapWord, + XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollAlways, + XtNwidth, w, XtNheight, h, XtNdisplayCaret, False, + XtNeditType, XawtextAppend, XtNtype, XawAsciiString, + XtNuseStringInPlace, False, NULL); + + if (wait == 2) { + msg_NO_clicked = 0; + + dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "Accept", XtNfromVert, msgtext, NULL); + XtAddCallback(dismiss, XtNcallback, msg_dismiss_proc, NULL); + + reject = XtVaCreateManagedWidget("reject", commandWidgetClass, myform, XtNlabel, "Reject", XtNfromVert, dismiss, NULL); + XtAddCallback(reject, XtNcallback, msg_NO_proc, NULL); + } else { + dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "OK", XtNfromVert, msgtext, NULL); + XtAddCallback(dismiss, XtNcallback, msg_dismiss_proc, NULL); + + } + + AppendMsg(""); + AppendMsg(msg); + + XtRealizeWidget(msgwin); + + XtPopup(msgwin, XtGrabNone); + + XSync(dpy, False); + msg_visible = 1; + while (wait && msg_visible) { + if (0) fprintf(stderr, "mv: %d\n", msg_visible); + XtAppProcessEvent(appContext, XtIMAll); + } + if (wait == 2) { + if (msg_NO_clicked) { + ret = 0; + } else { + ret = 1; + } + } + return ret; +} diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup_ad vnc_unixsrc/vncviewer/popup_ad --- vnc_unixsrc.orig/vncviewer/popup_ad 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/popup_ad 2008-02-17 13:32:34.000000000 -0500 @@ -0,0 +1,20 @@ +#!/usr/bin/perl + +$ok = 0; + +open(A, ") { + if (/popupButtonCount:/) { + $on = 1; + } elsif (/^\s*NULL/) { + $on = 0; + } + next unless $on; + chomp; + last if /NULL/; + $_ =~ s/^\s*"//; + $_ =~ s/",//; + $_ .= "\n" unless $_ =~ /\n/; + print; +} 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 2009-11-27 11:50:35.000000000 -0500 @@ -23,6 +23,7 @@ * rfbproto.c - functions to deal with client side of RFB protocol. */ +#include #include #include #include @@ -31,6 +32,9 @@ #include #include +int server_major = 0, server_minor = 0; +int viewer_major = 0, viewer_minor = 0; + static void InitCapabilities(void); static Bool SetupTunneling(void); static int ReadSecurityType(void); @@ -57,6 +61,44 @@ static Bool HandleTight16(int rx, int ry, int rw, int rh); static Bool HandleTight32(int rx, int ry, int rw, int rh); +/* runge add zrle */ +static Bool HandleZRLE8(int rx, int ry, int rw, int rh); +static Bool HandleZRLE15(int rx, int ry, int rw, int rh); +static Bool HandleZRLE16(int rx, int ry, int rw, int rh); +static Bool HandleZRLE24(int rx, int ry, int rw, int rh); +static Bool HandleZRLE24Up(int rx, int ry, int rw, int rh); +static Bool HandleZRLE24Down(int rx, int ry, int rw, int rh); +static Bool HandleZRLE32(int rx, int ry, int rw, int rh); + +typedef struct { + unsigned long length; +} rfbZRLEHeader; + +#define sz_rfbZRLEHeader 4 + +#define rfbZRLETileWidth 64 +#define rfbZRLETileHeight 64 + +#define DO_ZYWRLE 1 + +#if DO_ZYWRLE + +#ifndef ZRLE_ONCE +#define ZRLE_ONCE + +static const int bitsPerPackedPixel[] = { + 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 +}; + +int zywrle_level; +int zywrleBuf[rfbZRLETileWidth*rfbZRLETileHeight]; + +#include "zrlepalettehelper.h" +static zrlePaletteHelper paletteHelper; + +#endif /* ZRLE_ONCE */ +#endif /* DO_ZYWRLE */ + static void ReadConnFailedReason(void); static long ReadCompactLen (void); @@ -67,6 +109,22 @@ static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, int compressedLen); +extern int currentMsg; +extern double scale_factor_x; +extern double scale_factor_y; + +extern int skip_maybe_sync; + +int sent_FBU = 0; +int skip_XtUpdate = 0; +int skip_XtUpdateAll = 0; + +static double dt_out = 0.0; +static double dt_out_sc = 0.0; +double latency = 0.0; +double connect_time = 0.0; + +void raiseme(int force); int rfbsock; char *desktopName; @@ -75,6 +133,14 @@ char *serverCutText = NULL; Bool newServerCutText = False; +/* ultravnc mslogon */ +#define rfbUltraVncMsLogon 0xfffffffa +static Bool AuthUltraVncMsLogon(void); +extern void UvncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd); +extern void UvncEncryptBytes2(unsigned char *where, int length, unsigned char *key); +extern void UvncDecryptBytes2(unsigned char *where, int length, unsigned char *key); +extern unsigned int urandom(void); + int endianTest = 1; static Bool tightVncProtocol = False; @@ -177,8 +243,26 @@ sig_rfbEncodingPointerPos, "Pointer position update"); CapsAdd(encodingCaps, rfbEncodingLastRect, rfbTightVncVendor, sig_rfbEncodingLastRect, "LastRect protocol extension"); + + CapsAdd(encodingCaps, rfbEncodingNewFBSize, rfbTightVncVendor, + sig_rfbEncodingNewFBSize, "New FB size protocol extension"); + +#ifdef TURBOVNC + CapsAdd(encodingCaps, rfbJpegQualityLevel1, rfbTurboVncVendor, + sig_rfbEncodingNewFBSize, "TurboJPEG quality level"); + CapsAdd(encodingCaps, rfbJpegSubsamp1X, rfbTurboVncVendor, + sig_rfbEncodingNewFBSize, "TurboJPEG subsampling level"); +#endif } +static char msgbuf[10000]; + +static void wmsg(char *msg, int wait) { + fprintf(stderr, "%s", msg); + if (!use_tty() && !getenv("SSVNC_NO_MESSAGE_POPUP")) { + CreateMsg(msg, wait); + } +} /* * ConnectToRFBServer. @@ -187,24 +271,167 @@ Bool ConnectToRFBServer(const char *hostname, int port) { - unsigned int host; - - if (!StringToIPAddr(hostname, &host)) { - fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname); - return False; - } + unsigned int host; + char *q, *cmd = NULL; + Bool setnb; + struct stat sb; + + if (strstr(hostname, "exec=") == hostname) { + cmd = strdup(hostname); + q = strchr(cmd, '='); + *q = ' '; + if (getenv("SSVNC_BASEDIR")) { + char *base = getenv("SSVNC_BASEDIR"); + char *newcmd = (char *)malloc(strlen(base) + strlen(cmd) + 1000); + sprintf(newcmd, "%s/unwrap.so", base); + if (stat(newcmd, &sb) == 0) { +#if (defined(__MACH__) && defined(__APPLE__)) + sprintf(newcmd, "DYLD_FORCE_FLAT_NAMESPACE=1; export DYLD_FORCE_FLAT_NAMESPACE; DYLD_INSERT_LIBRARIES='%s/unwrap.so'; export DYLD_INSERT_LIBRARIES; %s", base, cmd); +#else + sprintf(newcmd, "LD_PRELOAD='%s/unwrap.so'; export LD_PRELOAD; %s", base, cmd); +#endif + cmd = newcmd; + } + } + } - rfbsock = ConnectToTcpAddr(host, port); + if (cmd != NULL) { + int sfd[2]; + char *q, *cmd2 = strdup(cmd); + pid_t pid; + + q = strstr(cmd2, "pw="); + if (q && !getenv("SSVNC_SHOW_ULTRAVNC_DSM_PASSWORD")) { + q += strlen("pw="); + while (*q != '\0' && !isspace(*q)) { + *q = '*'; + q++; + } + } + + fprintf(stderr, "exec-cmd: %s\n\n", cmd2); + free(cmd2); + + if (! SocketPair(sfd)) { + return False; + } + if (0) { + fprintf(stderr, "sfd: %d %d\n", sfd[0], sfd[1]); + fflush(stderr); + } + + pid = fork(); + if (pid == -1) { + perror("fork"); + return False; + } + if (pid == 0) { + char *args[4]; + int d; + args[0] = "/bin/sh"; + args[1] = "-c"; + args[2] = cmd; + args[3] = NULL; + + close(sfd[1]); + dup2(sfd[0], 0); + dup2(sfd[0], 1); + for (d=3; d < 256; d++) { + if (d != sfd[0]) { + close(d); + } + } + execvp(args[0], args); + perror("exec"); + exit(1); + } else { + close(sfd[0]); + rfbsock = sfd[1]; + } + if (rfbsock < 0) { + sprintf(msgbuf,"Unable to connect to exec'd command: %s\n", cmd); + wmsg(msgbuf, 1); + 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); + + rfbsock = ConnectToUnixSocket(thost); + free(thost); + + if (rfbsock < 0) { + sprintf(msgbuf,"Unable to connect to VNC server (unix-domain socket: %s)\n", hostname); + wmsg(msgbuf, 1); + return False; + } + + } else { + if (!StringToIPAddr(hostname, &host)) { + sprintf(msgbuf,"Couldn't convert '%s' to host address\n", hostname); + wmsg(msgbuf, 1); + return False; + } + + rfbsock = ConnectToTcpAddr(host, port); + + if (rfbsock < 0) { + sprintf(msgbuf,"Unable to connect to VNC server (%s:%d)\n", hostname, port); + wmsg(msgbuf, 1); + return False; + } + } - if (rfbsock < 0) { - fprintf(stderr,"Unable to connect to VNC server\n"); - return False; - } + setnb = SetNonBlocking(rfbsock); + return setnb; +} - return SetNonBlocking(rfbsock); +static void printFailureReason(void) { + CARD32 reasonLen; + ReadFromRFBServer((char *)&reasonLen, 4); + reasonLen = Swap32IfLE(reasonLen); + if (reasonLen < 4096) { + char *reason = (char *) malloc(reasonLen+1); + memset(reason, 0, reasonLen+1); + ReadFromRFBServer(reason, reasonLen); + sprintf(msgbuf, "Reason: %s\n", reason); + wmsg(msgbuf, 1); + free(reason); + } } +static char *pr_sec_type(int type) { + char *str = "unknown"; + if (type == rfbSecTypeInvalid) str = "rfbSecTypeInvalid"; + if (type == rfbSecTypeNone) str = "rfbSecTypeNone"; + if (type == rfbSecTypeVncAuth) str = "rfbSecTypeVncAuth"; + if (type == rfbSecTypeRA2) str = "rfbSecTypeRA2"; + if (type == rfbSecTypeRA2ne) str = "rfbSecTypeRA2ne"; + if (type == rfbSecTypeTight) str = "rfbSecTypeTight"; + if (type == rfbSecTypeUltra) str = "rfbSecTypeUltra"; + + if (type == rfbSecTypeAnonTls) str = "rfbSecTypeAnonTls"; + if (type == rfbSecTypeVencrypt) str = "rfbSecTypeVencrypt"; + + if (type == rfbUltraVncMsLogon) str = "rfbUltraVncMsLogon"; + return str; +} + +static char *pr_sec_subtype(int type) { + char *str = "unknown"; + if (type == rfbVencryptPlain) str = "rfbVencryptPlain"; + if (type == rfbVencryptTlsNone) str = "rfbVencryptTlsNone"; + if (type == rfbVencryptTlsVnc) str = "rfbVencryptTlsVnc"; + if (type == rfbVencryptTlsPlain) str = "rfbVencryptTlsPlain"; + if (type == rfbVencryptX509None) str = "rfbVencryptX509None"; + if (type == rfbVencryptX509Vnc) str = "rfbVencryptX509Vnc"; + if (type == rfbVencryptX509Plain) str = "rfbVencryptX509Plain"; + return str; +} +extern void ProcessXtEvents(void); /* * InitialiseRFBConnection. */ @@ -212,211 +439,649 @@ Bool InitialiseRFBConnection(void) { - rfbProtocolVersionMsg pv; - int server_major, server_minor; - int viewer_major, viewer_minor; - rfbClientInitMsg ci; - int secType; + rfbProtocolVersionMsg pv; + rfbClientInitMsg ci; + int i, secType, anon_dh = 0, accept_uvnc = 0; + FILE *pd; + char *hsfile = NULL; + char *hsparam[128]; + char *envsetsec = getenv("SSVNC_SET_SECURITY_TYPE"); + char line[128]; + double dt = 0.0; - /* if the connection is immediately closed, don't report anything, so - that pmw's monitor can make test connections */ + /* if the connection is immediately closed, don't report anything, so + that pmw's monitor can make test connections */ - if (listenSpecified) - errorMessageOnReadFailure = False; + if (listenSpecified) { + errorMessageOnReadFailure = False; + } - if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) - return False; + for (i=0; i < 128; i++) { + hsparam[i] = NULL; + } - errorMessageOnReadFailure = True; + skip_XtUpdateAll = 1; + ProcessXtEvents(); + skip_XtUpdateAll = 0; + + if (getenv("SSVNC_PREDIGESTED_HANDSHAKE")) { + double start = dnow(); + hsfile = getenv("SSVNC_PREDIGESTED_HANDSHAKE"); + while (dnow() < start + 10.0) { + int done = 0; + usleep(100 * 1000); + if ((pd = fopen(hsfile, "r")) != NULL) { + while (fgets(line, 128, pd) != NULL) { + if (strstr(line, "done") == line) { + done = 1; + usleep(100 * 1000); + break; + } + } + fclose(pd); + } + if (done) { + break; + } + } + if ((pd = fopen(hsfile, "r")) != NULL) { + i = 0; + while (fgets(line, 128, pd) != NULL) { + hsparam[i] = strdup(line); + fprintf(stderr, "%s", line); + if (i++ > 100) break; + } + fclose(pd); + } + unlink(hsfile); + } - pv[sz_rfbProtocolVersionMsg] = 0; + if (getenv("SSVNC_SKIP_RFB_PROTOCOL_VERSION")) { + viewer_major = 3; + viewer_minor = 8; + goto end_of_proto_msg; + } else if (hsfile) { + int k = 0; + while (hsparam[k] != NULL) { + char *str = hsparam[k++]; + if (strstr(str, "server=") == str) { + sprintf(pv, "%s", str + strlen("server=")); + goto readed_pv; + } + } + } - if (sscanf(pv, rfbProtocolVersionFormat, - &server_major, &server_minor) != 2) { - fprintf(stderr,"Not a valid VNC server\n"); - return False; - } + dt = dnow(); + if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) { + return False; + } + if (getenv("PRINT_DELAY1")) fprintf(stderr, "delay1: %.3f ms\n", (dnow() - dt) * 1000); + dt = 0.0; - viewer_major = rfbProtocolMajorVersion; - if (server_major == 3 && server_minor >= rfbProtocolMinorVersion) { - /* the server supports at least the standard protocol 3.7 */ - viewer_minor = rfbProtocolMinorVersion; - } else { - /* any other server version, request the standard 3.3 */ - viewer_minor = rfbProtocolFallbackMinorVersion; - } + readed_pv: - fprintf(stderr, "Connected to RFB server, using protocol version %d.%d\n", - viewer_major, viewer_minor); + errorMessageOnReadFailure = True; - sprintf(pv, rfbProtocolVersionFormat, viewer_major, viewer_minor); + pv[sz_rfbProtocolVersionMsg] = 0; - if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) - return False; + if (strstr(pv, "ID:") == pv) { + ; + } else if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) != 2) { + if (strstr(pv, "test") == pv) { + /* now some hacks for ultraVNC SC III (SSL) ... testA, etc */ + int i; + char *se = NULL; + + fprintf(stderr,"Trying UltraVNC Single Click III workaround: %s\n", pv); + for (i=0; i < 7 ; i++) { + pv[i] = pv[i+5]; + } + if (!ReadFromRFBServer(pv+7, 5)) { + return False; + } + + se = getenv("STUNNEL_EXTRA_OPTS"); + if (se == NULL) { + se = getenv("STUNNEL_EXTRA_OPTS_USER"); + } + if (se != NULL) { + if (strstr(se, "options")) { + if (strstr(se, "ALL") || strstr(se, "DONT_INSERT_EMPTY_FRAGMENTS")) { + ; /* good */ + } else { + se = NULL; + } + } else { + se = NULL; + } + } + if (se == NULL) { + msgbuf[0] = '\0'; + strcat(msgbuf, "\n"); + strcat(msgbuf, "***************************************************************\n"); + strcat(msgbuf, "To work around UltraVNC SC III SSL dropping after a few minutes\n"); + strcat(msgbuf, "you may need to set STUNNEL_EXTRA_OPTS_USER='options = ALL'.\n"); + strcat(msgbuf, "***************************************************************\n"); + strcat(msgbuf, "\n"); + wmsg(msgbuf, 0); + } + if (strstr(pv, "ID:") == pv) { + goto check_ID_string; + } + if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) == 2) { + goto ultra_vnc_nonsense; + } + } + sprintf(msgbuf, "Not a valid VNC server: '%s'\n", pv); + wmsg(msgbuf, 1); + return False; + } - /* Read or select the security type. */ - if (viewer_minor == rfbProtocolMinorVersion) { - secType = SelectSecurityType(); - } else { - secType = ReadSecurityType(); - } - if (secType == rfbSecTypeInvalid) - return False; + check_ID_string: + if (strstr(pv, "ID:") == pv) { + char tmp[256]; + fprintf(stderr, "UltraVNC Repeater string detected: %s\n", pv); + fprintf(stderr, "Pretending to be UltraVNC repeater: reading 250 bytes...\n\n"); + if (!ReadFromRFBServer(tmp, 250 - 12)) { + return False; + } + if (!ReadFromRFBServer(pv, 12)) { + return False; + } + if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) != 2) { + sprintf(msgbuf,"Not a valid VNC server: '%s'\n", pv); + wmsg(msgbuf, 1); + return False; + } + } - switch (secType) { - case rfbSecTypeNone: - fprintf(stderr, "No authentication needed\n"); - break; - case rfbSecTypeVncAuth: - if (!AuthenticateVNC()) - return False; - break; - case rfbSecTypeTight: - tightVncProtocol = True; - InitCapabilities(); - if (!SetupTunneling()) - return False; - if (!PerformAuthenticationTight()) - return False; - break; - default: /* should never happen */ - fprintf(stderr, "Internal error: Invalid security type\n"); - return False; - } + ultra_vnc_nonsense: + fprintf(stderr,"\nProto: %s\n", pv); - ci.shared = (appData.shareDesktop ? 1 : 0); + viewer_major = 3; - if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) - 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\n", viewer_major, viewer_minor); - if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) - return False; + } 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\n", viewer_major, viewer_minor); + + } else if (server_major > 3) { + viewer_minor = 8; + } 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\n"); + viewer_minor = 3; + + } else if (server_major == 3 && server_minor >= 8) { + /* the server supports at least the standard protocol 3.8 */ + viewer_minor = 8; + + } else if (server_major == 3 && server_minor == 7) { + /* the server supports at least the standard protocol 3.7 */ + viewer_minor = 7; + + } else { + /* any other server version, request the standard 3.3 */ + viewer_minor = 3; + } + /* n.b. Apple Remote Desktop uses 003.889, but we should be OK with 3.8 */ - si.framebufferWidth = Swap16IfLE(si.framebufferWidth); - si.framebufferHeight = Swap16IfLE(si.framebufferHeight); - si.format.redMax = Swap16IfLE(si.format.redMax); - si.format.greenMax = Swap16IfLE(si.format.greenMax); - si.format.blueMax = Swap16IfLE(si.format.blueMax); - si.nameLength = Swap32IfLE(si.nameLength); - - /* FIXME: Check arguments to malloc() calls. */ - desktopName = malloc(si.nameLength + 1); - if (!desktopName) { - fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n", - (unsigned long)si.nameLength); - return False; - } + if (appData.msLogon) { + if (server_minor == 4) { + fprintf(stderr,"Setting RFB version to 3.4 for UltraVNC MS Logon.\n\n"); + viewer_minor = 4; + } + } + if (getenv("SSVNC_ACCEPT_POPUP_SC")) { + if (server_minor == -4 || server_minor == -6 || server_minor == 14 || server_minor == 16) { + /* 4 and 6 work too? */ + viewer_minor = server_minor; + accept_uvnc = 1; + fprintf(stderr,"Reset RFB version to 3.%d for UltraVNC SSVNC_ACCEPT_POPUP_SC.\n\n", viewer_minor); + } + } - if (!ReadFromRFBServer(desktopName, si.nameLength)) return False; + fprintf(stderr, "Connected to RFB server, using protocol version %d.%d\n", viewer_major, viewer_minor); - desktopName[si.nameLength] = 0; + if (hsfile) { + int k = 0; + while (hsparam[k] != NULL) { + char *str = hsparam[k++]; + if (strstr(str, "latency=") == str) { + latency = 1000. * atof(str + strlen("latency=")); + } + } + k = 0; + while (hsparam[k] != NULL) { + char *str = hsparam[k++]; + int v1, v2; + if (sscanf(str, "viewer=RFB %d.%d\n", &v1, &v2) == 2) { + viewer_major = v1; + viewer_minor = v2; + fprintf(stderr, "\nPre-Handshake set protocol version to: %d.%d Latency: %.2f ms\n", viewer_major, viewer_minor, latency); + goto end_of_proto_msg; + } + } + } + sprintf(pv, rfbProtocolVersionFormat, viewer_major, viewer_minor); - fprintf(stderr,"Desktop name \"%s\"\n",desktopName); + if (!appData.appShare) { + usleep(100*1000); + } + dt = dnow(); + if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) { + return False; + } - fprintf(stderr,"VNC server default format:\n"); - PrintPixelFormat(&si.format); + end_of_proto_msg: - if (tightVncProtocol) { - /* Read interaction capabilities (protocol 3.7t) */ - if (!ReadInteractionCaps()) - return False; - } + if (envsetsec) { + secType = atoi(getenv("SSVNC_SET_SECURITY_TYPE")); + goto sec_type; + } + if (hsfile) { + int k = 0; + while (hsparam[k] != NULL) { + char *str = hsparam[k++]; + int st; + if (sscanf(str, "sectype=%d\n", &st) == 1) { + secType = st; + fprintf(stderr, "Pre-Handshake set Security-Type to: %d (%s)\n", st, pr_sec_type(st)); + if (secType == rfbSecTypeVencrypt) { + goto sec_type; + } else if (secType == rfbSecTypeAnonTls) { + break; + } + } + } + } - return True; + if (accept_uvnc) { + unsigned int msg_sz = 0; + unsigned int nimmer = 0; + char msg[3000]; + char *msg_buf, *sip = NULL, *sih = NULL; + + if (!ReadFromRFBServer((char *) &msg_sz, 4)) { + return False; + } + dt_out_sc = dnow(); + msg_sz = Swap32IfBE(msg_sz); + if (msg_sz < 0 || msg_sz > 1024) { + fprintf(stderr, "UVNC msg size too big: %d\n", msg_sz); + exit(1); + } + msg_buf = (char *)calloc(msg_sz + 100, 1); + if (!ReadFromRFBServer(msg_buf, msg_sz)) { + return False; + } + + if (0) { + fprintf(stderr, "msg_buf: "); + write(2, msg_buf, msg_sz); + fprintf(stderr, "\n"); + } + + sip = get_peer_ip(rfbsock); + if (strlen(sip) > 100) sip = "0.0.0.0"; + sih = ip2host(sip); + if (strlen(sih) > 300) sih = "unknown"; + + sprintf(msg, "\n(LISTEN) Reverse VNC connection from IP: %s\n Hostname: %s\n\n", sip, sih); + strcat(msg, "UltraVNC Server Message:\n"); + strcat(msg, msg_buf); + free(msg_buf); + strcat(msg, "\n\n"); + strcat(msg, "Accept or Reject VNC connection?"); + if (CreateMsg(msg, 2)) { + nimmer = 1; + fprintf(stderr, "Accepting connection.\n\n"); + } else { + nimmer = 0; + fprintf(stderr, "Refusing connection.\n\n"); + } + if (!WriteExact(rfbsock, (char *) &nimmer, 4)) { + return False; + } + } + + /* Read or select the security type. */ + dt_out = 0.0; + + skip_XtUpdateAll = 1; + if (viewer_minor >= 7 && !accept_uvnc) { + secType = SelectSecurityType(); + } else { + secType = ReadSecurityType(); + } + skip_XtUpdateAll = 0; + + if (accept_uvnc) { + dt_out = dt_out_sc; + } + + if (dt > 0.0 && dt_out > dt) { + latency = (dt_out - dt) * 1000; + } + + fprintf(stderr, "Security-Type: %d (%s) Latency: %.2f ms\n", (int) secType, pr_sec_type(secType), latency); + if (secType == rfbSecTypeInvalid) { + return False; + } + + sec_type: + + if (hsfile) { + int subsectype = 0; + int k = 0; + while (hsparam[k] != NULL) { + char *str = hsparam[k++]; + int st; + if (sscanf(str, "subtype=%d\n", &st) == 1) { + subsectype = st; + fprintf(stderr, "Pre-Handshake set Sub-Security-Type to: %d (%s)\n\n", st, pr_sec_subtype(st)); + break; + } + } + + if (!subsectype) { + ; + } else if (secType == rfbSecTypeVencrypt) { + if (subsectype == rfbVencryptTlsNone) { + anon_dh = 1; + secType = rfbSecTypeNone; + } else if (subsectype == rfbVencryptTlsVnc) { + anon_dh = 1; + secType = rfbSecTypeVncAuth; + } else if (subsectype == rfbVencryptTlsPlain) { + anon_dh = 1; + secType = rfbSecTypeNone; + } else if (subsectype == rfbVencryptX509None) { + secType = rfbSecTypeNone; + } else if (subsectype == rfbVencryptX509Vnc) { + secType = rfbSecTypeVncAuth; + } else if (subsectype == rfbVencryptX509Plain) { + secType = rfbSecTypeNone; + } + if (subsectype == rfbVencryptTlsPlain || subsectype == rfbVencryptX509Plain) { + usleep(300*1000); + } + if (subsectype == rfbVencryptTlsNone || subsectype == rfbVencryptTlsVnc || subsectype == rfbVencryptTlsPlain) { + char tmp[1000], line[100]; + tmp[0] = '\0'; + strcat(tmp, "\n"); + sprintf(line, "WARNING: Anonymous Diffie-Hellman TLS used (%s),\n", pr_sec_subtype(subsectype)); + strcat(tmp, line); + strcat(tmp, "WARNING: there will be *NO* Authentication of the VNC Server.\n"); + strcat(tmp, "WARNING: I.e. a Man-In-The-Middle attack is possible.\n"); + strcat(tmp, "WARNING: Configure the server to use X509 certs and verify them.\n\n"); + wmsg(tmp, 1); + } + if (subsectype == rfbVencryptTlsPlain || subsectype == rfbVencryptX509Plain) { + fprintf(stderr, "\nVeNCrypt Plain (username + passwd) selected.\n\n"); + if (appData.unixPW != NULL) { + unixpw(appData.unixPW, 1); + } else if (getenv("SSVNC_UNIXPW")) { + unixpw(getenv("SSVNC_UNIXPW"), 1); + } else { + unixpw(".", 1); + } + } + } + } + + switch (secType) { + case rfbSecTypeNone: + fprintf(stderr, "No VNC authentication needed\n"); + if (viewer_minor == 8) { + CARD32 authResult; + + if (!ReadFromRFBServer((char *)&authResult, 4)) { + return False; + } + + authResult = Swap32IfLE(authResult); + + if (authResult == rfbVncAuthOK) { + fprintf(stderr, "VNC authentication succeeded (%d) for rfbSecTypeNone (RFB 3.8)\n", authResult); + } else { + sprintf(msgbuf, "VNC authentication failed (%d) for rfbSecTypeNone (RFB 3.8)\n\n", authResult); + wmsg(msgbuf, 1); + return False; + } + } + fprintf(stderr, "\n"); + break; + case rfbSecTypeVncAuth: + if (!AuthenticateVNC()) { + return False; + } + break; + case rfbSecTypeTight: + tightVncProtocol = True; + InitCapabilities(); + if (!SetupTunneling()) { + return False; + } + if (!PerformAuthenticationTight()) { + return False; + } + break; + case rfbUltraVncMsLogon: + if (!AuthUltraVncMsLogon()) { + return False; + } + break; + default: /* should never happen */ + sprintf(msgbuf, "Internal error: Invalid security type: %d\n", secType); + wmsg(msgbuf, 1); + return False; + } + + connect_time = dnow(); + + ci.shared = (appData.shareDesktop ? 1 : 0); + + if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) { + return False; + } + + if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) { + return False; + } + + si.framebufferWidth = Swap16IfLE(si.framebufferWidth); + si.framebufferHeight = Swap16IfLE(si.framebufferHeight); + si.format.redMax = Swap16IfLE(si.format.redMax); + si.format.greenMax = Swap16IfLE(si.format.greenMax); + si.format.blueMax = Swap16IfLE(si.format.blueMax); + si.nameLength = Swap32IfLE(si.nameLength); + + if (appData.chatOnly) { + si.framebufferWidth = 32; + si.framebufferHeight = 32; + } + + /* FIXME: Check arguments to malloc() calls. */ + desktopName = malloc(si.nameLength + 1); + memset(desktopName, 0, si.nameLength + 1); + if (!desktopName) { + fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n", + (unsigned long)si.nameLength); + return False; + } + + if (!ReadFromRFBServer(desktopName, si.nameLength)) { + return False; + } + + desktopName[si.nameLength] = 0; + + if (appData.appShare) { + int x_hint, y_hint; + char *p, *q = NULL; + p = desktopName; + while (*p != '\0') { + char *t = strstr(p, " XY="); + if (t) q = t; + p++; + } + if (q) { + int ok = 1; + p = q + strlen(" XY="); + while (*p != '\0') { + if (!strpbrk(p, "0123456789,+-")) { + ok = 0; + } + p++; + } + if (ok && sscanf(q+1, "XY=%d,%d", &x_hint, &y_hint) == 2) { + fprintf(stderr,"Using x11vnc appshare position: %s\n\n", q); + *q = '\0'; + appshare_x_hint = x_hint; + appshare_y_hint = y_hint; + } + } + } + + fprintf(stderr,"Desktop name \"%s\"\n\n", desktopName); + + fprintf(stderr,"VNC server default format:\n"); + PrintPixelFormat(&si.format); + + if (tightVncProtocol) { + /* Read interaction capabilities (protocol 3.7t) */ + if (!ReadInteractionCaps()) { + return False; + } + } + + return True; } /* - * Read security type from the server (protocol version 3.3) + * Read security type from the server (protocol 3.3) */ static int ReadSecurityType(void) { - CARD32 secType; + CARD32 secType; - /* Read the security type */ - if (!ReadFromRFBServer((char *)&secType, sizeof(secType))) - return rfbSecTypeInvalid; + /* Read the security type */ + if (!ReadFromRFBServer((char *)&secType, sizeof(secType))) { + return rfbSecTypeInvalid; + } + dt_out = dnow(); - secType = Swap32IfLE(secType); + secType = Swap32IfLE(secType); - if (secType == rfbSecTypeInvalid) { - ReadConnFailedReason(); - return rfbSecTypeInvalid; - } + if (secType == rfbSecTypeInvalid) { + ReadConnFailedReason(); + return rfbSecTypeInvalid; + } - if (secType != rfbSecTypeNone && secType != rfbSecTypeVncAuth) { - fprintf(stderr, "Unknown security type from RFB server: %d\n", - (int)secType); - return rfbSecTypeInvalid; - } + if (secType == rfbSecTypeNone) { + ; /* OK */ + } else if (secType == rfbSecTypeVncAuth) { + ; /* OK */ + } else if (secType == rfbUltraVncMsLogon) { + ; /* OK */ + } else { + sprintf(msgbuf, "Unknown security type from RFB server: %d\n", (int)secType); + wmsg(msgbuf, 1); + return rfbSecTypeInvalid; + } - return (int)secType; + return (int)secType; } /* - * Select security type from the server's list (protocol version 3.7) + * Select security type from the server's list (protocol 3.7) */ static int SelectSecurityType(void) { - CARD8 nSecTypes; - char *secTypeNames[] = {"None", "VncAuth"}; - CARD8 knownSecTypes[] = {rfbSecTypeNone, rfbSecTypeVncAuth}; - int nKnownSecTypes = sizeof(knownSecTypes); - CARD8 *secTypes; - CARD8 secType = rfbSecTypeInvalid; - int i, j; - - /* Read the list of secutiry types. */ - if (!ReadFromRFBServer((char *)&nSecTypes, sizeof(nSecTypes))) - return rfbSecTypeInvalid; - - if (nSecTypes == 0) { - ReadConnFailedReason(); - return rfbSecTypeInvalid; - } + CARD8 nSecTypes; + char *secTypeNames[] = {"None", "VncAuth"}; + CARD8 knownSecTypes[] = {rfbSecTypeNone, rfbSecTypeVncAuth}; + int nKnownSecTypes = sizeof(knownSecTypes); + CARD8 *secTypes; + CARD8 secType = rfbSecTypeInvalid; + int i, j; + + /* Read the list of security types. */ + if (!ReadFromRFBServer((char *)&nSecTypes, sizeof(nSecTypes))) { + return rfbSecTypeInvalid; + } + dt_out = dnow(); - secTypes = malloc(nSecTypes); - if (!ReadFromRFBServer((char *)secTypes, nSecTypes)) - return rfbSecTypeInvalid; - - /* Find out if the server supports TightVNC protocol extensions */ - for (j = 0; j < (int)nSecTypes; j++) { - if (secTypes[j] == rfbSecTypeTight) { - free(secTypes); - secType = rfbSecTypeTight; - if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) - return rfbSecTypeInvalid; - fprintf(stderr, "Enabling TightVNC protocol extensions\n"); - return rfbSecTypeTight; - } - } + if (nSecTypes == 0) { + ReadConnFailedReason(); + return rfbSecTypeInvalid; + } - /* Find first supported security type */ - for (j = 0; j < (int)nSecTypes; j++) { - for (i = 0; i < nKnownSecTypes; i++) { - if (secTypes[j] == knownSecTypes[i]) { - secType = secTypes[j]; - if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) { - free(secTypes); - return rfbSecTypeInvalid; - } - break; - } - } - if (secType != rfbSecTypeInvalid) break; - } + secTypes = malloc(nSecTypes); + if (!ReadFromRFBServer((char *)secTypes, nSecTypes)) { + return rfbSecTypeInvalid; + } - free(secTypes); + if (getenv("SSVNC_DEBUG_SEC_TYPES")) { + for (j = 0; j < (int)nSecTypes; j++) { + fprintf(stderr, "sec-type[%d] %d\n", j, (int) secTypes[j]); + } + } - if (secType == rfbSecTypeInvalid) - fprintf(stderr, "Server did not offer supported security type\n"); + /* Find out if the server supports TightVNC protocol extensions */ + for (j = 0; j < (int)nSecTypes; j++) { + if (getenv("SSVNC_NO_SEC_TYPE_TIGHT")) { + break; + } +#ifdef TURBOVNC + break; +#endif + if (secTypes[j] == rfbSecTypeTight) { + free(secTypes); + secType = rfbSecTypeTight; + if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) { + return rfbSecTypeInvalid; + } + fprintf(stderr, "Enabling TightVNC protocol extensions\n"); + return rfbSecTypeTight; + } + } + + /* Find first supported security type */ + for (j = 0; j < (int)nSecTypes; j++) { + for (i = 0; i < nKnownSecTypes; i++) { + if (secTypes[j] == knownSecTypes[i]) { + secType = secTypes[j]; + if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) { + free(secTypes); + return rfbSecTypeInvalid; + } + break; + } + } + if (secType != rfbSecTypeInvalid) { + break; + } + } + + if (secType == rfbSecTypeInvalid) { + fprintf(stderr, "Server did not offer supported security type:\n"); + for (j = 0; j < (int)nSecTypes; j++) { + fprintf(stderr, " sectype[%d] %d\n", j, (int) secTypes[j]); + } + } + + free(secTypes); - return (int)secType; + return (int)secType; } @@ -451,6 +1116,9 @@ return True; } +static char *restart_session_pw = NULL; +static int restart_session_len = 0; + /* * Negotiate authentication scheme (protocol version 3.7t) @@ -459,58 +1127,388 @@ static Bool PerformAuthenticationTight(void) { - rfbAuthenticationCapsMsg caps; - CARD32 authScheme; - int i; + rfbAuthenticationCapsMsg caps; + CARD32 authScheme; + int i; - /* In the protocol version 3.7t, the server informs us about supported - authentication schemes. Here we read this information. */ + /* In the protocol version 3.7t, the server informs us about supported + authentication schemes. Here we read this information. */ - if (!ReadFromRFBServer((char *)&caps, sz_rfbAuthenticationCapsMsg)) - return False; + if (!ReadFromRFBServer((char *)&caps, sz_rfbAuthenticationCapsMsg)) { + return False; + } - caps.nAuthTypes = Swap32IfLE(caps.nAuthTypes); + caps.nAuthTypes = Swap32IfLE(caps.nAuthTypes); - if (!caps.nAuthTypes) { - fprintf(stderr, "No authentication needed\n"); - return True; - } + if (!caps.nAuthTypes) { + fprintf(stderr, "No VNC authentication needed\n\n"); + return True; + } - if (!ReadCapabilityList(authCaps, caps.nAuthTypes)) - return False; + if (!ReadCapabilityList(authCaps, caps.nAuthTypes)) { + return False; + } - /* Prefer Unix login authentication if a user name was given. */ - if (appData.userLogin && CapsIsEnabled(authCaps, rfbAuthUnixLogin)) { - authScheme = Swap32IfLE(rfbAuthUnixLogin); - if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme))) - return False; - return AuthenticateUnixLogin(); - } + /* Prefer Unix login authentication if a user name was given. */ + if (appData.userLogin && CapsIsEnabled(authCaps, rfbAuthUnixLogin)) { + authScheme = Swap32IfLE(rfbAuthUnixLogin); + if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme))) { + return False; + } + return AuthenticateUnixLogin(); + } - /* Otherwise, try server's preferred authentication scheme. */ - for (i = 0; i < CapsNumEnabled(authCaps); i++) { - authScheme = CapsGetByOrder(authCaps, i); - if (authScheme != rfbAuthUnixLogin && authScheme != rfbAuthVNC) - continue; /* unknown scheme - cannot use it */ - authScheme = Swap32IfLE(authScheme); - if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme))) - return False; - authScheme = Swap32IfLE(authScheme); /* convert it back */ - if (authScheme == rfbAuthUnixLogin) { - return AuthenticateUnixLogin(); - } else if (authScheme == rfbAuthVNC) { - return AuthenticateVNC(); - } else { - /* Should never happen. */ - fprintf(stderr, "Assertion failed: unknown authentication scheme\n"); - return False; - } - } + /* Otherwise, try server's preferred authentication scheme. */ + for (i = 0; i < CapsNumEnabled(authCaps); i++) { + authScheme = CapsGetByOrder(authCaps, i); + if (authScheme != rfbAuthUnixLogin && authScheme != rfbAuthVNC) { + continue; /* unknown scheme - cannot use it */ + } + authScheme = Swap32IfLE(authScheme); + if (!WriteExact(rfbsock, (char *)&authScheme, sizeof(authScheme))) { + return False; + } + authScheme = Swap32IfLE(authScheme); /* convert it back */ + if (authScheme == rfbAuthUnixLogin) { + return AuthenticateUnixLogin(); + } else if (authScheme == rfbAuthVNC) { + return AuthenticateVNC(); + } else { + /* Should never happen. */ + fprintf(stderr, "Assertion failed: unknown authentication scheme\n"); + return False; + } + } + + sprintf(msgbuf, "No suitable authentication schemes offered by server\n"); + wmsg(msgbuf, 1); + return False; +} + +#if 0 +unsigned char encPasswd[8]; +unsigned char encPasswd_MSLOGON[32]; +char clearPasswd_MSLOGIN[256]; +static Bool old_ultravnc_mslogon_code(void) { + char *passwd = NULL; + CARD8 challenge_mslogon[CHALLENGESIZE_MSLOGON]; + + /* code from the old uvnc way (1.0.2?) that would go into AuthenticateVNC() template */ + + if (appData.msLogon != NULL) { + raiseme(1); + if (!strcmp(appData.msLogon, "1")) { + char tmp[256]; + fprintf(stderr, "\nUltraVNC MS Logon Username[@Domain]: "); + if (fgets(tmp, 256, stdin) == NULL) { + exit(1); + } + appData.msLogon = strdup(tmp); + } + passwd = getpass("UltraVNC MS Logon Password: "); + if (! passwd) { + exit(1); + } + fprintf(stderr, "\n"); + + UvncEncryptPasswd_MSLOGON(encPasswd_MSLOGON, passwd); + } + if (appData.msLogon) { + if (!ReadFromRFBServer((char *)challenge_mslogon, CHALLENGESIZE_MSLOGON)) { + return False; + } + } + if (appData.msLogon) { + int i; + char tmp[256]; + char *q, *domain = "."; + for (i=0; i < 32; i++) { + challenge_mslogon[i] = encPasswd_MSLOGON[i] ^ challenge_mslogon[i]; + } + q = strchr(appData.msLogon, '@'); + if (q) { + *q = '\0'; + domain = strdup(q+1); + } + memset(tmp, 0, sizeof(tmp)); + strcat(tmp, appData.msLogon); + if (!WriteExact(rfbsock, tmp, 256)) { + return False; + } + memset(tmp, 0, sizeof(tmp)); + strcat(tmp, domain); + if (!WriteExact(rfbsock, tmp, 256)) { + return False; + } + memset(tmp, 0, sizeof(tmp)); + strcat(tmp, passwd); + if (!WriteExact(rfbsock, tmp, CHALLENGESIZE_MSLOGON)) { + return False; + } + } +} +#endif - fprintf(stderr, "No suitable authentication schemes offered by server\n"); - return False; +static void hexprint(char *label, char *data, int len) { + int i; + fprintf(stderr, "%s: ", label); + for (i=0; i < len; i++) { + unsigned char c = (unsigned char) data[i]; + fprintf(stderr, "%02x ", (int) c); + if ((i+1) % 20 == 0) { + fprintf(stderr, "\n%s: ", label); + } + } + fprintf(stderr, "\n"); +} + +#define DH_MAX_BITS 31 +static unsigned long long max_dh = ((unsigned long long) 1) << DH_MAX_BITS; + +static unsigned long long bytes_to_uint64(char *bytes) { + unsigned long long result = 0; + int i; + + for (i=0; i < 8; i++) { + result <<= 8; + result += (unsigned char) bytes[i]; + } + return result; +} + +static void uint64_to_bytes(unsigned long long n, char *bytes) { + int i; + + for (i=0; i < 8; i++) { + bytes[i] = (unsigned char) (n >> (8 * (7 - i))); + } +} + +static void try_invert(char *wireuser, char *wirepass, unsigned long long actual_key) { + return; +} + + +static unsigned long long XpowYmodN(unsigned long long x, unsigned long long y, unsigned long long N) { + unsigned long long result = 1; + unsigned long long oneShift63 = ((unsigned long long) 1) << 63; + int i; + + for (i = 0; i < 64; y <<= 1, i++) { + result = result * result % N; + if (y & oneShift63) { + result = result * x % N; + } + } + return result; } +/* + * UltraVNC MS-Logon authentication (for v1.0.5 and later.) + */ + +/* + * NOTE: The UltraVNC MS-Logon username and password exchange is + * VERY insecure. It can be brute forced in ~2e+9 operations. + * It's not clear we should support it... It is only worth using + * in an environment where no one is sniffing the network, in which + * case all of this DH exchange secrecy is unnecessary... + */ + +static Bool AuthUltraVncMsLogon(void) { + CARD32 authResult; + char gen[8], mod[8], pub[8], rsp[8]; + char user[256], passwd[64], *gpw; + unsigned char key[8]; + unsigned long long ugen, umod, ursp, upub, uprv, ukey; + double now = dnow(); + int db = 0; + + if (getenv("SSVNC_DEBUG_MSLOGON")) { + db = atoi(getenv("SSVNC_DEBUG_MSLOGON")); + } + + fprintf(stderr, "\nAuthUltraVncMsLogon()\n"); + + if (!ReadFromRFBServer(gen, sizeof(gen))) { + return False; + } + if (db) hexprint("gen", gen, sizeof(gen)); + + if (!ReadFromRFBServer(mod, sizeof(mod))) { + return False; + } + if (db) hexprint("mod", mod, sizeof(mod)); + + if (!ReadFromRFBServer(rsp, sizeof(rsp))) { + return False; + } + if (db) hexprint("rsp", rsp, sizeof(rsp)); + + ugen = bytes_to_uint64(gen); + umod = bytes_to_uint64(mod); + ursp = bytes_to_uint64(rsp); + + if (db) { + fprintf(stderr, "ugen: 0x%016llx %12llu\n", ugen, ugen); + fprintf(stderr, "umod: 0x%016llx %12llu\n", umod, umod); + fprintf(stderr, "ursp: 0x%016llx %12llu\n", ursp, ursp); + } + + if (ugen > max_dh) { + fprintf(stderr, "ugen: too big: 0x%016llx\n", ugen); + return False; + } + + if (umod > max_dh) { + fprintf(stderr, "umod: too big: 0x%016llx\n", umod); + return False; + } + + /* make a random long long: */ + uprv = 0xffffffff * (now - (unsigned int) now); + uprv << 32; + uprv |= (unsigned long long) urandom(); + uprv = uprv % max_dh; + + if (db) fprintf(stderr, "uprv: 0x%016llx %12llu\n", uprv, uprv); + + upub = XpowYmodN(ugen, uprv, umod); + + if (db) fprintf(stderr, "upub: 0x%016llx %12llu\n", upub, upub); + + uint64_to_bytes(upub, pub); + + if (db) hexprint("pub", pub, sizeof(pub)); + + if (!WriteExact(rfbsock, (char *)pub, sizeof(pub))) { + return False; + } + if (db) fprintf(stderr, "wrote pub.\n"); + + if (ursp > max_dh) { + fprintf(stderr, "ursp: too big: 0x%016llx\n", ursp); + return False; + } + + ukey = XpowYmodN(ursp, uprv, umod); + + if (db) fprintf(stderr, "ukey: 0x%016llx %12llu\n", ukey, ukey); + + if (1) { + char tmp[10000]; + tmp[0] = '\0'; + strcat(tmp, "\n"); + strcat(tmp, "WARNING: The UltraVNC Diffie-Hellman Key is weak (key < 2e+9, i.e. 31 bits)\n"); + strcat(tmp, "WARNING: and so an eavesdropper could recover your MS-Logon username and\n"); + strcat(tmp, "WARNING: password via brute force in a few seconds of CPU time. \n"); + strcat(tmp, "WARNING: If this connection is NOT being tunnelled through a separate SSL or\n"); + strcat(tmp, "WARNING: SSH encrypted tunnel, consider things carefully before proceeding...\n"); + strcat(tmp, "WARNING: Do not enter an important username+password when prompted below if\n"); + strcat(tmp, "WARNING: there is a risk of an eavesdropper sniffing this connection.\n"); + strcat(tmp, "WARNING: UltraVNC MSLogon encryption is VERY weak. You've been warned!\n"); + wmsg(tmp, 1); + } + + uint64_to_bytes(ukey, (char *) key); + + if (appData.msLogon == NULL || !strcmp(appData.msLogon, "1")) { + char tmp[256], *q, *s; + if (!use_tty()) { + fprintf(stderr, "\nEnter UltraVNC MS-Logon Username[@Domain] in the popup.\n"); + s = DoUserDialog(); + } else { + raiseme(1); + fprintf(stderr, "\nUltraVNC MS-Logon Username[@Domain]: "); + if (fgets(tmp, 256, stdin) == NULL) { + exit(1); + } + s = strdup(tmp); + } + q = strchr(s, '\n'); + if (q) *q = '\0'; + appData.msLogon = strdup(s); + } + + if (!use_tty()) { + gpw = DoPasswordDialog(); + } else { + raiseme(1); + gpw = getpass("UltraVNC MS-Logon Password: "); + } + if (! gpw) { + return False; + } + fprintf(stderr, "\n"); + + memset(user, 0, sizeof(user)); + strncpy(user, appData.msLogon, 255); + + memset(passwd, 0, sizeof(passwd)); + strncpy(passwd, gpw, 63); + + if (db > 1) { + fprintf(stderr, "user='%s'\n", user); + fprintf(stderr, "pass='%s'\n", passwd); + } + + UvncEncryptBytes2((unsigned char *) user, sizeof(user), key); + UvncEncryptBytes2((unsigned char *) passwd, sizeof(passwd), key); + + if (getenv("TRY_INVERT")) { + try_invert(user, passwd, ukey); + exit(0); + } + + if (db) { + hexprint("user", user, sizeof(user)); + hexprint("pass", passwd, sizeof(passwd)); + } + + if (!WriteExact(rfbsock, user, sizeof(user))) { + return False; + } + if (db) fprintf(stderr, "wrote user.\n"); + + if (!WriteExact(rfbsock, passwd, sizeof(passwd))) { + return False; + } + if (db) fprintf(stderr, "wrote passwd.\n"); + + if (!ReadFromRFBServer((char *) &authResult, 4)) { + return False; + } + authResult = Swap32IfLE(authResult); + + if (db) fprintf(stderr, "authResult: %d\n", (int) authResult); + + switch (authResult) { + case rfbVncAuthOK: + fprintf(stderr, "UVNC MS-Logon authentication succeeded.\n\n"); + break; + case rfbVncAuthFailed: + fprintf(stderr, "UVNC MS-Logon authentication failed.\n"); + if (viewer_minor >= 8) { + printFailureReason(); + } else { + sprintf(msgbuf, "UVNC MS-Logon authentication failed.\n"); + wmsg(msgbuf, 1); + } + fprintf(stderr, "\n"); + return False; + case rfbVncAuthTooMany: + sprintf(msgbuf, "UVNC MS-Logon authentication failed - too many tries.\n\n"); + wmsg(msgbuf, 1); + return False; + default: + sprintf(msgbuf, "Unknown UVNC MS-Logon authentication result: %d\n\n", + (int)authResult); + wmsg(msgbuf, 1); + return False; + } + + return True; +} /* * Standard VNC authentication. @@ -519,80 +1517,115 @@ static Bool AuthenticateVNC(void) { - CARD32 authScheme, authResult; - CARD8 challenge[CHALLENGESIZE]; - char *passwd; - char buffer[64]; - char* cstatus; - int len; + CARD32 authScheme, authResult; + CARD8 challenge[CHALLENGESIZE]; + char *passwd = NULL; + char buffer[64]; + char* cstatus; + int len; + int restart = 0; - fprintf(stderr, "Performing standard VNC authentication\n"); + fprintf(stderr, "\nPerforming standard VNC authentication\n"); - if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) - return False; + if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) { + return False; + } + + if (restart_session_pw != NULL) { + passwd = restart_session_pw; + restart_session_pw = NULL; + restart = 1; + } else if (appData.passwordFile) { + passwd = vncDecryptPasswdFromFile(appData.passwordFile); + if (!passwd) { + sprintf(msgbuf, "Cannot read valid password from file \"%s\"\n", appData.passwordFile); + wmsg(msgbuf, 1); + return False; + } + } else if (appData.autoPass) { + passwd = buffer; + raiseme(1); + cstatus = fgets(buffer, sizeof buffer, stdin); + if (cstatus == NULL) { + buffer[0] = '\0'; + } else { + len = strlen(buffer); + if (len > 0 && buffer[len - 1] == '\n') { + buffer[len - 1] = '\0'; + } + } + } else if (getenv("VNCVIEWER_PASSWORD")) { + passwd = strdup(getenv("VNCVIEWER_PASSWORD")); + } else if (appData.passwordDialog || !use_tty()) { + passwd = DoPasswordDialog(); + } else { + raiseme(1); + passwd = getpass("VNC Password: "); + } - if (appData.passwordFile) { - passwd = vncDecryptPasswdFromFile(appData.passwordFile); - if (!passwd) { - fprintf(stderr, "Cannot read valid password from file \"%s\"\n", - appData.passwordFile); - return False; - } - } else if (appData.autoPass) { - passwd = buffer; - cstatus = fgets(buffer, sizeof buffer, stdin); - if (cstatus == NULL) - buffer[0] = '\0'; - else - { - len = strlen(buffer); - if (len > 0 && buffer[len - 1] == '\n') - buffer[len - 1] = '\0'; - } - } else if (appData.passwordDialog) { - passwd = DoPasswordDialog(); - } else { - passwd = getpass("Password: "); - } + if (getenv("VNCVIEWER_PASSWORD")) { + putenv("VNCVIEWER_PASSWORD=none"); + } - if (!passwd || strlen(passwd) == 0) { - fprintf(stderr, "Reading password failed\n"); - return False; - } - if (strlen(passwd) > 8) { - passwd[8] = '\0'; - } + if (restart) { +#define EN0 0 +#define DE1 1 + unsigned char s_fixedkey[8] = {23,82,107,6,35,78,88,7}; + deskey(s_fixedkey, DE1); + des(passwd, passwd); + } else { + if (!passwd || strlen(passwd) == 0) { + sprintf(msgbuf, "Reading password failed\n\n"); + wmsg(msgbuf, 1); + return False; + } + if (strlen(passwd) > 8) { + passwd[8] = '\0'; + } + } - vncEncryptBytes(challenge, passwd); + vncEncryptBytes(challenge, passwd); + - /* Lose the password from memory */ - memset(passwd, '\0', strlen(passwd)); - if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) - return False; +// /* Lose the password from memory */ +// memset(passwd, '\0', strlen(passwd)); - if (!ReadFromRFBServer((char *)&authResult, 4)) - return False; + if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) { + return False; + } - authResult = Swap32IfLE(authResult); + if (!ReadFromRFBServer((char *)&authResult, 4)) { + return False; + } - switch (authResult) { - case rfbVncAuthOK: - fprintf(stderr, "VNC authentication succeeded\n"); - break; - case rfbVncAuthFailed: - fprintf(stderr, "VNC authentication failed\n"); - return False; - case rfbVncAuthTooMany: - fprintf(stderr, "VNC authentication failed - too many tries\n"); - return False; - default: - fprintf(stderr, "Unknown VNC authentication result: %d\n", - (int)authResult); - return False; - } + authResult = Swap32IfLE(authResult); - return True; + switch (authResult) { + case rfbVncAuthOK: + fprintf(stderr, "VNC authentication succeeded\n\n"); + break; + case rfbVncAuthFailed: + fprintf(stderr, "VNC authentication failed.\n"); + if (viewer_minor >= 8) { + printFailureReason(); + } else { + sprintf(msgbuf, "VNC authentication failed.\n"); + wmsg(msgbuf, 1); + } + fprintf(stderr, "\n"); + return False; + case rfbVncAuthTooMany: + sprintf(msgbuf, "VNC authentication failed - too many tries\n\n"); + wmsg(msgbuf, 1); + return False; + default: + sprintf(msgbuf, "Unknown VNC authentication result: %d\n\n", (int)authResult); + wmsg(msgbuf, 1); + return False; + } + + return True; } /* @@ -602,68 +1635,75 @@ static Bool AuthenticateUnixLogin(void) { - CARD32 loginLen, passwdLen, authResult; - char *login; - char *passwd; - struct passwd *ps; - - fprintf(stderr, "Performing Unix login-style authentication\n"); - - if (appData.userLogin) { - login = appData.userLogin; - } else { - ps = getpwuid(getuid()); - login = ps->pw_name; - } + CARD32 loginLen, passwdLen, authResult; + char *login; + char *passwd; + struct passwd *ps; + + fprintf(stderr, "\nPerforming Unix login-style authentication\n"); + + if (appData.userLogin) { + login = appData.userLogin; + } else { + ps = getpwuid(getuid()); + login = ps->pw_name; + } - fprintf(stderr, "Using user name \"%s\"\n", login); + fprintf(stderr, "Using user name \"%s\"\n", login); - if (appData.passwordDialog) { - passwd = DoPasswordDialog(); - } else { - passwd = getpass("Password: "); - } - if (!passwd || strlen(passwd) == 0) { - fprintf(stderr, "Reading password failed\n"); - return False; - } + if (appData.passwordDialog || !use_tty()) { + passwd = DoPasswordDialog(); + } else { + raiseme(1); + passwd = getpass("VNC Password: "); + } + if (!passwd || strlen(passwd) == 0) { + fprintf(stderr, "Reading password failed\n"); + return False; + } - loginLen = Swap32IfLE((CARD32)strlen(login)); - passwdLen = Swap32IfLE((CARD32)strlen(passwd)); + loginLen = Swap32IfLE((CARD32)strlen(login)); + passwdLen = Swap32IfLE((CARD32)strlen(passwd)); - if (!WriteExact(rfbsock, (char *)&loginLen, sizeof(loginLen)) || - !WriteExact(rfbsock, (char *)&passwdLen, sizeof(passwdLen))) - return False; + if (!WriteExact(rfbsock, (char *)&loginLen, sizeof(loginLen)) || + !WriteExact(rfbsock, (char *)&passwdLen, sizeof(passwdLen))) { + return False; + } - if (!WriteExact(rfbsock, login, strlen(login)) || - !WriteExact(rfbsock, passwd, strlen(passwd))) - return False; + if (!WriteExact(rfbsock, login, strlen(login)) || + !WriteExact(rfbsock, passwd, strlen(passwd))) { + return False; + } - /* Lose the password from memory */ - memset(passwd, '\0', strlen(passwd)); +// /* Lose the password from memory */ +// memset(passwd, '\0', strlen(passwd)); - if (!ReadFromRFBServer((char *)&authResult, sizeof(authResult))) - return False; + if (!ReadFromRFBServer((char *)&authResult, sizeof(authResult))) { + return False; + } - authResult = Swap32IfLE(authResult); + authResult = Swap32IfLE(authResult); - switch (authResult) { - case rfbVncAuthOK: - fprintf(stderr, "Authentication succeeded\n"); - break; - case rfbVncAuthFailed: - fprintf(stderr, "Authentication failed\n"); - return False; - case rfbVncAuthTooMany: - fprintf(stderr, "Authentication failed - too many tries\n"); - return False; - default: - fprintf(stderr, "Unknown authentication result: %d\n", - (int)authResult); - return False; - } + switch (authResult) { + case rfbVncAuthOK: + fprintf(stderr, "Authentication succeeded\n\n"); + break; + case rfbVncAuthFailed: + sprintf(msgbuf, "Authentication failed\n\n"); + wmsg(msgbuf, 1); + return False; + case rfbVncAuthTooMany: + sprintf(msgbuf, "Authentication failed - too many tries\n\n"); + wmsg(msgbuf, 1); + return False; + default: + sprintf(msgbuf, "Unknown authentication result: %d\n\n", + (int)authResult); + wmsg(msgbuf, 1); + return False; + } - return True; + return True; } @@ -675,19 +1715,20 @@ static Bool ReadInteractionCaps(void) { - rfbInteractionCapsMsg intr_caps; + rfbInteractionCapsMsg intr_caps; - /* Read the counts of list items following */ - if (!ReadFromRFBServer((char *)&intr_caps, sz_rfbInteractionCapsMsg)) - return False; - intr_caps.nServerMessageTypes = Swap16IfLE(intr_caps.nServerMessageTypes); - intr_caps.nClientMessageTypes = Swap16IfLE(intr_caps.nClientMessageTypes); - intr_caps.nEncodingTypes = Swap16IfLE(intr_caps.nEncodingTypes); - - /* Read the lists of server- and client-initiated messages */ - return (ReadCapabilityList(serverMsgCaps, intr_caps.nServerMessageTypes) && - ReadCapabilityList(clientMsgCaps, intr_caps.nClientMessageTypes) && - ReadCapabilityList(encodingCaps, intr_caps.nEncodingTypes)); + /* Read the counts of list items following */ + if (!ReadFromRFBServer((char *)&intr_caps, sz_rfbInteractionCapsMsg)) { + return False; + } + intr_caps.nServerMessageTypes = Swap16IfLE(intr_caps.nServerMessageTypes); + intr_caps.nClientMessageTypes = Swap16IfLE(intr_caps.nClientMessageTypes); + intr_caps.nEncodingTypes = Swap16IfLE(intr_caps.nEncodingTypes); + + /* Read the lists of server- and client-initiated messages */ + return (ReadCapabilityList(serverMsgCaps, intr_caps.nServerMessageTypes) && + ReadCapabilityList(clientMsgCaps, intr_caps.nClientMessageTypes) && + ReadCapabilityList(encodingCaps, intr_caps.nEncodingTypes)); } @@ -700,19 +1741,67 @@ static Bool ReadCapabilityList(CapsContainer *caps, int count) { - rfbCapabilityInfo msginfo; - int i; + rfbCapabilityInfo msginfo; + int i; - for (i = 0; i < count; i++) { - if (!ReadFromRFBServer((char *)&msginfo, sz_rfbCapabilityInfo)) - return False; - msginfo.code = Swap32IfLE(msginfo.code); - CapsEnable(caps, &msginfo); - } + for (i = 0; i < count; i++) { + if (!ReadFromRFBServer((char *)&msginfo, sz_rfbCapabilityInfo)) { + return False; + } + msginfo.code = Swap32IfLE(msginfo.code); + CapsEnable(caps, &msginfo); + } - return True; + return True; +} + + +/* used to have !tunnelSpecified */ + +static int guess_compresslevel(void) { + int n; + if (latency > 200.0) { + n = 8; + } else if (latency > 100.0) { + n = 7; + } else if (latency > 60.0) { + n = 6; + } else if (latency > 15.0) { + n = 4; + } else if (latency > 8.0) { + n = 2; + } else if (latency > 0.0) { + n = 1; + } else { + /* no latency measurement */ + n = 3; + } + return n; } +static int guess_qualitylevel(void) { + int n; + if (latency > 200.0) { + n = 4; + } else if (latency > 100.0) { + n = 5; + } else if (latency > 60.0) { + n = 6; + } else if (latency > 15.0) { + n = 7; + } else if (latency > 8.0) { + n = 8; + } else if (latency > 0.0) { + n = 9; + } else { + /* no latency measurement */ + n = 6; + } +#ifdef TURBOVNC + n *= 10; +#endif + return n; +} /* * SetFormatAndEncodings. @@ -729,6 +1818,17 @@ Bool requestCompressLevel = False; Bool requestQualityLevel = False; Bool requestLastRectEncoding = False; + Bool requestNewFBSizeEncoding = True; + Bool requestTextChatEncoding = True; + Bool requestSubsampLevel = False; + int dsm = 0; + int tQL, tQLmax = 9; + static int qlmsg = 0, clmsg = 0; +#ifdef TURBOVNC + tQLmax = 100; +#endif + +// fprintf(stderr, "SetFormatAndEncodings: sent_FBU state: %2d\n", sent_FBU); spf.type = rfbSetPixelFormat; spf.format = myFormat; @@ -736,15 +1836,32 @@ spf.format.greenMax = Swap16IfLE(spf.format.greenMax); spf.format.blueMax = Swap16IfLE(spf.format.blueMax); + + currentMsg = rfbSetPixelFormat; if (!WriteExact(rfbsock, (char *)&spf, sz_rfbSetPixelFormatMsg)) return False; se->type = rfbSetEncodings; se->nEncodings = 0; + if (appData.ultraDSM) { + dsm = 1; + } + if (appData.encodingsString) { char *encStr = appData.encodingsString; int encStrLen; + if (strchr(encStr, ',')) { + char *p; + encStr = strdup(encStr); + p = encStr; + while (*p != '\0') { + if (*p == ',') { + *p = ' '; + } + p++; + } + } do { char *nextEncStr = strchr(encStr, ' '); if (nextEncStr) { @@ -754,50 +1871,102 @@ encStrLen = strlen(encStr); } +if (getenv("DEBUG_SETFORMAT")) { + fprintf(stderr, "encs: "); + write(2, encStr, encStrLen); + fprintf(stderr, "\n"); +} + if (strncasecmp(encStr,"raw",encStrLen) == 0) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw); } else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect); - } else if (strncasecmp(encStr,"tight",encStrLen) == 0) { + } else if (strncasecmp(encStr,"tight",encStrLen) == 0 && !dsm) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); requestLastRectEncoding = True; - if (appData.compressLevel >= 0 && appData.compressLevel <= 9) - requestCompressLevel = True; - if (appData.enableJPEG) - requestQualityLevel = True; + if (appData.compressLevel >= 0 && appData.compressLevel <= 9) { + requestCompressLevel = True; + } + if (appData.enableJPEG) { + requestQualityLevel = True; + } +#ifdef TURBOVNC + requestSubsampLevel = True; +#endif } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile); - } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) { + } else if (strncasecmp(encStr,"zlib",encStrLen) == 0 && !dsm) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib); - if (appData.compressLevel >= 0 && appData.compressLevel <= 9) - requestCompressLevel = True; - } else if (strncasecmp(encStr,"corre",encStrLen) == 0) { + if (appData.compressLevel >= 0 && appData.compressLevel <= 9) { + requestCompressLevel = True; + } + } else if (strncasecmp(encStr,"corre",encStrLen) == 0 && !dsm) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE); } else if (strncasecmp(encStr,"rre",encStrLen) == 0) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE); + } else if (strncasecmp(encStr,"zrle",encStrLen) == 0) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZRLE); +#if DO_ZYWRLE + } else if (strncasecmp(encStr,"zywrle",encStrLen) == 0) { + int qlevel = appData.qualityLevel; + if (qlevel < 0 || qlevel > tQLmax) qlevel = guess_qualitylevel(); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZYWRLE); + requestQualityLevel = True; + if (qlevel < 3) { + zywrle_level = 3; + } else if (qlevel < 6) { + zywrle_level = 2; + } else { + zywrle_level = 1; + } +#endif } else { fprintf(stderr,"Unknown encoding '%.*s'\n",encStrLen,encStr); + if (dsm && strstr(encStr, "tight") == encStr) fprintf(stderr, "tight encoding does not yet work with ultraDSM, skipping it.\n"); + if (dsm && strstr(encStr, "corre") == encStr) fprintf(stderr, "corre encoding does not yet work with ultraDSM, skipping it.\n"); + if (dsm && strstr(encStr, "zlib" ) == encStr) fprintf(stderr, "zlib encoding does not yet work with ultraDSM, skipping it.\n"); } encStr = nextEncStr; } while (encStr && se->nEncodings < MAX_ENCODINGS); if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) { - encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + - rfbEncodingCompressLevel0); + ; + } else if (se->nEncodings < MAX_ENCODINGS) { + appData.compressLevel = guess_compresslevel(); + if (clmsg++ == 0) fprintf(stderr, "guessed: -compresslevel %d\n", appData.compressLevel); } + encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0); if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) { - if (appData.qualityLevel < 0 || appData.qualityLevel > 9) - appData.qualityLevel = 5; - encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + - rfbEncodingQualityLevel0); + if (appData.qualityLevel < 0 || appData.qualityLevel > tQLmax) { + appData.qualityLevel = guess_qualitylevel(); + if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel %d\n", appData.qualityLevel); + } + } else if (se->nEncodings < MAX_ENCODINGS) { + appData.qualityLevel = guess_qualitylevel(); + if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel %d\n", appData.qualityLevel); + } +#ifdef TURBOVNC + tQL = appData.qualityLevel / 10; + if (tQL < 0) tQL = 1; + if (tQL > 9) tQL = 9; + encs[se->nEncodings++] = Swap32IfLE(tQL + rfbEncodingQualityLevel0); + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbJpegQualityLevel1 - 1); + if (se->nEncodings < MAX_ENCODINGS && requestSubsampLevel) { + if (appData.subsampLevel < 0 || appData.subsampLevel > TVNC_SAMPOPT - 1) { + appData.subsampLevel = TVNC_1X; + } + encs[se->nEncodings++] = Swap32IfLE(appData.subsampLevel + rfbJpegSubsamp1X); } +#else + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbEncodingQualityLevel0); +#endif if (appData.useRemoteCursor) { if (se->nEncodings < MAX_ENCODINGS) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor); - if (se->nEncodings < MAX_ENCODINGS) + if (se->nEncodings < MAX_ENCODINGS && !appData.useX11Cursor) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor); if (se->nEncodings < MAX_ENCODINGS) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos); @@ -806,10 +1975,16 @@ if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect); } - } - else { + + if (se->nEncodings < MAX_ENCODINGS && requestNewFBSizeEncoding) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingNewFBSize); + } + + } else { + /* DIFFERENT CASE */ + if (SameMachine(rfbsock)) { - if (!tunnelSpecified) { + if (!tunnelSpecified && appData.useRawLocal) { fprintf(stderr,"Same machine: preferring raw encoding\n"); encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw); } else { @@ -818,44 +1993,84 @@ } encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect); - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); + if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZRLE); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZYWRLE); encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile); - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib); - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE); + if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib); + if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE); encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE); - if (appData.compressLevel >= 0 && appData.compressLevel <= 9) { - encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + - rfbEncodingCompressLevel0); - } else if (!tunnelSpecified) { - /* If -tunnel option was provided, we assume that server machine is - not in the local network so we use default compression level for - tight encoding instead of fast compression. Thus we are - requesting level 1 compression only if tunneling is not used. */ - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCompressLevel1); - } - - if (appData.enableJPEG) { - if (appData.qualityLevel < 0 || appData.qualityLevel > 9) - appData.qualityLevel = 5; - encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + - rfbEncodingQualityLevel0); + if (!dsm && appData.compressLevel >= 0 && appData.compressLevel <= 9) { + encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0); + } else { + /* + * OUT OF DATE: If -tunnel option was provided, we assume that server machine is + * not in the local network so we use default compression level for + * tight encoding instead of fast compression. Thus we are + * requesting level 1 compression only if tunneling is not used. + */ + appData.compressLevel = guess_compresslevel(); + if (clmsg++ == 0) fprintf(stderr, "guessed: -compresslevel %d\n", appData.compressLevel); + encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0); + } + + if (!dsm && appData.enableJPEG) { + if (appData.qualityLevel < 0 || appData.qualityLevel > tQLmax) { + appData.qualityLevel = guess_qualitylevel(); + if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel %d\n", appData.qualityLevel); + } + +#ifdef TURBOVNC + requestSubsampLevel = True; + tQL = appData.qualityLevel / 10; + if (tQL < 0) tQL = 1; + if (tQL > 9) tQL = 9; + encs[se->nEncodings++] = Swap32IfLE(tQL + rfbEncodingQualityLevel0); + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbJpegQualityLevel1 - 1); + if (se->nEncodings < MAX_ENCODINGS && requestSubsampLevel) { + if (appData.subsampLevel < 0 || appData.subsampLevel > TVNC_SAMPOPT - 1) { + appData.subsampLevel = TVNC_1X; + } + encs[se->nEncodings++] = Swap32IfLE(appData.subsampLevel + rfbJpegSubsamp1X); + } +#else + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbEncodingQualityLevel0); +#endif + } if (appData.useRemoteCursor) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor); - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor); + if (!appData.useX11Cursor) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor); + } encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos); } encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect); + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingNewFBSize); } len = sz_rfbSetEncodingsMsg + se->nEncodings * 4; - se->nEncodings = Swap16IfLE(se->nEncodings); + if (!appData.ultraDSM) { + se->nEncodings = Swap16IfLE(se->nEncodings); - if (!WriteExact(rfbsock, buf, len)) return False; + if (!WriteExact(rfbsock, buf, len)) return False; + } else { + /* for UltraVNC encryption DSM we have to send each encoding separately (why?) */ + int i, errs = 0, nenc = se->nEncodings; + + se->nEncodings = Swap16IfLE(se->nEncodings); + + currentMsg = rfbSetEncodings; + if (!WriteExact(rfbsock, buf, sz_rfbSetEncodingsMsg)) errs++; + for (i=0; i < nenc; i++) { + if (!WriteExact(rfbsock, (char *)&encs[i], sizeof(CARD32))) errs++; + } + if (errs) return False; + } return True; } @@ -868,31 +2083,86 @@ Bool SendIncrementalFramebufferUpdateRequest() { - return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, - 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); + + +static int dyn = -1; +extern int filexfer_sock; +extern int filexfer_listen; /* * SendFramebufferUpdateRequest. */ - Bool SendFramebufferUpdateRequest(int x, int y, int w, int h, Bool incremental) { - rfbFramebufferUpdateRequestMsg fur; + rfbFramebufferUpdateRequestMsg fur; + static int db = -1; + + if (db < 0) { + if (getenv("SSVNC_DEBUG_RECTS")) { + db = atoi(getenv("SSVNC_DEBUG_RECTS")); + } else { + db = 0; + } + } - fur.type = rfbFramebufferUpdateRequest; - fur.incremental = incremental ? 1 : 0; - fur.x = Swap16IfLE(x); - fur.y = Swap16IfLE(y); - fur.w = Swap16IfLE(w); - fur.h = Swap16IfLE(h); + if (db) fprintf(stderr, "SendFramebufferUpdateRequest(%d, %d, %d, %d, incremental=%d)\n", x, y, w, h, (int) incremental); - if (!WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg)) - return False; + if (dyn < 0) { + struct stat sb; + if (getenv("USER") && !strcmp(getenv("USER"), "runge")) { + if (stat("/tmp/nodyn", &sb) == 0) { + putenv("NOFTFBUPDATES=1"); + unlink("/tmp/nodyn"); + } + } + if (getenv("NOFTFBUPDATES")) { + dyn = 0; + } else { + dyn = 1; + } + } - return True; + if (appData.fileActive && filexfer_sock >= 0) { + static int first = 1; + if (first) { + fprintf(stderr, "SFU: dynamic fb updates during filexfer: %d\n", dyn); + first = 0; + } +if (db > 2 || 0) fprintf(stderr, "A sfur: %d %d %d %d d_last: %d\n", x, y, w, h, (int) (time(NULL) - last_filexfer)); + if (!dyn || time(NULL) < last_filexfer + delay_filexfer) { + return True; + } + } +if (db > 1) fprintf(stderr, "B sfur: %d %d %d %d\n", x, y, w, h); + + fur.type = rfbFramebufferUpdateRequest; + fur.incremental = incremental ? 1 : 0; + fur.x = Swap16IfLE(x); + fur.y = Swap16IfLE(y); + fur.w = Swap16IfLE(w); + fur.h = Swap16IfLE(h); + + if (incremental) { + sent_FBU = 1; + } else { + sent_FBU = 2; + } + + currentMsg = rfbFramebufferUpdateRequest; + if (!WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg)) { + return False; + } + + return True; } @@ -903,19 +2173,36 @@ Bool SendPointerEvent(int x, int y, int buttonMask) { - rfbPointerEventMsg pe; + rfbPointerEventMsg pe; + + if (appData.fileActive) { + if (!dyn || time(NULL) < last_filexfer + delay_filexfer) { + //fprintf(stderr, "skip SendPointerEvent: %d - %d\n", last_filexfer, time(NULL)); + return True; + } + } - 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); - return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg); + 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.x = Swap16IfLE(x); + pe.y = Swap16IfLE(y); + currentMsg = rfbPointerEvent; + return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg); } @@ -926,12 +2213,20 @@ Bool SendKeyEvent(CARD32 key, Bool down) { - rfbKeyEventMsg ke; + rfbKeyEventMsg ke; + + if (appData.fileActive) { + if (!dyn || time(NULL) < last_filexfer + delay_filexfer) { + //fprintf(stderr, "skip SendPointerEvent: %d - %d\n", last_filexfer, time(NULL)); + return True; + } + } - ke.type = rfbKeyEvent; - ke.down = down ? 1 : 0; - ke.key = Swap32IfLE(key); - return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg); + ke.type = rfbKeyEvent; + ke.down = down ? 1 : 0; + ke.key = Swap32IfLE(key); + currentMsg = rfbKeyEvent; + return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg); } @@ -942,281 +2237,1024 @@ Bool SendClientCutText(char *str, int len) { - rfbClientCutTextMsg cct; + rfbClientCutTextMsg cct; + + if (serverCutText) { + free(serverCutText); + } + serverCutText = NULL; + + if (appData.fileActive) { + if (!dyn || time(NULL) < last_filexfer + delay_filexfer) { + // ultravnc java viewer lets this one through. + return True; + } + } + + if (appData.viewOnly) { + return True; + } - if (serverCutText) - free(serverCutText); - serverCutText = NULL; - - cct.type = rfbClientCutText; - cct.length = Swap32IfLE(len); - return (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) && - WriteExact(rfbsock, str, len)); + cct.type = rfbClientCutText; + cct.length = Swap32IfLE(len); + currentMsg = rfbClientCutText; + return (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) && + WriteExact(rfbsock, str, len)); } +static int ultra_scale = 0; -/* - * HandleRFBServerMessage. - */ +Bool +SendServerScale(int nfac) +{ + rfbSetScaleMsg ssc; + if (nfac < 0 || nfac > 100) { + return True; + } + + ultra_scale = nfac; + ssc.type = rfbSetScale; + ssc.scale = nfac; + currentMsg = rfbSetScale; + return WriteExact(rfbsock, (char *)&ssc, sz_rfbSetScaleMsg); +} Bool -HandleRFBServerMessage() +SendServerInput(Bool enabled) { - rfbServerToClientMsg msg; + rfbSetServerInputMsg sim; - if (!ReadFromRFBServer((char *)&msg, 1)) - return False; + sim.type = rfbSetServerInput; + sim.status = enabled; + currentMsg = rfbSetServerInput; + return WriteExact(rfbsock, (char *)&sim, sz_rfbSetServerInputMsg); +} - switch (msg.type) { +Bool +SendSingleWindow(int x, int y) +{ + static int w_old = -1, h_old = -1; + rfbSetSWMsg sw; - case rfbSetColourMapEntries: - { - int i; - CARD16 rgb[3]; - XColor xc; + fprintf(stderr, "SendSingleWindow: %d %d\n", x, y); - if (!ReadFromRFBServer(((char *)&msg) + 1, - sz_rfbSetColourMapEntriesMsg - 1)) - return False; + if (x == -1 && y == -1) { + sw.type = rfbSetSW; + sw.x = Swap16IfLE(1); + sw.y = Swap16IfLE(1); + if (w_old > 0) { + si.framebufferWidth = w_old; + si.framebufferHeight = h_old; + ReDoDesktop(); + } + w_old = h_old = -1; + } else { + sw.type = rfbSetSW; + sw.x = Swap16IfLE(x); + sw.y = Swap16IfLE(y); + w_old = si.framebufferWidth; + h_old = si.framebufferHeight; + + } + sw.status = True; + currentMsg = rfbSetSW; + return WriteExact(rfbsock, (char *)&sw, sz_rfbSetSWMsg); +} - msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour); - msg.scme.nColours = Swap16IfLE(msg.scme.nColours); +Bool +SendTextChat(char *str) +{ + static int db = -1; + rfbTextChatMsg chat; - for (i = 0; i < msg.scme.nColours; i++) { - if (!ReadFromRFBServer((char *)rgb, 6)) - return False; - xc.pixel = msg.scme.firstColour + i; - xc.red = Swap16IfLE(rgb[0]); - xc.green = Swap16IfLE(rgb[1]); - xc.blue = Swap16IfLE(rgb[2]); - xc.flags = DoRed|DoGreen|DoBlue; - XStoreColor(dpy, cmap, &xc); - } + if (db < 0) { + if (getenv("SSVNC_DEBUG_CHAT")) { + db = 1; + } else { + db = 0; + } + } + if (!appData.chatActive) { + SendTextChatOpen(); + appData.chatActive = True; + } - break; - } + chat.type = rfbTextChat; + chat.pad1 = 0; + chat.pad2 = 0; + 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: - { - rfbFramebufferUpdateRectHeader rect; - int linesToRead; - 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) +{ + rfbTextChatMsg chat; + chat.type = rfbTextChat; + chat.pad1 = 0; + chat.pad2 = 0; + chat.length = Swap32IfLE(rfbTextChatClose); + appData.chatActive = False; + return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg); +} - for (i = 0; i < msg.fu.nRects; i++) { - if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) - return False; +Bool +SendTextChatFinished(void) +{ + rfbTextChatMsg chat; + chat.type = rfbTextChat; + chat.pad1 = 0; + chat.pad2 = 0; + chat.length = Swap32IfLE(rfbTextChatFinished); + appData.chatActive = False; + return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg); +} + +extern int do_format_change; +extern int do_cursor_change; +extern double do_fb_update; +extern void cutover_format_change(void); + +double dtime(double *t_old) { + /* + * usage: call with 0.0 to initialize, subsequent calls give + * the time difference since last call. + */ + double t_now, dt; + struct timeval now; + + gettimeofday(&now, NULL); + t_now = now.tv_sec + ( (double) now.tv_usec/1000000. ); + if (*t_old == 0.0) { + *t_old = t_now; + return t_now; + } + dt = t_now - *t_old; + *t_old = t_now; + return(dt); +} + +/* common dtime() activities: */ +double dtime0(double *t_old) { + *t_old = 0.0; + return dtime(t_old); +} + +double dnow(void) { + double t; + return dtime0(&t); +} + +static char fxfer[65536]; + +Bool HandleFileXfer(void) { + unsigned char hdr[12]; + unsigned int len; + + int rfbDirContentRequest = 1; + int rfbDirPacket = 2; // Full directory name or full file name. + int rfbFileTransferRequest = 3; + int rfbFileHeader = 4; + int rfbFilePacket = 5; // One slice of the file + int rfbEndOfFile = 6; + int rfbAbortFileTransfer = 7; + int rfbFileTransferOffer = 8; + int rfbFileAcceptHeader = 9; // The server accepts or rejects the file + int rfbCommand = 10; + int rfbCommandReturn = 11; + int rfbFileChecksums = 12; + + int rfbRDirContent = 1; // Request a Server Directory contents + int rfbRDrivesList = 2; // Request the server's drives list + + int rfbADirectory = 1; // Reception of a directory name + int rfbAFile = 2; // Reception of a file name + int rfbADrivesList = 3; // Reception of a list of drives + int rfbADirCreate = 4; // Response to a create dir command + int rfbADirDelete = 5; // Response to a delete dir command + int rfbAFileCreate = 6; // Response to a create file command + int rfbAFileDelete = 7; // Response to a delete file command + + int rfbCDirCreate = 1; // Request the server to create the given directory + int rfbCDirDelete = 2; // Request the server to delete the given directory + int rfbCFileCreate = 3; // Request the server to create the given file + int rfbCFileDelete = 4; // Request the server to delete the given file + + int rfbRErrorUnknownCmd = 1; // Unknown FileTransfer command. +#define rfbRErrorCmd 0xFFFFFFFF + + static int db = -1; + static int guess_x11vnc = 0; + +#if 0 + if (filexfer_sock < 0) { + return True; + } + // instead, we read and discard the ft msg data. +#endif - rect.encoding = Swap32IfLE(rect.encoding); - if (rect.encoding == rfbEncodingLastRect) - break; +//fprintf(stderr, "In HandleFileXfer\n"); - rect.r.x = Swap16IfLE(rect.r.x); - rect.r.y = Swap16IfLE(rect.r.y); - rect.r.w = Swap16IfLE(rect.r.w); - rect.r.h = Swap16IfLE(rect.r.h); - - if (rect.encoding == rfbEncodingXCursor || - rect.encoding == rfbEncodingRichCursor) { - 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)) { + skip_XtUpdateAll = 0; + return False; + } + if (filexfer_sock >= 0) { + write(filexfer_sock, hdr, 12); + } else { + fprintf(stderr, "filexfer_sock closed, discarding 12 bytes\n"); + } + if (db) fprintf(stderr, "\n"); + if (db) fprintf(stderr, "Got rfbFileTransfer hdr\n"); + if (db > 1) write(2, hdr, 12); + + if (db) { + int i; + fprintf(stderr, "HFX HDR:"); + for (i=0; i < 12; i++) { + fprintf(stderr, " %d", (int) hdr[i]); + } + fprintf(stderr, "\n"); } - continue; - } - 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) { + + } + + 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) { + if (!ReadFromRFBServer(fxfer, len)) { + skip_XtUpdateAll = 0; + 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); + } + } + + len = (hdr[4] << 24) | (hdr[5] << 16) | (hdr[6] << 8) | hdr[7]; + if (db) fprintf(stderr, "Got rfbFileTransfer: len2 %u\n", len); - /* 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); +#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; + return False; + } + 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 { + fprintf(stderr, "filexfer_sock closed, discarding %d bytes\n", len); + } + } - switch (rect.encoding) { + read_no_more: + + if (filexfer_sock < 0) { + int stop = 0; + static time_t last_stop = 0; +#if 0 + // this isn't working + if (hdr[1] == rfbFilePacket || hdr[1] == rfbFileHeader) { + fprintf(stderr, "filexfer_sock closed, trying to abort receive\n"); + stop = 1; + } +#endif + if (stop && time(NULL) > last_stop+1) { + unsigned char rpl[12]; + int k; + rpl[0] = rfbFileTransfer; + rpl[1] = rfbAbortFileTransfer; + for (k=2; k < 12; k++) { + rpl[k] = 0; + } + WriteExact(rfbsock, rpl, 12); + last_stop = time(NULL); + } + } - case rfbEncodingRaw: + if (db) fprintf(stderr, "Got rfbFileTransfer done.\n"); + skip_XtUpdateAll = 0; - bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; - linesToRead = BUFFER_SIZE / bytesPerLine; + 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; - CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, - linesToRead); +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; - - if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) - return False; - - cr.srcX = Swap16IfLE(cr.srcX); - cr.srcY = Swap16IfLE(cr.srcY); - - /* If RichCursor encoding is used, we should extend our - "cursor lock area" (previously set to destination - rectangle) to the source rectangle as well. */ - SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h); - - if (appData.copyRectDelay != 0) { - XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, - rect.r.w, rect.r.h); - XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, - rect.r.w, rect.r.h); - XSync(dpy,False); - usleep(appData.copyRectDelay * 1000); - XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, - 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(); } - XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY, - rect.r.w, rect.r.h, rect.r.x, rect.r.y); + switch (msg.type) { - break; - } + case rfbSetColourMapEntries: + { + int i; + CARD16 rgb[3]; + XColor xc; - case rfbEncodingRRE: - { - switch (myFormat.bitsPerPixel) { - case 8: - if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 16: - if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 32: - 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; } - break; - } - case rfbEncodingCoRRE: - { - switch (myFormat.bitsPerPixel) { - case 8: - if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 16: - if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 32: - if (!HandleCoRRE32(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; + } + xc.pixel = msg.scme.firstColour + i; + xc.red = Swap16IfLE(rgb[0]); + xc.green = Swap16IfLE(rgb[1]); + xc.blue = Swap16IfLE(rgb[2]); + if (appData.useGreyScale) { + int ave = (xc.red + xc.green + xc.blue)/3; + xc.red = ave; + xc.green = ave; + xc.blue = ave; + } + xc.flags = DoRed|DoGreen|DoBlue; + XStoreColor(dpy, cmap, &xc); } + break; - } + } - case rfbEncodingHextile: - { - switch (myFormat.bitsPerPixel) { - case 8: - if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 16: - if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 32: - if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; + case rfbFramebufferUpdate: + { + rfbFramebufferUpdateRectHeader rect; + int linesToRead; + int bytesPerLine; + int i; + int usecs; + + int area_copyrect = 0; + int area_tight = 0; + int area_zrle = 0; + int area_raw = 0; + static int rdb = -1; + static int delay_sync = -1; + static int delay_sync_env = -1; + int try_delay_sync = 0; + int cnt_pseudo = 0; + int cnt_image = 0; + + if (db) fprintf(stderr, "FBU-0: %.6f\n", dnow()); + if (rdb < 0) { + if (getenv("SSVNC_DEBUG_RECTS")) { + rdb = atoi(getenv("SSVNC_DEBUG_RECTS")); + } else { + rdb = 0; + } } - break; - } + if (delay_sync < 0) { + if (getenv("SSVNC_DELAY_SYNC")) { + delay_sync = atoi(getenv("SSVNC_DELAY_SYNC")); + delay_sync_env = delay_sync; + } else { + delay_sync = 0; + } + } + + int skip_incFBU = 0; + sent_FBU = -1; - case rfbEncodingZlib: - { - switch (myFormat.bitsPerPixel) { - case 8: - if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 16: - if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 32: - if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; + if (appData.pipelineUpdates) { + /* turbovnc speed idea */ + XEvent ev; + memset(&ev, 0, sizeof(ev)); + ev.xclient.type = ClientMessage; + ev.xclient.window = XtWindow(desktop); + ev.xclient.message_type = XA_INTEGER; + ev.xclient.format = 8; + strcpy(ev.xclient.data.b, "SendRFBUpdate"); + XSendEvent(dpy, XtWindow(desktop), False, 0, &ev); } - break; - } - case rfbEncodingTight: - { - switch (myFormat.bitsPerPixel) { - case 8: - if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 16: - if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; - case 32: - if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) - return False; - break; + if (!ReadFromRFBServer(((char *)&msg.fu) + 1, sz_rfbFramebufferUpdateMsg - 1)) { + return False; } - break; - } - default: - fprintf(stderr,"Unknown rect encoding %d\n", - (int)rect.encoding); - return False; - } + msg.fu.nRects = Swap16IfLE(msg.fu.nRects); - /* Now we may discard "soft cursor locks". */ - SoftCursorUnlockScreen(); - } + if (rdb) fprintf(stderr, "Begin rect loop %d\n", msg.fu.nRects); + + if (delay_sync) { + try_delay_sync = 1; + } else { + if (delay_sync_env != -1 && delay_sync_env == 0) { + ; + } else if (appData.yCrop > 0) { + ; + } else if (scale_factor_x > 0.0 && scale_factor_x != 1.0) { + ; + } else if (scale_factor_y > 0.0 && scale_factor_y != 1.0) { + ; + } else { + static int msg = 0; + /* fullScreen? */ + /* useXserverBackingStore? */ + /* useX11Cursor & etc? */ + /* scrollbars? */ + if (!msg) { + fprintf(stderr, "enabling 'delay_sync' mode for faster local drawing,\ndisable via env SSVNC_DELAY_SYNC=0 if there are painting errors.\n"); + msg = 1; + } + try_delay_sync = 1; + } + } + if (try_delay_sync) { + skip_maybe_sync = 1; + } +#define STOP_DELAY_SYNC \ + if (try_delay_sync) { \ + if (cnt_image && skip_maybe_sync) { \ + XSync(dpy, False); \ + } \ + try_delay_sync = 0; \ + skip_maybe_sync = 0; \ + } + + for (i = 0; i < msg.fu.nRects; i++) { + if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) { + return False; + } + + rect.encoding = Swap32IfLE(rect.encoding); + if (rect.encoding == rfbEncodingLastRect) { + break; + } + + rect.r.x = Swap16IfLE(rect.r.x); + rect.r.y = Swap16IfLE(rect.r.y); + rect.r.w = Swap16IfLE(rect.r.w); + rect.r.h = Swap16IfLE(rect.r.h); + + if (rdb > 1) fprintf(stderr, "nRects: %d i=%d enc: %d %dx%d+%d+%d\n", msg.fu.nRects, i, rect.encoding, rect.r.w, rect.r.h, rect.r.x, rect.r.y); + + if (rect.encoding == rfbEncodingXCursor || rect.encoding == rfbEncodingRichCursor) { + cnt_pseudo++; + STOP_DELAY_SYNC + + if (db) fprintf(stderr, "FBU-Cur1 %.6f\n", dnow()); + if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, rect.encoding)) { + return False; + } + if (db) fprintf(stderr, "FBU-Cur2 %.6f\n", dnow()); + continue; + } + + if (rect.encoding == rfbEncodingPointerPos) { + cnt_pseudo++; + STOP_DELAY_SYNC + if (db) fprintf(stderr, "FBU-Pos1 %.6f\n", dnow()); + if (0) fprintf(stderr, "CursorPos: %d %d / %d %d\n", rect.r.x, rect.r.y, rect.r.w, rect.r.h); + if (ultra_scale > 0) { + int f = ultra_scale; + if (!HandleCursorPos(rect.r.x/f, rect.r.y/f)) { + return False; + } + } else { + if (!HandleCursorPos(rect.r.x, rect.r.y)) { + return False; + } + } + if (db) fprintf(stderr, "FBU-Pos2 %.6f\n", dnow()); + continue; + } + if (rect.encoding == rfbEncodingNewFBSize) { + cnt_pseudo++; + STOP_DELAY_SYNC + 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; + //fprintf(stderr, "si: %d %d\n", si.framebufferWidth, si.framebufferHeight); + ReDoDesktop(); + continue; + } + if (rdb) fprintf(stderr,"Rect: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); + cnt_image++; + + if (appData.ultraDSM) { + /* + * What a huge mess the UltraVNC DSM plugin is!!! + * We read and ignore their little "this much data" hint... + */ + switch (rect.encoding) + { + case rfbEncodingRaw: + case rfbEncodingRRE: + case rfbEncodingCoRRE: + case rfbEncodingHextile: + //case rfbEncodingUltra: +// case rfbEncodingZlib: + //case rfbEncodingXOR_Zlib: + //case rfbEncodingXORMultiColor_Zlib: + //case rfbEncodingXORMonoColor_Zlib: + //case rfbEncodingSolidColor: + case rfbEncodingTight: + case rfbEncodingZlibHex: + case rfbEncodingZRLE: + case rfbEncodingZYWRLE: + { + CARD32 discard; + ReadFromRFBServer((char *)&discard, sizeof(CARD32)); + } + break; + } + } + + if ((rect.r.x + rect.r.w > si.framebufferWidth) || + (rect.r.y + rect.r.h > si.framebufferHeight)) { + 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) { + fprintf(stderr,"*** Warning *** Zero size rect: %dx%d+%d+%d encoding=%d\n", + rect.r.w, rect.r.h, rect.r.x, rect.r.y, rect.encoding); + if (0) continue; + } + + /* If RichCursor encoding is used, we should prevent collisions + between framebuffer updates and cursor drawing operations. */ + if (db) fprintf(stderr, "FBU-SCL1 %.6f\n", dnow()); + + SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h); + + if (db) fprintf(stderr, "FBU-SCL2 %.6f\n", dnow()); + + + switch (rect.encoding) { + + case rfbEncodingRaw: + + bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; + linesToRead = BUFFER_SIZE / bytesPerLine; + + if (db) fprintf(stderr, "Raw: %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); + area_raw += rect.r.w * rect.r.h; + + while (rect.r.h > 0) { + if (linesToRead > rect.r.h) { + linesToRead = rect.r.h; + } + + if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) { + return False; + } + + CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, linesToRead); + + rect.r.h -= linesToRead; + rect.r.y += linesToRead; + } + break; + + case rfbEncodingCopyRect: + { + rfbCopyRect cr; + + STOP_DELAY_SYNC + XSync(dpy, False); + + if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) { + return False; + } + if (appData.chatOnly) { + break; + } + + cr.srcX = Swap16IfLE(cr.srcX); + cr.srcY = Swap16IfLE(cr.srcY); + + if (db) fprintf(stderr, "Copy: %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); + area_copyrect += rect.r.w * rect.r.h; + + /* If RichCursor encoding is used, we should extend our + "cursor lock area" (previously set to destination + rectangle) to the source rectangle as well. */ + + if (db) fprintf(stderr, "FBU-SCL3 %.6f\n", dnow()); + + SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h); + + if (db) fprintf(stderr, "FBU-SCL4 %.6f\n", dnow()); + + if (appData.copyRectDelay != 0) { + XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); + XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h); + XSync(dpy,False); + usleep(appData.copyRectDelay * 1000); + XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h); + XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); + } + + if (db) fprintf(stderr, "FBU-CPA1 %.6f\n", dnow()); + 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, 0); + XSync(dpy, False); + } else { + XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY, + rect.r.w, rect.r.h, rect.r.x, rect.r.y); + } + if (db) fprintf(stderr, "FBU-CPA2 %.6f\n", dnow()); + + break; + } + + case rfbEncodingRRE: + { + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 16: + if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 32: + if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + } + break; + } + + case rfbEncodingCoRRE: + { + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 16: + if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 32: + if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + } + break; + } + + case rfbEncodingHextile: + { + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 16: + if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 32: + if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + } + break; + } + + case rfbEncodingZlib: + { + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 16: + if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 32: + if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + } + break; + } + + case rfbEncodingTight: + { + if (db) fprintf(stderr, "Tight: %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); + area_tight += rect.r.w * rect.r.h; + if (db) fprintf(stderr, "FBU-TGH1 %.6f\n", dnow()); + + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 16: + if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 32: + if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + } + if (db) fprintf(stderr, "FBU-TGH2 %.6f\n", dnow()); + break; + } + + /* runge adds zrle and zywrle: */ + case rfbEncodingZRLE: +#if DO_ZYWRLE + zywrle_level = 0; + case rfbEncodingZYWRLE: +#endif + { + if (db) fprintf(stderr, "ZRLE: %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); + area_zrle += rect.r.w * rect.r.h; + switch (myFormat.bitsPerPixel) { + case 8: + if (!HandleZRLE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + break; + case 16: + if (myFormat.greenMax > 0x1f) { + if (!HandleZRLE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + } else { + if (!HandleZRLE15(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { + return False; + } + } + break; + case 32: + { + unsigned int maxColor=(myFormat.redMax< do_fb_update + 1.1) { + do_fb_update = 0.0; + SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, + si.framebufferHeight, False); + } + } #ifdef MITSHM /* if using shared memory PutImage, make sure that the X server has @@ -1224,59 +3262,168 @@ mainly to avoid copyrect using invalid screen contents - not sure if we'd need it otherwise. */ - if (appData.useShm) - XSync(dpy, False); + if (appData.useShm) { + XSync(dpy, False); + } else #endif + { + /* we do it always now. */ + XSync(dpy, False); + } + + if (skip_XtUpdate || skip_incFBU) { + ; + } else if (appData.pipelineUpdates) { + ; + } else if (!SendIncrementalFramebufferUpdateRequest()) { + return False; + } - if (!SendIncrementalFramebufferUpdateRequest()) - return False; - - break; + break; } case rfbBell: { - Window toplevelWin; + Window toplevelWin; + + if (appData.useBell) { + XBell(dpy, 0); + } - XBell(dpy, 0); + if (appData.raiseOnBeep) { + toplevelWin = XtWindow(toplevel); + XMapRaised(dpy, toplevelWin); + } - if (appData.raiseOnBeep) { - toplevelWin = XtWindow(toplevel); - XMapRaised(dpy, toplevelWin); + break; } - break; - } + case rfbServerCutText: + { + if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbServerCutTextMsg - 1)) { + return False; + } - case rfbServerCutText: - { - if (!ReadFromRFBServer(((char *)&msg) + 1, - sz_rfbServerCutTextMsg - 1)) - return False; + msg.sct.length = Swap32IfLE(msg.sct.length); - msg.sct.length = Swap32IfLE(msg.sct.length); + if (serverCutText) { + free(serverCutText); + } - if (serverCutText) - free(serverCutText); + serverCutText = malloc(msg.sct.length+1); - serverCutText = malloc(msg.sct.length+1); + if (!ReadFromRFBServer(serverCutText, msg.sct.length)) { + return False; + } - if (!ReadFromRFBServer(serverCutText, msg.sct.length)) - return False; + serverCutText[msg.sct.length] = 0; - serverCutText[msg.sct.length] = 0; + newServerCutText = True; - newServerCutText = True; + break; + } - break; - } + case rfbTextChat: + { + char *buffer = NULL; + if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbTextChatMsg - 1)) { + return False; + } + msg.tc.length = Swap32IfLE(msg.tc.length); + switch(msg.tc.length) { + case rfbTextChatOpen: + if (appData.termChat) { + printChat("\n*ChatOpen*\n\nSend: ", True); + } else { + printChat("\n*ChatOpen*\n", True); + } + appData.chatActive = True; + break; + case rfbTextChatClose: + printChat("\n*ChatClose*\n", False); + appData.chatActive = False; + break; + case rfbTextChatFinished: + printChat("\n*ChatFinished*\n", False); + appData.chatActive = False; + break; + default: + buffer = (char *)malloc(msg.tc.length+1); + if (!ReadFromRFBServer(buffer, msg.tc.length)) { + free(buffer); + return False; + } + buffer[msg.tc.length] = '\0'; + appData.chatActive = True; + GotChatText(buffer, msg.tc.length); + free(buffer); + } + break; + } - default: - fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type); - return False; - } + case rfbResizeFrameBuffer: + { + rfbResizeFrameBufferMsg rsmsg; + if (!ReadFromRFBServer(((char *)&rsmsg) + 1, sz_rfbResizeFrameBufferMsg - 1)) { + return False; + } + si.framebufferWidth = Swap16IfLE(rsmsg.framebufferWidth); + si.framebufferHeight = Swap16IfLE(rsmsg.framebufferHeight); + fprintf(stderr,"UltraVNC ReSize: %dx%d\n", si.framebufferWidth, si.framebufferHeight); + ReDoDesktop(); + break; + } - return True; + case rfbRestartConnection: + { + rfbRestartConnectionMsg rc; + int len; + char *rs_str; + char buf[5] = "\xff\xff\xff\xff"; + fprintf(stderr, "rfbRestartConnection. type=%d\n", (int) rc.type); + if (!ReadFromRFBServer((char *)&rc + 1, sz_rfbRestartConnectionMsg - 1)) { + return False; + } + len = Swap32IfLE(rc.length); + fprintf(stderr, "rfbRestartConnection. pad1=%d\n", (int) rc.pad1); + fprintf(stderr, "rfbRestartConnection. pad2=%d\n", (int) rc.pad2); + fprintf(stderr, "rfbRestartConnection. len=%d\n", len); + if (len) { + rs_str = (char *)malloc(2*len); + if (!ReadFromRFBServer(rs_str, len)) { + return False; + } + restart_session_pw = rs_str; + restart_session_len = len; + } + if (!WriteExact(rfbsock, buf, 4)) { + return False; + } + InitialiseRFBConnection(); + SetVisualAndCmap(); + SetFormatAndEncodings(); + DesktopCursorOff(); + SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, si.framebufferHeight, False); + + break; + } + + default: + fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type); + return False; + } + + if (appData.fileActive) { + if (filexfer_sock < 0 && filexfer_listen < 0) { + appData.fileActive = False; + SendFramebufferUpdateRequest(0, 0, 1, 1, False); + } else { +//fprintf(stderr, "CFX: A\n"); + CheckFileXfer(); + } + } + + return True; } @@ -1296,26 +3443,93 @@ #define CONCAT2(a,b) a##b #define CONCAT2E(a,b) CONCAT2(a,b) +#define CONCAT3(a,b,c) a##b##c +#define CONCAT3E(a,b,c) CONCAT3(a,b,c) + +static unsigned char* frameBuffer = NULL; +static int frameBufferLen = 0; + +#ifdef TURBOVNC +#include "turbovnc/turbojpeg.h" +tjhandle tjhnd=NULL; +static char *compressedData = NULL; +static char *uncompressedData = NULL; +#define CopyDataToImage CopyDataToScreen +static void turbovnc_FillRectangle(XGCValues *gcv, int rx, int ry, int rw, int rh) { + if (!appData.useXserverBackingStore) { + FillScreen(rx, ry, rw, rh, gcv->foreground); + } else { + XChangeGC(dpy, gc, GCForeground, gcv); + XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); + } +} +static void CopyImageToScreen(int x, int y, int w, int h) { + put_image(x, y, x, y, w, h, 0); +} +#endif + #define BPP 8 #include "rre.c" #include "corre.c" #include "hextile.c" #include "zlib.c" +// +#ifdef TURBOVNC +#undef FillRectangle +#define FillRectangle turbovnc_FillRectangle +#include "turbovnc/tight.c" +#undef FillRectangle +#else #include "tight.c" +#endif +// +#include "zrle.c" #undef BPP + #define BPP 16 #include "rre.c" #include "corre.c" #include "hextile.c" #include "zlib.c" +// +#ifdef TURBOVNC +#undef FillRectangle +#define FillRectangle turbovnc_FillRectangle +#include "turbovnc/tight.c" +#undef FillRectangle +#else #include "tight.c" +#endif +// +#include "zrle.c" +#define REALBPP 15 +#include "zrle.c" #undef BPP + #define BPP 32 #include "rre.c" #include "corre.c" #include "hextile.c" #include "zlib.c" +// +#ifdef TURBOVNC +#undef FillRectangle +#define FillRectangle turbovnc_FillRectangle +#include "turbovnc/tight.c" +#undef FillRectangle +#else #include "tight.c" +#endif +// +#include "zrle.c" +#define REALBPP 24 +#include "zrle.c" +#define REALBPP 24 +#define UNCOMP 8 +#include "zrle.c" +#define REALBPP 24 +#define UNCOMP -8 +#include "zrle.c" #undef BPP /* @@ -1325,23 +3539,27 @@ static void ReadConnFailedReason(void) { - CARD32 reasonLen; - char *reason = NULL; + CARD32 reasonLen; + char *reason = NULL; - if (ReadFromRFBServer((char *)&reasonLen, sizeof(reasonLen))) { - reasonLen = Swap32IfLE(reasonLen); - if ((reason = malloc(reasonLen)) != NULL && - ReadFromRFBServer(reason, reasonLen)) { - fprintf(stderr,"VNC connection failed: %.*s\n", (int)reasonLen, reason); - free(reason); - return; - } - } + if (ReadFromRFBServer((char *)&reasonLen, sizeof(reasonLen))) { + reasonLen = Swap32IfLE(reasonLen); + if ((reason = malloc(reasonLen)) != NULL && + ReadFromRFBServer(reason, reasonLen)) { + int len = reasonLen < sizeof(msgbuf) - 10 ? (int) reasonLen : sizeof(msgbuf) - 10; + sprintf(msgbuf,"VNC connection failed: %.*s\n", len, reason); + wmsg(msgbuf, 1); + free(reason); + return; + } + } - fprintf(stderr, "VNC connection failed\n"); + sprintf(msgbuf, "VNC connection failed\n"); + wmsg(msgbuf, 1); - if (reason != NULL) - free(reason); + if (reason != NULL) { + free(reason); + } } /* @@ -1358,9 +3576,9 @@ " %s significant bit in each byte is leftmost on the screen.\n", (format->bigEndian ? "Most" : "Least")); } else { - fprintf(stderr," %d bits per pixel.\n",format->bitsPerPixel); + fprintf(stderr," %d bits per pixel. ",format->bitsPerPixel); if (format->bitsPerPixel != 8) { - fprintf(stderr," %s significant byte first in each pixel.\n", + fprintf(stderr,"%s significant byte first in each pixel.\n", (format->bigEndian ? "Most" : "Least")); } if (format->trueColour) { @@ -1462,4 +3680,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 2008-10-05 15:16:30.000000000 -0400 @@ -29,6 +29,18 @@ #define HandleRREBPP CONCAT2E(HandleRRE,BPP) #define CARDBPP CONCAT2E(CARD,BPP) +#define FillRectangle(x, y, w, h, color) \ + { \ + XGCValues _gcv; \ + _gcv.foreground = color; \ + if (!appData.useXserverBackingStore) { \ + FillScreen(x, y, w, h, _gcv.foreground); \ + } else { \ + XChangeGC(dpy, gc, GCForeground, &_gcv); \ + XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \ + } \ + } + static Bool HandleRREBPP (int rx, int ry, int rw, int rh) { @@ -49,11 +61,19 @@ #if (BPP == 8) gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix); #else +#if (BPP == 16) + gcv.foreground = (appData.useBGR565 ? BGR565ToPixel[pix] : pix); +#else gcv.foreground = pix; #endif +#endif +#if 0 XChangeGC(dpy, gc, GCForeground, &gcv); XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); +#else + FillRectangle(rx, ry, rw, rh, gcv.foreground); +#endif for (i = 0; i < hdr.nSubrects; i++) { if (!ReadFromRFBServer((char *)&pix, sizeof(pix))) @@ -70,13 +90,23 @@ #if (BPP == 8) gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix); #else +#if (BPP == 16) + gcv.foreground = (appData.useBGR565 ? BGR565ToPixel[pix] : pix); +#else gcv.foreground = pix; #endif +#endif +#if 0 XChangeGC(dpy, gc, GCForeground, &gcv); XFillRectangle(dpy, desktopWin, gc, rx + subrect.x, ry + subrect.y, subrect.w, subrect.h); +#else + FillRectangle(rx + subrect.x, ry + subrect.y, subrect.w, subrect.h, gcv.foreground); +#endif } return True; } + +#undef FillRectangle diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/selection.c vnc_unixsrc/vncviewer/selection.c --- vnc_unixsrc.orig/vncviewer/selection.c 2004-03-03 04:11:52.000000000 -0500 +++ vnc_unixsrc/vncviewer/selection.c 2009-11-24 13:34:03.000000000 -0500 @@ -43,13 +43,16 @@ unsigned long* length, int* format); static void LoseSelection(Widget w, Atom *selection); -static Bool iAmSelectionOwner = False; +static Bool PrimarySelectionOwner = False; +static Bool ClipboardSelectionOwner = False; static Time prevSelectionTime = 0L; static Time cutBufferTime = 0L; #define TIME_LATER(a, b) ((a) != 0 && ((b) == 0 || (INT32)((a) - (b)) > 0)) +static Atom clipboard_atom = None; + /* * InitialiseSelection() must be called after realizing widgets (because * otherwise XtGetSelectionValue() fails). We register events on the root @@ -62,22 +65,28 @@ * available. */ -void -InitialiseSelection() -{ +static int dbg_sel = -1; + +void InitialiseSelection() { #if XtSpecificationRelease >= 6 - XtRegisterDrawable(dpy, DefaultRootWindow(dpy), toplevel); + XtRegisterDrawable(dpy, DefaultRootWindow(dpy), toplevel); #else - _XtRegisterWindow(DefaultRootWindow(dpy), toplevel); + _XtRegisterWindow(DefaultRootWindow(dpy), toplevel); #endif - XSelectInput(dpy, DefaultRootWindow(dpy), PropertyChangeMask); + XSelectInput(dpy, DefaultRootWindow(dpy), PropertyChangeMask); - XtAddRawEventHandler(toplevel, PropertyChangeMask, False, CutBufferChange, - NULL); + XtAddRawEventHandler(toplevel, PropertyChangeMask, False, CutBufferChange, NULL); - XtGetSelectionValue(toplevel, XA_PRIMARY, + clipboard_atom = XInternAtom(dpy, "CLIPBOARD", False); + + XtGetSelectionValue(toplevel, XA_PRIMARY, XInternAtom(dpy, "TIMESTAMP", False), GetInitialSelectionTimeCallback, NULL, CurrentTime); + + if (dbg_sel < 0) { + dbg_sel = 0; + if (getenv("SSVNC_DEBUG_SELECTION")) dbg_sel = 1; + } } @@ -93,13 +102,15 @@ Atom* selection, Atom* type, XtPointer value, unsigned long* length, int* format) { - if (value && *format == 32 && *length == 1) - prevSelectionTime = *(CARD32 *)value; - else - prevSelectionTime = 0L; - - if (value) - XtFree(value); + if (value && *format == 32 && *length == 1) { + prevSelectionTime = *(CARD32 *)value; + } else { + prevSelectionTime = 0L; + } + + if (value) { + XtFree(value); + } } @@ -121,26 +132,29 @@ void SelectionToVNC(Widget w, XEvent *event, String *params, Cardinal *num_params) { - Bool always = False; + Bool always = appData.sendAlways; + Atom sendsel = XA_PRIMARY; - if (*num_params != 0) { - if (strcmp(params[0],"always") == 0) { - always = True; - } else if (strcmp(params[0],"new") == 0) { - always = False; - } else { - fprintf(stderr,"Invalid params: SelectionToVNC(always|new)\n"); - return; - } - } - - if (always) { - XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL, - TimeFromEvent(event)); - } else { - XtGetSelectionValue(w, XA_PRIMARY, XInternAtom(dpy, "TIMESTAMP", False), - GetSelectionTimeCallback, NULL, TimeFromEvent(event)); - } + if (*num_params != 0) { + if (strcmp(params[0],"always") == 0) { + always = True; + } else if (strcmp(params[0],"new") == 0) { + always = False; + } else { + fprintf(stderr,"Invalid params: SelectionToVNC(always|new)\n"); + return; + } + } + if (appData.sendClipboard && clipboard_atom != None) { + sendsel = clipboard_atom; + } + if (dbg_sel) fprintf(stderr, "SelectionToVNC %s\n", sendsel == XA_PRIMARY ? "PRIMARY" : "CLIPBOARD"); + + if (always) { + XtGetSelectionValue(w, sendsel, XA_STRING, GetSelectionCallback, NULL, TimeFromEvent(event)); + } else { + XtGetSelectionValue(w, sendsel, XInternAtom(dpy, "TIMESTAMP", False), GetSelectionTimeCallback, NULL, TimeFromEvent(event)); + } } @@ -158,10 +172,12 @@ int len = *length; char *str = (char *)value; - if (str) - SendClientCutText(str, len); - else - SendCutBuffer(); + if (str) { + if (dbg_sel) fprintf(stderr, "SendClientCutText len: %d\n", len); + SendClientCutText(str, len); + } else if (!getenv("VNCVIEWER_NO_CUTBUFFER")) { + SendCutBuffer(); + } } @@ -180,26 +196,23 @@ Atom* type, XtPointer value, unsigned long* length, int* format) { - if (value && *format == 32 && *length == 1) { + if (value && *format == 32 && *length == 1) { + Time t = *(CARD32 *)value; - Time t = *(CARD32 *)value; - - if (TIME_LATER(t, prevSelectionTime)) { - prevSelectionTime = t; - XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL, - CurrentTime); - } - - } else { - - if (TIME_LATER(cutBufferTime, prevSelectionTime)) { - prevSelectionTime = cutBufferTime; - SendCutBuffer(); - } - } - - if (value) - XtFree(value); + if (TIME_LATER(t, prevSelectionTime)) { + prevSelectionTime = t; + XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL, CurrentTime); + } + } else if (!getenv("VNCVIEWER_NO_CUTBUFFER")) { + if (TIME_LATER(cutBufferTime, prevSelectionTime)) { + prevSelectionTime = cutBufferTime; + SendCutBuffer(); + } + } + + if (value) { + XtFree(value); + } } @@ -209,16 +222,17 @@ */ static void -SendCutBuffer() -{ - char *str; - int len; +SendCutBuffer() { + char *str; + int len; - str = XFetchBytes(dpy, &len); - if (!str) return; + if (dbg_sel) fprintf(stderr, "SendCutBuffer len: %d\n", len); - SendClientCutText(str, len); - XFree(str); + str = XFetchBytes(dpy, &len); + if (!str) return; + + SendClientCutText(str, len); + XFree(str); } @@ -230,10 +244,11 @@ static void CutBufferChange(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont) { - if (ev->type != PropertyNotify || ev->xproperty.atom != XA_CUT_BUFFER0) - return; + if (ev->type != PropertyNotify || ev->xproperty.atom != XA_CUT_BUFFER0) { + return; + } - cutBufferTime = ev->xproperty.time; + cutBufferTime = ev->xproperty.time; } @@ -249,36 +264,68 @@ void SelectionFromVNC(Widget w, XEvent *event, String *params, Cardinal *num_params) { - Bool always = False; - Time t = TimeFromEvent(event); - - if (*num_params != 0) { - if (strcmp(params[0],"always") == 0) { - always = True; - } else if (strcmp(params[0],"new") == 0) { - always = False; - } else { - fprintf(stderr,"Invalid params: SelectionFromVNC(always|new)\n"); - return; - } - } - - if (t == CurrentTime) { - fprintf(stderr,"Error in translations: SelectionFromVNC() must act on " - "event with time field\n"); - return; - } - - if (!serverCutText || (!always && !newServerCutText)) - return; - - newServerCutText = False; - - XStoreBytes(dpy, serverCutText, strlen(serverCutText)); - if (XtOwnSelection(desktop, XA_PRIMARY, t, ConvertSelection, LoseSelection, - NULL)) { - iAmSelectionOwner = True; - } + Bool always = False; + Time t = TimeFromEvent(event); + int hold_primary = 0; + int hold_clipboard = 0; + + if (dbg_sel) fprintf(stderr, "SelectionFromVNC\n"); + + if (*num_params != 0) { + if (strcmp(params[0],"always") == 0) { + always = True; + } else if (strcmp(params[0],"new") == 0) { + always = False; + } else { + fprintf(stderr,"Invalid params: SelectionFromVNC(always|new)\n"); + return; + } + } + + if (t == CurrentTime) { + fprintf(stderr,"Error in translations: SelectionFromVNC() must act on " + "event with time field\n"); + return; + } + + if (!serverCutText || (!always && !newServerCutText)) { + return; + } + + newServerCutText = False; + + if (appData.appShare) { + if (strstr(serverCutText, "X11VNC_APPSHARE_CMD:") == serverCutText) { + /* do something with it? */ + return; + } + } + + XStoreBytes(dpy, serverCutText, strlen(serverCutText)); + + if (appData.recvText == NULL) { + appData.recvText = strdup("both"); + } + if (!strcasecmp(appData.recvText, "primary")) { + hold_primary = 1; + } else if (!strcasecmp(appData.recvText, "clipboard")) { + hold_clipboard = 1; + } else { + hold_primary = hold_clipboard = 1; + } + + if (!hold_primary) { + ; + } else if (XtOwnSelection(desktop, XA_PRIMARY, t, ConvertSelection, LoseSelection, NULL)) { + PrimarySelectionOwner = True; + if (dbg_sel) fprintf(stderr, "Own PRIMARY\n"); + } + if (!hold_clipboard || clipboard_atom == None) { + ; + } else if (XtOwnSelection(desktop, clipboard_atom, t, ConvertSelection, LoseSelection, NULL)) { + ClipboardSelectionOwner = True; + if (dbg_sel) fprintf(stderr, "Own CLIPBOARD\n"); + } } @@ -293,37 +340,36 @@ XtPointer* value, unsigned long* length, int* format) { - if (*target == XA_STRING && serverCutText != NULL) { - *type = XA_STRING; - *length = strlen(serverCutText); - *value = (XtPointer)XtMalloc(*length); - memcpy((char*)*value, serverCutText, *length); - *format = 8; - return True; - } + if (*target == XA_STRING && serverCutText != NULL) { + *type = XA_STRING; + *length = strlen(serverCutText); + *value = (XtPointer)XtMalloc(*length); + memcpy((char*)*value, serverCutText, *length); + *format = 8; + return True; + } - if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type, + if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type, (XPointer*)value, length, format)) { - if (*target == XInternAtom(dpy, "TARGETS", False)) { - /* add STRING to list of standard targets */ - Atom* targetP; - Atom* std_targets = (Atom*)*value; - unsigned long std_length = *length; - - *length = std_length + 1; - *value = (XtPointer)XtMalloc(sizeof(Atom)*(*length)); - targetP = *(Atom**)value; - *targetP++ = XA_STRING; - memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); - XtFree((char*)std_targets); - *type = XA_ATOM; - *format = 32; - return True; - } - - return True; - } - return False; + if (*target == XInternAtom(dpy, "TARGETS", False)) { + /* add STRING to list of standard targets */ + Atom* targetP; + Atom* std_targets = (Atom*)*value; + unsigned long std_length = *length; + + *length = std_length + 1; + *value = (XtPointer)XtMalloc(sizeof(Atom)*(*length)); + targetP = *(Atom**)value; + *targetP++ = XA_STRING; + memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); + XtFree((char*)std_targets); + *type = XA_ATOM; + *format = 32; + return True; + } + return True; + } + return False; } @@ -332,7 +378,12 @@ */ static void -LoseSelection(Widget w, Atom *selection) -{ - iAmSelectionOwner = False; +LoseSelection(Widget w, Atom *selection) { + if (*selection == XA_PRIMARY) { + if (dbg_sel) fprintf(stderr, "lost PRIMARY\n"); + PrimarySelectionOwner = False; + } else if (clipboard_atom != None && *selection == clipboard_atom) { + if (dbg_sel) fprintf(stderr, "lost CLIPBOARD\n"); + ClipboardSelectionOwner = False; + } } 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 2009-11-28 02:25:03.000000000 -0500 @@ -30,71 +30,108 @@ static Bool caughtShmError = False; static Bool needShmCleanup = False; -void -ShmCleanup() -{ - fprintf(stderr,"ShmCleanup called\n"); - if (needShmCleanup) { - shmdt(shminfo.shmaddr); - shmctl(shminfo.shmid, IPC_RMID, 0); - needShmCleanup = False; - } +static int ShmCreationXErrorHandler(Display *dpy, XErrorEvent *error) { + caughtShmError = True; + return 0; } -static int -ShmCreationXErrorHandler(Display *dpy, XErrorEvent *error) -{ - caughtShmError = True; - return 0; +void ShmDetach() { + if (needShmCleanup) { + XErrorHandler oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler); + fprintf(stderr,"ShmDetach called.\n"); + XShmDetach(dpy, &shminfo); + XSync(dpy, False); + XSetErrorHandler(oldXErrorHandler); + } } -XImage * -CreateShmImage() -{ - XImage *image; - XErrorHandler oldXErrorHandler; - - if (!XShmQueryExtension(dpy)) - return NULL; - - image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo, - si.framebufferWidth, si.framebufferHeight); - if (!image) return NULL; - - shminfo.shmid = shmget(IPC_PRIVATE, - image->bytes_per_line * image->height, - IPC_CREAT|0777); +void ShmCleanup() { + if (needShmCleanup) { + fprintf(stderr,"ShmCleanup called.\n"); + XSync(dpy, False); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); - if (shminfo.shmid == -1) { - XDestroyImage(image); - return NULL; - } - - shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0); - - if (shminfo.shmaddr == (char *)-1) { - XDestroyImage(image); - shmctl(shminfo.shmid, IPC_RMID, 0); - return NULL; - } + needShmCleanup = False; + } +} - shminfo.readOnly = True; +Bool UsingShm() { + return needShmCleanup; +} - oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler); - XShmAttach(dpy, &shminfo); - XSync(dpy, False); - XSetErrorHandler(oldXErrorHandler); +int scale_round(int len, double fac); +extern int scale_x, scale_y; +extern double scale_factor_x, scale_factor_y; - if (caughtShmError) { - XDestroyImage(image); - shmdt(shminfo.shmaddr); - shmctl(shminfo.shmid, IPC_RMID, 0); - return NULL; - } +XImage * +CreateShmImage(int do_ycrop) +{ + XImage *image; + XErrorHandler oldXErrorHandler; + int ymax = si.framebufferHeight; + int xmax = si.framebufferWidth; + + if (!XShmQueryExtension(dpy)) { + return NULL; + } + if (!appData.useShm) { + return NULL; + } + if (do_ycrop == -1) { + /* kludge to test for shm prescence */ + return (XImage *) 0x1; + } + + if (do_ycrop) { + ymax = appData.yCrop; + } + + 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; + } + + shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height, IPC_CREAT|0777); + + if (shminfo.shmid == -1) { + XDestroyImage(image); + //fprintf(stderr, "CreateShmImage: destroyed 'image' (1)\n"); + return NULL; + } + + shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0); + + if (shminfo.shmaddr == (char *)-1) { + XDestroyImage(image); + //fprintf(stderr, "CreateShmImage: destroyed 'image' (2)\n"); + shmctl(shminfo.shmid, IPC_RMID, 0); + return NULL; + } + + shminfo.readOnly = True; + + oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler); + XShmAttach(dpy, &shminfo); + XSync(dpy, False); + XSetErrorHandler(oldXErrorHandler); + + if (caughtShmError) { + XDestroyImage(image); + //fprintf(stderr, "CreateShmImage: destroyed 'image' (3)\n"); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + return NULL; + } - needShmCleanup = True; + needShmCleanup = True; - fprintf(stderr,"Using shared memory PutImage\n"); + fprintf(stderr,"Using shared memory (PutImage ycrop=%d, Size %dx%d)\n", do_ycrop, xmax, ymax); - return image; + return image; } diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/smake vnc_unixsrc/vncviewer/smake --- vnc_unixsrc.orig/vncviewer/smake 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/smake 2007-02-19 12:28:05.000000000 -0500 @@ -0,0 +1,11 @@ +#!/bin/sh + +PATH=`pwd`/../..:/usr/sfw/bin:/usr/ccs/bin:$PATH +export PATH +if [ "X$1" != "X" ]; then + "$@" +else + make + strip vncviewer + ls -l vncviewer +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 2009-11-27 13:55:46.000000000 -0500 @@ -27,11 +27,17 @@ #include #include #include +#include #include #include #include #include +/* Solaris (sysv?) needs INADDR_NONE */ +#ifndef INADDR_NONE +#define INADDR_NONE ((in_addr_t) 0xffffffff) +#endif + void PrintInHex(char *buf, int len); Bool errorMessageOnReadFailure = True; @@ -56,31 +62,376 @@ */ static Bool rfbsockReady = False; +static Bool xfrsockReady = False; +static XtInputId rfbsockId = 0; +static XtInputId xfrsockId = 0; +static int do_rfbsockId = 0; +static int do_xfrsockId = 0; + static void rfbsockReadyCallback(XtPointer clientData, int *fd, XtInputId *id) { - rfbsockReady = True; - XtRemoveInput(*id); + rfbsockReady = True; +// XtRemoveInput(*id); + XtRemoveInput(rfbsockId); + if (do_xfrsockId) { + XtRemoveInput(xfrsockId); + } } static void -ProcessXtEvents() +xfrsockReadyCallback(XtPointer clientData, int *fd, XtInputId *id) { - rfbsockReady = False; - XtAppAddInput(appContext, rfbsock, (XtPointer)XtInputReadMask, - rfbsockReadyCallback, NULL); - while (!rfbsockReady) { - XtAppProcessEvent(appContext, XtIMAll); - } + xfrsockReady = True; + XtRemoveInput(xfrsockId); + if (do_rfbsockId) { + XtRemoveInput(rfbsockId); + } +} + + +extern int skip_XtUpdate; +extern int skip_XtUpdateAll; +extern int filexfer_sock, filexfer_listen; +extern time_t start_listen; +extern void CheckTextInput(void); +extern time_t last_filexfer; + +static char fxfer[65536]; +int fxfer_size = 65536; + +int rfbsock_is_ready(void) { + fd_set fds; + struct timeval tv; + + if (rfbsock < 0) { + return 0; + } + FD_ZERO(&fds); + FD_SET(rfbsock,&fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + if (select(rfbsock+1, &fds, NULL, NULL, &tv) > 0) { + if (FD_ISSET(rfbsock, &fds)) { + return 1; + } + } + return 0; +} + +time_t filexfer_start = 0; + +void CheckFileXfer() { + fd_set fds; + struct timeval tv; + int i, icnt = 0, igot = 0, bytes0 = 0, bytes = 0, grace = 0, n, list = 0; + int db = 0; + + if (!appData.fileActive || (filexfer_sock < 0 && filexfer_listen < 0)) { + return; + } + + if (filexfer_listen >= 0 && time(NULL) > start_listen + 30) { + fprintf(stderr, "filexfer closing aging listen socket.\n"); + close(filexfer_listen); + filexfer_listen = -1; + return; + } +//fprintf(stderr, "In CheckFileXfer\n"); + + if (filexfer_listen >=0) { + n = filexfer_listen; + list = 1; + } else { + n = filexfer_sock; + } + + while (1) { + icnt++; + 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)) { + if (list) { + if (filexfer_sock >= 0) { + fprintf(stderr, "filexfer close stale(?) filexfer_sock.\n"); + close(filexfer_sock); + filexfer_sock = -1; + } + filexfer_sock = AcceptTcpConnection(filexfer_listen); + if (filexfer_sock >= 0) { + fprintf(stderr, "filexfer accept OK.\n"); + close(filexfer_listen); + filexfer_listen = -1; + filexfer_start = last_filexfer = time(NULL); + } else { + fprintf(stderr, "filexfer accept failed.\n"); + } + break; + } else { + ssize_t rn; + unsigned char hdr[12]; + unsigned int len; + if (db) fprintf(stderr, "try read filexfer...\n"); +#if 1 + rn = read(n, fxfer, 1*8192); +if (db) { + int i; + fprintf(stderr, "CFX HDR:"); + for (i=0; i < 12; i++) { + 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); + break; + } else if (rn == 0) { + fprintf(stderr, "filexfer gone.\n"); + close(n); + filexfer_sock = -1; + last_filexfer = time(NULL); + //fprintf(stderr, "last_filexfer-2a: %d\n", last_filexfer); + appData.fileActive = False; + SendFramebufferUpdateRequest(0, 0, 1, 1, False); + return; + } else if (rn > 0) { + if (db > 1) write(2, fxfer, rn); + if (db) fprintf(stderr, "\n"); + bytes += rn; + last_filexfer = time(NULL); + //fprintf(stderr, "last_filexfer-2b: %d\n", last_filexfer); + + if (0) { + /* WE TRY TO FIX THIS IN THE JAVA NOW */ + if (appData.ultraDSM) { + unsigned char msg = rfbFileTransfer; + unsigned char hdc = (unsigned char) fxfer[0]; + if (msg == hdc) { + /* cross your fingers... */ + WriteExact(rfbsock, (char *)&msg, 1); + } + } + } + if (!WriteExact(rfbsock, fxfer, rn)) { + return; + } + igot = 1; + } +#else + // not working, not always 7 msg type. + rn = read(n, hdr, 12); + if (db) fprintf(stderr, "filexfer read %d.\n", rn); + if (rn == 0) { + fprintf(stderr, "filexfer gone.\n"); + close(n); + filexfer_sock = -1; + last_filexfer = time(NULL); + return; + } + if (rn == 12) { + len = (hdr[8] << 24) | (hdr[9] << 16) | (hdr[10] << 8) | hdr[11]; + if (db) fprintf(stderr, "n=%d len=%d\n", rn, len); + if (db > 1) write(2, hdr, rn); + if (db) fprintf(stderr, "\n"); + WriteExact(rfbsock, hdr, rn); + if (len > 0) { + rn = read(len, fxfer, len); + if (!WriteExact(rfbsock, fxfer, len)) { + last_filexfer = time(NULL); + return; + } + if (db > 1) write(2, fxfer, len); + } + if (db) fprintf(stderr, "\n"); + } else { + if (db) fprintf(stderr, "bad rn: %d\n", rn); + } + igot = 1; +#endif + } + } + } else { + if (bytes >= 8192) { + int ok = 0; + if (bytes0 == 0) { + ok = 1; + } else if (bytes >= bytes0 + 12) { + ok = 1; + } else if (grace < 20) { + ok = 1; + } + if (ok) { + grace++; + bytes0 = bytes; + //fprintf(stderr, "grace: %d\n", grace); + // forgot that this is about... + usleep(10 * 1000); + continue; + } + } + break; + } + } + if (igot) { + last_filexfer = time(NULL); + //fprintf(stderr, "last_filexfer-2c: %d\n", last_filexfer); + } +//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 + +extern double start_time; + +void ProcessXtEvents() +{ + int y, db = 0; + static int dyn = -1; + static int chat_was_active = 0; + int check_chat = 0; + + if (dyn < 0) { + struct stat sb; + if (getenv("USER") && !strcmp(getenv("USER"), "runge")) { + if (stat("/tmp/nodyn", &sb) == 0) { + putenv("NOFTFBUPDATES=1"); + unlink("/tmp/nodyn"); + } + } + if (getenv("NOFTFBUPDATES")) { + dyn = 0; + } else { + dyn = 1; + } + } + + //if (0) fprintf(stderr, "ProcessXtEvents: %d %.4f\n", skip_XtUpdateAll, dnow() - start_time); + + if (skip_XtUpdateAll) { + return; + } + + /* 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; + } + + rfbsockReady = False; + xfrsockReady = False; + do_rfbsockId = 1; + rfbsockId = XtAppAddInput(appContext, rfbsock, (XtPointer)XtInputReadMask, + rfbsockReadyCallback, NULL); + + do_xfrsockId = 0; + if (filexfer_sock >= 0) { + do_xfrsockId = 1; + xfrsockId = XtAppAddInput(appContext, filexfer_sock, (XtPointer)XtInputReadMask, + xfrsockReadyCallback, NULL); + } + + time_mark = time(NULL); + + if (appData.fileActive) { + static int first = 1; + if (first) { + fprintf(stderr, "PXT: dynamic fb updates during filexfer: %d\n", dyn); + first = 0; + } + } + + if (db) fprintf(stderr, "XtAppAddInput: "); + while (!rfbsockReady && !xfrsockReady) { + int w = si.framebufferWidth; + int h = si.framebufferHeight; + if (db) fprintf(stderr, "."); + if (dyn && filexfer_sock >= 0 && time(NULL) > time_mark + delay_filexfer) { + SendFramebufferUpdateRequest(0, 0, w, h, False); + } + XtAppProcessEvent(appContext, XtIMAll); + } + if (db) fprintf(stderr, " done. r: %d x: %d\n", rfbsockReady, xfrsockReady); + + if (xfrsockReady) { + CheckFileXfer(); + } } Bool ReadFromRFBServer(char *out, unsigned int n) { +// double start = dnow(), dn = n; if (n <= buffered) { memcpy(out, bufoutptr, n); bufoutptr += n; buffered -= n; +//fprintf(stderr, "R0: %06d\n", (int) dn); return True; } @@ -119,6 +470,7 @@ memcpy(out, bufoutptr, n); bufoutptr += n; buffered -= n; +//fprintf(stderr, "R1: %06d %06d %10.2f KB/sec\n", (int) dn, buffered+n, 1e-3 * (buffered+n)/(dnow() - start)); return True; } else { @@ -146,11 +498,14 @@ n -= i; } +//fprintf(stderr, "R2: %06d %06d %10.2f KB/sec\n", (int) dn, (int) dn, 1e-3 * (dn)/(dnow() - start)); return True; } } +int currentMsg = -1; + /* * Write an exact number of bytes, and don't return until you've sent them. */ @@ -158,37 +513,81 @@ Bool WriteExact(int sock, char *buf, int n) { - fd_set fds; - int i = 0; - int j; - - while (i < n) { - j = write(sock, buf + i, (n - i)); - if (j <= 0) { - if (j < 0) { - if (errno == EWOULDBLOCK || errno == EAGAIN) { - FD_ZERO(&fds); - FD_SET(rfbsock,&fds); + fd_set fds; + int i = 0; + int j; + + if (appData.ultraDSM && currentMsg >= 0) { + /* this is for goofy UltraVNC DSM send RFB msg char twice: */ + unsigned char msg = (unsigned char) currentMsg; + currentMsg = -1; + if (!WriteExact(sock, (char *)&msg, sizeof(msg))) { + return False; + } + } + currentMsg = -1; - if (select(rfbsock+1, NULL, &fds, NULL, NULL) <= 0) { - fprintf(stderr,programName); - perror(": select"); - return False; - } - j = 0; - } else { - fprintf(stderr,programName); - perror(": write"); - return False; + while (i < n) { + j = write(sock, buf + i, (n - i)); + if (j <= 0) { + if (j < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + FD_ZERO(&fds); + FD_SET(rfbsock,&fds); + + if (select(rfbsock+1, NULL, &fds, NULL, NULL) <= 0) { + fprintf(stderr,programName); + perror(": select"); + return False; + } + j = 0; + } else { + fprintf(stderr,programName); + perror(": write"); + return False; + } + } else { + fprintf(stderr,"%s: write failed\n",programName); + return False; + } + } + i += j; } - } else { - fprintf(stderr,"%s: write failed\n",programName); - return False; - } - } - i += j; - } - return True; + return True; +} + +int +ConnectToUnixSocket(char *file) { + int sock; + struct sockaddr_un addr; + int i; + + memset(&addr, 0, sizeof(struct sockaddr_un)); + + addr.sun_family = AF_UNIX; + + for (i=0; i < 108; i++) { + addr.sun_path[i] = file[i]; + if (file[i] == '\0') { + break; + } + } + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + fprintf(stderr,programName); + perror(": ConnectToUnixSocket: socket"); + return -1; + } + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + fprintf(stderr, programName); + perror(": ConnectToUnixSocket: connect"); + close(sock); + return -1; + } + + return sock; } @@ -203,6 +602,8 @@ struct sockaddr_in addr; int one = 1; + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = host; @@ -232,7 +633,22 @@ return sock; } +Bool SocketPair(int fd[2]) { + if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd) == -1) { + perror("socketpair"); + return False; + } + return True; +} +Bool SetNoDelay(int sock) { + const int one = 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { + perror("setsockopt"); + return False; + } + return True; +} /* * FindFreeTcpPort tries to find unused TCP port in the range @@ -245,6 +661,8 @@ int sock, port; struct sockaddr_in addr; + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; @@ -272,6 +690,8 @@ * ListenAtTcpPort starts listening at the given TCP port. */ +int use_loopback = 0; + int ListenAtTcpPort(int port) { @@ -279,10 +699,16 @@ struct sockaddr_in addr; int one = 1; + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; + if (getenv("VNCVIEWER_LISTEN_LOCALHOST") || use_loopback) { + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { fprintf(stderr,programName); @@ -305,7 +731,7 @@ return -1; } - if (listen(sock, 5) < 0) { + if (listen(sock, 32) < 0) { fprintf(stderr,programName); perror(": ListenAtTcpPort: listen"); close(sock); @@ -392,6 +818,42 @@ return False; } +char *get_peer_ip(int sock) { + struct sockaddr_in saddr; + unsigned int saddr_len; + int saddr_port; + char *saddr_ip_str = NULL; + + saddr_len = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + saddr_port = -1; + if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) { + saddr_ip_str = inet_ntoa(saddr.sin_addr); + } + if (! saddr_ip_str) { + saddr_ip_str = "unknown"; + } + return strdup(saddr_ip_str); +} + +char *ip2host(char *ip) { + char *str; + struct hostent *hp; + in_addr_t iaddr; + + iaddr = inet_addr(ip); + if (iaddr == htonl(INADDR_NONE)) { + return strdup("unknown"); + } + + hp = gethostbyaddr((char *)&iaddr, sizeof(in_addr_t), AF_INET); + if (!hp) { + return strdup("unknown"); + } + str = strdup(hp->h_name); + return str; +} + /* * Test if the other end of a socket is on the same machine. 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 2008-10-05 15:16:35.000000000 -0400 @@ -129,14 +129,21 @@ #endif #if (BPP == 8) - gcv.foreground = (appData.useBGR233) ? - BGR233ToPixel[fill_colour] : fill_colour; + gcv.foreground = (appData.useBGR233) ? BGR233ToPixel[fill_colour] : fill_colour; +#else +#if (BPP == 16) + gcv.foreground = (appData.useBGR565) ? BGR565ToPixel[fill_colour] : fill_colour; #else gcv.foreground = fill_colour; #endif +#endif - XChangeGC(dpy, gc, GCForeground, &gcv); - XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); + if (!appData.useXserverBackingStore) { + FillScreen(rx, ry, rw, rh, gcv.foreground); + } else { + XChangeGC(dpy, gc, GCForeground, &gcv); + XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); + } return True; } diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tmake vnc_unixsrc/vncviewer/tmake --- vnc_unixsrc.orig/vncviewer/tmake 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/tmake 2009-10-25 10:31:22.000000000 -0400 @@ -0,0 +1,17 @@ +#!/bin/sh +TURBOVNC_DIR=/home/runge/turbojpeg +make clean +(cd ../libvncauth || exit 1; make) +if [ "X$1" = "X-a" ]; then + exit +fi +make CCOPTIONS=-DTURBOVNC EXTRA_LIBRARIES="-L$TURBOVNC_DIR -Xlinker --rpath=$TURBOVNC_DIR -Xlinker --rpath=/usr/local/lib -lturbojpeg" +cp -p vncviewer vncviewer.turbovnc +strip vncviewer.turbovnc +ls -l vncviewer.turbovnc +ldd vncviewer.turbovnc + +echo +make clean all +ls -l vncviewer +ldd vncviewer diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tunnel.c vnc_unixsrc/vncviewer/tunnel.c --- vnc_unixsrc.orig/vncviewer/tunnel.c 2003-07-31 04:03:49.000000000 -0400 +++ vnc_unixsrc/vncviewer/tunnel.c 2007-05-08 21:28:01.000000000 -0400 @@ -132,6 +132,7 @@ { char *colonPos; int len, portOffset; + int disp; if (tunnelArgIndex >= *pargc - 2) usage(); @@ -153,7 +154,14 @@ if (!len || strspn(colonPos, "-0123456789") != len) { usage(); } +#if 0 *remotePort = atoi(colonPos) + portOffset; +#else + disp = atoi(colonPos); + if (portOffset != 0 && disp >= 100) + portOffset = 0; + *remotePort = disp + portOffset; +#endif } sprintf(lastArgv, "localhost::%d", localPort); diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/turbovnc/tight.c vnc_unixsrc/vncviewer/turbovnc/tight.c --- vnc_unixsrc.orig/vncviewer/turbovnc/tight.c 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/turbovnc/tight.c 2008-08-20 13:35:58.000000000 -0400 @@ -0,0 +1,613 @@ +/* + * Copyright (C) 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (C) 2004 Landmark Graphics Corporation. All Rights Reserved. + * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* + * tight.c - handle ``tight'' encoding. + * + * This file shouldn't be compiled directly. It is included multiple + * times by rfbproto.c, each time with a different definition of the + * macro BPP. For each value of BPP, this file defines a function + * which handles a tight-encoded rectangle with BPP bits per pixel. + * + */ + +#define TIGHT_MIN_TO_COMPRESS 12 + +#define CARDBPP CONCAT2E(CARD,BPP) +#define filterPtrBPP CONCAT2E(filterPtr,BPP) + +#define HandleTightBPP CONCAT2E(HandleTight,BPP) +#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP) +#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP) +#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP) +#define FilterCopyBPP CONCAT2E(FilterCopy,BPP) +#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP) +#define FilterGradientBPP CONCAT2E(FilterGradient,BPP) + +#if BPP != 8 +#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP) +#endif + +#ifndef RGB_TO_PIXEL + +#define RGB_TO_PIXEL(bpp,r,g,b) \ + (((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift | \ + ((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift | \ + ((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift) + +#define RGB24_TO_PIXEL(bpp,r,g,b) \ + ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255 \ + << myFormat.redShift | \ + (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \ + << myFormat.greenShift | \ + (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \ + << myFormat.blueShift) + +#define RGB24_TO_PIXEL32(r,g,b) \ + (((CARD32)(r) & 0xFF) << myFormat.redShift | \ + ((CARD32)(g) & 0xFF) << myFormat.greenShift | \ + ((CARD32)(b) & 0xFF) << myFormat.blueShift) + +#endif + +extern XImage *image; + +/* Type declarations */ + +typedef void (*filterPtrBPP)(int, int, int); + +/* Prototypes */ + +static int InitFilterCopyBPP (int rw, int rh); +static int InitFilterPaletteBPP (int rw, int rh); +static int InitFilterGradientBPP (int rw, int rh); +static void FilterCopyBPP (int srcx, int srcy, int numRows); +static void FilterPaletteBPP (int srcx, int srcy, int numRows); +static void FilterGradientBPP (int srcx, int srcy, int numRows); + +static Bool DecompressJpegRectBPP(int x, int y, int w, int h); + +/* Definitions */ + +static Bool +HandleTightBPP (int rx, int ry, int rw, int rh) +{ + CARDBPP fill_colour; + XGCValues gcv; + CARD8 comp_ctl; + CARD8 filter_id; + filterPtrBPP filterFn; + z_streamp zs; + int err, stream_id, compressedLen, bitsPixel; + int bufferSize, rowSize, numRows; + Bool readUncompressed = False; + CARDBPP *rawData; + + if (!ReadFromRFBServer((char *)&comp_ctl, 1)) + return False; + + /* Flush zlib streams if we are told by the server to do so. */ + for (stream_id = 0; stream_id < 4; stream_id++) { + if ((comp_ctl & 1) && zlibStreamActive[stream_id]) { + if (inflateEnd (&zlibStream[stream_id]) != Z_OK && + zlibStream[stream_id].msg != NULL) + fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg); + zlibStreamActive[stream_id] = False; + } + comp_ctl >>= 1; + } + + if ((comp_ctl & rfbTightNoZlib) == rfbTightNoZlib) { + comp_ctl &= ~(rfbTightNoZlib); + readUncompressed = True; + } + + /* Handle solid rectangles. */ + if (comp_ctl == rfbTightFill) { +#if BPP == 32 + if (myFormat.depth == 24 && myFormat.redMax == 0xFF && + myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { + if (!ReadFromRFBServer(buffer, 3)) + return False; + fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]); + } else { + if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour))) + return False; + } +#else + if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour))) + return False; +#endif + +#if (BPP == 8) + gcv.foreground = (appData.useBGR233) ? + BGR233ToPixel[fill_colour] : fill_colour; +#else + gcv.foreground = fill_colour; +#endif + + FillRectangle(&gcv, rx, ry, rw, rh); + return True; + } + +#if BPP == 8 + if (comp_ctl == rfbTightJpeg) { + fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n"); + return False; + } +#else + if (comp_ctl == rfbTightJpeg) { + return DecompressJpegRectBPP(rx, ry, rw, rh); + } +#endif + + /* Quit on unsupported subencoding value. */ + if (comp_ctl > rfbTightMaxSubencoding) { + fprintf(stderr, "Tight encoding: bad subencoding value received.\n"); + return False; + } + + /* + * Here primary compression mode handling begins. + * Data was processed with optional filter + zlib compression. + */ + + /* First, we should identify a filter to use. */ + if ((comp_ctl & rfbTightExplicitFilter) != 0) { + if (!ReadFromRFBServer((char*)&filter_id, 1)) + return False; + + switch (filter_id) { + case rfbTightFilterCopy: + filterFn = FilterCopyBPP; + bitsPixel = InitFilterCopyBPP(rw, rh); + break; + case rfbTightFilterPalette: + filterFn = FilterPaletteBPP; + bitsPixel = InitFilterPaletteBPP(rw, rh); + break; + case rfbTightFilterGradient: + filterFn = FilterGradientBPP; + bitsPixel = InitFilterGradientBPP(rw, rh); + break; + default: + fprintf(stderr, "Tight encoding: unknown filter code received.\n"); + return False; + } + } else { + filterFn = FilterCopyBPP; + bitsPixel = InitFilterCopyBPP(rw, rh); + } + if (bitsPixel == 0) { + fprintf(stderr, "Tight encoding: error receiving palette.\n"); + return False; + } + + /* Determine if the data should be decompressed or just copied. */ + rowSize = (rw * bitsPixel + 7) / 8; + bufferSize = -1; + if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) + bufferSize = rh * rowSize; + else if (readUncompressed) { + bufferSize = (int)ReadCompactLen(); + } + if (bufferSize != -1) { + uncompressedData = (char *)realloc(uncompressedData, bufferSize); + if (!uncompressedData) { + fprintf(stderr, "Memory allocation error\n"); + return False; + } + if (!ReadFromRFBServer(uncompressedData, bufferSize)) + return False; + filterFn(rx, ry, rh); + if (appData.useBGR233) CopyDataToImage(buffer, rx, ry, rw, rh); + if (!appData.doubleBuffer) CopyImageToScreen(rx, ry, rw, rh); + + return True; + } + + /* Read the length (1..3 bytes) of compressed data following. */ + compressedLen = (int)ReadCompactLen(); + if (compressedLen <= 0) { + fprintf(stderr, "Incorrect data received from the server.\n"); + return False; + } + + /* Now let's initialize compression stream if needed. */ + stream_id = comp_ctl & 0x03; + zs = &zlibStream[stream_id]; + if (!zlibStreamActive[stream_id]) { + zs->zalloc = Z_NULL; + zs->zfree = Z_NULL; + zs->opaque = Z_NULL; + err = inflateInit(zs); + if (err != Z_OK) { + if (zs->msg != NULL) + fprintf(stderr, "InflateInit error: %s.\n", zs->msg); + return False; + } + zlibStreamActive[stream_id] = True; + } + + /* Read, decode and draw actual pixel data in a loop. */ + + compressedData = (char *)realloc(compressedData, compressedLen); + if (!compressedData) { + fprintf(stderr, "Memory allocation error\n"); + return False; + } + uncompressedData = (char *)realloc(uncompressedData, rh * rowSize); + if (!uncompressedData) { + fprintf(stderr, "Memory allocation error\n"); + return False; + } + + if (!ReadFromRFBServer(compressedData, compressedLen)) + return False; + zs->next_in = (Bytef *)compressedData; + zs->avail_in = compressedLen; + zs->next_out = (Bytef *)uncompressedData; + zs->avail_out = rh * rowSize; + + err = inflate(zs, Z_SYNC_FLUSH); + if (err != Z_OK && err != Z_STREAM_END) { + if (zs->msg != NULL) { + fprintf(stderr, "Inflate error: %s.\n", zs->msg); + } else { + fprintf(stderr, "Inflate error: %d.\n", err); + } + return False; + } + + filterFn(rx, ry, rh); + if (appData.useBGR233) CopyDataToImage(buffer, rx, ry, rw, rh); + if (!appData.doubleBuffer) CopyImageToScreen(rx, ry, rw, rh); + + return True; +} + +/*---------------------------------------------------------------------------- + * + * Filter stuff. + * + */ + +/* + The following variables are defined in rfbproto.c: + static Bool cutZeros; + static int rectWidth, rectColors; + static CARD8 tightPalette[256*4]; + static CARD8 tightPrevRow[2048*3*sizeof(CARD16)]; +*/ + +static int +InitFilterCopyBPP (int rw, int rh) +{ + rectWidth = rw; + +#if BPP == 32 + if (myFormat.depth == 24 && myFormat.redMax == 0xFF && + myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { + cutZeros = True; + return 24; + } else { + cutZeros = False; + } +#endif + + return BPP; +} + +static void +FilterCopyBPP (int srcx, int srcy, int numRows) +{ + CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line + + srcx * image->bits_per_pixel/8]; + int dstw = image->bytes_per_line / (image->bits_per_pixel / 8); + int y; +#if BPP == 32 + int x; +#endif + + if (appData.useBGR233) { + dst = (CARDBPP *)buffer; + dstw = rectWidth; + } + +#if BPP == 32 + if (cutZeros) { + for (y = 0; y < numRows; y++) { + for (x = 0; x < rectWidth; x++) { + dst[y*dstw+x] = + RGB24_TO_PIXEL32(uncompressedData[(y*rectWidth+x)*3], + uncompressedData[(y*rectWidth+x)*3+1], + uncompressedData[(y*rectWidth+x)*3+2]); + } + } + return; + } +#endif + + for (y = 0; y < numRows; y++) + memcpy (&dst[y*dstw], &uncompressedData[y*rectWidth], rectWidth * (BPP / 8)); +} + +static int +InitFilterGradientBPP (int rw, int rh) +{ + int bits; + + bits = InitFilterCopyBPP(rw, rh); + if (cutZeros) + memset(tightPrevRow, 0, rw * 3); + else + memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16)); + + return bits; +} + +#if BPP == 32 + +static void +FilterGradient24 (int srcx, int srcy, int numRows) +{ + CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line + + srcx * image->bits_per_pixel/8]; + int dstw = image->bytes_per_line / (image->bits_per_pixel / 8); + int x, y, c; + CARD8 thisRow[2048*3]; + CARD8 pix[3]; + int est[3]; + + if (appData.useBGR233) { + dst = (CARDBPP *)buffer; + dstw = rectWidth; + } + + for (y = 0; y < numRows; y++) { + + /* First pixel in a row */ + for (c = 0; c < 3; c++) { + pix[c] = tightPrevRow[c] + uncompressedData[y*rectWidth*3+c]; + thisRow[c] = pix[c]; + } + dst[y*dstw] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]); + + /* Remaining pixels of a row */ + for (x = 1; x < rectWidth; x++) { + for (c = 0; c < 3; c++) { + est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] - + (int)tightPrevRow[(x-1)*3+c]; + if (est[c] > 0xFF) { + est[c] = 0xFF; + } else if (est[c] < 0x00) { + est[c] = 0x00; + } + pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c]; + thisRow[x*3+c] = pix[c]; + } + dst[y*dstw+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]); + } + + memcpy(tightPrevRow, thisRow, rectWidth * 3); + } +} + +#endif + +static void +FilterGradientBPP (int srcx, int srcy, int numRows) +{ + int x, y, c; + CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line + + srcx * image->bits_per_pixel/8]; + int dstw = image->bytes_per_line / (image->bits_per_pixel / 8); + CARDBPP *src = (CARDBPP *)uncompressedData; + CARD16 *thatRow = (CARD16 *)tightPrevRow; + CARD16 thisRow[2048*3]; + CARD16 pix[3]; + CARD16 max[3]; + int shift[3]; + int est[3]; + + if (appData.useBGR233) { + dst = (CARDBPP *)buffer; + dstw = rectWidth; + } + +#if BPP == 32 + if (cutZeros) { + FilterGradient24(srcx, srcy, numRows); + return; + } +#endif + + max[0] = myFormat.redMax; + max[1] = myFormat.greenMax; + max[2] = myFormat.blueMax; + + shift[0] = myFormat.redShift; + shift[1] = myFormat.greenShift; + shift[2] = myFormat.blueShift; + + for (y = 0; y < numRows; y++) { + + /* First pixel in a row */ + for (c = 0; c < 3; c++) { + pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]); + thisRow[c] = pix[c]; + } + dst[y*dstw] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]); + + /* Remaining pixels of a row */ + for (x = 1; x < rectWidth; x++) { + for (c = 0; c < 3; c++) { + est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c]; + if (est[c] > (int)max[c]) { + est[c] = (int)max[c]; + } else if (est[c] < 0) { + est[c] = 0; + } + pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]); + thisRow[x*3+c] = pix[c]; + } + dst[y*dstw+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]); + } + memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16)); + } +} + +static int +InitFilterPaletteBPP (int rw, int rh) +{ + int i; + CARD8 numColors; + CARDBPP *palette = (CARDBPP *)tightPalette; + + rectWidth = rw; + + if (!ReadFromRFBServer((char*)&numColors, 1)) + return 0; + + rectColors = (int)numColors; + if (++rectColors < 2) + return 0; + +#if BPP == 32 + if (myFormat.depth == 24 && myFormat.redMax == 0xFF && + myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { + if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3)) + return 0; + for (i = rectColors - 1; i >= 0; i--) { + palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3], + tightPalette[i*3+1], + tightPalette[i*3+2]); + } + return (rectColors == 2) ? 1 : 8; + } +#endif + + if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8))) + return 0; + + return (rectColors == 2) ? 1 : 8; +} + +static void +FilterPaletteBPP (int srcx, int srcy, int numRows) +{ + int x, y, b, w; + CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line + + srcx * image->bits_per_pixel/8]; + int dstw = image->bytes_per_line / (image->bits_per_pixel / 8); + CARD8 *src = (CARD8 *)uncompressedData; + CARDBPP *palette = (CARDBPP *)tightPalette; + + if (appData.useBGR233) { + dst = (CARDBPP *)buffer; + dstw = rectWidth; + } + + if (rectColors == 2) { + w = (rectWidth + 7) / 8; + for (y = 0; y < numRows; y++) { + for (x = 0; x < rectWidth / 8; x++) { + for (b = 7; b >= 0; b--) + dst[y*dstw+x*8+7-b] = palette[src[y*w+x] >> b & 1]; + } + for (b = 7; b >= 8 - rectWidth % 8; b--) { + dst[y*dstw+x*8+7-b] = palette[src[y*w+x] >> b & 1]; + } + } + } else { + for (y = 0; y < numRows; y++) + for (x = 0; x < rectWidth; x++) + dst[y*dstw+x] = palette[(int)src[y*rectWidth+x]]; + } +} + +#if BPP != 8 + +/*---------------------------------------------------------------------------- + * + * JPEG decompression. + * + */ + +/* + The following variables are defined in rfbproto.c: + static Bool jpegError; + static struct jpeg_source_mgr jpegSrcManager; + static JOCTET *jpegBufferPtr; + static size_t *jpegBufferLen; +*/ + +static Bool +DecompressJpegRectBPP(int x, int y, int w, int h) +{ + int compressedLen; + char *dstptr; + int ps, flags=0; + + compressedLen = (int)ReadCompactLen(); + if (compressedLen <= 0) { + fprintf(stderr, "Incorrect data received from the server.\n"); + return False; + } + + compressedData = (char *)realloc(compressedData, compressedLen); + if (compressedData == NULL) { + fprintf(stderr, "Memory allocation error.\n"); + return False; + } + + if (!ReadFromRFBServer(compressedData, compressedLen)) { + return False; + } + + if(!tjhnd) { + if((tjhnd=tjInitDecompress())==NULL) { + fprintf(stderr, "TurboJPEG error: %s\n", tjGetErrorStr()); + return False; + } + } + + ps=image->bits_per_pixel/8; + if(myFormat.bigEndian && ps==4) flags|=TJ_ALPHAFIRST; + if(myFormat.redShift==16 && myFormat.blueShift==0) + flags|=TJ_BGR; + if(myFormat.bigEndian) flags^=TJ_BGR; + + dstptr=&image->data[image->bytes_per_line*y+x*ps]; + if(tjDecompress(tjhnd, (unsigned char *)compressedData, (unsigned long)compressedLen, + (unsigned char *)dstptr, w, image->bytes_per_line, h, ps, flags)==-1) { + fprintf(stderr, "TurboJPEG error: %s\n", tjGetErrorStr()); + return False; + } + + if (!appData.doubleBuffer) + CopyImageToScreen(x, y, w, h); + + return True; +} + +#endif + diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/turbovnc/turbojpeg.h vnc_unixsrc/vncviewer/turbovnc/turbojpeg.h --- vnc_unixsrc.orig/vncviewer/turbovnc/turbojpeg.h 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/turbovnc/turbojpeg.h 2008-04-03 04:28:56.000000000 -0400 @@ -0,0 +1,229 @@ +/* Copyright (C)2004 Landmark Graphics + * Copyright (C)2005, 2006 Sun Microsystems, Inc. + * + * This library is free software and may be redistributed and/or modified under + * the terms of the wxWindows Library License, Version 3.1 or (at your option) + * any later version. The full license is in the LICENSE.txt file included + * with this distribution. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * wxWindows Library License for more details. + */ + +#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) && defined(_WIN32) && defined(DLLDEFINE) +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +#define DLLCALL + +/* Subsampling */ +#define NUMSUBOPT 4 + +enum {TJ_444=0, TJ_422, TJ_411, TJ_GRAYSCALE}; + +/* Flags */ +#define TJ_BGR 1 +#define TJ_BOTTOMUP 2 +#define TJ_FORCEMMX 8 /* Force IPP to use MMX code even if SSE available */ +#define TJ_FORCESSE 16 /* Force IPP to use SSE1 code even if SSE2 available */ +#define TJ_FORCESSE2 32 /* Force IPP to use SSE2 code (useful if auto-detect is not working properly) */ +#define TJ_ALPHAFIRST 64 /* BGR buffer is ABGR and RGB buffer is ARGB */ +#define TJ_FORCESSE3 128 /* Force IPP to use SSE3 code (useful if auto-detect is not working properly) */ + +typedef void* tjhandle; + +#define TJPAD(p) (((p)+3)&(~3)) +#ifndef max + #define max(a,b) ((a)>(b)?(a):(b)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* API follows */ + + +/* + tjhandle tjInitCompress(void) + + Creates a new JPEG compressor instance, allocates memory for the structures, + and returns a handle to the instance. Most applications will only + need to call this once at the beginning of the program or once for each + concurrent thread. Don't try to create a new instance every time you + compress an image, because this will cause performance to suffer. + + RETURNS: NULL on error +*/ +DLLEXPORT tjhandle DLLCALL tjInitCompress(void); + + +/* + int tjCompress(tjhandle j, + unsigned char *srcbuf, int width, int pitch, int height, int pixelsize, + unsigned char *dstbuf, unsigned long *size, + int jpegsubsamp, int jpegqual, int flags) + + [INPUT] j = instance handle previously returned from a call to + tjInitCompress() + [INPUT] srcbuf = pointer to user-allocated image buffer containing pixels in + RGB(A) or BGR(A) form + [INPUT] width = width (in pixels) of the source image + [INPUT] pitch = bytes per line of the source image (width*pixelsize if the + bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap + is padded to the nearest 32-bit boundary, such as is the case for Windows + bitmaps. You can also be clever and use this parameter to skip lines, etc., + as long as the pitch is greater than 0.) + [INPUT] height = height (in pixels) of the source image + [INPUT] pixelsize = size (in bytes) of each pixel in the source image + RGBA and BGRA: 4, RGB and BGR: 3 + [INPUT] dstbuf = pointer to user-allocated image buffer which will receive + the JPEG image. Use the macro TJBUFSIZE(width, height) to determine + the appropriate size for this buffer based on the image width and height. + [OUTPUT] size = pointer to unsigned long which receives the size (in bytes) + of the compressed image + [INPUT] jpegsubsamp = Specifies either 4:1:1, 4:2:2, or 4:4:4 subsampling. + When the image is converted from the RGB to YCbCr colorspace as part of the + JPEG compression process, every other Cb and Cr (chrominance) pixel can be + discarded to produce a smaller image with little perceptible loss of + image clarity (the human eye is more sensitive to small changes in + brightness than small changes in color.) + + TJ_411: 4:1:1 subsampling. Discards every other Cb, Cr pixel in both + horizontal and vertical directions. + TJ_422: 4:2:2 subsampling. Discards every other Cb, Cr pixel only in + the horizontal direction. + TJ_444: no subsampling. + TJ_GRAYSCALE: Generate grayscale JPEG image + + [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive.) + [INPUT] flags = the bitwise OR of one or more of the following + + TJ_BGR: The components of each pixel in the source image are stored in + B,G,R order, not R,G,B + TJ_BOTTOMUP: The source image is stored in bottom-up (Windows) order, + not top-down + TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation + of this codec-- force IPP to use MMX code (bypass CPU auto-detection) + TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation + of this codec-- force IPP to use SSE code (bypass CPU auto-detection) + TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation + of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection) + TJ_FORCESSE3: Valid only for the Intel Performance Primitives implementation + of this codec-- force IPP to use SSE3 code (bypass CPU auto-detection) + + RETURNS: 0 on success, -1 on error +*/ +DLLEXPORT int DLLCALL tjCompress(tjhandle j, + unsigned char *srcbuf, int width, int pitch, int height, int pixelsize, + unsigned char *dstbuf, unsigned long *size, + int jpegsubsamp, int jpegqual, int flags); + +DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height); + +/* + tjhandle tjInitDecompress(void) + + Creates a new JPEG decompressor instance, allocates memory for the + structures, and returns a handle to the instance. Most applications will + only need to call this once at the beginning of the program or once for each + concurrent thread. Don't try to create a new instance every time you + decompress an image, because this will cause performance to suffer. + + RETURNS: NULL on error +*/ +DLLEXPORT tjhandle DLLCALL tjInitDecompress(void); + + +/* + int tjDecompressHeader(tjhandle j, + unsigned char *srcbuf, unsigned long size, + int *width, int *height) + + [INPUT] j = instance handle previously returned from a call to + tjInitDecompress() + [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image + to decompress + [INPUT] size = size of the JPEG image buffer (in bytes) + [OUTPUT] width = width (in pixels) of the JPEG image + [OUTPUT] height = height (in pixels) of the JPEG image + + RETURNS: 0 on success, -1 on error +*/ +DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j, + unsigned char *srcbuf, unsigned long size, + int *width, int *height); + + +/* + int tjDecompress(tjhandle j, + unsigned char *srcbuf, unsigned long size, + unsigned char *dstbuf, int width, int pitch, int height, int pixelsize, + int flags) + + [INPUT] j = instance handle previously returned from a call to + tjInitDecompress() + [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image + to decompress + [INPUT] size = size of the JPEG image buffer (in bytes) + [INPUT] dstbuf = pointer to user-allocated image buffer which will receive + the bitmap image. This buffer should normally be pitch*height + bytes in size, although this pointer may also be used to decompress into + a specific region of a larger buffer. + [INPUT] width = width (in pixels) of the destination image + [INPUT] pitch = bytes per line of the destination image (width*pixelsize if the + bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap + is padded to the nearest 32-bit boundary, such as is the case for Windows + bitmaps. You can also be clever and use this parameter to skip lines, etc., + as long as the pitch is greater than 0.) + [INPUT] height = height (in pixels) of the destination image + [INPUT] pixelsize = size (in bytes) of each pixel in the destination image + RGBA/RGBx and BGRA/BGRx: 4, RGB and BGR: 3 + [INPUT] flags = the bitwise OR of one or more of the following + + TJ_BGR: The components of each pixel in the destination image should be + written in B,G,R order, not R,G,B + TJ_BOTTOMUP: The destination image should be stored in bottom-up + (Windows) order, not top-down + TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation + of this codec-- force IPP to use MMX code (bypass CPU auto-detection) + TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation + of this codec-- force IPP to use SSE code (bypass CPU auto-detection) + TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation + of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection) + + RETURNS: 0 on success, -1 on error +*/ +DLLEXPORT int DLLCALL tjDecompress(tjhandle j, + unsigned char *srcbuf, unsigned long size, + unsigned char *dstbuf, int width, int pitch, int height, int pixelsize, + int flags); + + +/* + int tjDestroy(tjhandle h) + + Frees structures associated with a compression or decompression instance + + [INPUT] h = instance handle (returned from a previous call to + tjInitCompress() or tjInitDecompress() + + RETURNS: 0 on success, -1 on error +*/ +DLLEXPORT int DLLCALL tjDestroy(tjhandle h); + + +/* + char *tjGetErrorStr(void) + + Returns a descriptive error message explaining why the last command failed +*/ +DLLEXPORT char* DLLCALL tjGetErrorStr(void); + +#ifdef __cplusplus +} +#endif diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer._man vnc_unixsrc/vncviewer/vncviewer._man --- vnc_unixsrc.orig/vncviewer/vncviewer._man 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/vncviewer._man 2009-11-25 00:03:28.000000000 -0500 @@ -0,0 +1,823 @@ +'\" t +.\" ** The above line should force tbl to be a preprocessor ** +.\" Man page for X vncviewer +.\" +.\" Copyright (C) 1998 Marcus.Brinkmann@ruhr-uni-bochum.de +.\" Copyright (C) 2000,2001 Red Hat, Inc. +.\" Copyright (C) 2001-2003 Constantin Kaplinsky +.\" Copyright (C) 2006-2009 Karl J. Runge +.\" +.\" You may distribute under the terms of the GNU General Public +.\" License as specified in the file LICENCE.TXT that comes with the +.\" TightVNC distribution. +.\" +.TH ssvncviewer 1 "September 2009" "" "SSVNC" +.SH NAME +ssvncviewer \- an X viewer client for VNC +.SH SYNOPSIS +.B ssvncviewer +.RI [\| options \|] +.RI [\| host \|][\| :display \|] +.br +.B ssvncviewer +.RI [\| options \|] +.RI [\| host \|][\| ::port \|] +.br +.B ssvncviewer +.RI [\| options \|] +.RI exec=[\| cmd+args... \|] +.br +.B ssvncviewer +.RI [\| options \|] +.RI fd=n +.br +.B ssvncviewer +.RI [\| options \|] +.RI /path/to/unix/socket +.br +.B ssvncviewer +.RI [\| options \|] +.IR \-listen +.RI [\| display \|] +.br +.B ssvncviewer +.IR \-help +.br +.SH DESCRIPTION +.B ssvncviewer +is an Xt\-based client application for the VNC (Virtual Network +Computing) system. It can connect to any VNC\-compatible server such +as \fBXvnc\fR, WinVNC, or \fBx11vnc\fR, allowing you to control desktop environment +of a different machine. + +ssvncviewer is an enhanced version of the tightvnc unix viewer that can +take advantage of features in the \fBx11vnc\fR and UltraVNC VNC servers. +See below for the description of these features. + +You can use F8 to display a pop\-up utility menu. Press F8 twice to +pass single F8 to the remote side. +.SH OPTIONS +.TP +\fB\-help\fR +Prints a short usage notice to stderr. +.TP +\fB\-listen\fR +Make the viewer listen on port 5500+\fIdisplay\fR for reverse +connections from a server. WinVNC supports reverse connections using +the "Add New Client" menu option, or the \-connect command line +option. \fBXvnc\fR requires the use of the helper program +\fBvncconnect\fR. +.TP +\fB\-via\fR \fIgateway\fR +Automatically create encrypted TCP tunnel to the \fIgateway\fR machine +before connection, connect to the \fIhost\fR through that tunnel +(TightVNC\-specific). By default, this option invokes SSH local port +forwarding, assuming that SSH client binary can be accessed as +/usr/bin/ssh. Note that when using the \fB\-via\fR option, the host +machine name should be specified as known to the gateway machine, e.g. +"localhost" denotes the \fIgateway\fR, not the machine where vncviewer +was launched. See the ENVIRONMENT section below for the information on +configuring the \fB\-via\fR option. +.TP +\fB\-shared\fR +When connecting, specify that a shared connection is requested. In +TightVNC, this is the default mode, allowing you to share the desktop +with other clients already using it. +.TP +\fB\-noshared\fR +When connecting, specify that the session may not be shared. This +would either disconnect other connected clients or refuse your +connection, depending on the server configuration. +.TP +\fB\-viewonly\fR +Disable transfer of mouse and keyboard events from the client to the +server. +.TP +\fB\-fullscreen\fR +Start in full\-screen mode. Please be aware that operating in +full\-screen mode may confuse X window managers. Typically, such +conflicts cause incorrect handling of input focus or make the viewer +window disappear mysteriously. See the grabKeyboard setting in the +RESOURCES section below for a method to solve input focus problem. +.TP +\fB\-noraiseonbeep\fR +By default, the viewer shows and raises its window on remote beep +(bell) event. This option disables such behaviour +(TightVNC\-specific). +.TP +\fB\-user\fR \fIusername\fR +User name for Unix login authentication. Default is to use current +Unix user name. If this option was given, the viewer will prefer Unix +login authentication over the standard VNC authentication. +.TP +\fB\-passwd\fR \fIpasswd\-file\fR +File from which to get the password (as generated by the +\fBvncpasswd\fR(1) program). This option affects only the standard VNC +authentication. +.TP +\fB\-encodings\fR \fIencoding\-list\fR +TightVNC supports several different compression methods to encode +screen updates; this option specifies a set of them to use in order of +preference. Encodings are specified separated with spaces, and must +thus be enclosed in quotes if more than one is specified. Commas may be used to avoid spaces. +Available encodings, in default order for a remote connection, are +"copyrect tight hextile zlib corre rre raw". For a local connection +(to the same machine), the default order to try is "raw copyrect tight +hextile zlib corre rre". Raw encoding is always assumed as a last option +if no other encoding can be used for some reason. For more information +on encodings, see the section ENCODINGS below. +.TP +\fB\-bgr233\fR +Always use the BGR233 format to encode pixel data. This reduces +network traffic, but colors may be represented inaccurately. The +bgr233 format is an 8\-bit "true color" format, with 2 bits blue, 3 +bits green, and 3 bits red. +.TP +\fB\-owncmap\fR +Try to use a PseudoColor visual and a private colormap. This allows +the VNC server to control the colormap. +.TP +\fB\-truecolour\fR, \fB\-truecolor\fR +Try to use a TrueColor visual. +.TP +\fB\-depth\fR \fIdepth\fR +On an X server which supports multiple TrueColor visuals of different +depths, attempt to use the specified one (in bits per pixel); if +successful, this depth will be requested from the VNC server. +.TP +\fB\-compresslevel \fIlevel\fR +Use specified compression \fIlevel\fR (0..9) for "tight" and "zlib" +encodings (TightVNC\-specific). Level 1 uses minimum of CPU time and +achieves weak compression ratios, while level 9 offers best +compression but is slow in terms of CPU time consumption on the server +side. Use high levels with very slow network connections, and low +levels when working over high\-speed LANs. It's not recommended to use +compression level 0, reasonable choices start from the level 1. +.TP +\fB\-quality \fIlevel\fR +Use the specified JPEG quality \fIlevel\fR (0..9) for the "tight" +encoding (TightVNC\-specific). Quality level 0 denotes bad image +quality but very impressive compression ratios, while level 9 offers +very good image quality at lower compression ratios. Note that the +"tight" encoder uses JPEG to encode only those screen areas that look +suitable for lossy compression, so quality level 0 does not always +mean unacceptable image quality. +.TP +\fB\-nojpeg\fR +Disable lossy JPEG compression in Tight encoding (TightVNC\-specific). +Disabling JPEG compression is not a good idea in typical cases, as +that makes the Tight encoder less efficient. You might want to use +this option if it's absolutely necessary to achieve perfect image +quality (see also the \fB\-quality\fR option). +.TP +\fB\-nocursorshape\fR +Disable cursor shape updates, protocol extensions used to handle +remote cursor movements locally on the client side +(TightVNC\-specific). Using cursor shape updates decreases delays with +remote cursor movements, and can improve bandwidth usage dramatically. +.TP +\fB\-x11cursor\fR +Use a real X11 cursor with X-style cursor shape updates, instead of +drawing the remote cursor on the framebuffer. This option also +disables the dot cursor, and disables cursor position updates in +non-fullscreen mode. +.TP +\fB\-autopass\fR +Read a plain-text password from stdin. This option affects only the +standard VNC authentication. + +.SH Enhanced TightVNC Viewer (SSVNC) OPTIONS +.TP +Enhanced TightVNC Viewer (SSVNC) web page is located at: +.TP +http://www.karlrunge.com/x11vnc/ssvnc.html +.TP +Note: ZRLE and ZYWRLE encodings are now supported. +.TP +Note: F9 is shortcut to Toggle FullScreen mode. +.TP +Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1 +to allow more than one incoming VNC server at a time. +This is the same as -multilisten described below. Set +SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than "n" +simultaneous reverse connections. + +If the host:port is specified as "exec=command args..." +then instead of making a TCP/IP socket connection to the +remote VNC server, "command args..." is executed and the +viewer is attached to its stdio. This enables tunnelling +established via an external command, e.g. an stunnel(8) +that does not involve a listening socket. +This mode does not work for -listen reverse connections. + +If the host:port is specified as "fd=n" then it is assumed +n is an already opened file descriptor to the socket. (i.e +the parent did fork+exec) + +If the host:port contains a '/' it is interpreted as a +unix-domain socket (AF_LOCAL insead of AF_INET) +.TP +\fB\-multilisten\fR +As in -listen (reverse connection listening) except +allow more than one incoming VNC server to be connected +at a time. The default for -listen of only one at a +time tries to play it safe by not allowing anyone on +the network to put (many) desktops on your screen over +a long window of time. Use -multilisten for no limit. +.TP +\fB\-acceptpopup\fR +In \fB\-listen\fR (reverse connection listening) mode when +a reverse VNC connection comes in show a popup asking +whether to Accept or Reject the connection. The IP +address of the connecting host is shown. Same as +setting the env. var. SSVNC_ACCEPT_POPUP=1. +.TP +\fB\-acceptpopupsc\fR +As in \fB\-acceptpopup\fR except assume UltraVNC Single +Click (SC) server. Retrieve User and ComputerName +info from UltraVNC Server and display in the Popup. +.TP +\fB\-use64\fR +In \fB\-bgr233\fR mode, use 64 colors instead of 256. +.TP +\fB\-bgr222\fR +Same as \fB\-use64\fR. +.TP +\fB\-use8\fR +In \fB\-bgr233\fR mode, use 8 colors instead of 256. +.TP +\fB\-bgr111\fR +Same as \fB\-use8\fR. +.TP +\fB\-16bpp\fR +If the vnc viewer X display is depth 24 at 32bpp +request a 16bpp format from the VNC server to cut +network traffic by up to 2X, then tranlate the +pixels to 32bpp locally. +.TP +\fB\-bgr565\fR +Same as \fB\-16bpp\fR. +.TP +\fB\-grey\fR +Use a grey scale for the 16- and 8\fB\-bpp\fR modes. +.TP +\fB\-alpha\fR +Use alphablending transparency for local cursors +requires: x11vnc server, both client and server +must be 32bpp and same endianness. +.TP +\fB\-scale\fR \fIstr\fR +Scale the desktop locally. The string "str" can +a floating point ratio, e.g. "0.9", or a fraction, +e.g. "3/4", or WxH, e.g. 1280x1024. Use "fit" +to fit in the current screen size. Use "auto" to +fit in the window size. "str" can also be set by +the env. var. SSVNC_SCALE. + +If you observe mouse trail painting errors, enable +X11 Cursor mode (either via Popup or \fB\-x11cursor\fR.) + +Note that scaling is done in software and so can be +slow and requires more memory. Some speedup Tips: + +ZRLE is faster than Tight in this mode. When +scaling is first detected, the encoding will +be automatically switched to ZRLE. Use the +Popup menu if you want to go back to Tight. +Set SSVNC_PRESERVE_ENCODING=1 to disable this. + +Use a solid background on the remote side. +(e.g. manually or via x11vnc \fB\-solid\fR ...) + +If the remote server is x11vnc, try client +side caching: x11vnc \fB\-ncache\fR 10 ... +.TP +\fB\-ycrop\fR n +Only show the top n rows of the framebuffer. For +use with x11vnc \fB\-ncache\fR client caching option +to help "hide" the pixel cache region. +Use a negative value (e.g. \fB\-1\fR) for autodetection. +Autodetection will always take place if the remote +fb height is more than 2 times the width. +.TP +\fB\-sbwidth\fR n +Scrollbar width for x11vnc \fB\-ncache\fR mode (\fB\-ycrop\fR), +default is very narrow: 2 pixels, it is narrow to +avoid distraction in \fB\-ycrop\fR mode. +.TP +\fB\-nobell\fR +Disable bell. +.TP +\fB\-rawlocal\fR +Prefer raw encoding for localhost, default is +no, i.e. assumes you have a SSH tunnel instead. +.TP +\fB\-notty\fR +Try to avoid using the terminal for interactive +responses: use windows for messages and prompting +instead. Messages will also be printed to terminal. +.TP +\fB\-sendclipboard\fR +Send the X CLIPBOARD selection (i.e. Ctrl+C, +Ctrl+V) instead of the X PRIMARY selection (mouse +select and middle button paste.) +.TP +\fB\-sendalways\fR +Whenever the mouse enters the VNC viewer main +window, send the selection to the VNC server even if +it has not changed. This is like the Xt resource +translation SelectionToVNC(always) +.TP +\fB\-recvtext\fR +str When cut text is received from the VNC server, +ssvncviewer will set both the X PRIMARY and the +X CLIPBOARD local selections. To control which +is set, specify 'str' as 'primary', 'clipboard', +or 'both' (the default.) +.TP +\fB\-graball\fR +Grab the entire X server when in fullscreen mode, +needed by some old window managers like fvwm2. +.TP +\fB\-popupfix\fR +Warp the popup back to the pointer position, +needed by some old window managers like fvwm2. +.TP +\fB\-grabkbd\fR +Grab the X keyboard when in fullscreen mode, +needed by some window managers. Same as \fB\-grabkeyboard\fR. +\fB\-grabkbd\fR is the default, use \fB\-nograbkbd\fR to disable. +.TP +\fB\-bs\fR, \fB\-nobs\fR +Whether or not to use X server Backingstore for the +main viewer window. The default is to not, mainly +because most Linux, etc, systems X servers disable +*all* Backingstore by default. To re\fB\-enable\fR it put + +Option "Backingstore" + +in the Device section of /etc/X11/xorg.conf. +In \fB\-bs\fR mode with no X server backingstore, whenever an +area of the screen is re\fB\-exposed\fR it must go out to the +VNC server to retrieve the pixels. This is too slow. + +In \fB\-nobs\fR mode, memory is allocated by the viewer to +provide its own backing of the main viewer window. This +actually makes some activities faster (changes in large +regions) but can appear to "flash" too much. +.TP +\fB\-noshm\fR +Disable use of MIT shared memory extension (not recommended) +.TP +\fB\-termchat\fR +Do the UltraVNC chat in the terminal vncviewer is in +instead of in an independent window. +.TP +\fB\-unixpw\fR \fIstr\fR +Useful for logging into x11vnc in \fB\-unixpw\fR mode. "str" is a +string that allows many ways to enter the Unix Username +and Unix Password. These characters: username, newline, +password, newline are sent to the VNC server after any VNC +authentication has taken place. Under x11vnc they are +used for the \fB\-unixpw\fR login. Other VNC servers could do +something similar. + +You can also indicate "str" via the environment +variable SSVNC_UNIXPW. + +Note that the Escape key is actually sent first to tell +x11vnc to not echo the Unix Username back to the VNC +viewer. Set SSVNC_UNIXPW_NOESC=1 to override this. + +If str is ".", then you are prompted at the command line +for the username and password in the normal way. If str is +"-" the stdin is read via getpass(3) for username@password. +Otherwise if str is a file, it is opened and the first line +read is taken as the Unix username and the 2nd as the +password. If str prefixed by "rm:" the file is removed +after reading. Otherwise, if str has a "@" character, +it is taken as username@password. Otherwise, the program +exits with an error. Got all that? +.TP +\fB-repeater\fR \fIstr\fR +This is for use with UltraVNC repeater proxy described +here: http://www.uvnc.com/addons/repeater.html. The "str" +is the ID string to be sent to the repeater. E.g. ID:1234 +It can also be the hostname and port or display of the VNC +server, e.g. 12.34.56.78:0 or snoopy.com:1. Note that when +using -repeater, the host:dpy on the cmdline is the repeater +server, NOT the VNC server. The repeater will connect you. + +Example: vncviewer ... -repeater ID:3333 repeat.host:5900 + +Example: vncviewer ... -repeater vhost:0 repeat.host:5900 + +Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a +Single Click III (SSL) repeater (repeater_SSL.exe) and you +are passing the SSL part of the connection through stunnel, socat, etc. +This way the magic UltraVNC string 'testB' needed to work with the +repeater is sent to it. +.TP +\fB-rfbversion\fR \fIstr\fR +Set the advertised RFB version. E.g.: -rfbversion 3.6 For some +servers, e.g. UltraVNC this needs to be done. +.TP +\fB-ultradsm\fR +UltraVNC has symmetric private encryption DSM plugins. See +http://www.uvnc.com/features/encryption.html. It is assumed +you are using a unix program (e.g. our ultravnc_dsm_helper) to +encrypt and decrypt the UltraVNC DSM stream. IN ADDITION TO +THAT supply -ultradsm to tell THIS viewer to modify the RFB +data sent so as to work with the UltraVNC Server. For some +reason, each RFB msg type must be sent twice under DSM. +.TP +\fB\-mslogon\fR \fIuser\fR +Use Windows MS Logon to an UltraVNC server. Supply the +username or "1" to be prompted. The default is to +autodetect the UltraVNC MS Logon server and prompt for +the username and password. + +IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman +exchange is very weak and can be brute forced to recover +your username and password in a few seconds of CPU +time. To be safe, be sure to use an additional encrypted +tunnel (e.g. SSL or SSH) for the entire VNC session. +.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, +-env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi +.TP +\fB\-printres\fR +Print out the Ssvnc X resources (appdefaults) and +then exit. You can save them to a file and customize them (e.g. the +keybindings and Popup menu) Then point to the file via +XENVIRONMENT or XAPPLRESDIR. +.TP +\fB\-pipeline\fR +Like TurboVNC, request the next framebuffer update as soon +as possible instead of waiting until the end of the current +framebuffer update coming in. Helps 'pipeline' the updates. +This is currently the default, use \fB-nopipeline\fR to disable. +.TP +\fB\-appshare\fR +Enable features for use with x11vnc's \fB\-appshare\fR mode where +instead of sharing the full desktop only the application's +windows are shared. Viewer multilisten mode is used to +create the multiple windows: \fB\-multilisten\fR is implied. +See 'x11vnc \fB\-appshare\fR \fB\-help\fR' more information on the mode. +Features enabled in the viewer under \fB\-appshare\fR are: +Minimum extra text in the title, auto \fB\-ycrop\fR is disabled, +x11vnc \fB\-remote_prefix\fR X11VNC_APPSHARE_CMD: message channel, +x11vnc initial window position hints. See also Escape Keys +below for additional key and mouse bindings. +.TP +\fB\-escape \fR\fIstr\fR +This sets the 'Escape Keys' modifier sequence and enables +escape keys mode. When the modifier keys escape sequence +is held down, the next keystroke is interpreted locally +to perform a special action instead of being sent to the +remote VNC server. + +Use '\fB\-escape\fR default' for the default modifier sequence. +(Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L) + +Here are the 'Escape Keys: Help+Set' instructions from the Popup: + +Escape Keys: Enter a comma separated list of modifier keys to be the 'escape +sequence'. When these keys are held down, the next keystroke is +interpreted locally to invoke a special action instead of being sent to +the remote VNC server. In other words, a set of 'Hot Keys'. + +Here is the list of local key mappings to special actions: + +r: refresh desktop b: toggle bell c: toggle full-color + +f: file transfer x: x11cursor z: toggle Tight/ZRLE + +l: full screen g: graball e: escape keys dialog + +s: scale dialog +: scale up (=) -: scale down (_) + +t: text chat a: alphablend cursor + +V: toggle viewonly Q: quit viewer 123456: UltraVNC scale 1/n + +Arrow keys: pan the viewport about 10% for each keypress. + +PageUp/PageDown: pan the viewport by a screenful vertically. + +Home/End: pan the viewport by a screenful horizontally. + +KeyPad Arrows: pan the viewport by 1 pixel for each keypress. + +Dragging the Mouse with Button1 pressed also pans the viewport. + +Clicking Mouse Button3 brings up the Popup Menu. + +The above mappings are \fBalways\fR active in ViewOnly mode, unless you set +the Escape Keys value to 'never'. + +x11vnc -appshare hot-keys: x11vnc has a simple application sharing mode +that enables the viewer-side to move, resize, or raise the remote toplevel +windows. To enable it, hold down Shift + the Escape Keys and press these: + +Arrow keys: move the remote window around in its desktop. + +PageUp/PageDn/Home/End: resize the remote window. + ++/-: raise or lower the remote window. + +M or Button1 move win to local position; D or Button3: delete remote win. + +If the Escape Keys value below is set to 'default' then a default list of +of modifier keys is used. For Unix it is: Alt_L,Super_L and for MacOSX it +is Control_L,Meta_L. Note: the Super_L key usually has a Windows(TM) Flag +on it. Also note the _L and _R mean the key is on the LEFT or RIGHT side +of the keyboard. + +On Unix the default is Alt and Windows keys on Left side of keyboard. +On MacOSX the default is Control and Command keys on Left side of keyboard. + +Example: Press and hold the Alt and Windows keys on the LEFT side of the +keyboard and then press 'c' to toggle the full-color state. Or press 't' +to toggle the ultravnc Text Chat window, etc. + +To use something besides the default, supply a comma separated list (or a +single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L +Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch. +.TP +\fB New Popup actions:\fR + + ViewOnly: ~ -viewonly + Disable Bell: ~ -nobell + Cursor Shape: ~ -nocursorshape + X11 Cursor: ~ -x11cursor + Cursor Alphablend: ~ -alpha + Toggle Tight/Hextile: ~ -encodings hextile... + Toggle Tight/ZRLE: ~ -encodings zrle... + Toggle ZRLE/ZYWRLE: ~ -encodings zywrle... + Quality Level ~ -quality (both Tight and ZYWRLE) + Compress Level ~ -compresslevel + Disable JPEG: ~ -nojpeg (Tight) + Pipeline Updates ~ -pipeline + + Full Color as many colors as local screen allows. + Grey scale (16 & 8-bpp) ~ -grey, for low colors 16/8bpp modes only. + 16 bit color (BGR565) ~ -16bpp / -bgr565 + 8 bit color (BGR233) ~ -bgr233 + 256 colors ~ -bgr233 default # of colors. + 64 colors ~ -bgr222 / -use64 + 8 colors ~ -bgr111 / -use8 + Scale Viewer ~ -scale + Escape Keys: Toggle ~ -escape + Escape Keys: Help+Set ~ -escape + Set Y Crop (y-max) ~ -ycrop + Set Scrollbar Width ~ -sbwidth + XGrabServer ~ -graball + + UltraVNC Extensions: + + Set 1/n Server Scale Ultravnc ext. Scale desktop by 1/n. + Text Chat Ultravnc ext. Do Text Chat. + File Transfer Ultravnc ext. File xfer via Java helper. + Single Window Ultravnc ext. Grab and view a single window. + (select then click on the window you want). + Disable Remote Input Ultravnc ext. Try to prevent input and + viewing of monitor at physical display. + + Note: the Ultravnc extensions only apply to servers that support + them. x11vnc/libvncserver supports some of them. + + Send Clipboard not Primary ~ -sendclipboard + Send Selection Every time ~ -sendalways + +.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. +If the client represents itself as able to use multiple formats, the +server will choose one. + +.I Pixel format +refers to the representation of an individual pixel. The most common +formats are 24 and 16 bit "true\-color" values, and 8\-bit "color map" +representations, where an arbitrary map converts the color number to +RGB values. + +.I Encoding +refers to how a rectangle of pixels are sent (all pixel information in +VNC is sent as rectangles). All rectangles come with a header giving +the location and size of the rectangle and an encoding type used by +the data which follows. These types are listed below. +.TP +.B Raw +The raw encoding simply sends width*height pixel values. All clients +are required to support this encoding type. Raw is also the fastest +when the server and viewer are on the same machine, as the connection +speed is essentially infinite and raw encoding minimizes processing +time. +.TP +.B CopyRect +The Copy Rectangle encoding is efficient when something is being +moved; the only data sent is the location of a rectangle from which +data should be copied to the current location. Copyrect could also be +used to efficiently transmit a repeated pattern. +.TP +.B RRE +The Rise\-and\-Run\-length\-Encoding is basically a 2D version of +run\-length encoding (RLE). In this encoding, a sequence of identical +pixels are compressed to a single value and repeat count. In VNC, this +is implemented with a background color, and then specifications of an +arbitrary number of subrectangles and color for each. This is an +efficient encoding for large blocks of constant color. +.TP +.B CoRRE +This is a minor variation on RRE, using a maximum of 255x255 pixel +rectangles. This allows for single\-byte values to be used, reducing +packet size. This is in general more efficient, because the savings +from sending 1\-byte values generally outweighs the losses from the +(relatively rare) cases where very large regions are painted the same +color. +.TP +.B Hextile +Here, rectangles are split up in to 16x16 tiles, which are sent in a +predetermined order. The data within the tiles is sent either raw or +as a variant on RRE. Hextile encoding is usually the best choice for +using in high\-speed network environments (e.g. Ethernet local\-area +networks). +.TP +.B Zlib +Zlib is a very simple encoding that uses zlib library to compress raw +pixel data. This encoding achieves good compression, but consumes a +lot of CPU time. Support for this encoding is provided for +compatibility with VNC servers that might not understand Tight +encoding which is more efficient than Zlib in nearly all real\-life +situations. +.TP +.B Tight +Like Zlib encoding, Tight encoding uses zlib library to compress the +pixel data, but it pre\-processes data to maximize compression ratios, +and to minimize CPU usage on compression. Also, JPEG compression may +be used to encode color\-rich screen areas (see the description of +\-quality and \-nojpeg options above). Tight encoding is usually the +best choice for low\-bandwidth network environments (e.g. slow modem +connections). +.TP +.B ZRLE +The SSVNC viewer has ported the RealVNC (www.realvnc.com) ZRLE encoding +to the unix tightvnc viewer. +.TP +.B ZYWRLE +The SSVNC viewer has ported the Hitachi lossy wavelet based ZRLE +encoding from http://mobile.hitachi-system.co.jp/publications/ZYWRLE/ +to the unix tightvnc viewer. +.SH RESOURCES +X resources that \fBvncviewer\fR knows about, aside from the +normal Xt resources, are as follows: +.TP +.B shareDesktop +Equivalent of \fB\-shared\fR/\fB\-noshared\fR options. Default true. +.TP +.B viewOnly +Equivalent of \fB\-viewonly\fR option. Default false. +.TP +.B fullScreen +Equivalent of \fB\-fullscreen\fR option. Default false. +.TP +.B grabKeyboard +Grab keyboard in full-screen mode. This can help to solve problems +with losing keyboard focus. Default false. +.TP +.B raiseOnBeep +Equivalent of \fB\-noraiseonbeep\fR option, when set to false. Default +true. +.TP +.B passwordFile +Equivalent of \fB\-passwd\fR option. +.TP +.B userLogin +Equivalent of \fB\-user\fR option. +.TP +.B passwordDialog +Whether to use a dialog box to get the password (true) or get it from +the tty (false). Irrelevant if \fBpasswordFile\fR is set. Default +false. +.TP +.B encodings +Equivalent of \fB\-encodings\fR option. +.TP +.B compressLevel +Equivalent of \fB\-compresslevel\fR option (TightVNC\-specific). +.TP +.B qualityLevel +Equivalent of \fB\-quality\fR option (TightVNC\-specific). +.TP +.B enableJPEG +Equivalent of \fB\-nojpeg\fR option, when set to false. Default true. +.TP +.B useRemoteCursor +Equivalent of \fB\-nocursorshape\fR option, when set to false +(TightVNC\-specific). Default true. +.TP +.B useBGR233 +Equivalent of \fB\-bgr233\fR option. Default false. +.TP +.B nColours +When using BGR233, try to allocate this many "exact" colors from the +BGR233 color cube. When using a shared colormap, setting this resource +lower leaves more colors for other X clients. Irrelevant when using +truecolor. Default is 256 (i.e. all of them). +.TP +.B useSharedColours +If the number of "exact" BGR233 colors successfully allocated is less +than 256 then the rest are filled in using the "nearest" colors +available. This resource says whether to only use the "exact" BGR233 +colors for this purpose, or whether to use other clients' "shared" +colors as well. Default true (i.e. use other clients' colors). +.TP +.B forceOwnCmap +Equivalent of \fB\-owncmap\fR option. Default false. +.TP +.B forceTrueColour +Equivalent of \fB\-truecolour\fR option. Default false. +.TP +.B requestedDepth +Equivalent of \fB\-depth\fR option. +.TP +.B useSharedMemory +Use MIT shared memory extension if on the same machine as the X +server. Default true. +.TP +.B wmDecorationWidth, wmDecorationHeight +The total width and height taken up by window manager decorations. +This is used to calculate the maximum size of the VNC viewer window. +Default is width 4, height 24. +.TP +.B bumpScrollTime, bumpScrollPixels +When in full screen mode and the VNC desktop is bigger than the X +display, scrolling happens whenever the mouse hits the edge of the +screen. The maximum speed of scrolling is bumpScrollPixels pixels +every bumpScrollTime milliseconds. The actual speed of scrolling will +be slower than this, of course, depending on how fast your machine is. +Default 20 pixels every 25 milliseconds. +.TP +.B popupButtonCount +The number of buttons in the popup window. See the README file for +more information on how to customize the buttons. +.TP +.B debug +For debugging. Default false. +.TP +.B rawDelay, copyRectDelay +For debugging, see the README file for details. Default 0 (off). +.SH ENVIRONMENT +When started with the \fB\-via\fR option, vncviewer reads the +\fBVNC_VIA_CMD\fR environment variable, expands patterns beginning +with the "%" character, and executes result as a command assuming that +it would create TCP tunnel that should be used for VNC connection. If +not set, this environment variable defaults to "/usr/bin/ssh -f -L +%L:%H:%R %G sleep 20". + +The following patterns are recognized in the \fBVNC_VIA_CMD\fR (note +that all the patterns %G, %H, %L and %R must be present in the command +template): +.TP +.B %% +A literal "%"; +.TP +.B %G +gateway host name; +.TP +.B %H +remote VNC host name, as known to the gateway; +.TP +.B %L +local TCP port number; +.TP +.B %R +remote TCP port number. +.SH SEE ALSO +\fBvncserver\fR(1), \fBx11vnc\fR(1), \fBssvnc\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1), +\fBvncconnect\fR(1), \fBssh\fR(1), http://www.karlrunge.com/x11vnc, http://www.karlrunge.com/x11vnc/ssvnc.html +.SH AUTHORS +Original VNC was developed in AT&T Laboratories Cambridge. TightVNC +additions was implemented by Constantin Kaplinsky. Many other people +participated in development, testing and support. Karl J. Runge +added all of the SSVNC related features and improvements. + +\fBMan page authors:\fR +.br +Marcus Brinkmann , +.br +Terran Melconian , +.br +Tim Waugh , +.br +Constantin Kaplinsky +.br +Karl J. Runge 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 2009-11-24 19:41:33.000000000 -0500 @@ -22,6 +22,7 @@ */ #include "vncviewer.h" +#include char *programName; XtAppContext appContext; @@ -29,11 +30,258 @@ Widget toplevel; +extern void raiseme(int force); + +void set_sbwidth(int sbw) { + char *q, *p, t[5]; + int i, k, N = 4; + int db = 0; + + if (sbw < 1) { + sbw = 2; + } else if (sbw > 100) { + sbw = 100; + } + if (db) fprintf(stderr, "sbw: %d\n", sbw); + + sprintf(t, "%4d", sbw); + k = 0; + while (fallback_resources[k] != NULL) { + q = strstr(fallback_resources[k], "horizontal.height: "); + if (!q) { + q = strstr(fallback_resources[k], "vertical.width: "); + } + if (q) { + p = strdup(fallback_resources[k]); + q = strstr(p, ": "); + if (q) { + q++; + q++; + for (i=0; i < N; i++) { + *(q+i) = t[i]; + } + fallback_resources[k] = p; + if (db) fprintf(stderr, "res: %s\n\n", p); + } + } + k++; + } +} + +void min_title(void) { + char *q, *p; + int i, k, N = 4; + int db = 0; + + k = 0; + while (fallback_resources[k] != NULL) { + q = strstr(fallback_resources[k], "Ssvnc.title: "); + if (q) { + fallback_resources[k] = strdup("Ssvnc.title: %s"); + } + k++; + } +} + +#include +#include +#include + +void unixpw(char *instr, int vencrypt_plain) { + char *str, *q, *infile = NULL; + FILE *in; + int i, rmfile = 0; + struct stat sb; + int N = 99; + char username[100], passwd[100]; + static int did = 0; + + if (did) { + return; + } + did = 1; + + for (i=0; i<100; i++) { + username[i] = '\0'; + passwd[i] = '\0'; + } + + if (instr == NULL) { + return; + } else if (!strcmp(instr, "")) { + return; + } + + str = strdup(instr); + + if (strstr(str, "rm:") == str) { + rmfile = 1; + infile = str + strlen("rm:"); + } else if (stat(str, &sb) == 0) { + infile = str; + } + if (!strcmp(str, ".")) { + char *p; + if (!use_tty()) { + char *u; + fprintf(stderr, "\nEnter Unix Username and Password in the popups.\n"); + u = DoUserDialog(); + if (strlen(u) >= 100) { + exit(1); + } + sprintf(username, u); + p = DoPasswordDialog(); + } else { + raiseme(1); + fprintf(stderr, "\nUnix Username: "); + if (fgets(username, N, stdin) == NULL) { + exit(1); + } + p = getpass("Unix Password: "); + } + if (! p) { + exit(1); + } + strncpy(passwd, p, N); + fprintf(stderr, "\n"); + + } else if (!strcmp(str, "-")) { + char *p, *q; + if (!use_tty()) { + fprintf(stderr, "\nEnter unixuser@unixpasswd in the popup.\n"); + p = DoPasswordDialog(); + } else { + raiseme(1); + p = getpass("unixuser@unixpasswd: "); + } + if (! p) { + exit(1); + } + q = strchr(p, '@'); + if (! q) { + exit(1); + } + *q = '\0'; + strncpy(username, p, N); + strncpy(passwd, q+1, N); + + } else if (infile) { + in = fopen(infile, "r"); + if (in == NULL) { + fprintf(stderr, "failed to open -unixpw file.\n"); + exit(1); + } + if (fgets(username, N, in) == NULL) { + exit(1); + } + if (fgets(passwd, N, in) == NULL) { + exit(1); + } + fclose(in); + fprintf(stderr, "read username@passwd from file: %s\n", infile); + if (rmfile) { + fprintf(stderr, "deleting username@passwd file: %s\n", infile); + unlink(infile); + } + } else if (strchr(str, '@')) { + char *q = strchr(str, '@'); + *q = '\0'; + strncpy(username, str, N); + strncpy(passwd, q+1, N); + } else { + exit(1); + } + + free(str); + + if (vencrypt_plain) { + CARD32 ulen, plen; + char *q; + + q = strrchr(username, '\n'); + if (q) *q = '\0'; + q = strrchr(passwd, '\n'); + if (q) *q = '\0'; + + ulen = Swap32IfLE((CARD32)strlen(username)); + plen = Swap32IfLE((CARD32)strlen(passwd)); + + if (!WriteExact(rfbsock, (char *)&ulen, 4) || + !WriteExact(rfbsock, (char *)&plen, 4)) { + return; + } + + if (!WriteExact(rfbsock, username, strlen(username)) || + !WriteExact(rfbsock, passwd, strlen(passwd))) { + return; + } + return; + } + + + if (! getenv("SSVNC_UNIXPW_NOESC")) { + SendKeyEvent(XK_Escape, 1); + SendKeyEvent(XK_Escape, 0); + } + + q = username; + while (*q != '\0' && *q != '\n') { + char c = *q; + if (c >= 0x20 && c <= 0x07e) { + KeySym ks = (KeySym) c; + SendKeyEvent(ks, 1); + SendKeyEvent(ks, 0); + } + q++; + } + + SendKeyEvent(XK_Return, 1); + SendKeyEvent(XK_Return, 0); + + q = passwd; + while (*q != '\0' && *q != '\n') { + char c = *q; + if (c >= 0x20 && c <= 0x07e) { + KeySym ks = (KeySym) c; + SendKeyEvent(ks, 1); + SendKeyEvent(ks, 0); + } + q++; + } + + SendKeyEvent(XK_Return, 1); + 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 saw_appshare = 0; + int main(int argc, char **argv) { - int i; - programName = argv[0]; + int i, save_sbw, saw_listen = 0; + char *pw_loc = NULL; + programName = argv[0]; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-env")) { + if (i+1 < argc) { + char *estr = argv[i+1]; + if (strchr(estr, '=')) { + putenv(estr); + } + } + } + } /* 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 +293,1667 @@ listenForIncomingConnections() returns, setting the listenSpecified flag. */ - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-listen") == 0) { - listenForIncomingConnections(&argc, argv, i); - break; - } - if (strcmp(argv[i], "-tunnel") == 0 || strcmp(argv[i], "-via") == 0) { - if (!createTunnel(&argc, argv, i)) - exit(1); - break; - } - } + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-appshare")) { + putenv("SSVNC_MULTIPLE_LISTEN=1"); + fprintf(stderr, "Enabling -multilisten mode for 'x11vnc -appshare' usage.\n\n"); + saw_appshare = 1; + } + if (!strcmp(argv[i], "-multilisten")) { + putenv("SSVNC_MULTIPLE_LISTEN=1"); + saw_listen = 2; + } + if (!strcmp(argv[i], "-listen")) { + saw_listen = 1; + } + if (!strcmp(argv[i], "-acceptpopup")) { + putenv("SSVNC_ACCEPT_POPUP=1"); + } + if (!strcmp(argv[i], "-acceptpopupsc")) { + putenv("SSVNC_ACCEPT_POPUP_SC=1"); + } + if (strstr(argv[i], " pw=") != NULL) { + pw_loc = strstr(argv[i], " pw=") + 1; + } + } + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-appshare") && !saw_listen) { + listenForIncomingConnections(&argc, argv, i); + break; + } + if (!strcmp(argv[i], "-multilisten")) { + listenForIncomingConnections(&argc, argv, i); + break; + } + if (!strcmp(argv[i], "-listen")) { + listenForIncomingConnections(&argc, argv, i); + break; + } + if (!strcmp(argv[i], "-tunnel") || !strcmp(argv[i], "-via")) { + if (!createTunnel(&argc, argv, i)) { + exit(1); + } + break; + } + if (!strcmp(argv[i], "-printres") || !strcmp(argv[i], "-res")) { + int j = 0; + fprintf(stdout, "\n! Ssvnc fallback X resources:\n\n"); + while (1) { + char *p = fallback_resources[j++]; + int k = 0; + if (p == NULL) break; + while (*p != '\0') { + fprintf(stdout, "%c", *p); + if (k > 0 && *p == 'n' && *(p-1) == '\\') { + fprintf(stdout, "\\\n"); + } + p++; k++; + } + fprintf(stdout, "\n\n"); + } + exit(0); + } + } + + + if (argc > 1 && strstr(argv[1], "-h") == argv[1]) { + usage(); + return 0; + } /* Call the main Xt initialisation function. It parses command-line options, generating appropriate resource specs, and makes a connection to the X display. */ - toplevel = XtVaAppInitialize(&appContext, "Vncviewer", - cmdLineOptions, numCmdLineOptions, - &argc, argv, fallback_resources, - XtNborderWidth, 0, NULL); + if (saw_appshare || getenv("VNCVIEWER_MIN_TITLE")) { + min_title(); + } + appData.sbWidth = 0; + if (getenv("VNCVIEWER_SBWIDTH")) { + int sbw = atoi(getenv("VNCVIEWER_SBWIDTH")); + if (sbw > 0) { + appData.sbWidth = sbw; + } + } + if (appData.sbWidth == 0) { + int i, sbw = 0; + for (i = 1; i < argc - 1; i++) { + if (!strcmp(argv[i], "-sbwidth")) { + sbw = atoi(argv[i+1]); + } + } + if (sbw > 0) { + appData.sbWidth = sbw; + } + } + save_sbw = appData.sbWidth; + if (save_sbw > 0) { + set_sbwidth(save_sbw); + } else { + set_sbwidth(6); + } + + toplevel = XtVaAppInitialize(&appContext, "Ssvnc", cmdLineOptions, + numCmdLineOptions, &argc, argv, fallback_resources, + XtNborderWidth, 0, NULL); - dpy = XtDisplay(toplevel); + dpy = XtDisplay(toplevel); /* Interpret resource specs and process any remaining command-line arguments (i.e. the VNC server name). If the server name isn't specified on the command line, getArgsAndResources() will pop up a dialog box and wait for one to be entered. */ - GetArgsAndResources(argc, argv); + GetArgsAndResources(argc, argv); + + if (saw_appshare) { + appData.appShare = True; + } + + 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 */ - if (!listenSpecified) { - if (!ConnectToRFBServer(vncServerHost, vncServerPort)) exit(1); - } + if (appData.repeaterUltra == NULL) { + if (getenv("SSVNC_REPEATER") != NULL) { + appData.repeaterUltra = strdup(getenv("SSVNC_REPEATER")); + } + } + + if (!listenSpecified) { + if (!ConnectToRFBServer(vncServerHost, vncServerPort)) { + exit(1); + } + if (appData.repeaterUltra != NULL) { + char tmp[256]; + if (strstr(appData.repeaterUltra, "SCIII=") == appData.repeaterUltra) { + appData.repeaterUltra = strdup(appData.repeaterUltra + strlen("SCIII=")); + fprintf(stderr, "sending 'testB' to ultravnc SC III SSL repeater...\n"); + WriteExact(rfbsock, "testB" , 5); + } + if (ReadFromRFBServer(tmp, 12)) { + tmp[12] = '\0'; + fprintf(stderr, "repeater 1st proto line: '%s'\n", tmp); + if (strstr(tmp, "RFB 000.000") == tmp) { + int i; + for (i=0; i<256; i++) { + tmp[i] = '\0'; + } + for (i=0; i<250; i++) { + if (i >= strlen(appData.repeaterUltra)) { + break; + } + tmp[i] = appData.repeaterUltra[i]; + } + fprintf(stderr, "sending '%s' to repeater...\n", tmp); + WriteExact(rfbsock, tmp, 250); + } + } else { + fprintf(stderr, "repeater NO proto line!\n"); + } + } + } /* Initialise the VNC connection, including reading the password */ - if (!InitialiseRFBConnection()) exit(1); + if (!InitialiseRFBConnection()) { + Cleanup(); + exit(1); + } + if (appData.unixPW != NULL) { + unixpw(appData.unixPW, 0); + } else if (getenv("SSVNC_UNIXPW")) { + unixpw(getenv("SSVNC_UNIXPW"), 0); + } /* Create the "popup" widget - this won't actually appear on the screen until some user-defined event causes the "ShowPopup" action to be invoked */ - CreatePopup(); + CreatePopup(); + CreateScaleN(); + CreateTurboVNC(); + CreateQuality(); + CreateCompress(); + CreateChat(); /* Find the best pixel format and X visual/colormap to use */ - SetVisualAndCmap(); + SetVisualAndCmap(); /* Create the "desktop" widget, and perform initialisation which needs doing before the widgets are realized */ - ToplevelInitBeforeRealization(); + ToplevelInitBeforeRealization(); - DesktopInitBeforeRealization(); + DesktopInitBeforeRealization(); /* "Realize" all the widgets, i.e. actually create and map their X windows */ - XtRealizeWidget(toplevel); + XtRealizeWidget(toplevel); /* Perform initialisation that needs doing after realization, now that the X windows exist */ - InitialiseSelection(); + InitialiseSelection(); - ToplevelInitAfterRealization(); + ToplevelInitAfterRealization(); - DesktopInitAfterRealization(); + DesktopInitAfterRealization(); /* Tell the VNC server which pixel format and encodings we want to use */ - 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. */ - while (1) { - if (!HandleRFBServerMessage()) - break; - } + while (1) { + if (!HandleRFBServerMessage()) { + break; + } + if (appData.chatOnly) { + chat_window_only(); + } + } + + Cleanup(); + + return 0; +} + +/* + * Toggle8bpp + */ + +static int last_ncolors = 0; +static int save_useBGR233 = 0; +static Bool save_useBGR565 = False; + +static Widget b8 = NULL; +static Widget b16 = NULL; +static Widget bfull = NULL; + +int do_format_change = 0; +int do_cursor_change = 0; +int do_fb_update = 0.0; +static void schedule_format_change(void) { + do_format_change = 1; + do_cursor_change = 0; +} +extern double dnow(void); +static void schedule_fb_update(void) { + do_fb_update = dnow(); +} +static void init_format_change(void) { + appDataNew.useBGR233 = appData.useBGR233; + appDataNew.useBGR565 = appData.useBGR565; + appDataNew.useGreyScale = appData.useGreyScale; + appDataNew.enableJPEG = appData.enableJPEG; + appDataNew.encodingsString = appData.encodingsString; + appDataNew.useRemoteCursor = appData.useRemoteCursor; + appDataNew.useX11Cursor = appData.useX11Cursor; + appDataNew.useRawLocal = appData.useRawLocal; + appDataNew.qualityLevel = appData.qualityLevel; + appDataNew.compressLevel = appData.compressLevel; +} +void cutover_format_change(void) { + appData.useBGR233 = appDataNew.useBGR233; + appData.useBGR565 = appDataNew.useBGR565; + appData.useGreyScale = appDataNew.useGreyScale; + appData.enableJPEG = appDataNew.enableJPEG; + appData.encodingsString = appDataNew.encodingsString; + appData.useRemoteCursor = appDataNew.useRemoteCursor; + appData.useX11Cursor = appDataNew.useX11Cursor; + appData.useRawLocal = appDataNew.useRawLocal; + appData.qualityLevel = appDataNew.qualityLevel; + appData.compressLevel = appDataNew.compressLevel; +} + +void +Toggle8bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + fprintf(stderr, "Toggle8bpp: %d\n", appData.useBGR233); + b8 = w; + init_format_change(); + if (appData.useBGR233) { + last_ncolors = appData.useBGR233; + appDataNew.useBGR233 = 0; + appDataNew.useBGR565 = save_useBGR565; + fprintf(stderr, "8bpp: off\n"); + } else { + if (!last_ncolors) last_ncolors = 256; + appDataNew.useBGR233 = last_ncolors; + save_useBGR565 = appData.useBGR565; + appDataNew.useBGR565 = False; + fprintf(stderr, "8bpp: on (%d colors)\n", appDataNew.useBGR233); + } + schedule_format_change(); +} + + +void +Toggle16bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + fprintf(stderr, "Toggle16bpp: %d\n", appData.useBGR565); + b16 = w; + init_format_change(); + if (appData.useBGR565) { + appDataNew.useBGR565 = False; + appDataNew.useBGR233 = save_useBGR233; + fprintf(stderr, "16bpp: off\n"); + } else { + appDataNew.useBGR565 = True; + save_useBGR233 = appData.useBGR233; + appDataNew.useBGR233 = 0; + fprintf(stderr, "16bpp: on\n"); + } + schedule_format_change(); +} + +void +ToggleFullColor(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + fprintf(stderr, "ToggleFullColor\n"); + bfull = w; + init_format_change(); + if (appData.useBGR565 || appData.useBGR233) { + save_useBGR565 = appData.useBGR565; + appDataNew.useBGR565 = False; + save_useBGR233 = appData.useBGR233; + appDataNew.useBGR233 = 0; + fprintf(stderr, "FullColor: on\n"); + } else { + if (save_useBGR565) { + appDataNew.useBGR565 = True; + appDataNew.useBGR233 = 0; + fprintf(stderr, "FullColor off -> 16bpp.\n"); + } else { + appDataNew.useBGR565 = False; + if (!save_useBGR233) save_useBGR233 = 256; + appDataNew.useBGR233 = save_useBGR233; + fprintf(stderr, "FullColor off -> 8bpp.\n"); + } + } + schedule_format_change(); +} + +void +ToggleXGrab(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.grabAll) { + appData.grabAll = False; + } else { + appData.grabAll = True; + } + fprintf(stderr, "ToggleXGrab, current=%d\n", appData.grabAll); + /* always ungrab to be sure, fullscreen will handle the rest */ + XUngrabServer(dpy); +} + +void +ToggleEscapeActive(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.escapeActive) { + appData.escapeActive = False; + } else { + appData.escapeActive = True; + } +} + +/* + * ToggleNColors + */ + +static Widget w256 = NULL; +static Widget w64 = NULL; +static Widget w8 = NULL; + +void +Toggle256Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + w256 = w; + if (appData.useBGR233 != 256) { + fprintf(stderr, "256 colors: on\n"); + init_format_change(); + last_ncolors = appDataNew.useBGR233 = 256; + save_useBGR565 = appData.useBGR565; + appDataNew.useBGR565 = False; + schedule_format_change(); + } +} + +void +Toggle64Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + w64 = w; + if (appData.useBGR233 != 64) { + fprintf(stderr, "64 colors: on\n"); + init_format_change(); + last_ncolors = appDataNew.useBGR233 = 64; + save_useBGR565 = appData.useBGR565; + appDataNew.useBGR565 = False; + schedule_format_change(); + } +} + +void +Toggle8Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + w8 = w; + if (appData.useBGR233 != 8) { + fprintf(stderr, "8 colors: on\n"); + init_format_change(); + last_ncolors = appDataNew.useBGR233 = 8; + save_useBGR565 = appData.useBGR565; + appDataNew.useBGR565 = False; + schedule_format_change(); + } +} + +void +ToggleGreyScale(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + fprintf(stderr, "ToggleGreyScale\n"); + init_format_change(); + if (appData.useGreyScale) { + appDataNew.useGreyScale = False; + fprintf(stderr, "greyscale: off\n"); + } else { + appDataNew.useGreyScale = True; + fprintf(stderr, "greyscale: on\n"); + } + schedule_format_change(); +} + +/* + * ToggleJPEG + */ + +void +ToggleJPEG(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + init_format_change(); + if (appData.enableJPEG) { + appDataNew.enableJPEG = False; + fprintf(stderr, "JPEG: off\n"); + } else { + appDataNew.enableJPEG = True; + fprintf(stderr, "JPEG: on\n"); + } + schedule_format_change(); +} + +/* + * ToggleTightZRLE + */ + +static Bool usingZRLE = False; +static Bool usingZYWRLE = False; +static Bool usingHextile = False; +extern int skip_maybe_sync; + +void +ToggleTightZRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char prefTight[] = "copyrect tight zrle zywrle zlib hextile corre rre raw"; + char prefZRLE[] = "copyrect zrle zywrle tight zlib hextile corre rre raw"; + init_format_change(); + usingHextile = False; + if (! appData.encodingsString) { + appDataNew.encodingsString = strdup(prefZRLE); + usingZRLE = True; + fprintf(stderr, "prefer: ZRLE\n"); + } else { + char *t, *z; + static int first = 1; + t = strstr(appData.encodingsString, "tight"); + z = strstr(appData.encodingsString, "zrle"); + if (first && usingZRLE) { + appDataNew.encodingsString = strdup(prefTight); + usingZRLE = False; + usingZYWRLE = False; + } else if (! t) { + appDataNew.encodingsString = strdup(prefZRLE); + usingZRLE = True; + fprintf(stderr, "prefer: ZRLE\n"); + } else if (! z) { + appDataNew.encodingsString = strdup(prefTight); + usingZRLE = False; + usingZYWRLE = False; + skip_maybe_sync = 0; + fprintf(stderr, "prefer: Tight\n"); + } else { + if (t < z) { + appDataNew.encodingsString = strdup(prefZRLE); + usingZRLE = True; + fprintf(stderr, "prefer: ZRLE\n"); + } else { + appDataNew.encodingsString = strdup(prefTight); + usingZRLE = False; + usingZYWRLE = False; + skip_maybe_sync = 0; + fprintf(stderr, "prefer: Tight\n"); + } + } + first = 0; + } + schedule_format_change(); +} + +void +ToggleZRLEZYWRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char prefZYWRLE[] = "copyrect zywrle zrle tight zlib hextile corre rre raw"; + char prefZRLE[] = "copyrect zrle zywrle tight zlib hextile corre rre raw"; + init_format_change(); + usingZRLE = True; + usingHextile = False; + if (! appData.encodingsString) { + appDataNew.encodingsString = strdup(prefZYWRLE); + usingZYWRLE = True; + fprintf(stderr, "prefer: ZYWRLE\n"); + } else { + char *z, *w; + w = strstr(appData.encodingsString, "zywrle"); + z = strstr(appData.encodingsString, "zrle"); + if (usingZYWRLE) { + appDataNew.encodingsString = strdup(prefZRLE); + fprintf(stderr, "prefer: ZRLE\n"); + usingZYWRLE = False; + skip_maybe_sync = 0; + } else { + appDataNew.encodingsString = strdup(prefZYWRLE); + fprintf(stderr, "prefer: ZYWRLE\n"); + usingZYWRLE = True; + } + } + schedule_format_change(); +} + +void +ToggleTightHextile(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char prefTight[] = "copyrect tight zrle zywrle zlib hextile corre rre raw"; + char prefHextile[] = "copyrect hextile tight zrle zywrle zlib corre rre raw"; + init_format_change(); + usingZRLE = False; + usingZYWRLE = False; + if (! appData.encodingsString) { + appDataNew.encodingsString = strdup(prefHextile); + usingHextile = True; + fprintf(stderr, "prefer: Hextile\n"); + } else { + char *t, *z; + static int first = 1; + t = strstr(appData.encodingsString, "tight"); + z = strstr(appData.encodingsString, "hextile"); + if (first && usingHextile) { + appDataNew.encodingsString = strdup(prefTight); + usingHextile = False; + } else if (! t) { + appDataNew.encodingsString = strdup(prefHextile); + usingHextile = True; + fprintf(stderr, "prefer: Hextile\n"); + } else if (! z) { + appDataNew.encodingsString = strdup(prefTight); + usingHextile = False; + skip_maybe_sync = 0; + fprintf(stderr, "prefer: Tight\n"); + } else { + if (t < z) { + appDataNew.encodingsString = strdup(prefHextile); + usingHextile = True; + fprintf(stderr, "prefer: Hextile\n"); + } else { + appDataNew.encodingsString = strdup(prefTight); + usingHextile = False; + skip_maybe_sync = 0; + fprintf(stderr, "prefer: Tight\n"); + } + } + first = 0; + } + schedule_format_change(); +} + +void scale_check_zrle(void) { + static int didit = 0; + if (didit) { + return; + } + didit = 1; + if (getenv("SSVNC_PRESERVE_ENCODING")) { + return; + } + if (!usingZRLE && !usingHextile) { + Widget w; + fprintf(stderr, "\nSwitching to faster ZRLE encoding in client-side scaling mode.\n"); + fprintf(stderr, "Switch back to Tight via the Popup menu if you prefer it.\n\n"); + ToggleTightZRLE(w, NULL, NULL, NULL); + } +} + +/* + * ToggleViewOnly + */ + +void +ToggleViewOnly(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.viewOnly) { + appData.viewOnly = False; + fprintf(stderr, "viewonly: off\n"); + } else { + appData.viewOnly = True; + fprintf(stderr, "viewonly: on\n"); + } + Xcursors(1); +} + +void +ToggleCursorShape(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + init_format_change(); + if (appData.useRemoteCursor) { + appDataNew.useRemoteCursor = False; + fprintf(stderr, "useRemoteCursor: off\n"); + } else { + appDataNew.useRemoteCursor = True; + fprintf(stderr, "useRemoteCursor: on\n"); + } + schedule_format_change(); + if (!appDataNew.useRemoteCursor) { + do_cursor_change = 1; + } else { + do_cursor_change = -1; + } +} + +void +ToggleCursorAlpha(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.useCursorAlpha) { + appData.useCursorAlpha = False; + fprintf(stderr, "useCursorAlpha: off\n"); + } else { + appData.useCursorAlpha = True; + fprintf(stderr, "useCursorAlpha: on\n"); + } +} + +void +ToggleX11Cursor(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + init_format_change(); + if (appData.useX11Cursor) { + appDataNew.useX11Cursor = False; + fprintf(stderr, "useX11Cursor: off\n"); + } else { + appDataNew.useX11Cursor = True; + fprintf(stderr, "useX11Cursor: on\n"); + } + schedule_format_change(); + do_cursor_change = 1; +} + +void +ToggleBell(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.useBell) { + appData.useBell = False; + fprintf(stderr, "useBell: off\n"); + } else { + appData.useBell = True; + fprintf(stderr, "useBell: on\n"); + } +} + +void +ToggleRawLocal(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + init_format_change(); + if (appData.useRawLocal) { + appDataNew.useRawLocal = False; + fprintf(stderr, "useRawLocal: off\n"); + } else { + appDataNew.useRawLocal = True; + fprintf(stderr, "useRawLocal: on\n"); + } + schedule_format_change(); +} + +void +ToggleServerInput(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.serverInput) { + appData.serverInput= False; + fprintf(stderr, "serverInput: off\n"); + SendServerInput(True); + } else { + appData.serverInput = True; + fprintf(stderr, "serverInput: on\n"); + SendServerInput(False); + } +} + +void +TogglePipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.pipelineUpdates) { + appData.pipelineUpdates= False; + fprintf(stderr, "pipeline-update: off\n"); + } else { + appData.pipelineUpdates = True; + fprintf(stderr, "pipeline-update: on\n"); + } + /* XXX request one to be sure? */ +} + +void +ToggleSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.sendClipboard) { + appData.sendClipboard= False; + fprintf(stderr, "Send CLIPBOARD Selection: off (send PRIMARY instead)\n"); + } else { + appData.sendClipboard = True; + fprintf(stderr, "Send CLIPBOARD Selection: on (do not send PRIMARY)\n"); + } +} + +void +ToggleSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.sendAlways) { + appData.sendAlways= False; + fprintf(stderr, "Send Selection Always: off\n"); + } else { + appData.sendAlways = True; + fprintf(stderr, "Send Selection Always: on\n"); + } +} + + +Bool _sw1_ = False; /* XXX this is a weird bug... */ +Bool _sw2_ = False; +Bool _sw3_ = False; +Bool selectingSingleWindow = False; + +extern Cursor bogoCursor; + +void +ToggleSingleWindow(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.singleWindow) { + appData.singleWindow= False; + fprintf(stderr, "singleWindow: off\n"); + SendSingleWindow(-1, -1); + } else { + appData.singleWindow = True; + selectingSingleWindow = True; + fprintf(stderr, "singleWindow: on\n"); + if (bogoCursor != None) { + XDefineCursor(dpy, desktopWin, bogoCursor); + } + } +} + +void raiseme(int force); +void AppendChatInput(char *); + +void printChat(char *str, Bool raise) { + if (appData.termChat) { + if (raise) { + raiseme(0); + } + fprintf(stderr, str); + } else { + if (raise) { + ShowChat(); + } + AppendChatInput(str); + } +} + +void +ToggleTextChat(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.chatActive) { + printChat("\n*SentClose*\n\n", False); + SendTextChatClose(); + SendTextChatFinished(); + HideChat(0, NULL, NULL, NULL); + appData.chatActive= False; + } else { + ShowChat(); + SendTextChatOpen(); + if (appData.termChat) { + printChat("\n*SentOpen*\n\nSend: ", True); + } else { + printChat("\n*SentOpen*\n", True); + } + appData.chatActive = True; + } +} + +extern int filexfer_sock; +extern pid_t java_helper; +#define KILLJAVA +#ifdef KILLJAVA +#include +#endif + +void +ToggleFileXfer(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + static double last_start = 0.0; + if (appData.fileActive) { + //HideFile(w, ev, params, num_params); + //appData.fileActive = False; +#ifndef KILLJAVA + if (filexfer_sock >= 0) { + close(filexfer_sock); + } +#else + if (java_helper != 0) { + int i; + if (dnow() < last_start + 6.0) { + fprintf(stderr, "skipping early kill of java helper (less than 5 secs)\n"); + } else { + for (i=1; i<=5; i++) { + pid_t p = java_helper + i; + fprintf(stderr, "trying to kill java helper: %d\n", p); + if (kill(p, SIGTERM) == 0) { + java_helper = 0; + break; + } + } + } + } +#endif + } else { + ShowFile(w, ev, params, num_params); + appData.fileActive = True; + last_start = dnow(); + } +} + +static int fooHandler(Display *dpy, XErrorEvent *error) { + return 0; +} + +void raiseme(int force) { + if ((force || appData.termChat) && getenv("WINDOWID")) { + unsigned long w; + if (sscanf(getenv("WINDOWID"), "%lu", &w) == 1) { + ; + } else if (sscanf(getenv("WINDOWID"), "0x%lx", &w) == 1) { + ; + } else { + w = 0; + } + if (w != 0) { + XErrorHandler old = XSetErrorHandler(fooHandler); + XMapRaised(dpy, (Window) w); + XSync(dpy, False); + XSetErrorHandler(old); + } + } +} + +void set_server_scale(int n) { + if (n >= 1 && n < 100) { + int w = si.framebufferWidth; + int h = si.framebufferHeight; + appData.serverScale = n; + SendServerScale(n); + if (0) SendFramebufferUpdateRequest(0, 0, w, h, False); + schedule_fb_update(); + } +} + +void +DoServerScale(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char str[100], *s, *q; + int n; + if (1) { + s = DoScaleNDialog(); + } else { + raiseme(1); + fprintf(stderr, "\n\n\a\nEnter integer n for 1/n server scaling: "); + str[0] = '\0'; + fgets(str, 100, stdin); + s = str; + q = strstr(str, "\n"); + if (q) *q = '\0'; + } + if (s[0] != '\0') { + n = atoi(s); + set_server_scale(n); + } +} + +void set_server_quality(int n) { + fprintf(stderr, "set_quality: %d\n", n); + if (n >= 0 && n <= 9) { + int w = si.framebufferWidth; + int h = si.framebufferHeight; + init_format_change(); + appDataNew.qualityLevel = n; + SendFramebufferUpdateRequest(0, 0, w, h, False); + schedule_format_change(); + } +} + +void +DoServerQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char str[100], *s, *q; + int n; + if (1) { + s = DoQualityDialog(); + } else { + raiseme(1); + fprintf(stderr, "\n\n\a\nEnter integer 1 <= n <= 9 for quality setting: "); + str[0] = '\0'; + fgets(str, 100, stdin); + s = str; + q = strstr(str, "\n"); + if (q) *q = '\0'; + } + if (s[0] != '\0') { + n = atoi(s); + set_server_quality(n); + } +} + +void set_server_compress(int n) { + fprintf(stderr, "set_compress: %d\n", n); + if (n >= 0 && n <= 9) { + int w = si.framebufferWidth; + int h = si.framebufferHeight; + init_format_change(); + appDataNew.compressLevel = n; + SendFramebufferUpdateRequest(0, 0, w, h, False); + schedule_format_change(); + } +} + +void +DoServerCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char str[100], *s, *q; + int n; + if (1) { + s = DoCompressDialog(); + } else { + raiseme(1); + fprintf(stderr, "\n\n\a\nEnter integer 1 <= n <= 9 for compress level setting: "); + str[0] = '\0'; + fgets(str, 100, stdin); + s = str; + q = strstr(str, "\n"); + if (q) *q = '\0'; + } + if (s[0] != '\0') { + n = atoi(s); + set_server_compress(n); + } +} + +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; + double fx, fy; + 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.scale != NULL) { + get_scale_values(&fx, &fy); + if (fx <= 0.0 || fy <= 0.0) { + appData.scale = NULL; + return; + } + } + + if (appData.fullScreen) { + fs = 1; + FullScreenOff(); + } + rescale_image(); + if (fs) { + FullScreenOn(); + } + } +} + +void +SetEscapeKeys(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char *s; + s = DoEscapeKeysDialog(); + fprintf(stderr, "set escape keys: '%s'\n", s); + if (s[0] != '\0') { + appData.escapeKeys = strdup(s); + } +} + +void set_ycrop(int n) { + if (n >= 1) { + int w = si.framebufferWidth; + int h = si.framebufferHeight; + appData.yCrop = n; + ReDoDesktop(); + SendFramebufferUpdateRequest(0, 0, w, h, False); + schedule_fb_update(); + } +} - Cleanup(); +void +SetYCrop(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char str[100], *q, *s; + int n; + if (1) { + s = DoYCropDialog(); + } else { + raiseme(1); + fprintf(stderr, "\n\n\a\nEnter pixel size n -ycrop maximum y-height: "); + str[0] = '\0'; + fgets(str, 100, stdin); + s = str; + q = strstr(str, "\n"); + if (q) *q = '\0'; + } + if (s[0] != '\0') { + n = atoi(s); + set_ycrop(n); + } +} + +void set_scbar(int n) { + if (n >= 1) { + int w = si.framebufferWidth; + int h = si.framebufferHeight; +fprintf(stderr, "set_scbat: %d\n", n); + appData.sbWidth = n; + ReDoDesktop(); + SendFramebufferUpdateRequest(0, 0, w, h, False); + schedule_fb_update(); + } +} + +void +SetScbar(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + char str[100], *q, *s; + int n; + if (1) { + s = DoScbarDialog(); + } else { + raiseme(1); + fprintf(stderr, "\n\n\a\nEnter pixel size n scrollbar width: "); + str[0] = '\0'; + fgets(str, 100, stdin); + s = str; + q = strstr(str, "\n"); + if (q) *q = '\0'; + } + if (s[0] != '\0') { + n = atoi(s); + set_scbar(n); + } +} + +void +SetScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (*num_params != 0) { + int n = atoi(params[0]); + set_server_scale(n); + } +} + +void UpdateQual(void) { + SetFormatAndEncodings(); + UpdateSubsampButtons(); + UpdateQualSlider(); +} + +extern double latency; + +static void LosslessRefresh(void) { + String encodings = appData.encodingsString; + int compressLevel = appData.compressLevel; + int qual = appData.qualityLevel; + Bool enableJPEG = appData.enableJPEG; + appData.qualityLevel = -1; + appData.enableJPEG = False; + appData.encodingsString = "tight copyrect"; + appData.compressLevel = 1; + SetFormatAndEncodings(); + SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, si.framebufferHeight, False); + if (latency > 0.0) { + if (0) usleep((int) latency * 1000); + } + appData.qualityLevel = qual; + appData.enableJPEG = enableJPEG; + appData.encodingsString = encodings; + appData.compressLevel = compressLevel; + SetFormatAndEncodings(); +} + +static void QualHigh(void) { + appData.encodingsString = "tight copyrect"; + if(appData.useBGR233 || appDataNew.useBGR565) { + fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n"); + } else { + appData.enableJPEG = True; + } + appData.subsampLevel = TVNC_1X; + appData.qualityLevel = 95; + UpdateQual(); +} + +static void QualMed(void) { + appData.encodingsString = "tight copyrect"; + if(appData.useBGR233 || appDataNew.useBGR565) { + fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n"); + } else { + appData.enableJPEG = True; + } + appData.subsampLevel = TVNC_2X; + appData.qualityLevel = 80; + UpdateQual(); +} + +static void QualLow(void) { + appData.encodingsString = "tight copyrect"; + if(appData.useBGR233 || appDataNew.useBGR565) { + fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n"); + } else { + appData.enableJPEG = True; + } + appData.subsampLevel = TVNC_4X; + appData.qualityLevel = 30; + UpdateQual(); +} + +static void QualLossless(void) { + appData.encodingsString = "tight copyrect"; + appData.enableJPEG = False; + appData.compressLevel = 0; + UpdateQual(); +} - return 0; +static void QualLosslessWAN(void) { + appData.encodingsString = "tight copyrect"; + appData.enableJPEG = False; + appData.compressLevel = 1; + UpdateQual(); +} + +void +SetTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (*num_params != 0) { + int n = atoi(params[0]); + if (0) fprintf(stderr, "SetTurboVNC: %d\n", n); + if (n == 1) { + QualHigh(); + } else if (n == 2) { + QualMed(); + } else if (n == 3) { + QualLow(); + } else if (n == 4) { + QualLossless(); + } else if (n == 5) { + QualLosslessWAN(); + } else if (n == 6) { + appData.subsampLevel = TVNC_1X; + UpdateQual(); + } else if (n == 7) { + appData.subsampLevel = TVNC_2X; + UpdateQual(); + } else if (n == 8) { + appData.subsampLevel = TVNC_4X; + UpdateQual(); + } else if (n == 9) { + appData.subsampLevel = TVNC_GRAY; + UpdateQual(); + } else if (n == 10) { + LosslessRefresh(); + } + } +} + +void +SetQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (*num_params != 0) { + int n = atoi(params[0]); + set_server_quality(n); + } +} + +void +SetCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (*num_params != 0) { + int n = atoi(params[0]); + set_server_compress(n); + } +} + +void +GotChatText(char *str, int len) +{ + static char *b = NULL; + static int blen = -1; + int i, k; + if (appData.termChat) { + printChat("\nChat: ", True); + } else { + printChat("Chat: ", True); + } + + if (len < 0) len = 0; + + if (blen < len+1) { + if (b) free(b); + blen = 2 * (len + 10); + b = (char *) malloc(blen); + } + + k = 0; + for (i=0; i < len; i++) { + if (str[i] != '\r') { + b[k++] = str[i]; + } + } + b[k] = '\0'; + b[len] = '\0'; + printChat(b, True); + + if (appData.termChat) { + if (strstr(str, "\n")) { + printChat("Send: ", True); + } else { + printChat("\nSend: ", True); + } + } +} + +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); + } +} + +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); + } +} + +void +SetQualityState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (*num_params != 0) { + int n = atoi(params[0]); + if (appData.qualityLevel == n) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } + } +} + +void +SetCompressState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (*num_params != 0) { + int n = atoi(params[0]); + if (appData.compressLevel == n) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } + } +} + +void +SetScaleNState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (*num_params != 0) { + int n = atoi(params[0]); + if (appData.serverScale == n || (appData.serverScale >= 6 && n >= 6)) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } + } +} + +void +Set8bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.useBGR233) { + XtVaSetValues(w, XtNstate, True, NULL); + if (b16 != NULL) { + XtVaSetValues(b16, XtNstate, False, NULL); + } + if (bfull != NULL) { + XtVaSetValues(bfull, XtNstate, False, NULL); + } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +Set16bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.useBGR565) { + XtVaSetValues(w, XtNstate, True, NULL); + if (b8 != NULL) { + XtVaSetValues(b8, XtNstate, False, NULL); + } + if (bfull != NULL) { + XtVaSetValues(bfull, XtNstate, False, NULL); + } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +SetFullColorState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.useBGR565 || appData.useBGR233) { + 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); + } + } +} + +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); + } +} + +void +SetEscapeKeysState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.escapeActive) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +Set256ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + 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); + } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +Set64ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + 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); + } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +Set8ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + 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); + } + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +SetGreyScaleState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (appData.useGreyScale) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +static init_state(void) { + static int first = 1; + if (first && appData.encodingsString) { + char *t, *z, *y, *h; + char *str = appData.encodingsString; + int len = strlen(str); + + t = strstr(str, "tight"); + z = strstr(str, "zrle"); + y = strstr(str, "zywrle"); + h = strstr(str, "hextile"); + + if (!t) t = str + len; + if (!z) z = str + len; + if (!y) y = str + len; + if (!h) h = str + len; + + usingZRLE = False; + usingZYWRLE = False; + usingHextile = False; + + if (t < z && t < y && t < h) { + ; + } else if (z < t && z < y && z < h) { + usingZRLE = True; + } else if (y < t && y < z && y < h) { + usingZYWRLE = True; + usingZRLE = True; + } else if (h < t && h < z && h < y) { + usingHextile = True; + } + } + first = 0; + +} + +void +SetZRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + init_state(); + if (usingZRLE) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +SetHextileState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + init_state(); + if (usingHextile) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +SetZYWRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + init_state(); + 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); + } +} + +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); + } +} + +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); + } +} + +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); + } +} + +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); + } +} + +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); + } +} + +void +SetPipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (!appData.pipelineUpdates) { + XtVaSetValues(w, XtNstate, False, NULL); + } else { + XtVaSetValues(w, XtNstate, True, NULL); + } +} + +void +SetSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (!appData.sendClipboard) { + XtVaSetValues(w, XtNstate, False, NULL); + } else { + XtVaSetValues(w, XtNstate, True, NULL); + } +} + +void +SetSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (!appData.sendAlways) { + XtVaSetValues(w, XtNstate, False, NULL); + } else { + XtVaSetValues(w, XtNstate, True, 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); + } +} + +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); + } +} + +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); + } } 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 2009-11-28 00:45:15.000000000 -0500 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,13 @@ (((l) & 0x0000ff00) << 8) | \ (((l) & 0x000000ff) << 24)) : (l)) -#define MAX_ENCODINGS 20 +#define Swap32IfBE(l) \ + (*(char *)&endianTest ? (l) : ((((l) & 0xff000000) >> 24) | \ + (((l) & 0x00ff0000) >> 8) | \ + (((l) & 0x0000ff00) << 8) | \ + (((l) & 0x000000ff) << 24)) ) + +#define MAX_ENCODINGS 24 #define FLASH_PORT_OFFSET 5400 #define LISTEN_PORT_OFFSET 5500 @@ -64,60 +71,126 @@ #define DEFAULT_VIA_CMD \ (DEFAULT_SSH_CMD " -f -L %L:%H:%R %G sleep 20") +#define TVNC_SAMPOPT 4 +enum {TVNC_1X=0, TVNC_4X, TVNC_2X, TVNC_GRAY}; -/* argsresources.c */ - -typedef struct { - Bool shareDesktop; - Bool viewOnly; - Bool fullScreen; - Bool grabKeyboard; - Bool raiseOnBeep; - - String encodingsString; - - Bool useBGR233; - int nColours; - Bool useSharedColours; - Bool forceOwnCmap; - Bool forceTrueColour; - int requestedDepth; - - Bool useShm; - - int wmDecorationWidth; - int wmDecorationHeight; - - char *userLogin; - - char *passwordFile; - Bool passwordDialog; - - int rawDelay; - int copyRectDelay; +static const char *subsampLevel2str[TVNC_SAMPOPT] = { + "1X", "4X", "2X", "Gray" +}; +#ifdef TURBOVNC +#define rfbTightNoZlib 0x0A +#define rfbTurboVncVendor "TRBO" +#define rfbJpegQualityLevel1 0xFFFFFE01 +#define rfbJpegQualityLevel100 0xFFFFFE64 +#define rfbJpegSubsamp1X 0xFFFFFD00 +#define rfbJpegSubsamp4X 0xFFFFFD01 +#define rfbJpegSubsamp2X 0xFFFFFD02 +#define rfbJpegSubsampGray 0xFFFFFD03 +#endif - Bool debug; +/* for debugging width, height, etc */ +//#define XtVaSetValues printf("%s:%d\n", __FILE__, __LINE__); XtVaSetValues - int popupButtonCount; - int bumpScrollTime; - int bumpScrollPixels; +/* argsresources.c */ - int compressLevel; - int qualityLevel; - Bool enableJPEG; - Bool useRemoteCursor; - Bool useX11Cursor; - Bool autoPass; +typedef struct { + Bool shareDesktop; + Bool viewOnly; + Bool fullScreen; + Bool grabKeyboard; + Bool raiseOnBeep; + + String encodingsString; + + int useBGR233; + int nColours; + Bool useSharedColours; + Bool forceOwnCmap; + Bool forceTrueColour; + int requestedDepth; + Bool useBGR565; + Bool useGreyScale; + + Bool grabAll; + Bool useXserverBackingStore; + Bool overrideRedir; + Bool popupFix; + + Bool useShm; + Bool termChat; + + int wmDecorationWidth; + int wmDecorationHeight; + + char *userLogin; + char *unixPW; + char *msLogon; + char *repeaterUltra; + Bool ultraDSM; + Bool acceptPopup; + char *rfbVersion; + + char *passwordFile; + Bool passwordDialog; + Bool notty; + + int rawDelay; + int copyRectDelay; + + int yCrop; + int sbWidth; + Bool useCursorAlpha; + Bool useRawLocal; + + Bool debug; + + int popupButtonCount; + int popupButtonBreak; + + int bumpScrollTime; + int bumpScrollPixels; + + int compressLevel; + int qualityLevel; + Bool enableJPEG; + Bool useRemoteCursor; + Bool useX11Cursor; + Bool useBell; + Bool autoPass; + + Bool serverInput; + Bool singleWindow; + int serverScale; + Bool chatActive; + Bool chatOnly; + Bool fileActive; + + char *scale; + char *escapeKeys; + Bool appShare; + Bool escapeActive; + Bool pipelineUpdates; + + Bool sendClipboard; + Bool sendAlways; + char *recvText; + + /* only for turbovnc mode */ + String subsampString; + int subsampLevel; + Bool doubleBuffer; } AppData; extern AppData appData; +extern AppData appDataNew; extern char *fallback_resources[]; extern char vncServerHost[]; extern int vncServerPort; extern Bool listenSpecified; +extern pid_t listenParent; extern int listenPort, flashPort; extern XrmOptionDescRec cmdLineOptions[]; @@ -130,10 +203,11 @@ /* colour.c */ extern unsigned long BGR233ToPixel[]; +extern unsigned long BGR565ToPixel[]; extern Colormap cmap; extern Visual *vis; -extern unsigned int visdepth, visbpp; +extern unsigned int visdepth, visbpp, isLSB; extern void SetVisualAndCmap(); @@ -155,15 +229,60 @@ extern GC srcGC, dstGC; extern Dimension dpyWidth, dpyHeight; +extern int appshare_0_hint; +extern int appshare_x_hint; +extern int appshare_y_hint; + extern void DesktopInitBeforeRealization(); extern void DesktopInitAfterRealization(); +extern void Xcursors(int set); extern void SendRFBEvent(Widget w, XEvent *event, String *params, Cardinal *num_params); extern void CopyDataToScreen(char *buf, int x, int y, int width, int height); +extern void FillScreen(int x, int y, int width, int height, unsigned long fill); extern void SynchroniseScreen(); +extern void ReDoDesktop(); +extern void DesktopCursorOff(); +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 int use_tty(void); + +extern void ScaleDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoScaleDialog(); + +extern void EscapeDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoEscapeKeysDialog(); + +extern void YCropDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoYCropDialog(); + +extern void ScbarDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoScbarDialog(); + +extern void ScaleNDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoScaleNDialog(); + +extern void QualityDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoQualityDialog(); + +extern void CompressDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoCompressDialog(); + extern void ServerDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params); extern char *DoServerDialog(); @@ -171,6 +290,10 @@ Cardinal *num_params); extern char *DoPasswordDialog(); +extern void UserDialogDone(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern char *DoUserDialog(); + /* fullscreen.c */ extern void ToggleFullScreen(Widget w, XEvent *event, String *params, @@ -181,6 +304,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); +extern void JumpDown(Widget w, XEvent *event, String *params, Cardinal *num_params); + /* listen.c */ extern void listenForIncomingConnections(); @@ -196,6 +326,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 +339,29 @@ Cardinal *num_params); extern void CreatePopup(); +extern void HideScaleN(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern void CreateScaleN(); + +extern void HideTurboVNC(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern void CreateTurboVNC(); +extern void UpdateSubsampButtons(); +extern void UpdateQualSlider(); +extern void UpdateQual(); + +extern void HideQuality(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern void CreateQuality(); + +extern void HideCompress(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern void CreateCompress(); + +extern void Noop(Widget w, XEvent *event, String *params, + Cardinal *num_params); + +extern int CreateMsg(char *msg, int wait); /* rfbproto.c */ extern int rfbsock; @@ -229,8 +384,19 @@ extern Bool SendClientCutText(char *str, int len); extern Bool HandleRFBServerMessage(); +extern Bool SendServerInput(Bool enabled); +extern Bool SendSingleWindow(int x, int y); +extern Bool SendServerScale(int n); + +extern Bool SendTextChat(char *str); +extern Bool SendTextChatOpen(void); +extern Bool SendTextChatClose(void); +extern Bool SendTextChatFinish(void); + extern void PrintPixelFormat(rfbPixelFormat *format); +extern double dnow(void); + /* selection.c */ extern void InitialiseSelection(); @@ -241,8 +407,10 @@ /* shm.c */ -extern XImage *CreateShmImage(); +extern XImage *CreateShmImage(int do_ycrop); extern void ShmCleanup(); +extern void ShmDetach(); +extern Bool UsingShm(); /* sockets.c */ @@ -253,10 +421,15 @@ extern int FindFreeTcpPort(void); extern int ListenAtTcpPort(int port); extern int ConnectToTcpAddr(unsigned int host, int port); +extern int ConnectToUnixSocket(char *file); extern int AcceptTcpConnection(int listenSock); extern Bool SetNonBlocking(int sock); +extern Bool SetNoDelay(int sock); +extern Bool SocketPair(int fd[2]); extern int StringToIPAddr(const char *str, unsigned int *addr); +extern char *get_peer_ip(int sock); +extern char *ip2host(char *ip); extern Bool SameMachine(int sock); /* tunnel.c */ @@ -271,3 +444,82 @@ extern XtAppContext appContext; extern Display* dpy; extern Widget toplevel; + +extern void GotChatText(char *str, int len); +extern void unixpw(char *instr, int vencrypt_plain); + +extern void Toggle8bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Toggle16bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleFullColor(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Toggle256Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Toggle64Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Toggle8Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleGreyScale(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleTightZRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleTightHextile(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleZRLEZYWRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleViewOnly(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleJPEG(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleCursorShape(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleCursorAlpha(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleX11Cursor(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleBell(Widget w, XEvent *ev, String *params, Cardinal *num_params); +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 TogglePipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleSendAlways(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 ToggleEscapeActive(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetEscapeKeys(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); +extern void ShowTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ShowQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ShowCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleTextChat(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleFileXfer(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void ToggleTermTextChat(Widget w, XEvent *ev, String *params, Cardinal *num_params); + +extern void scale_check_zrle(void); + +extern void SetViewOnlyState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetNOJPEGState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetScaleNState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetQualityState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetCompressState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Set8bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Set16bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetFullColorState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Set256ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Set64ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void Set8ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetGreyScaleState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetZRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetHextileState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetZYWRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetCursorShapeState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetCursorAlphaState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetX11CursorState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetBellState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetRawLocalState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetServerInputState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetPipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params); +extern void SetSingleWindowState(Widget w, XEvent *ev, String *params, Cardinal *num_params); +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); +extern void SetEscapeKeysState(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 2009-11-25 00:03:28.000000000 -0500 @@ -5,38 +5,55 @@ .\" Copyright (C) 1998 Marcus.Brinkmann@ruhr-uni-bochum.de .\" Copyright (C) 2000,2001 Red Hat, Inc. .\" Copyright (C) 2001-2003 Constantin Kaplinsky +.\" Copyright (C) 2006-2009 Karl J. Runge .\" .\" You may distribute under the terms of the GNU General Public .\" License as specified in the file LICENCE.TXT that comes with the .\" TightVNC distribution. .\" -.TH vncviewer 1 "January 2003" "" "TightVNC" +.TH ssvncviewer 1 "September 2009" "" "SSVNC" .SH NAME -vncviewer \- an X viewer client for VNC +ssvncviewer \- an X viewer client for VNC .SH SYNOPSIS -.B vncviewer +.B ssvncviewer .RI [\| options \|] .RI [\| host \|][\| :display \|] .br -.B vncviewer +.B ssvncviewer .RI [\| options \|] .RI [\| host \|][\| ::port \|] .br -.B vncviewer +.B ssvncviewer +.RI [\| options \|] +.RI exec=[\| cmd+args... \|] +.br +.B ssvncviewer +.RI [\| options \|] +.RI fd=n +.br +.B ssvncviewer +.RI [\| options \|] +.RI /path/to/unix/socket +.br +.B ssvncviewer .RI [\| options \|] .IR \-listen .RI [\| display \|] .br -.B vncviewer +.B ssvncviewer .IR \-help .br .SH DESCRIPTION -.B vncviewer +.B ssvncviewer is an Xt\-based client application for the VNC (Virtual Network Computing) system. It can connect to any VNC\-compatible server such -as \fBXvnc\fR or WinVNC, allowing you to control desktop environment +as \fBXvnc\fR, WinVNC, or \fBx11vnc\fR, allowing you to control desktop environment of a different machine. +ssvncviewer is an enhanced version of the tightvnc unix viewer that can +take advantage of features in the \fBx11vnc\fR and UltraVNC VNC servers. +See below for the description of these features. + You can use F8 to display a pop\-up utility menu. Press F8 twice to pass single F8 to the remote side. .SH OPTIONS @@ -102,13 +119,13 @@ TightVNC supports several different compression methods to encode screen updates; this option specifies a set of them to use in order of preference. Encodings are specified separated with spaces, and must -thus be enclosed in quotes if more than one is specified. Available -encodings, in default order for a remote connection, are "copyrect -tight hextile zlib corre rre raw". For a local connection (to the same -machine), the default order to try is "raw copyrect tight hextile zlib -corre rre". Raw encoding is always assumed as a last option if no -other encoding can be used for some reason. For more information on -encodings, see the section ENCODINGS below. +thus be enclosed in quotes if more than one is specified. Commas may be used to avoid spaces. +Available encodings, in default order for a remote connection, are +"copyrect tight hextile zlib corre rre raw". For a local connection +(to the same machine), the default order to try is "raw copyrect tight +hextile zlib corre rre". Raw encoding is always assumed as a last option +if no other encoding can be used for some reason. For more information +on encodings, see the section ENCODINGS below. .TP \fB\-bgr233\fR Always use the BGR233 format to encode pixel data. This reduces @@ -168,6 +185,418 @@ \fB\-autopass\fR Read a plain-text password from stdin. This option affects only the standard VNC authentication. + +.SH Enhanced TightVNC Viewer (SSVNC) OPTIONS +.TP +Enhanced TightVNC Viewer (SSVNC) web page is located at: +.TP +http://www.karlrunge.com/x11vnc/ssvnc.html +.TP +Note: ZRLE and ZYWRLE encodings are now supported. +.TP +Note: F9 is shortcut to Toggle FullScreen mode. +.TP +Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1 +to allow more than one incoming VNC server at a time. +This is the same as -multilisten described below. Set +SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than "n" +simultaneous reverse connections. + +If the host:port is specified as "exec=command args..." +then instead of making a TCP/IP socket connection to the +remote VNC server, "command args..." is executed and the +viewer is attached to its stdio. This enables tunnelling +established via an external command, e.g. an stunnel(8) +that does not involve a listening socket. +This mode does not work for -listen reverse connections. + +If the host:port is specified as "fd=n" then it is assumed +n is an already opened file descriptor to the socket. (i.e +the parent did fork+exec) + +If the host:port contains a '/' it is interpreted as a +unix-domain socket (AF_LOCAL insead of AF_INET) +.TP +\fB\-multilisten\fR +As in -listen (reverse connection listening) except +allow more than one incoming VNC server to be connected +at a time. The default for -listen of only one at a +time tries to play it safe by not allowing anyone on +the network to put (many) desktops on your screen over +a long window of time. Use -multilisten for no limit. +.TP +\fB\-acceptpopup\fR +In \fB\-listen\fR (reverse connection listening) mode when +a reverse VNC connection comes in show a popup asking +whether to Accept or Reject the connection. The IP +address of the connecting host is shown. Same as +setting the env. var. SSVNC_ACCEPT_POPUP=1. +.TP +\fB\-acceptpopupsc\fR +As in \fB\-acceptpopup\fR except assume UltraVNC Single +Click (SC) server. Retrieve User and ComputerName +info from UltraVNC Server and display in the Popup. +.TP +\fB\-use64\fR +In \fB\-bgr233\fR mode, use 64 colors instead of 256. +.TP +\fB\-bgr222\fR +Same as \fB\-use64\fR. +.TP +\fB\-use8\fR +In \fB\-bgr233\fR mode, use 8 colors instead of 256. +.TP +\fB\-bgr111\fR +Same as \fB\-use8\fR. +.TP +\fB\-16bpp\fR +If the vnc viewer X display is depth 24 at 32bpp +request a 16bpp format from the VNC server to cut +network traffic by up to 2X, then tranlate the +pixels to 32bpp locally. +.TP +\fB\-bgr565\fR +Same as \fB\-16bpp\fR. +.TP +\fB\-grey\fR +Use a grey scale for the 16- and 8\fB\-bpp\fR modes. +.TP +\fB\-alpha\fR +Use alphablending transparency for local cursors +requires: x11vnc server, both client and server +must be 32bpp and same endianness. +.TP +\fB\-scale\fR \fIstr\fR +Scale the desktop locally. The string "str" can +a floating point ratio, e.g. "0.9", or a fraction, +e.g. "3/4", or WxH, e.g. 1280x1024. Use "fit" +to fit in the current screen size. Use "auto" to +fit in the window size. "str" can also be set by +the env. var. SSVNC_SCALE. + +If you observe mouse trail painting errors, enable +X11 Cursor mode (either via Popup or \fB\-x11cursor\fR.) + +Note that scaling is done in software and so can be +slow and requires more memory. Some speedup Tips: + +ZRLE is faster than Tight in this mode. When +scaling is first detected, the encoding will +be automatically switched to ZRLE. Use the +Popup menu if you want to go back to Tight. +Set SSVNC_PRESERVE_ENCODING=1 to disable this. + +Use a solid background on the remote side. +(e.g. manually or via x11vnc \fB\-solid\fR ...) + +If the remote server is x11vnc, try client +side caching: x11vnc \fB\-ncache\fR 10 ... +.TP +\fB\-ycrop\fR n +Only show the top n rows of the framebuffer. For +use with x11vnc \fB\-ncache\fR client caching option +to help "hide" the pixel cache region. +Use a negative value (e.g. \fB\-1\fR) for autodetection. +Autodetection will always take place if the remote +fb height is more than 2 times the width. +.TP +\fB\-sbwidth\fR n +Scrollbar width for x11vnc \fB\-ncache\fR mode (\fB\-ycrop\fR), +default is very narrow: 2 pixels, it is narrow to +avoid distraction in \fB\-ycrop\fR mode. +.TP +\fB\-nobell\fR +Disable bell. +.TP +\fB\-rawlocal\fR +Prefer raw encoding for localhost, default is +no, i.e. assumes you have a SSH tunnel instead. +.TP +\fB\-notty\fR +Try to avoid using the terminal for interactive +responses: use windows for messages and prompting +instead. Messages will also be printed to terminal. +.TP +\fB\-sendclipboard\fR +Send the X CLIPBOARD selection (i.e. Ctrl+C, +Ctrl+V) instead of the X PRIMARY selection (mouse +select and middle button paste.) +.TP +\fB\-sendalways\fR +Whenever the mouse enters the VNC viewer main +window, send the selection to the VNC server even if +it has not changed. This is like the Xt resource +translation SelectionToVNC(always) +.TP +\fB\-recvtext\fR +str When cut text is received from the VNC server, +ssvncviewer will set both the X PRIMARY and the +X CLIPBOARD local selections. To control which +is set, specify 'str' as 'primary', 'clipboard', +or 'both' (the default.) +.TP +\fB\-graball\fR +Grab the entire X server when in fullscreen mode, +needed by some old window managers like fvwm2. +.TP +\fB\-popupfix\fR +Warp the popup back to the pointer position, +needed by some old window managers like fvwm2. +.TP +\fB\-grabkbd\fR +Grab the X keyboard when in fullscreen mode, +needed by some window managers. Same as \fB\-grabkeyboard\fR. +\fB\-grabkbd\fR is the default, use \fB\-nograbkbd\fR to disable. +.TP +\fB\-bs\fR, \fB\-nobs\fR +Whether or not to use X server Backingstore for the +main viewer window. The default is to not, mainly +because most Linux, etc, systems X servers disable +*all* Backingstore by default. To re\fB\-enable\fR it put + +Option "Backingstore" + +in the Device section of /etc/X11/xorg.conf. +In \fB\-bs\fR mode with no X server backingstore, whenever an +area of the screen is re\fB\-exposed\fR it must go out to the +VNC server to retrieve the pixels. This is too slow. + +In \fB\-nobs\fR mode, memory is allocated by the viewer to +provide its own backing of the main viewer window. This +actually makes some activities faster (changes in large +regions) but can appear to "flash" too much. +.TP +\fB\-noshm\fR +Disable use of MIT shared memory extension (not recommended) +.TP +\fB\-termchat\fR +Do the UltraVNC chat in the terminal vncviewer is in +instead of in an independent window. +.TP +\fB\-unixpw\fR \fIstr\fR +Useful for logging into x11vnc in \fB\-unixpw\fR mode. "str" is a +string that allows many ways to enter the Unix Username +and Unix Password. These characters: username, newline, +password, newline are sent to the VNC server after any VNC +authentication has taken place. Under x11vnc they are +used for the \fB\-unixpw\fR login. Other VNC servers could do +something similar. + +You can also indicate "str" via the environment +variable SSVNC_UNIXPW. + +Note that the Escape key is actually sent first to tell +x11vnc to not echo the Unix Username back to the VNC +viewer. Set SSVNC_UNIXPW_NOESC=1 to override this. + +If str is ".", then you are prompted at the command line +for the username and password in the normal way. If str is +"-" the stdin is read via getpass(3) for username@password. +Otherwise if str is a file, it is opened and the first line +read is taken as the Unix username and the 2nd as the +password. If str prefixed by "rm:" the file is removed +after reading. Otherwise, if str has a "@" character, +it is taken as username@password. Otherwise, the program +exits with an error. Got all that? +.TP +\fB-repeater\fR \fIstr\fR +This is for use with UltraVNC repeater proxy described +here: http://www.uvnc.com/addons/repeater.html. The "str" +is the ID string to be sent to the repeater. E.g. ID:1234 +It can also be the hostname and port or display of the VNC +server, e.g. 12.34.56.78:0 or snoopy.com:1. Note that when +using -repeater, the host:dpy on the cmdline is the repeater +server, NOT the VNC server. The repeater will connect you. + +Example: vncviewer ... -repeater ID:3333 repeat.host:5900 + +Example: vncviewer ... -repeater vhost:0 repeat.host:5900 + +Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a +Single Click III (SSL) repeater (repeater_SSL.exe) and you +are passing the SSL part of the connection through stunnel, socat, etc. +This way the magic UltraVNC string 'testB' needed to work with the +repeater is sent to it. +.TP +\fB-rfbversion\fR \fIstr\fR +Set the advertised RFB version. E.g.: -rfbversion 3.6 For some +servers, e.g. UltraVNC this needs to be done. +.TP +\fB-ultradsm\fR +UltraVNC has symmetric private encryption DSM plugins. See +http://www.uvnc.com/features/encryption.html. It is assumed +you are using a unix program (e.g. our ultravnc_dsm_helper) to +encrypt and decrypt the UltraVNC DSM stream. IN ADDITION TO +THAT supply -ultradsm to tell THIS viewer to modify the RFB +data sent so as to work with the UltraVNC Server. For some +reason, each RFB msg type must be sent twice under DSM. +.TP +\fB\-mslogon\fR \fIuser\fR +Use Windows MS Logon to an UltraVNC server. Supply the +username or "1" to be prompted. The default is to +autodetect the UltraVNC MS Logon server and prompt for +the username and password. + +IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman +exchange is very weak and can be brute forced to recover +your username and password in a few seconds of CPU +time. To be safe, be sure to use an additional encrypted +tunnel (e.g. SSL or SSH) for the entire VNC session. +.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, +-env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi +.TP +\fB\-printres\fR +Print out the Ssvnc X resources (appdefaults) and +then exit. You can save them to a file and customize them (e.g. the +keybindings and Popup menu) Then point to the file via +XENVIRONMENT or XAPPLRESDIR. +.TP +\fB\-pipeline\fR +Like TurboVNC, request the next framebuffer update as soon +as possible instead of waiting until the end of the current +framebuffer update coming in. Helps 'pipeline' the updates. +This is currently the default, use \fB-nopipeline\fR to disable. +.TP +\fB\-appshare\fR +Enable features for use with x11vnc's \fB\-appshare\fR mode where +instead of sharing the full desktop only the application's +windows are shared. Viewer multilisten mode is used to +create the multiple windows: \fB\-multilisten\fR is implied. +See 'x11vnc \fB\-appshare\fR \fB\-help\fR' more information on the mode. +Features enabled in the viewer under \fB\-appshare\fR are: +Minimum extra text in the title, auto \fB\-ycrop\fR is disabled, +x11vnc \fB\-remote_prefix\fR X11VNC_APPSHARE_CMD: message channel, +x11vnc initial window position hints. See also Escape Keys +below for additional key and mouse bindings. +.TP +\fB\-escape \fR\fIstr\fR +This sets the 'Escape Keys' modifier sequence and enables +escape keys mode. When the modifier keys escape sequence +is held down, the next keystroke is interpreted locally +to perform a special action instead of being sent to the +remote VNC server. + +Use '\fB\-escape\fR default' for the default modifier sequence. +(Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L) + +Here are the 'Escape Keys: Help+Set' instructions from the Popup: + +Escape Keys: Enter a comma separated list of modifier keys to be the 'escape +sequence'. When these keys are held down, the next keystroke is +interpreted locally to invoke a special action instead of being sent to +the remote VNC server. In other words, a set of 'Hot Keys'. + +Here is the list of local key mappings to special actions: + +r: refresh desktop b: toggle bell c: toggle full-color + +f: file transfer x: x11cursor z: toggle Tight/ZRLE + +l: full screen g: graball e: escape keys dialog + +s: scale dialog +: scale up (=) -: scale down (_) + +t: text chat a: alphablend cursor + +V: toggle viewonly Q: quit viewer 123456: UltraVNC scale 1/n + +Arrow keys: pan the viewport about 10% for each keypress. + +PageUp/PageDown: pan the viewport by a screenful vertically. + +Home/End: pan the viewport by a screenful horizontally. + +KeyPad Arrows: pan the viewport by 1 pixel for each keypress. + +Dragging the Mouse with Button1 pressed also pans the viewport. + +Clicking Mouse Button3 brings up the Popup Menu. + +The above mappings are \fBalways\fR active in ViewOnly mode, unless you set +the Escape Keys value to 'never'. + +x11vnc -appshare hot-keys: x11vnc has a simple application sharing mode +that enables the viewer-side to move, resize, or raise the remote toplevel +windows. To enable it, hold down Shift + the Escape Keys and press these: + +Arrow keys: move the remote window around in its desktop. + +PageUp/PageDn/Home/End: resize the remote window. + ++/-: raise or lower the remote window. + +M or Button1 move win to local position; D or Button3: delete remote win. + +If the Escape Keys value below is set to 'default' then a default list of +of modifier keys is used. For Unix it is: Alt_L,Super_L and for MacOSX it +is Control_L,Meta_L. Note: the Super_L key usually has a Windows(TM) Flag +on it. Also note the _L and _R mean the key is on the LEFT or RIGHT side +of the keyboard. + +On Unix the default is Alt and Windows keys on Left side of keyboard. +On MacOSX the default is Control and Command keys on Left side of keyboard. + +Example: Press and hold the Alt and Windows keys on the LEFT side of the +keyboard and then press 'c' to toggle the full-color state. Or press 't' +to toggle the ultravnc Text Chat window, etc. + +To use something besides the default, supply a comma separated list (or a +single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L +Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch. +.TP +\fB New Popup actions:\fR + + ViewOnly: ~ -viewonly + Disable Bell: ~ -nobell + Cursor Shape: ~ -nocursorshape + X11 Cursor: ~ -x11cursor + Cursor Alphablend: ~ -alpha + Toggle Tight/Hextile: ~ -encodings hextile... + Toggle Tight/ZRLE: ~ -encodings zrle... + Toggle ZRLE/ZYWRLE: ~ -encodings zywrle... + Quality Level ~ -quality (both Tight and ZYWRLE) + Compress Level ~ -compresslevel + Disable JPEG: ~ -nojpeg (Tight) + Pipeline Updates ~ -pipeline + + Full Color as many colors as local screen allows. + Grey scale (16 & 8-bpp) ~ -grey, for low colors 16/8bpp modes only. + 16 bit color (BGR565) ~ -16bpp / -bgr565 + 8 bit color (BGR233) ~ -bgr233 + 256 colors ~ -bgr233 default # of colors. + 64 colors ~ -bgr222 / -use64 + 8 colors ~ -bgr111 / -use8 + Scale Viewer ~ -scale + Escape Keys: Toggle ~ -escape + Escape Keys: Help+Set ~ -escape + Set Y Crop (y-max) ~ -ycrop + Set Scrollbar Width ~ -sbwidth + XGrabServer ~ -graball + + UltraVNC Extensions: + + Set 1/n Server Scale Ultravnc ext. Scale desktop by 1/n. + Text Chat Ultravnc ext. Do Text Chat. + File Transfer Ultravnc ext. File xfer via Java helper. + Single Window Ultravnc ext. Grab and view a single window. + (select then click on the window you want). + Disable Remote Input Ultravnc ext. Try to prevent input and + viewing of monitor at physical display. + + Note: the Ultravnc extensions only apply to servers that support + them. x11vnc/libvncserver supports some of them. + + Send Clipboard not Primary ~ -sendclipboard + Send Selection Every time ~ -sendalways + .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 +667,15 @@ \-quality and \-nojpeg options above). Tight encoding is usually the best choice for low\-bandwidth network environments (e.g. slow modem connections). +.TP +.B ZRLE +The SSVNC viewer has ported the RealVNC (www.realvnc.com) ZRLE encoding +to the unix tightvnc viewer. +.TP +.B ZYWRLE +The SSVNC viewer has ported the Hitachi lossy wavelet based ZRLE +encoding from http://mobile.hitachi-system.co.jp/publications/ZYWRLE/ +to the unix tightvnc viewer. .SH RESOURCES X resources that \fBvncviewer\fR knows about, aside from the normal Xt resources, are as follows: @@ -364,12 +802,13 @@ .B %R remote TCP port number. .SH SEE ALSO -\fBvncserver\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1), -\fBvncconnect\fR(1), \fBssh\fR(1) +\fBvncserver\fR(1), \fBx11vnc\fR(1), \fBssvnc\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1), +\fBvncconnect\fR(1), \fBssh\fR(1), http://www.karlrunge.com/x11vnc, http://www.karlrunge.com/x11vnc/ssvnc.html .SH AUTHORS Original VNC was developed in AT&T Laboratories Cambridge. TightVNC additions was implemented by Constantin Kaplinsky. Many other people -participated in development, testing and support. +participated in development, testing and support. Karl J. Runge +added all of the SSVNC related features and improvements. \fBMan page authors:\fR .br @@ -380,3 +819,5 @@ Tim Waugh , .br Constantin Kaplinsky +.br +Karl J. Runge 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 2009-11-19 23:34:28.000000000 -0500 @@ -0,0 +1,620 @@ +/* + * Copyright (C) 2005 Johannes E. Schindelin. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* + * zrle.c - handle zrle encoding. + * + * This file shouldn't be compiled directly. It is included multiple times by + * rfbproto.c, each time with a different definition of the macro BPP. For + * each value of BPP, this file defines a function which handles an zrle + * encoded rectangle with BPP bits per pixel. + */ + +#ifndef REALBPP +#define REALBPP BPP +#endif + +#if !defined(UNCOMP) || UNCOMP==0 +#define HandleZRLE CONCAT2E(HandleZRLE,REALBPP) +#define HandleZRLETile CONCAT2E(HandleZRLETile,REALBPP) +#elif UNCOMP>0 +#define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Down) +#define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Down) +#else +#define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Up) +#define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Up) +#endif +#undef CARDBPP +#undef CARDREALBPP +#define CARDBPP CONCAT2E(CARD, BPP) +#define CARDREALBPP CONCAT2E(CARD,REALBPP) + +#define FillRectangle(x, y, w, h, color) \ + { \ + XGCValues _gcv; \ + _gcv.foreground = color; \ + if (!appData.useXserverBackingStore) { \ + FillScreen(x, y, w, h, _gcv.foreground); \ + } else { \ + XChangeGC(dpy, gc, GCForeground, &_gcv); \ + XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \ + } \ + } + +#if defined(__sparc) || defined(__sparc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) +#define IS_BIG_ENDIAN 1 +#else +#define IS_BIG_ENDIAN 0 +#endif + +#if DO_ZYWRLE + +#define ENDIAN_LITTLE 0 +#define ENDIAN_BIG 1 +#define ENDIAN_NO 2 +#if IS_BIG_ENDIAN +#define ZYWRLE_ENDIAN ENDIAN_BIG +#else +#define ZYWRLE_ENDIAN ENDIAN_LITTLE +#endif +#undef END_FIX +#if ZYWRLE_ENDIAN == ENDIAN_LITTLE +# define END_FIX LE +#elif ZYWRLE_ENDIAN == ENDIAN_BIG +# define END_FIX BE +#else +# define END_FIX NE +#endif +#define __RFB_CONCAT3E(a,b,c) CONCAT3E(a,b,c) +#define __RFB_CONCAT2E(a,b) CONCAT2E(a,b) +#undef CPIXEL +#if REALBPP != BPP +#if UNCOMP == 0 +#define CPIXEL REALBPP +#elif UNCOMP>0 +#define CPIXEL CONCAT2E(REALBPP,Down) +#else +#define CPIXEL CONCAT2E(REALBPP,Up) +#endif +#endif +#define PIXEL_T CARDBPP +#if BPP!=8 +#define ZYWRLE_DECODE 1 +#include "zywrletemplate.c" +#endif +#undef CPIXEL + +#endif /* DO_ZYWRLE */ + +static int HandleZRLETile( + unsigned char* buffer,size_t buffer_length, + int x,int y,int w,int h); + +static Bool +HandleZRLE (int rx, int ry, int rw, int rh) +{ + rfbZRLEHeader header; + int remaining; + int inflateResult; + int toRead; + int min_buffer_size = rw * rh * (REALBPP / 8) * 2; + + /* First make sure we have a large enough raw buffer to hold the + * decompressed data. In practice, with a fixed REALBPP, fixed frame + * buffer size and the first update containing the entire frame + * buffer, this buffer allocation should only happen once, on the + * first update. + */ + if ( raw_buffer_size < min_buffer_size) { + + if ( raw_buffer != NULL ) { + + free( raw_buffer ); + + } + + raw_buffer_size = min_buffer_size; + raw_buffer = (char*) malloc( raw_buffer_size ); + + } + + if (!ReadFromRFBServer((char *)&header, sz_rfbZRLEHeader)) + return False; + + remaining = Swap32IfLE(header.length); + + /* Need to initialize the decompressor state. */ + decompStream.next_in = ( Bytef * )buffer; + decompStream.avail_in = 0; + decompStream.next_out = ( Bytef * )raw_buffer; + decompStream.avail_out = raw_buffer_size; + decompStream.data_type = Z_BINARY; + + /* Initialize the decompression stream structures on the first invocation. */ + if ( decompStreamInited == False ) { + + inflateResult = inflateInit( &decompStream ); + + if ( inflateResult != Z_OK ) { + fprintf(stderr, + "inflateInit returned error: %d, msg: %s\n", + inflateResult, + decompStream.msg); + return False; + } + + decompStreamInited = True; + + } + + inflateResult = Z_OK; + + /* Process buffer full of data until no more to process, or + * some type of inflater error, or Z_STREAM_END. + */ + while (( remaining > 0 ) && + ( inflateResult == Z_OK )) { + + if ( remaining > BUFFER_SIZE ) { + toRead = BUFFER_SIZE; + } + else { + toRead = remaining; + } + + /* Fill the buffer, obtaining data from the server. */ + if (!ReadFromRFBServer(buffer,toRead)) + return False; + + decompStream.next_in = ( Bytef * )buffer; + decompStream.avail_in = toRead; + + /* Need to uncompress buffer full. */ + inflateResult = inflate( &decompStream, Z_SYNC_FLUSH ); + + /* We never supply a dictionary for compression. */ + if ( inflateResult == Z_NEED_DICT ) { + fprintf(stderr, "zlib inflate needs a dictionary!\n"); + return False; + } + if ( inflateResult < 0 ) { + fprintf(stderr, + "zlib inflate returned error: %d, msg: %s\n", + inflateResult, + decompStream.msg); + return False; + } + + /* Result buffer allocated to be at least large enough. We should + * never run out of space! + */ + if (( decompStream.avail_in > 0 ) && + ( decompStream.avail_out <= 0 )) { + fprintf(stderr, "zlib inflate ran out of space!\n"); + return False; + } + + remaining -= toRead; + + } /* while ( remaining > 0 ) */ + + if ( inflateResult == Z_OK ) { + void* buf=raw_buffer; + int i,j; + + remaining = raw_buffer_size-decompStream.avail_out; + + for(j=0; jrw)?rw-i:rfbZRLETileWidth; + int subHeight=(j+rfbZRLETileHeight>rh)?rh-j:rfbZRLETileHeight; + int result=HandleZRLETile(buf,remaining,rx+i,ry+j,subWidth,subHeight); + + if(result<0) { + fprintf(stderr, "ZRLE decoding failed (%d)\n",result); +return True; + return False; + } + + buf+=result; + remaining-=result; + } + } + else { + + fprintf(stderr, + "zlib inflate returned error: %d, msg: %s\n", + inflateResult, + decompStream.msg); + return False; + + } + + return True; +} + +#if REALBPP!=BPP && defined(UNCOMP) && UNCOMP!=0 +# if BPP == 32 && IS_BIG_ENDIAN +# define UncompressCPixel(p) ( (*p << myFormat.redShift) | (*(p+1) << myFormat.greenShift) | (*(p+2) << myFormat.blueShift) ) +# else +# if UNCOMP>0 +# define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)>>UNCOMP) +# else +# define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)<<(-(UNCOMP))) +# endif +# endif +#else +# define UncompressCPixel(pointer) (*(CARDBPP*)pointer) +#endif + +extern XImage *image; +extern XImage *image_scale; +extern int skip_maybe_sync; + +static int HandleZRLETile( + unsigned char* buffer,size_t buffer_length, + int x,int y,int w,int h) { + unsigned char* buffer_copy = buffer; + unsigned char* buffer_end = buffer+buffer_length; + unsigned char type; + + if(buffer_length<1) + return -2; + + if (frameBufferLen < w * h * BPP/8) { + if(frameBuffer) { + free(frameBuffer); + } + frameBufferLen = w * h * BPP/8 * 2; + frameBuffer = (unsigned char *) malloc(frameBufferLen); + } + +zywrle_top: + type = *buffer; + buffer++; + switch(type) { + case 0: /* raw */ + { +#if DO_ZYWRLE && BPP != 8 + if (zywrle_level > 0 && !(zywrle_level & 0x80) ) { + zywrle_level |= 0x80; + goto zywrle_top; + } else +#endif + { +#if REALBPP!=BPP + int m0 = 0, i,j; + + + if(1+w*h*REALBPP/8>buffer_length) { + fprintf(stderr, "expected %d bytes, got only %d (%dx%d)\n",1+w*h*REALBPP/8,buffer_length,w,h); + return -3; + } + + for(j=y*si.framebufferWidth; j<(y+h)*si.framebufferWidth; j+=si.framebufferWidth) { + for(i=x; ibuffer_length) + return -4; + + if ((BPP == 8 && appData.useBGR233) || (BPP == 16 && appData.useBGR565)) { + int m0; + for (m0=0; m0 < w*h; m0++) { + ((CARDBPP*)frameBuffer)[m0] = color; + } + CopyDataToScreen((char *)frameBuffer, x, y, w, h); + } else { + FillRectangle(x, y, w, h, color); + } +if (0) fprintf(stderr, "cha2: %dx%d+%d+%d\n", w, h, x, y); + + buffer+=REALBPP/8; + + break; + } + case 2 ... 127: /* packed Palette */ + { + CARDBPP palette[16]; + int m0, i,j,shift, + bpp=(type>4?(type>16?8:4):(type>2?2:1)), + mask=(1<buffer_length) + return -5; + + /* read palette */ + for(i=0; i>shift)&mask]; + /* alt */ + CARDBPP color = palette[((*buffer)>>shift)&mask]; + CopyDataToScreen((char *)&color, i, j/si.framebufferWidth, 1, 1); +# else + ((CARDBPP*)frameBuffer)[m0++] = palette[((*buffer)>>shift)&mask]; +# endif + shift-=bpp; + if(shift<0) { + shift=8-bpp; + buffer++; + } + } + if(shift<8-bpp) + buffer++; + } + CopyDataToScreen((char *)frameBuffer, x, y, w, h); +if (0) fprintf(stderr, "cha3: %dx%d+%d+%d\n", w, h, x, y); + + break; + } + /* case 17 ... 127: not used, but valid */ + case 128: /* plain RLE */ + { + int m0=0, i=0,j=0; + while(jbuffer_end) + return -7; + color = UncompressCPixel(buffer); + buffer+=REALBPP/8; + /* read run length */ + length=1; + while(*buffer==0xff) { + if(buffer+1>=buffer_end) + return -8; + length+=*buffer; + buffer++; + } + length+=*buffer; + buffer++; + while(j0) { +# if 0 + ((CARDBPP*)frameBuffer)[(y+j)*si.framebufferWidth+x+i] = color; + /* alt */ + CopyDataToScreen((char *)&color, x+i, y+j, 1, 1); +# else + ((CARDBPP*)frameBuffer)[m0++] = color; +# endif + length--; + i++; + if(i>=w) { + i=0; + j++; + } + } + if(length>0) + fprintf(stderr, "Warning: possible ZRLE corruption\n"); + } + CopyDataToScreen((char *)frameBuffer, x, y, w, h); +if (0) fprintf(stderr, "cha4: %dx%d+%d+%d\n", w, h, x, y); + + break; + } + case 129: /* unused */ + { + return -8; + } + case 130 ... 255: /* palette RLE */ + { + CARDBPP palette[128]; + int m0 = 0, i,j; + + if(2+(type-128)*REALBPP/8>buffer_length) + return -9; + + /* read palette */ + for(i=0; i=buffer_end) + return -10; + color = palette[(*buffer)&0x7f]; + length=1; + if(*buffer&0x80) { + if(buffer+1>=buffer_end) + return -11; + buffer++; + /* read run length */ + while(*buffer==0xff) { + if(buffer+1>=buffer_end) + return -8; + length+=*buffer; + buffer++; + } + length+=*buffer; + } + buffer++; + while(j0) { +# if 0 + ((CARDBPP*)frameBuffer)[(y+j)*si.framebufferWidth+x+i] = color; + /* alt */ + CopyDataToScreen((char *)&color, x+i, y+j, 1, 1); +# else + ((CARDBPP*)frameBuffer)[m0++] = color; +# endif + length--; + i++; + if(i>=w) { + i=0; + j++; + } + } + if(length>0) + fprintf(stderr, "Warning: possible ZRLE corruption\n"); + } + CopyDataToScreen((char *)frameBuffer, x, y, w, h); +if (0) fprintf(stderr, "cha5: %dx%d+%d+%d\n", w, h, x, y); + + break; + } + } + +#if DO_ZYWRLE && BPP != 8 + if (zywrle_level & 0x80) { + int th, tx; + int widthInBytes = w * BPP / 8; + int scrWidthInBytes; + 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; + if (ptmp_len < rfbZRLETileWidth*rfbZRLETileHeight) { + ptmp_len = rfbZRLETileWidth*rfbZRLETileHeight; + } + if (ptmp) { + free(ptmp); + } + ptmp = (CARDBPP *) malloc(ptmp_len * sizeof(CARDBPP)); + } + + zywrle_level &= 0x7F; + // Reverse copy: screen to buf/ptmp: + // make this CopyDataFromScreen() or something. + if (!appData.useBGR565) { + scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8; + if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line; + scr = im->data + y * scrWidthInBytes + x * myFormat.bitsPerPixel / 8; + buf = (char *) ptmp; + + for (th = 0; th < h; th++) { + memcpy(buf, scr, widthInBytes); + buf += widthInBytes; + scr += scrWidthInBytes; + } + } else { + scrWidthInBytes = si.framebufferWidth * 4; + if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line; + scr = im->data + y * scrWidthInBytes + x * 4; + buf = (char *) ptmp; + + for (th = 0; th < h; th++) { + for (tx = 0; tx < w; tx++) { + unsigned long pix = *((unsigned int *)scr + tx); + unsigned int r1 = (pix & 0xff0000) >> 16; + unsigned int g1 = (pix & 0x00ff00) >> 8; + unsigned int b1 = (pix & 0x0000ff) >> 0; + int r2, g2, b2, idx; + int rok = 0, gok = 0, bok = 0, is0, sh = 10; + r2 = (31 * r1)/255; + g2 = (63 * g1)/255; + b2 = (31 * b1)/255; + for (is0 = 0; is0 < sh; is0++) { + int is, i, t; + for (i = 0; i < 2; i++) { + if (i == 0) { + is = -is0; + } else { + is = +is0; + } + if (!rok) { + t = r2 + is; + if (r1 == (255 * t)/31) { + r2 = t; rok = 1; + } + } + if (!gok) { + t = g2 + is; + if (g1 == (255 * t)/63) { + g2 = t; gok = 1; + } + } + if (!bok) { + t = b2 + is; + if (b1 == (255 * t)/31) { + b2 = t; bok = 1; + } + } + } + if (rok && gok && bok) { + break; + } + } + idx = (r2 << 11) | (g2 << 5) | (b2 << 0); + *((CARDBPP *)buf + tx) = (CARDBPP) idx; + } + buf += widthInBytes; + scr += scrWidthInBytes; + } + } + ZYWRLE_SYNTHESIZE((PIXEL_T *)ptmp, (PIXEL_T *)ptmp, w, h, w, zywrle_level, zywrleBuf ); + skip_maybe_sync = 1; + + if (appData.yCrop > 0) { + skip_maybe_sync = 0; + } + CopyDataToScreen((char *)ptmp, x, y, w, h); + + } +#endif + + return buffer-buffer_copy; +} + +#undef CARDBPP +#undef CARDREALBPP +#undef HandleZRLE +#undef HandleZRLETile +#undef UncompressCPixel +#undef REALBPP + +#undef UNCOMP + +#undef FillRectangle +#undef IS_BIG_ENDIAN diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrleencodetemplate.c vnc_unixsrc/vncviewer/zrleencodetemplate.c --- vnc_unixsrc.orig/vncviewer/zrleencodetemplate.c 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/zrleencodetemplate.c 2007-02-04 23:18:09.000000000 -0500 @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* + * Before including this file, you must define a number of CPP macros. + * + * BPP should be 8, 16 or 32 depending on the bits per pixel. + * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data + * into the given buffer. EXTRA_ARGS can be defined to pass any other + * arguments needed by GET_IMAGE_INTO_BUF. + * + * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel + * bigger than the largest tile of pixel data, since the ZRLE encoding + * algorithm writes to the position one past the end of the pixel data. + */ + +#include "zrleoutstream.h" +#include "zrlepalettehelper.h" +#include + +/* __RFB_CONCAT2 concatenates its two arguments. __RFB_CONCAT2E does the same + but also expands its arguments if they are macros */ + +#ifndef __RFB_CONCAT2E +#define __RFB_CONCAT2(a,b) a##b +#define __RFB_CONCAT2E(a,b) __RFB_CONCAT2(a,b) +#endif + +#ifndef __RFB_CONCAT3E +#define __RFB_CONCAT3(a,b,c) a##b##c +#define __RFB_CONCAT3E(a,b,c) __RFB_CONCAT3(a,b,c) +#endif + +#undef END_FIX +#if ZYWRLE_ENDIAN == ENDIAN_LITTLE +# define END_FIX LE +#elif ZYWRLE_ENDIAN == ENDIAN_BIG +# define END_FIX BE +#else +# define END_FIX NE +#endif + +#ifdef CPIXEL +#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP) +#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,CPIXEL) +#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,CPIXEL,END_FIX) +#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,CPIXEL,END_FIX) +#define BPPOUT 24 +#elif BPP==15 +#define PIXEL_T __RFB_CONCAT2E(zrle_U,16) +#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,16) +#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX) +#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX) +#define BPPOUT 16 +#else +#define PIXEL_T __RFB_CONCAT2E(zrle_U,BPP) +#define zrleOutStreamWRITE_PIXEL __RFB_CONCAT2E(zrleOutStreamWriteOpaque,BPP) +#define ZRLE_ENCODE __RFB_CONCAT3E(zrleEncode,BPP,END_FIX) +#define ZRLE_ENCODE_TILE __RFB_CONCAT3E(zrleEncodeTile,BPP,END_FIX) +#define BPPOUT BPP +#endif + +#ifndef ZRLE_ONCE +#define ZRLE_ONCE + +static const int bitsPerPackedPixel[] = { + 0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 +}; + +int zywrle_level; +int zywrleBuf[rfbZRLETileWidth*rfbZRLETileHeight]; + +static zrlePaletteHelper paletteHelper; + +#endif /* ZRLE_ONCE */ + +void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os); + +#if BPP!=8 +#define ZYWRLE_ENCODE +#include "zywrletemplate.c" +#endif + +static void ZRLE_ENCODE (int x, int y, int w, int h, + zrleOutStream* os, void* buf + EXTRA_ARGS + ) +{ + int ty; + for (ty = y; ty < y+h; ty += rfbZRLETileHeight) { + int tx, th = rfbZRLETileHeight; + if (th > y+h-ty) th = y+h-ty; + for (tx = x; tx < x+w; tx += rfbZRLETileWidth) { + int tw = rfbZRLETileWidth; + if (tw > x+w-tx) tw = x+w-tx; + + GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf); + + ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os); + } + } + zrleOutStreamFlush(os); +} + + +void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os) +{ + /* First find the palette and the number of runs */ + + zrlePaletteHelper *ph; + + int runs = 0; + int singlePixels = 0; + + rfbBool useRle; + rfbBool usePalette; + + int estimatedBytes; + int plainRleBytes; + int i; + + PIXEL_T* ptr = data; + PIXEL_T* end = ptr + h * w; + *end = ~*(end-1); /* one past the end is different so the while loop ends */ + + ph = &paletteHelper; + zrlePaletteHelperInit(ph); + + while (ptr < end) { + PIXEL_T pix = *ptr; + if (*++ptr != pix) { + singlePixels++; + } else { + while (*++ptr == pix) ; + runs++; + } + zrlePaletteHelperInsert(ph, pix); + } + + /* Solid tile is a special case */ + + if (ph->size == 1) { + zrleOutStreamWriteU8(os, 1); + zrleOutStreamWRITE_PIXEL(os, ph->palette[0]); + return; + } + + /* Try to work out whether to use RLE and/or a palette. We do this by + estimating the number of bytes which will be generated and picking the + method which results in the fewest bytes. Of course this may not result + in the fewest bytes after compression... */ + + useRle = FALSE; + usePalette = FALSE; + + estimatedBytes = w * h * (BPPOUT/8); /* start assuming raw */ + +#if BPP!=8 + if( (zywrle_level>0)&& !(zywrle_level & 0x80) ){ + estimatedBytes >>= zywrle_level; + } +#endif + + plainRleBytes = ((BPPOUT/8)+1) * (runs + singlePixels); + + if (plainRleBytes < estimatedBytes) { + useRle = TRUE; + estimatedBytes = plainRleBytes; + } + + if (ph->size < 128) { + int paletteRleBytes = (BPPOUT/8) * ph->size + 2 * runs + singlePixels; + + if (paletteRleBytes < estimatedBytes) { + useRle = TRUE; + usePalette = TRUE; + estimatedBytes = paletteRleBytes; + } + + if (ph->size < 17) { + int packedBytes = ((BPPOUT/8) * ph->size + + w * h * bitsPerPackedPixel[ph->size-1] / 8); + + if (packedBytes < estimatedBytes) { + useRle = FALSE; + usePalette = TRUE; + estimatedBytes = packedBytes; + } + } + } + + if (!usePalette) ph->size = 0; + + zrleOutStreamWriteU8(os, (useRle ? 128 : 0) | ph->size); + + for (i = 0; i < ph->size; i++) { + zrleOutStreamWRITE_PIXEL(os, ph->palette[i]); + } + + if (useRle) { + + PIXEL_T* ptr = data; + PIXEL_T* end = ptr + w * h; + PIXEL_T* runStart; + PIXEL_T pix; + while (ptr < end) { + int len; + runStart = ptr; + pix = *ptr++; + while (*ptr == pix && ptr < end) + ptr++; + len = ptr - runStart; + if (len <= 2 && usePalette) { + int index = zrlePaletteHelperLookup(ph, pix); + if (len == 2) + zrleOutStreamWriteU8(os, index); + zrleOutStreamWriteU8(os, index); + continue; + } + if (usePalette) { + int index = zrlePaletteHelperLookup(ph, pix); + zrleOutStreamWriteU8(os, index | 128); + } else { + zrleOutStreamWRITE_PIXEL(os, pix); + } + len -= 1; + while (len >= 255) { + zrleOutStreamWriteU8(os, 255); + len -= 255; + } + zrleOutStreamWriteU8(os, len); + } + + } else { + + /* no RLE */ + + if (usePalette) { + int bppp; + PIXEL_T* ptr = data; + + /* packed pixels */ + + assert (ph->size < 17); + + bppp = bitsPerPackedPixel[ph->size-1]; + + for (i = 0; i < h; i++) { + zrle_U8 nbits = 0; + zrle_U8 byte = 0; + + PIXEL_T* eol = ptr + w; + + while (ptr < eol) { + PIXEL_T pix = *ptr++; + zrle_U8 index = zrlePaletteHelperLookup(ph, pix); + byte = (byte << bppp) | index; + nbits += bppp; + if (nbits >= 8) { + zrleOutStreamWriteU8(os, byte); + nbits = 0; + } + } + if (nbits > 0) { + byte <<= 8 - nbits; + zrleOutStreamWriteU8(os, byte); + } + } + } else { + + /* raw */ + +#if BPP!=8 + if( (zywrle_level>0)&& !(zywrle_level & 0x80) ){ + ZYWRLE_ANALYZE( data, data, w, h, w, zywrle_level, zywrleBuf ); + zywrle_level |= 0x80; + ZRLE_ENCODE_TILE( data, w, h, os ); + zywrle_level &= 0x7F; + }else +#endif + { +#ifdef CPIXEL + PIXEL_T *ptr; + for (ptr = data; ptr < data+w*h; ptr++) { + zrleOutStreamWRITE_PIXEL(os, *ptr); + } +#else + zrleOutStreamWriteBytes(os, (zrle_U8 *)data, w*h*(BPP/8)); +#endif + } + } + } +} + +#undef PIXEL_T +#undef zrleOutStreamWRITE_PIXEL +#undef ZRLE_ENCODE +#undef ZRLE_ENCODE_TILE +#undef ZYWRLE_ENCODE_TILE +#undef BPPOUT diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrleoutstream.c vnc_unixsrc/vncviewer/zrleoutstream.c --- vnc_unixsrc.orig/vncviewer/zrleoutstream.c 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/zrleoutstream.c 2005-05-15 10:57:54.000000000 -0400 @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "zrleoutstream.h" +#include + +#define ZRLE_IN_BUFFER_SIZE 16384 +#define ZRLE_OUT_BUFFER_SIZE 1024 +#undef ZRLE_DEBUG + +static rfbBool zrleBufferAlloc(zrleBuffer *buffer, int size) +{ + buffer->ptr = buffer->start = malloc(size); + if (buffer->start == NULL) { + buffer->end = NULL; + return FALSE; + } + + buffer->end = buffer->start + size; + + return TRUE; +} + +static void zrleBufferFree(zrleBuffer *buffer) +{ + if (buffer->start) + free(buffer->start); + buffer->start = buffer->ptr = buffer->end = NULL; +} + +static rfbBool zrleBufferGrow(zrleBuffer *buffer, int size) +{ + int offset; + + size += buffer->end - buffer->start; + offset = ZRLE_BUFFER_LENGTH (buffer); + + buffer->start = realloc(buffer->start, size); + if (!buffer->start) { + return FALSE; + } + + buffer->end = buffer->start + size; + buffer->ptr = buffer->start + offset; + + return TRUE; +} + +zrleOutStream *zrleOutStreamNew(void) +{ + zrleOutStream *os; + + os = malloc(sizeof(zrleOutStream)); + if (os == NULL) + return NULL; + + if (!zrleBufferAlloc(&os->in, ZRLE_IN_BUFFER_SIZE)) { + free(os); + return NULL; + } + + if (!zrleBufferAlloc(&os->out, ZRLE_OUT_BUFFER_SIZE)) { + zrleBufferFree(&os->in); + free(os); + return NULL; + } + + os->zs.zalloc = Z_NULL; + os->zs.zfree = Z_NULL; + os->zs.opaque = Z_NULL; + if (deflateInit(&os->zs, Z_DEFAULT_COMPRESSION) != Z_OK) { + zrleBufferFree(&os->in); + free(os); + return NULL; + } + + return os; +} + +void zrleOutStreamFree (zrleOutStream *os) +{ + deflateEnd(&os->zs); + zrleBufferFree(&os->in); + zrleBufferFree(&os->out); + free(os); +} + +rfbBool zrleOutStreamFlush(zrleOutStream *os) +{ + os->zs.next_in = os->in.start; + os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in); + +#ifdef ZRLE_DEBUG + rfbLog("zrleOutStreamFlush: avail_in %d\n", os->zs.avail_in); +#endif + + while (os->zs.avail_in != 0) { + do { + int ret; + + if (os->out.ptr >= os->out.end && + !zrleBufferGrow(&os->out, os->out.end - os->out.start)) { + rfbLog("zrleOutStreamFlush: failed to grow output buffer\n"); + return FALSE; + } + + os->zs.next_out = os->out.ptr; + os->zs.avail_out = os->out.end - os->out.ptr; + +#ifdef ZRLE_DEBUG + rfbLog("zrleOutStreamFlush: calling deflate, avail_in %d, avail_out %d\n", + os->zs.avail_in, os->zs.avail_out); +#endif + + if ((ret = deflate(&os->zs, Z_SYNC_FLUSH)) != Z_OK) { + rfbLog("zrleOutStreamFlush: deflate failed with error code %d\n", ret); + return FALSE; + } + +#ifdef ZRLE_DEBUG + rfbLog("zrleOutStreamFlush: after deflate: %d bytes\n", + os->zs.next_out - os->out.ptr); +#endif + + os->out.ptr = os->zs.next_out; + } while (os->zs.avail_out == 0); + } + + os->in.ptr = os->in.start; + + return TRUE; +} + +static int zrleOutStreamOverrun(zrleOutStream *os, + int size) +{ +#ifdef ZRLE_DEBUG + rfbLog("zrleOutStreamOverrun\n"); +#endif + + while (os->in.end - os->in.ptr < size && os->in.ptr > os->in.start) { + os->zs.next_in = os->in.start; + os->zs.avail_in = ZRLE_BUFFER_LENGTH (&os->in); + + do { + int ret; + + if (os->out.ptr >= os->out.end && + !zrleBufferGrow(&os->out, os->out.end - os->out.start)) { + rfbLog("zrleOutStreamOverrun: failed to grow output buffer\n"); + return FALSE; + } + + os->zs.next_out = os->out.ptr; + os->zs.avail_out = os->out.end - os->out.ptr; + +#ifdef ZRLE_DEBUG + rfbLog("zrleOutStreamOverrun: calling deflate, avail_in %d, avail_out %d\n", + os->zs.avail_in, os->zs.avail_out); +#endif + + if ((ret = deflate(&os->zs, 0)) != Z_OK) { + rfbLog("zrleOutStreamOverrun: deflate failed with error code %d\n", ret); + return 0; + } + +#ifdef ZRLE_DEBUG + rfbLog("zrleOutStreamOverrun: after deflate: %d bytes\n", + os->zs.next_out - os->out.ptr); +#endif + + os->out.ptr = os->zs.next_out; + } while (os->zs.avail_out == 0); + + /* output buffer not full */ + + if (os->zs.avail_in == 0) { + os->in.ptr = os->in.start; + } else { + /* but didn't consume all the data? try shifting what's left to the + * start of the buffer. + */ + rfbLog("zrleOutStreamOverrun: out buf not full, but in data not consumed\n"); + memmove(os->in.start, os->zs.next_in, os->in.ptr - os->zs.next_in); + os->in.ptr -= os->zs.next_in - os->in.start; + } + } + + if (size > os->in.end - os->in.ptr) + size = os->in.end - os->in.ptr; + + return size; +} + +static int zrleOutStreamCheck(zrleOutStream *os, int size) +{ + if (os->in.ptr + size > os->in.end) { + return zrleOutStreamOverrun(os, size); + } + return size; +} + +void zrleOutStreamWriteBytes(zrleOutStream *os, + const zrle_U8 *data, + int length) +{ + const zrle_U8* dataEnd = data + length; + while (data < dataEnd) { + int n = zrleOutStreamCheck(os, dataEnd - data); + memcpy(os->in.ptr, data, n); + os->in.ptr += n; + data += n; + } +} + +void zrleOutStreamWriteU8(zrleOutStream *os, zrle_U8 u) +{ + zrleOutStreamCheck(os, 1); + *os->in.ptr++ = u; +} + +void zrleOutStreamWriteOpaque8(zrleOutStream *os, zrle_U8 u) +{ + zrleOutStreamCheck(os, 1); + *os->in.ptr++ = u; +} + +void zrleOutStreamWriteOpaque16 (zrleOutStream *os, zrle_U16 u) +{ + zrleOutStreamCheck(os, 2); + *os->in.ptr++ = ((zrle_U8*)&u)[0]; + *os->in.ptr++ = ((zrle_U8*)&u)[1]; +} + +void zrleOutStreamWriteOpaque32 (zrleOutStream *os, zrle_U32 u) +{ + zrleOutStreamCheck(os, 4); + *os->in.ptr++ = ((zrle_U8*)&u)[0]; + *os->in.ptr++ = ((zrle_U8*)&u)[1]; + *os->in.ptr++ = ((zrle_U8*)&u)[2]; + *os->in.ptr++ = ((zrle_U8*)&u)[3]; +} + +void zrleOutStreamWriteOpaque24A(zrleOutStream *os, zrle_U32 u) +{ + zrleOutStreamCheck(os, 3); + *os->in.ptr++ = ((zrle_U8*)&u)[0]; + *os->in.ptr++ = ((zrle_U8*)&u)[1]; + *os->in.ptr++ = ((zrle_U8*)&u)[2]; +} + +void zrleOutStreamWriteOpaque24B(zrleOutStream *os, zrle_U32 u) +{ + zrleOutStreamCheck(os, 3); + *os->in.ptr++ = ((zrle_U8*)&u)[1]; + *os->in.ptr++ = ((zrle_U8*)&u)[2]; + *os->in.ptr++ = ((zrle_U8*)&u)[3]; +} diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrleoutstream.h vnc_unixsrc/vncviewer/zrleoutstream.h --- vnc_unixsrc.orig/vncviewer/zrleoutstream.h 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/zrleoutstream.h 2004-05-25 06:05:15.000000000 -0400 @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __ZRLE_OUT_STREAM_H__ +#define __ZRLE_OUT_STREAM_H__ + +#include +#include "zrletypes.h" +#include "rfb/rfb.h" + +typedef struct { + zrle_U8 *start; + zrle_U8 *ptr; + zrle_U8 *end; +} zrleBuffer; + +typedef struct { + zrleBuffer in; + zrleBuffer out; + + z_stream zs; +} zrleOutStream; + +#define ZRLE_BUFFER_LENGTH(b) ((b)->ptr - (b)->start) + +zrleOutStream *zrleOutStreamNew (void); +void zrleOutStreamFree (zrleOutStream *os); +rfbBool zrleOutStreamFlush (zrleOutStream *os); +void zrleOutStreamWriteBytes (zrleOutStream *os, + const zrle_U8 *data, + int length); +void zrleOutStreamWriteU8 (zrleOutStream *os, + zrle_U8 u); +void zrleOutStreamWriteOpaque8 (zrleOutStream *os, + zrle_U8 u); +void zrleOutStreamWriteOpaque16 (zrleOutStream *os, + zrle_U16 u); +void zrleOutStreamWriteOpaque32 (zrleOutStream *os, + zrle_U32 u); +void zrleOutStreamWriteOpaque24A(zrleOutStream *os, + zrle_U32 u); +void zrleOutStreamWriteOpaque24B(zrleOutStream *os, + zrle_U32 u); + +#endif /* __ZRLE_OUT_STREAM_H__ */ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrlepalettehelper.c vnc_unixsrc/vncviewer/zrlepalettehelper.c --- vnc_unixsrc.orig/vncviewer/zrlepalettehelper.c 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/zrlepalettehelper.c 2004-05-25 06:05:15.000000000 -0400 @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "zrlepalettehelper.h" +#include +#include + +#define ZRLE_HASH(pix) (((pix) ^ ((pix) >> 17)) & 4095) + +void zrlePaletteHelperInit(zrlePaletteHelper *helper) +{ + memset(helper->palette, 0, sizeof(helper->palette)); + memset(helper->index, 255, sizeof(helper->index)); + memset(helper->key, 0, sizeof(helper->key)); + helper->size = 0; +} + +void zrlePaletteHelperInsert(zrlePaletteHelper *helper, zrle_U32 pix) +{ + if (helper->size < ZRLE_PALETTE_MAX_SIZE) { + int i = ZRLE_HASH(pix); + + while (helper->index[i] != 255 && helper->key[i] != pix) + i++; + if (helper->index[i] != 255) return; + + helper->index[i] = helper->size; + helper->key[i] = pix; + helper->palette[helper->size] = pix; + } + helper->size++; +} + +int zrlePaletteHelperLookup(zrlePaletteHelper *helper, zrle_U32 pix) +{ + int i = ZRLE_HASH(pix); + + assert(helper->size <= ZRLE_PALETTE_MAX_SIZE); + + while (helper->index[i] != 255 && helper->key[i] != pix) + i++; + if (helper->index[i] != 255) return helper->index[i]; + + return -1; +} diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrlepalettehelper.h vnc_unixsrc/vncviewer/zrlepalettehelper.h --- vnc_unixsrc.orig/vncviewer/zrlepalettehelper.h 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/zrlepalettehelper.h 2004-05-25 06:05:15.000000000 -0400 @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2003 Sun Microsystems, Inc. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/* + * The PaletteHelper class helps us build up the palette from pixel data by + * storing a reverse index using a simple hash-table + */ + +#ifndef __ZRLE_PALETTE_HELPER_H__ +#define __ZRLE_PALETTE_HELPER_H__ + +#include "zrletypes.h" + +#define ZRLE_PALETTE_MAX_SIZE 127 + +typedef struct { + zrle_U32 palette[ZRLE_PALETTE_MAX_SIZE]; + zrle_U8 index[ZRLE_PALETTE_MAX_SIZE + 4096]; + zrle_U32 key[ZRLE_PALETTE_MAX_SIZE + 4096]; + int size; +} zrlePaletteHelper; + +void zrlePaletteHelperInit (zrlePaletteHelper *helper); +void zrlePaletteHelperInsert(zrlePaletteHelper *helper, + zrle_U32 pix); +int zrlePaletteHelperLookup(zrlePaletteHelper *helper, + zrle_U32 pix); + +#endif /* __ZRLE_PALETTE_HELPER_H__ */ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrletypes.h vnc_unixsrc/vncviewer/zrletypes.h --- vnc_unixsrc.orig/vncviewer/zrletypes.h 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/zrletypes.h 2004-05-25 06:05:15.000000000 -0400 @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef __ZRLE_TYPES_H__ +#define __ZRLE_TYPES_H__ + +typedef unsigned char zrle_U8; +typedef unsigned short zrle_U16; +typedef unsigned int zrle_U32; +typedef signed char zrle_S8; +typedef signed short zrle_S16; +typedef signed int zrle_S32; + +#endif /* __ZRLE_TYPES_H__ */ diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zywrletemplate.c vnc_unixsrc/vncviewer/zywrletemplate.c --- vnc_unixsrc.orig/vncviewer/zywrletemplate.c 1969-12-31 19:00:00.000000000 -0500 +++ vnc_unixsrc/vncviewer/zywrletemplate.c 2008-02-15 23:33:13.000000000 -0500 @@ -0,0 +1,824 @@ + +/******************************************************************** + * * + * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE. * + * * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE. * + * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006 * + * BY Hitachi Systems & Services, Ltd. * + * (Noriaki Yamazaki, Research & Developement Center) * * + * * + ******************************************************************** +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Hitachi Systems & Services, Ltd. nor +the names of its contributors may be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************/ + +/* Change Log: + V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline + (Thanks Johannes Schindelin, author of LibVNC + Server/Client) + V0.01 : 2007/02/06 : Initial release +*/ + +/* #define ZYWRLE_ENCODE */ +/* #define ZYWRLE_DECODE */ +#define ZYWRLE_QUANTIZE + +/* +[References] + PLHarr: + Senecal, J. G., P. Lindstrom, M. A. Duchaineau, and K. I. Joy, "An Improved N-Bit to N-Bit Reversible Haar-Like Transform," Pacific Graphics 2004, October 2004, pp. 371-380. + EZW: + Shapiro, JM: Embedded Image Coding Using Zerotrees of Wavelet Coefficients, IEEE Trans. Signal. Process., Vol.41, pp.3445-3462 (1993). +*/ + + +/* Template Macro stuffs. */ +#undef ZYWRLE_ANALYZE +#undef ZYWRLE_SYNTHESIZE +#define ZYWRLE_ANALYZE __RFB_CONCAT3E(zywrleAnalyze,BPP,END_FIX) +#define ZYWRLE_SYNTHESIZE __RFB_CONCAT3E(zywrleSynthesize,BPP,END_FIX) + +#define ZYWRLE_RGBYUV __RFB_CONCAT3E(zywrleRGBYUV,BPP,END_FIX) +#define ZYWRLE_YUVRGB __RFB_CONCAT3E(zywrleYUVRGB,BPP,END_FIX) +#define ZYWRLE_YMASK __RFB_CONCAT2E(ZYWRLE_YMASK,BPP) +#define ZYWRLE_UVMASK __RFB_CONCAT2E(ZYWRLE_UVMASK,BPP) +#define ZYWRLE_LOAD_PIXEL __RFB_CONCAT2E(ZYWRLE_LOAD_PIXEL,BPP) +#define ZYWRLE_SAVE_PIXEL __RFB_CONCAT2E(ZYWRLE_SAVE_PIXEL,BPP) + +/* Packing/Unpacking pixel stuffs. + Endian conversion stuffs. */ +#undef S_0 +#undef S_1 +#undef L_0 +#undef L_1 +#undef L_2 +#if ZYWRLE_ENDIAN == ENDIAN_BIG +# define S_0 1 +# define S_1 0 +# define L_0 3 +# define L_1 2 +# define L_2 1 +#else +# define S_0 0 +# define S_1 1 +# define L_0 0 +# define L_1 1 +# define L_2 2 +#endif + +/* Load/Save pixel stuffs. */ +#define ZYWRLE_YMASK15 0xFFFFFFF8 +#define ZYWRLE_UVMASK15 0xFFFFFFF8 +#define ZYWRLE_LOAD_PIXEL15(pSrc,R,G,B) { \ + R = (((unsigned char*)pSrc)[S_1]<< 1)& 0xF8; \ + G = ((((unsigned char*)pSrc)[S_1]<< 6)|(((unsigned char*)pSrc)[S_0]>> 2))& 0xF8; \ + B = (((unsigned char*)pSrc)[S_0]<< 3)& 0xF8; \ +} +#define ZYWRLE_SAVE_PIXEL15(pDst,R,G,B) { \ + R &= 0xF8; \ + G &= 0xF8; \ + B &= 0xF8; \ + ((unsigned char*)pDst)[S_1] = (unsigned char)( (R>>1)|(G>>6) ); \ + ((unsigned char*)pDst)[S_0] = (unsigned char)(((B>>3)|(G<<2))& 0xFF); \ +} +#define ZYWRLE_YMASK16 0xFFFFFFFC +#define ZYWRLE_UVMASK16 0xFFFFFFF8 +#define ZYWRLE_LOAD_PIXEL16(pSrc,R,G,B) { \ + R = ((unsigned char*)pSrc)[S_1] & 0xF8; \ + G = ((((unsigned char*)pSrc)[S_1]<< 5)|(((unsigned char*)pSrc)[S_0]>> 3))& 0xFC; \ + B = (((unsigned char*)pSrc)[S_0]<< 3)& 0xF8; \ +} +#define ZYWRLE_SAVE_PIXEL16(pDst,R,G,B) { \ + R &= 0xF8; \ + G &= 0xFC; \ + B &= 0xF8; \ + ((unsigned char*)pDst)[S_1] = (unsigned char)( R |(G>>5) ); \ + ((unsigned char*)pDst)[S_0] = (unsigned char)(((B>>3)|(G<<3))& 0xFF); \ +} +#define ZYWRLE_YMASK32 0xFFFFFFFF +#define ZYWRLE_UVMASK32 0xFFFFFFFF +#define ZYWRLE_LOAD_PIXEL32(pSrc,R,G,B) { \ + R = ((unsigned char*)pSrc)[L_2]; \ + G = ((unsigned char*)pSrc)[L_1]; \ + B = ((unsigned char*)pSrc)[L_0]; \ +} +#define ZYWRLE_SAVE_PIXEL32(pDst,R,G,B) { \ + ((unsigned char*)pDst)[L_2] = (unsigned char)R; \ + ((unsigned char*)pDst)[L_1] = (unsigned char)G; \ + ((unsigned char*)pDst)[L_0] = (unsigned char)B; \ +} + +#ifndef ZYWRLE_ONCE +#define ZYWRLE_ONCE + +#ifdef WIN32 +#define InlineX __inline +#else +#define InlineX inline +#endif + +#ifdef ZYWRLE_ENCODE +/* Tables for Coefficients filtering. */ +# ifndef ZYWRLE_QUANTIZE +/* Type A:lower bit omitting of EZW style. */ +const static unsigned int zywrleParam[3][3]={ + {0x0000F000,0x00000000,0x00000000}, + {0x0000C000,0x00F0F0F0,0x00000000}, + {0x0000C000,0x00C0C0C0,0x00F0F0F0}, +/* {0x0000FF00,0x00000000,0x00000000}, + {0x0000FF00,0x00FFFFFF,0x00000000}, + {0x0000FF00,0x00FFFFFF,0x00FFFFFF}, */ +}; +# else +/* Type B:Non liner quantization filter. */ +static const signed char zywrleConv[4][256]={ +{ /* bi=5, bo=5 r=0.0:PSNR=24.849 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}, +{ /* bi=5, bo=5 r=2.0:PSNR=74.031 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 64, 64, 64, 64, + 64, 64, 64, 64, 72, 72, 72, 72, + 72, 72, 72, 72, 80, 80, 80, 80, + 80, 80, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 96, 96, + 96, 96, 96, 104, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 120, + 0, -120, -120, -120, -120, -120, -120, -120, + -120, -120, -120, -112, -112, -112, -112, -112, + -112, -112, -112, -112, -104, -104, -104, -104, + -104, -104, -104, -104, -104, -104, -96, -96, + -96, -96, -96, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -80, + -80, -80, -80, -80, -80, -72, -72, -72, + -72, -72, -72, -72, -72, -64, -64, -64, + -64, -64, -64, -64, -64, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, + -48, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}, +{ /* bi=5, bo=4 r=2.0:PSNR=64.441 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, + 104, 104, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 112, 112, 112, 112, 112, + 112, 112, 112, 112, 120, 120, 120, 120, + 120, 120, 120, 120, 120, 120, 120, 120, + 0, -120, -120, -120, -120, -120, -120, -120, + -120, -120, -120, -120, -120, -112, -112, -112, + -112, -112, -112, -112, -112, -112, -104, -104, + -104, -104, -104, -104, -104, -104, -104, -104, + -104, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, + -80, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, + -64, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, + -48, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}, +{ /* bi=5, bo=2 r=2.0:PSNR=43.175 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, + 0, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, + -88, -88, -88, -88, -88, -88, -88, -88, + -88, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +} +}; +const static signed char* zywrleParam[3][3][3]={ + {{zywrleConv[0],zywrleConv[2],zywrleConv[0]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]}}, + {{zywrleConv[0],zywrleConv[3],zywrleConv[0]},{zywrleConv[1],zywrleConv[1],zywrleConv[1]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]}}, + {{zywrleConv[0],zywrleConv[3],zywrleConv[0]},{zywrleConv[2],zywrleConv[2],zywrleConv[2]},{zywrleConv[1],zywrleConv[1],zywrleConv[1]}}, +}; +# endif +#endif + +static InlineX void Harr(signed char* pX0, signed char* pX1) +{ + /* Piecewise-Linear Harr(PLHarr) */ + int X0 = (int)*pX0, X1 = (int)*pX1; + int orgX0 = X0, orgX1 = X1; + if ((X0 ^ X1) & 0x80) { + /* differ sign */ + X1 += X0; + if (((X1^orgX1)&0x80)==0) { + /* |X1| > |X0| */ + X0 -= X1; /* H = -B */ + } + } else { + /* same sign */ + X0 -= X1; + if (((X0 ^ orgX0) & 0x80) == 0) { + /* |X0| > |X1| */ + X1 += X0; /* L = A */ + } + } + *pX0 = (signed char)X1; + *pX1 = (signed char)X0; +} +/* + 1D-Wavelet transform. + + In coefficients array, the famous 'pyramid' decomposition is well used. + + 1D Model: + |L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0 + |L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1 + + But this method needs line buffer because H/L is different position from X0/X1. + So, I used 'interleave' decomposition instead of it. + + 1D Model: + |L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0 + |L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1 + + In this method, H/L and X0/X1 is always same position. + This lead us to more speed and less memory. + Of cause, the result of both method is quite same + because it's only difference that coefficient position. +*/ +static InlineX void WaveletLevel(int* data, int size, int l, int SkipPixel) +{ + int s, ofs; + signed char* pX0; + signed char* end; + + pX0 = (signed char*)data; + s = (8<>(l+1))*s; + s -= 2; + ofs = (4<>1; + if (r & 0x02) + pH += (s>>1)*width; + for (y = 0; y < height / s; y++) { + for (x = 0; x < width / s; x++) { + /* + these are same following code. + pH[x] = pH[x] / (~pM[x]+1) * (~pM[x]+1); + ( round pH[x] with pM[x] bit ) + '&' operator isn't 'round' but is 'floor'. + So, we must offset when pH[x] is negative. + */ + if (((signed char*)pH)[0] & 0x80) + ((signed char*)pH)[0] += ~((signed char*)pM)[0]; + if (((signed char*)pH)[1] & 0x80) + ((signed char*)pH)[1] += ~((signed char*)pM)[1]; + if (((signed char*)pH)[2] & 0x80) + ((signed char*)pH)[2] += ~((signed char*)pM)[2]; + *pH &= *pM; + pH += s; + } + pH += (s-1)*width; + } + } +} +# else +/* + Type B:Non liner quantization filter. + + Coefficients have Gaussian curve and smaller value which is + large part of coefficients isn't more important than larger value. + So, I use filter of Non liner quantize/dequantize table. + In general, Non liner quantize formula is explained as following. + + y=f(x) = sign(x)*round( ((abs(x)/(2^7))^ r )* 2^(bo-1) )*2^(8-bo) + x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi) + ( r:power coefficient bi:effective MSB in input bo:effective MSB in output ) + + r < 1.0 : Smaller value is more important than larger value. + r > 1.0 : Larger value is more important than smaller value. + r = 1.0 : Liner quantization which is same with EZW style. + + r = 0.75 is famous non liner quantization used in MP3 audio codec. + In contrast to audio data, larger value is important in wavelet coefficients. + So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ). + + As compared with EZW style liner quantization, this filter tended to be + more sharp edge and be more compression rate but be more blocking noise and be less quality. + Especially, the surface of graphic objects has distinguishable noise in middle quality mode. + + We need only quantized-dequantized(filtered) value rather than quantized value itself + because all values are packed or palette-lized in later ZRLE section. + This lead us not to need to modify client decoder when we change + the filtering procedure in future. + Client only decodes coefficients given by encoder. +*/ +static InlineX void FilterWaveletSquare(int* pBuf, int width, int height, int level, int l) +{ + int r, s; + int x, y; + int* pH; + const signed char** pM; + + pM = zywrleParam[level-1][l]; + s = 2<>1; + if (r & 0x02) + pH += (s>>1)*width; + for (y = 0; y < height / s; y++) { + for (x = 0; x < width / s; x++) { + ((signed char*)pH)[0] = pM[0][((unsigned char*)pH)[0]]; + ((signed char*)pH)[1] = pM[1][((unsigned char*)pH)[1]]; + ((signed char*)pH)[2] = pM[2][((unsigned char*)pH)[2]]; + pH += s; + } + pH += (s-1)*width; + } + } +} +# endif + +static InlineX void Wavelet(int* pBuf, int width, int height, int level) +{ + int l, s; + int* pTop; + int* pEnd; + + for (l = 0; l < level; l++) { + pTop = pBuf; + pEnd = pBuf+height*width; + s = width<= 0; l--) { + pTop = pBuf; + pEnd = pBuf+width; + s = 1< YUV conversion stuffs. + YUV coversion is explained as following formula in strict meaning: + Y = 0.299R + 0.587G + 0.114B ( 0<=Y<=255) + U = -0.169R - 0.331G + 0.500B (-128<=U<=127) + V = 0.500R - 0.419G - 0.081B (-128<=V<=127) + + I use simple conversion RCT(reversible color transform) which is described + in JPEG-2000 specification. + Y = (R + 2G + B)/4 ( 0<=Y<=255) + U = B-G (-256<=U<=255) + V = R-G (-256<=V<=255) +*/ +#define ROUND(x) (((x)<0)?0:(((x)>255)?255:(x))) + /* RCT is N-bit RGB to N-bit Y and N+1-bit UV. + For make Same N-bit, UV is lossy. + More exact PLHarr, we reduce to odd range(-127<=x<=127). */ +#define ZYWRLE_RGBYUV1(R,G,B,Y,U,V,ymask,uvmask) { \ + Y = (R+(G<<1)+B)>>2; \ + U = B-G; \ + V = R-G; \ + Y -= 128; \ + U >>= 1; \ + V >>= 1; \ + Y &= ymask; \ + U &= uvmask; \ + V &= uvmask; \ + if (Y == -128) \ + Y += (0xFFFFFFFF-ymask+1); \ + if (U == -128) \ + U += (0xFFFFFFFF-uvmask+1); \ + if (V == -128) \ + V += (0xFFFFFFFF-uvmask+1); \ +} +#define ZYWRLE_YUVRGB1(R,G,B,Y,U,V) { \ + Y += 128; \ + U <<= 1; \ + V <<= 1; \ + G = Y-((U+V)>>2); \ + B = U+G; \ + R = V+G; \ + G = ROUND(G); \ + B = ROUND(B); \ + R = ROUND(R); \ +} + +/* + coefficient packing/unpacking stuffs. + Wavelet transform makes 4 sub coefficient image from 1 original image. + + model with pyramid decomposition: + +------+------+ + | | | + | L | Hx | + | | | + +------+------+ + | | | + | H | Hxy | + | | | + +------+------+ + + So, we must transfer each sub images individually in strict meaning. + But at least ZRLE meaning, following one decompositon image is same as + avobe individual sub image. I use this format. + (Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L) + for simplified procedure for any wavelet level.) + + +------+------+ + | L | + +------+------+ + | Hx | + +------+------+ + | Hy | + +------+------+ + | Hxy | + +------+------+ +*/ +#define INC_PTR(data) \ + data++; \ + if( data-pData >= (w+uw) ){ \ + data += scanline-(w+uw); \ + pData = data; \ + } + +#define ZYWRLE_TRANSFER_COEFF(pBuf,data,r,w,h,scanline,level,TRANS) \ + pH = pBuf; \ + s = 2<>1; \ + if (r & 0x02) \ + pH += (s>>1)*w; \ + pEnd = pH+h*w; \ + while (pH < pEnd) { \ + pLine = pH+w; \ + while (pH < pLine) { \ + TRANS \ + INC_PTR(data) \ + pH += s; \ + } \ + pH += (s-1)*w; \ + } + +#define ZYWRLE_PACK_COEFF(pBuf,data,r,width,height,scanline,level) \ + ZYWRLE_TRANSFER_COEFF(pBuf,data,r,width,height,scanline,level,ZYWRLE_LOAD_COEFF(pH,R,G,B);ZYWRLE_SAVE_PIXEL(data,R,G,B);) + +#define ZYWRLE_UNPACK_COEFF(pBuf,data,r,width,height,scanline,level) \ + ZYWRLE_TRANSFER_COEFF(pBuf,data,r,width,height,scanline,level,ZYWRLE_LOAD_PIXEL(data,R,G,B);ZYWRLE_SAVE_COEFF(pH,R,G,B);) + +#define ZYWRLE_SAVE_UNALIGN(data,TRANS) \ + pTop = pBuf+w*h; \ + pEnd = pBuf + (w+uw)*(h+uh); \ + while (pTop < pEnd) { \ + TRANS \ + INC_PTR(data) \ + pTop++; \ + } + +#define ZYWRLE_LOAD_UNALIGN(data,TRANS) \ + pTop = pBuf+w*h; \ + if (uw) { \ + pData= data + w; \ + pEnd = (int*)(pData+ h*scanline); \ + while (pData < (PIXEL_T*)pEnd) { \ + pLine = (int*)(pData + uw); \ + while (pData < (PIXEL_T*)pLine) { \ + TRANS \ + pData++; \ + pTop++; \ + } \ + pData += scanline-uw; \ + } \ + } \ + if (uh) { \ + pData= data + h*scanline; \ + pEnd = (int*)(pData+ uh*scanline); \ + while (pData < (PIXEL_T*)pEnd) { \ + pLine = (int*)(pData + w); \ + while (pData < (PIXEL_T*)pLine) { \ + TRANS \ + pData++; \ + pTop++; \ + } \ + pData += scanline-w; \ + } \ + } \ + if (uw && uh) { \ + pData= data + w+ h*scanline; \ + pEnd = (int*)(pData+ uh*scanline); \ + while (pData < (PIXEL_T*)pEnd) { \ + pLine = (int*)(pData + uw); \ + while (pData < (PIXEL_T*)pLine) { \ + TRANS \ + pData++; \ + pTop++; \ + } \ + pData += scanline-uw; \ + } \ + } + +static InlineX void zywrleCalcSize(int* pW, int* pH, int level) +{ + *pW &= ~((1<client messages. */ @@ -968,6 +1050,8 @@ rfbFileDownloadDataMsg fdd; rfbFileUploadCancelMsg fuc; rfbFileDownloadFailedMsg fdf; + rfbRestartConnectionMsg rc; + rfbTextChatMsg tc; } rfbServerToClientMsg; @@ -1221,6 +1305,41 @@ #define sz_rfbFileCreateDirRequestMsg 4 +/* ultra */ +typedef struct _rfbSetScaleMsg { + CARD8 type; /* always rfbSetScale */ + CARD8 scale; /* Scale value 1server messages. */ @@ -1241,4 +1360,9 @@ rfbFileDownloadCancelMsg fdc; rfbFileUploadFailedMsg fuf; rfbFileCreateDirRequestMsg fcdr; + rfbSetScaleMsg ssc; + rfbPalmVNCSetScaleFactorMsg pssf; + rfbSetServerInputMsg sim; + rfbSetSWMsg sw; + rfbTextChatMsg tc; } rfbClientToServerMsg; diff -Naur -X ./exclude vnc_unixsrc.orig/include/vncauth.h vnc_unixsrc/include/vncauth.h --- vnc_unixsrc.orig/include/vncauth.h 2000-06-11 08:00:53.000000000 -0400 +++ vnc_unixsrc/include/vncauth.h 2009-03-21 00:37:23.000000000 -0400 @@ -23,8 +23,11 @@ #define MAXPWLEN 8 #define CHALLENGESIZE 16 +#define CHALLENGESIZE_MSLOGON 64 extern int vncEncryptAndStorePasswd(char *passwd, char *fname); extern char *vncDecryptPasswdFromFile(char *fname); extern void vncRandomBytes(unsigned char *bytes); extern void vncEncryptBytes(unsigned char *bytes, char *passwd); + +extern void vncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd); diff -Naur -X ./exclude vnc_unixsrc.orig/libvncauth/vncauth.c vnc_unixsrc/libvncauth/vncauth.c --- vnc_unixsrc.orig/libvncauth/vncauth.c 2003-03-01 11:48:06.000000000 -0500 +++ vnc_unixsrc/libvncauth/vncauth.c 2009-04-12 22:28:08.000000000 -0400 @@ -30,6 +30,7 @@ #include #include +#include /* * Make sure we call srandom() only once. @@ -195,6 +196,44 @@ return (i < 16) ? 1 : 2; } +unsigned int urandom(void) { + unsigned int val = 0; + struct stat sb; + int fd = -1; + if (fd < 0 && stat("/dev/urandom", &sb) == 0) { + fd = open("/dev/urandom", O_RDONLY); + } + if (fd < 0 && stat("/dev/random", &sb) == 0) { + fd = open("/dev/random", O_RDONLY); + } + if (fd < 0 && stat("/proc/loadavg", &sb) == 0) { + fd = open("/proc/loadavg", O_RDONLY); + } + if (fd < 0 && stat("/bin/bash", &sb) == 0) { + fd = open("/bin/bash", O_RDONLY); + lseek(fd, (off_t) (unsigned int) getpid(), SEEK_SET); + } + if (fd >= 0) { + int i; + for (i=0; i < 3; i++) { + char buf[2]; + if (read(fd, buf, 1) > 0) { + unsigned char uc = (unsigned char) buf[0]; + if (i==0) { + val += uc; + } else if (i==1) { + val += uc * 256; + } else if (i==2) { + val += uc * 256 * 256; + } + } + } + close(fd); + } else { + val = (unsigned int) getpid(); + } + return val; +} /* * Generate CHALLENGESIZE random bytes for use in challenge-response @@ -207,11 +246,13 @@ int i; unsigned int seed; - if (!s_srandom_called) { - seed = (unsigned int)time(0) ^ (unsigned int)getpid(); - srandom(seed); - s_srandom_called = 1; - } + if (!s_srandom_called) { + seed = (unsigned int)time(0) ^ (unsigned int)getpid(); + seed += urandom(); + + srandom(seed); + s_srandom_called = 1; + } for (i = 0; i < CHALLENGESIZE; i++) { bytes[i] = (unsigned char)(random() & 255); @@ -245,3 +286,48 @@ des(bytes+i, bytes+i); } } + +void UvncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd) { + unsigned int i; + for (i=0; i < 32; i++) { + if (i < strlen(passwd)) { + encryptedPasswd[i] = passwd[i]; + } else { + encryptedPasswd[i] = '\0'; + } + } + deskey(s_fixedkey, EN0); + des(encryptedPasswd, encryptedPasswd); +} + +void UvncEncryptBytes2(unsigned char *where, int length, unsigned char *key) { + int i, j; + deskey(key, EN0); + for (i=0; i < 8; i++) { + where[i] ^= key[i]; + } + des(where, where); + for (i=8; i < length; i += 8) { + for (j=0; j < 8; j++) { + where[i+j] ^= where[i+j-8]; + } + des(where+i, where+i); + } +} + +void UvncDecryptBytes2(unsigned char *where, int length, unsigned char *key) { + int i, j; + deskey(key, DE1); + for (i = length - 8; i > 0; i -= 8) { + des(where + i, where + i); + for (j=0; j < 8; j++) { + where[i+j] ^= where[i+j-8]; + } + } + /* i=0 */ + des(where, where); + for (i=0; i < 8; i++) { + where[i] ^= key[i]; + } +} +