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 2008-10-29 08:20:51.000000000 -0400 @@ -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\ @@ -58,23 +110,112 @@ "*serverDialog.dialog.value.translations: #override\\n\ Return: ServerDialogDone()", + "*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" + "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" + "Current Escape Keys Value:", + "*escapeDialog.dialog.value:", + "*escapeDialog.dialog.value.width: 275", + "*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: Password:", "*passwordDialog.dialog.value:", "*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", + + "*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: 38", + "*popupButtonBreak: 19", "*popup*button1.label: Dismiss popup", "*popup*button1.translations: #override\\n\ @@ -84,7 +225,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 +246,332 @@ "*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/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: Scale Viewer", + "*popup*button27.translations: #override\\n\ + ,: HidePopup() SetScale()", + + "*popup*button28.label: Escape Keys: Toggle", + "*popup*button28.type: toggle", + "*popup*button28.translations: #override\\n\ + : SetEscapeKeysState()\\n\ + , : toggle() ToggleEscapeActive() HidePopup()", + + "*popup*button29.label: Escape Keys: Help+Set", + "*popup*button29.translations: #override\\n\ + , : HidePopup() SetEscapeKeys()", + + "*popup*button30.label: Set Y Crop (y-max)", + "*popup*button30.translations: #override\\n\ + ,: HidePopup() SetYCrop()", + + "*popup*button31.label: Set Scrollbar Width", + "*popup*button31.translations: #override\\n\ + ,: HidePopup() SetScbar()", + + "*popup*button32.label: XGrabServer", + "*popup*button32.type: toggle", + "*popup*button32.translations: #override\\n\ + : SetXGrabState()\\n\ + ,: toggle() ToggleXGrab() HidePopup()", + + "*popup*button33.label: UltraVNC Extensions:", + "*popup*button33.translations: #override\\n\ + ,: HidePopup()", + + "*popup*button34.label: - Set 1/n Server Scale", + "*popup*button34.translations: #override\\n\ + ,: HidePopup() ShowScaleN()", + + "*popup*button35.label: - Text Chat", + "*popup*button35.type: toggle", + "*popup*button35.translations: #override\\n\ + : SetTextChatState()\\n\ + ,: toggle() ToggleTextChat() HidePopup()", + + "*popup*button36.label: - File Transfer", + "*popup*button36.type: toggle", + "*popup*button36.translations: #override\\n\ + : SetFileXferState()\\n\ + ,: toggle() ToggleFileXfer() HidePopup()", + + "*popup*button37.label: - Single Window", + "*popup*button37.type: toggle", + "*popup*button37.translations: #override\\n\ + : SetSingleWindowState()\\n\ + ,: toggle() ToggleSingleWindow() HidePopup()", + + "*popup*button38.label: - Disable Remote Input", + "*popup*button38.type: toggle", + "*popup*button38.translations: #override\\n\ + : SetServerInputState()\\n\ + ,: toggle() ToggleServerInput() HidePopup()", + +// "*popup*button3x.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()", + NULL }; @@ -124,7 +581,7 @@ * from a dialog box. */ -char vncServerHost[256]; +char vncServerHost[1024]; int vncServerPort = 0; @@ -135,6 +592,7 @@ */ AppData appData; +AppData appDataNew; static XtResource appDataResourceList[] = { {"shareDesktop", "ShareDesktop", XtRBool, sizeof(Bool), @@ -155,14 +613,38 @@ {"userLogin", "UserLogin", XtRString, sizeof(String), XtOffsetOf(AppData, userLogin), XtRImmediate, (XtPointer) 0}, + {"unixPW", "UnixPW", XtRString, sizeof(String), + XtOffsetOf(AppData, unixPW), 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}, + + {"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 +661,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 +676,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}, @@ -207,7 +695,7 @@ XtOffsetOf(AppData, bumpScrollPixels), XtRImmediate, (XtPointer) 20}, {"compressLevel", "CompressionLevel", XtRInt, sizeof(int), - XtOffsetOf(AppData, compressLevel), XtRImmediate, (XtPointer) -1}, + XtOffsetOf(AppData, compressLevel), XtRImmediate, (XtPointer) 7}, {"qualityLevel", "QualityLevel", XtRInt, sizeof(int), XtOffsetOf(AppData, qualityLevel), XtRImmediate, (XtPointer) 6}, @@ -218,14 +706,63 @@ {"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}, + {"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}, + + {"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 +779,25 @@ {"-noraiseonbeep", "*raiseOnBeep", XrmoptionNoArg, "False"}, {"-passwd", "*passwordFile", XrmoptionSepArg, 0}, {"-user", "*userLogin", XrmoptionSepArg, 0}, + {"-unixpw", "*unixPW", XrmoptionSepArg, 0}, + {"-repeater", "*repeaterUltra", XrmoptionSepArg, 0}, + {"-ultradsm", "*ultraDSM", 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"}, + {"-alpha", "*useCursorAlpha", XrmoptionNoArg, "True"}, {"-owncmap", "*forceOwnCmap", XrmoptionNoArg, "True"}, {"-truecolor", "*forceTrueColour", XrmoptionNoArg, "True"}, {"-truecolour", "*forceTrueColour", XrmoptionNoArg, "True"}, @@ -253,8 +807,22 @@ {"-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}, + {"-escapekeys", "*escapeKeys", XrmoptionSepArg, 0} }; int numCmdLineOptions = XtNumber(cmdLineOptions); @@ -267,16 +835,88 @@ static XtActionsRec actions[] = { {"SendRFBEvent", SendRFBEvent}, {"ShowPopup", ShowPopup}, + {"Noop", Noop}, {"HidePopup", HidePopup}, + {"HideScaleN", HideScaleN}, + {"HideQuality", HideQuality}, + {"HideCompress", HideCompress}, {"ToggleFullScreen", ToggleFullScreen}, + {"JumpLeft", JumpLeft}, + {"JumpRight", JumpRight}, + {"JumpUp", JumpUp}, + {"JumpDown", JumpDown}, {"SetFullScreenState", SetFullScreenState}, {"SelectionFromVNC", SelectionFromVNC}, {"SelectionToVNC", SelectionToVNC}, {"ServerDialogDone", ServerDialogDone}, + {"YCropDialogDone", YCropDialogDone}, + {"ScbarDialogDone", ScbarDialogDone}, + {"ScaleNDialogDone", ScaleNDialogDone}, + {"ScaleDialogDone", ScaleDialogDone}, {"PasswordDialogDone", PasswordDialogDone}, {"Pause", Pause}, {"RunCommand", RunCommand}, {"Quit", Quit}, + {"HideChat", HideChat}, + {"Toggle8bpp", Toggle8bpp}, + {"Toggle16bpp", Toggle16bpp}, + {"ToggleFullColor", ToggleFullColor}, + {"Toggle256Colors", Toggle256Colors}, + {"Toggle64Colors", Toggle64Colors}, + {"Toggle8Colors", Toggle8Colors}, + {"ToggleGreyScale", ToggleGreyScale}, + {"ToggleTightZRLE", ToggleTightZRLE}, + {"ToggleZRLEZYWRLE", ToggleZRLEZYWRLE}, + {"ToggleViewOnly", ToggleViewOnly}, + {"ToggleJPEG", ToggleJPEG}, + {"ToggleCursorShape", ToggleCursorShape}, + {"ToggleCursorAlpha", ToggleCursorAlpha}, + {"ToggleX11Cursor", ToggleX11Cursor}, + {"ToggleBell", ToggleBell}, + {"ToggleRawLocal", ToggleRawLocal}, + {"ToggleServerInput", ToggleServerInput}, + {"ToggleSingleWindow", ToggleSingleWindow}, + {"ToggleTextChat", ToggleTextChat}, + {"ToggleFileXfer", ToggleFileXfer}, + {"ToggleXGrab", ToggleXGrab}, + {"DoServerScale", DoServerScale}, + {"SetScale", SetScale}, + {"SetYCrop", SetYCrop}, + {"SetScbar", SetScbar}, + {"ShowScaleN", ShowScaleN}, + {"ShowQuality", ShowQuality}, + {"ShowCompress", ShowCompress}, + {"SetScaleN", SetScaleN}, + {"SetQuality", SetQuality}, + {"SetCompress", SetCompress}, + {"Set8bppState", Set8bppState}, + {"Set16bppState", Set16bppState}, + {"SetFullColorState", SetFullColorState}, + {"Set256ColorsState", Set256ColorsState}, + {"Set64ColorsState", Set64ColorsState}, + {"Set8ColorsState", Set8ColorsState}, + {"SetGreyScaleState", SetGreyScaleState}, + {"SetZRLEState", SetZRLEState}, + {"SetZYWRLEState", SetZYWRLEState}, + {"SetNOJPEGState", SetNOJPEGState}, + {"SetScaleNState", SetScaleNState}, + {"SetQualityState", SetQualityState}, + {"SetCompressState", SetCompressState}, + {"SetViewOnlyState", SetViewOnlyState}, + {"SetCursorShapeState", SetCursorShapeState}, + {"SetCursorAlphaState", SetCursorAlphaState}, + {"SetX11CursorState", SetX11CursorState}, + {"SetBellState", SetBellState}, + {"SetRawLocalState", SetRawLocalState}, + {"SetServerInputState", SetServerInputState}, + {"SetSingleWindowState", SetSingleWindowState}, + {"SetTextChatState", SetTextChatState}, + {"SetFileXferState", SetFileXferState}, + {"SetXGrabState", SetXGrabState}, + {"SetEscapeKeysState", SetEscapeKeysState}, + {"ToggleEscapeActive", ToggleEscapeActive}, + {"EscapeDialogDone", EscapeDialogDone}, + {"SetEscapeKeys", SetEscapeKeys} }; @@ -302,11 +942,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" @@ -332,10 +975,287 @@ " -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" + " -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.\n" + "\n" + " Note that scaling is done in software and can be slow\n" + " and requires more memory. \"str\" can also be set by\n" + " the env. var. SSVNC_SCALE.\n" + "\n" + " -ycrop n Only show the top n rows of the framebuffer. For\n" + " use with x11vnc -ncache client caching option\n" + " to help \"hide\" the pixel cache region.\n" + " 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" + " -graball Grab the entire X server when in fullscreen mode,\n" + " needed by some old window managers like fvwm2.\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" + " -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" + " -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/ZRLE: ~ -encodings ...\n" + " Toggle ZRLE/ZYWRLE: ~ -encodings zywrle...\n" + " Quality Level ~ -quality (both Tight and ZYWRLE)\n" + " Compress Level ~ -compresslevel\n" + " Disable JPEG: ~ -nojpeg (Tight)\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" + "\n", programName, programName, programName, programName, programName, programName, programName); exit(1); } +#if 0 + " -nooverride Do not apply OverrideRedirect in fullscreen mode.\n" +#endif /* @@ -347,73 +1267,161 @@ 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")) { + 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_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 (appData.escapeKeys != NULL) { + appData.escapeActive = True; + } + /* 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 (appData.useBGR233 && appData.useBGR565) { + appData.useBGR233 = 0; + } + + 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 (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 2007-03-22 21:36:12.000000000 -0400 @@ -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(); + /* * 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(); + 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); + } + + idx = (b< 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 +643,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 +659,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 +686,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 +cp -p ./vncviewer $HOME/etv_col/Linux.i686 +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 2008-10-29 07:32:30.000000000 -0400 @@ -28,28 +28,473 @@ #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; 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 (fx != NULL) { + *fx = frac_x; + } + if (fy != NULL) { + *fy = frac_y; + } +} + +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) { + create_image(); + return; + } + } + + last_rescale = dnow(); + + SoftCursorLockArea(0, 0, si.framebufferWidth, si.framebufferHeight); + + if (image_scale == NULL) { + /* switching from not scaled */ + int i, start_over = 0; + int Bpl = image->bytes_per_line; + char *dst, *src = image->data; + + image_scale = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, + si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); + + image_scale->data = (char *) malloc(image_scale->bytes_per_line * image_scale->height); + + fprintf(stderr, "rescale_image: switching from not scaled. created image_scale %dx%d\n", image_scale->width, image_scale->height); + fprintf(stderr, "rescale_image: copying image -> image_scale %dx%d -> %dx%d\n", image->width, image->height, image_scale->width, image_scale->height); + + dst = image_scale->data; + + /* copy from image->data */ + for (i=0; i < image->height; i++) { + memcpy(dst, src, Bpl); + dst += Bpl; + src += Bpl; + } + } + + /* now destroy image */ + if (image && image->data) { + if (UsingShm()) { + ShmCleanup(); + } + XDestroyImage(image); + fprintf(stderr, "rescale_image: destroyed 'image'\n"); + image = NULL; + } + if (image_ycrop && image_ycrop->data) { + XDestroyImage(image_ycrop); + fprintf(stderr, "rescale_image: destroyed 'image_ycrop'\n"); + image_ycrop = NULL; + } + + if (frac_x == 1.0 && frac_y == 1.0) { + /* switching to not scaled */ + fprintf(stderr, "rescale_image: switching to not scaled.\n"); + w = si.framebufferWidth; + h = si.framebufferHeight; + + scale_factor_x = 0.0; + scale_factor_y = 0.0; + scale_x = 0; + scale_y = 0; + } else { + w = scale_round(si.framebufferWidth, frac_x); + h = scale_round(si.framebufferHeight, frac_y); + + scale_factor_x = frac_x; + scale_factor_y = frac_y; + scale_x = w; + scale_y = h; + } + + adjust_Xt_win(w, h); + + fprintf(stderr, "rescale: %dx%d %.4f %.4f\n", w, h, scale_factor_x, scale_factor_y); + + try_create_image(); + + if (image && image->data && image_scale && frac_x == 1.0 && frac_y == 1.0) { + /* switched to not scaled */ + int i; + int Bpl = image->bytes_per_line; + char *dst = image->data; + char *src = image_scale->data; + + fprintf(stderr, "rescale_image: switching to not scaled.\n"); + + for (i=0; i < image->height; i++) { + memcpy(dst, src, Bpl); + dst += Bpl; + src += Bpl; + } + XDestroyImage(image_scale); + fprintf(stderr, "rescale_image: destroyed 'image_scale'\n"); + image_scale = NULL; + } + + if (appData.yCrop > 0) { + int ycrop = appData.yCrop; + /* do the top part first so they can see it earlier */ + put_image(0, 0, 0, 0, si.framebufferWidth, ycrop, 0); + if (si.framebufferHeight > ycrop) { + /* this is a big fb and so will take a long time */ + if (waitCursor != None) { + XDefineCursor(dpy, desktopWin, waitCursor); + XSync(dpy, False); + } + put_image(0, 0, 0, 0, si.framebufferWidth, si.framebufferHeight - ycrop, 0); + if (waitCursor != None) { + Xcursors(1); + if (appData.useX11Cursor) { + XSetWindowAttributes attr; + unsigned long valuemask = 0; + if (appData.viewOnly) { + attr.cursor = dotCursor4; + } else { + attr.cursor = dotCursor3; + } + valuemask |= CWCursor; + XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); + } + } + } + } else { + put_image(0, 0, 0, 0, si.framebufferWidth, si.framebufferHeight, 0); + } + + SoftCursorUnlockScreen(); + + fprintf(stderr, "rescale: image_scale=0x%x image=0x%x image_ycrop=0x%x\n", image_scale, image, image_ycrop); + last_rescale = dnow(); + +} + +void try_create_image(void) { + + image_is_shm = 0; + if (appData.useShm) { +#ifdef MITSHM + image = CreateShmImage(0); + if (!image) { + if (appData.yCrop > 0) { + 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); + } + } +} + +void create_image() { + image = NULL; + image_ycrop = NULL; + image_scale = NULL; + + fprintf(stderr, "create_image()\n"); + + if (CreateShmImage(-1) == NULL) { + appData.useShm = False; + } + if (appData.scale != NULL) { + if (appData.useXserverBackingStore) { + fprintf(stderr, "Cannot scale when using X11 backingstore.\n"); + } else { + double frac_x = -1.0, frac_y = -1.0; + + scale_factor_x = 0.0; + scale_factor_y = 0.0; + scale_x = 0; + scale_y = 0; + + get_scale_values(&frac_x, &frac_y); + + if (frac_x < 0.0) { + fprintf(stderr, "Cannot figure out scale factor!\n"); + } else { + int w, h, hyc; + + w = scale_round(si.framebufferWidth, frac_x); + h = scale_round(si.framebufferHeight, frac_y); + hyc = h; + if (appData.yCrop > 0) { + hyc = scale_round(appData.yCrop, frac_y); + } + + /* image scale is full framebuffer */ + image_scale = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, + si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); + + image_scale->data = (char *) malloc(image_scale->bytes_per_line * image_scale->height); + + fprintf(stderr, "create_image: created image_scale %dx%d\n", image_scale->width, image_scale->height); + + if (!image_scale->data) { + fprintf(stderr, "create_image: malloc failed\n"); + XDestroyImage(image_scale); + fprintf(stderr, "create_image: destroyed 'image_scale'\n"); + image_scale = NULL; + } else { + int h2; + scale_factor_x = frac_x; + scale_factor_y = frac_y; + scale_x = w; + scale_y = h; + + XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, hyc, NULL); + + h2 = scale_round(si.framebufferHeight, frac_y); + XtVaSetValues(desktop, XtNwidth, w, XtNheight, h2, NULL); + + } + fprintf(stderr, "create_image: scale: %dx%d %.4f %.4f\n", w, h, + scale_factor_x, scale_factor_y); + } + } + } + try_create_image(); +} + +int old_width = 0; +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.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,91 +504,964 @@ void DesktopInitBeforeRealization() { - int i; + int i; + int h = si.framebufferHeight; + int w = si.framebufferWidth; + double frac_x = 1.0, frac_y = 1.0; + + start_time = dnow(); + + prev_fb_width = si.framebufferWidth; + prev_fb_height = si.framebufferHeight; + + if (appData.scale != NULL) { + get_scale_values(&frac_x, &frac_y); + w = scale_round(w, frac_x); + h = scale_round(h, frac_y); + } - form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel, - XtNborderWidth, 0, - 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; + } + + /* 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; + } + } + + 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 - XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); +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 0) src_x--; + if (src_y > 0) src_y--; + } + for (i=0; i < 4; i++) { + if (src_x + width < xmax) width++; + if (src_y + height < ymax) height++; + } +if (db) fprintf(stderr, "put_image(%d %d %d %d %d %d)\n", src_x, src_y, dst_x, dst_y, width, height); +if (db) fprintf(stderr, "scale_rect(%d %d %d %d)\n", src_x, src_y, width, height); + + scale_rect(scale_factor_x, scale_factor_y, 1, 0, &src_x, &src_y, &width, &height, solid); + dst_x = src_x; + dst_y = src_y; + } + +#ifdef MITSHM + if (appData.useShm) { + double fac = image_scale ? scale_factor_y : 1.0; + if (image_ycrop == NULL) { + 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,41 +1470,392 @@ static void HandleBasicDesktopEvent(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont) { - int i; + int i, x, y, width, height; + static double last_expose = 0.0; + double now = dnow(); - switch (ev->type) { + if (0) { + PR_EXPOSE; + } + + switch (ev->type) { case Expose: case GraphicsExpose: /* 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; } + check_things(); } +extern Position desktopX, desktopY; + +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(); + } + 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 (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; +} /* * SendRFBEvent is an action which sends an RFB event. It can be used in two @@ -201,127 +1870,322 @@ * 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; + + 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 (appData.viewOnly) return; + 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 (appData.escapeKeys != NULL && !strcasecmp(appData.escapeKeys, "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 (do_escape) { + int W = si.framebufferWidth; + int H = si.framebufferHeight; + 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) { + 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) { + 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_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_Left) { + scroll_desktop(-1, 0, 0.1); + } else if (ks == XK_Right) { + scroll_desktop(+1, 0, 0.1); + } else if (ks == XK_Up) { + scroll_desktop(0, +1, 0.1); + } else if (ks == XK_Down) { + scroll_desktop(0, -1, 0.1); + } else if (ks == XK_KP_Left) { + scroll_desktop(-1, 0, 0.0); + } else if (ks == XK_KP_Right) { + scroll_desktop(+1, 0, 0.0); + } else if (ks == XK_KP_Up) { + scroll_desktop(0, +1, 0.0); + } else if (ks == XK_KP_Down) { + scroll_desktop(0, -1, 0.0); + } else if (ks == XK_Next || ks == XK_KP_Next) { + scroll_desktop(0, -1, 1.0); + } else if (ks == XK_Prior || ks == XK_KP_Prior) { + scroll_desktop(0, +1, 1.0); + } else if (ks == XK_End || ks == XK_KP_End) { + scroll_desktop(+1, 0, 1.0); + } else if (ks == XK_Home || ks == XK_KP_Home) { + scroll_desktop(-1, 0, 1.0); + } else if (ks == XK_equal || ks == XK_plus) { + scale_desktop(1, 0.1); + } else if (ks == XK_underscore || ks == XK_minus) { + 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 (*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; - } + XLookupString(&ev->xkey, keyname, 256, &ks, NULL); - switch (ev->type) { + if (IsModifierKey(ks)) { + ks = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0); + modifierPressed[ev->xkey.keycode] = (ev->type == KeyPress); + } - 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); - } + 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 +2193,185 @@ * 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; + return cursor; +} +#endif + +int skip_maybe_sync = 0; +void maybe_sync(int width, int height) { + static int singles = 0; + if (skip_maybe_sync) { + return; + } + if (width > 1 || height > 1) { + XSync(dpy, False); + singles = 0; + } else { + if (++singles >= 32) { + singles = 0; + XSync(dpy, False); + } + } +} +/* + * 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; + } + + 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 +2382,37 @@ 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; + + 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 +2423,297 @@ 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; + int p, q; + int xoff = 7 - (x & 7); + int xcur; + int fbwb = si.framebufferWidth / 8; + XImage *im = image_scale ? image_scale : image; + CARD8 *scr1 = ((CARD8 *)im->data) + y * fbwb + x / 8; + CARD8 *scrt; + CARD8 *scr8 = ( (CARD8 *)im->data) + y * si.framebufferWidth + x; + CARD16 *scr16 = ((CARD16 *)im->data) + y * si.framebufferWidth + x; + CARD32 *scr32 = ((CARD32 *)im->data) + y * si.framebufferWidth + x; + int b0, b1, b2; - switch (visbpp) { + 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; + 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 24: + if (isLSB) { + b0 = 0; b1 = 1; b2 = 2; + } else { + b0 = 2; b1 = 1; b2 = 0; + } + scr8 = ((CARD8 *)im->data) + (y * si.framebufferWidth + x) * 3; + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + CARD32 v = BGR233ToPixel[*(buf++)]; + *(scr8 + b0) = (unsigned char) ((v & 0x0000ff) >> 0); + *(scr8 + b1) = (unsigned char) ((v & 0x00ff00) >> 8); + *(scr8 + b2) = (unsigned char) ((v & 0xff0000) >> 16); + scr8 += 3; + } + scr8 += (si.framebufferWidth - width) * 3; + } + break; + + case 32: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(scr32++) = BGR233ToPixel[*(buf++)]; + } + scr32 += si.framebufferWidth - 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 *scr= (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++)]; + *(scr + b0) = (unsigned char) ((v & 0x0000ff) >> 0); + *(scr + b1) = (unsigned char) ((v & 0x00ff00) >> 8); + *(scr + b2) = (unsigned char) ((v & 0xff0000) >> 16); + scr += 3; + } + scr += (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; + CARD32 *scr32 = ((CARD32 *)im->data) + y * si.framebufferWidth + 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++) { + *(scr32++) = BGR565ToPixel[*(buf++)]; + } + scr32 += si.framebufferWidth - width; + } +} + +static void reset_image(void) { + if (UsingShm()) { + ShmCleanup(); + } + if (image && image->data) { + XDestroyImage(image); + fprintf(stderr, "reset_image: destroyed 'image'\n"); + } + image = NULL; + if (image_ycrop && image_ycrop->data) { + XDestroyImage(image_ycrop); + fprintf(stderr, "reset_image: destroyed 'image_ycrop'\n"); + } + image_ycrop = NULL; + if (image_scale && image_scale->data) { + XDestroyImage(image_scale); + fprintf(stderr, "reset_image: destroyed 'image_scale'\n"); + } + image_scale = NULL; + + create_image(); + XFlush(dpy); +} + +void ReDoDesktop(void) { + int w, w0, h, h0, x, y, dw, dh; + int fs = 0; + int autoscale = 0; + + if (!appData.fullScreen && appData.scale != NULL && !strcmp(appData.scale, "auto")) { + autoscale = 1; + } + + fprintf(stderr, "ReDoDesktop: ycrop: %d\n", appData.yCrop); + + 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); + + x = (dpyWidth - w - dw)/2; + y = (dpyHeight - h - dh)/2; + + 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); + } + + if (!autoscale) { + XtConfigureWidget(toplevel, x + dw, y + dh, w, h, 0); + } + + reset_image(); + + if (fs) { + FullScreenOn(); + } } diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncviewer/dialogs.c --- vnc_unixsrc.orig/vncviewer/dialogs.c 2000-10-26 15:19:19.000000000 -0400 +++ vnc_unixsrc/vncviewer/dialogs.c 2008-10-29 08:04:15.000000000 -0400 @@ -26,6 +26,393 @@ static Bool serverDialogDone = 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); + +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)); + } +} + +char * +DoScaleDialog() +{ + Widget pshell, dialog; + char *scaleValue; + char *valueString; + + pshell = XtVaCreatePopupShell("scaleDialog", transientShellWidgetClass, + toplevel, NULL); + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + + dialog_over(pshell); + + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (appData.scale != NULL) { + String label; + char tmp[410]; + XtVaGetValues(dialog, XtNlabel, &label, NULL); + if (strlen(label) + strlen(appData.scale) < 400) { + sprintf(tmp, "%s %s", label, appData.scale); + XtVaSetValues(dialog, XtNlabel, tmp, NULL); + } + } + + + if (appData.popupFix) { + popupFixer(pshell); + } + dialog_input(pshell); + 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); + + 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); + } + 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); + + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (appData.popupFix) { + popupFixer(pshell); + } + dialog_input(pshell); + 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); + + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (appData.popupFix) { + popupFixer(pshell); + } + dialog_input(pshell); + 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()"); + + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (appData.popupFix) { + popupFixer(pshell); + } + dialog_input(pshell); + 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); + + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (appData.popupFix) { + popupFixer(pshell); + } + dialog_input(pshell); + 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); + + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, + HeightOfScreen(XtScreen(pshell))*2/5); + XtPopup(pshell, XtGrabNonexclusive); + XtRealizeWidget(pshell); + + if (appData.popupFix) { + popupFixer(pshell); + } + dialog_input(pshell); + 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) @@ -44,11 +431,19 @@ toplevel, NULL); dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + dialog_over(pshell); + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); XtPopup(pshell, XtGrabNonexclusive); XtRealizeWidget(pshell); + if (appData.popupFix) { + popupFixer(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "ServerDialogDone()"); + serverDialogDone = False; while (!serverDialogDone) { @@ -56,6 +451,7 @@ } valueString = XawDialogGetValueString(dialog); + rmNL(valueString); vncServerName = XtNewString(valueString); XtPopdown(pshell); @@ -80,11 +476,19 @@ toplevel, NULL); dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); + dialog_over(pshell); + XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); XtPopup(pshell, XtGrabNonexclusive); XtRealizeWidget(pshell); + if (appData.popupFix) { + popupFixer(pshell); + } + dialog_input(pshell); + wm_delete(pshell, "PasswordDialogDone()"); + passwordDialogDone = False; while (!passwordDialogDone) { @@ -92,6 +496,7 @@ } valueString = XawDialogGetValueString(dialog); + rmNL(valueString); password = XtNewString(valueString); XtPopdown(pshell); 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 2008-10-05 15:16:24.000000000 -0400 @@ -30,6 +30,18 @@ #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); \ + } \ + } + static Bool HandleHextileBPP (int rx, int ry, int rw, int rh) { @@ -66,14 +78,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 +124,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 +150,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 +174,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 +186,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 2008-09-26 15:43:23.000000000 -0400 @@ -32,6 +32,7 @@ #define FLASHDELAY 1 /* seconds */ Bool listenSpecified = False; +pid_t listenParent = 0; int listenPort = 0, flashPort = 0; static Font flashFont; @@ -58,8 +59,11 @@ int n; int i; char *displayname = NULL; + 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 +112,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 +153,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 +184,48 @@ } 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"); + + 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; + } + totalconn++; XCloseDisplay(d); @@ -170,18 +240,23 @@ case 0: /* child - return to caller */ close(listenSocket); - close(flashSocket); +// close(flashSocket); 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 +275,13 @@ char **fontNames; int nFontNames; +#if 1 + + /* no longer used */ + return; + +#else + sprintf(fontName,"-*-courier-bold-r-*-*-%d-*-*-*-*-*-iso8859-1", FLASHWIDTH); fontNames = XListFonts(d, fontName, 1, &nFontNames); @@ -209,6 +291,9 @@ sprintf(fontName,"fixed"); } flashFont = XLoadFont(d, fontName); + +#endif + } @@ -222,6 +307,11 @@ Window w1, w2, w3, w4; XSetWindowAttributes attr; +#if 1 + /* no longer used */ + return; +#else + XBell(d, 0); XForceScreenSaver(d, ScreenSaverReset); @@ -284,6 +374,9 @@ XDestroyWindow(d, w3); XDestroyWindow(d, w4); XFlush(d); + +#endif + } /* diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/misc.c vnc_unixsrc/vncviewer/misc.c --- vnc_unixsrc.orig/vncviewer/misc.c 2003-01-15 02:58:32.000000000 -0500 +++ vnc_unixsrc/vncviewer/misc.c 2008-10-14 22:32:04.000000000 -0400 @@ -33,12 +33,14 @@ Dimension dpyWidth, dpyHeight; Atom wmDeleteWindow, wmState; +int fullscreen_startup = 0; static Bool xloginIconified = False; static XErrorHandler defaultXErrorHandler; static XIOErrorHandler defaultXIOErrorHandler; static XtErrorHandler defaultXtErrorHandler; +int XError_ign = 0; /* * ToplevelInitBeforeRealization sets the title, geometry and other resources @@ -48,87 +50,103 @@ void ToplevelInitBeforeRealization() { - char *titleFormat; - char *title; - char *geometry; - - XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL); - title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1); - sprintf(title, titleFormat, desktopName); - XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL); - - XtVaSetValues(toplevel, XtNmaxWidth, si.framebufferWidth, - XtNmaxHeight, si.framebufferHeight, NULL); - - dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); - dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); - - if (appData.fullScreen) { - - /* full screen - set position to 0,0, but defer size calculation until - widgets are realized */ - - XtVaSetValues(toplevel, XtNoverrideRedirect, True, - XtNgeometry, "+0+0", NULL); - - } else { - - /* not full screen - work out geometry for middle of screen unless - specified by user */ - - XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL); - - if (geometry == NULL) { - Dimension toplevelX, toplevelY; - Dimension toplevelWidth = si.framebufferWidth; - Dimension toplevelHeight = si.framebufferHeight; - - if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) - toplevelWidth = dpyWidth - appData.wmDecorationWidth; - - if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) - toplevelHeight = dpyHeight - appData.wmDecorationHeight; - - toplevelX = (dpyWidth - toplevelWidth - appData.wmDecorationWidth) / 2; - - toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2; - - /* set position via "geometry" so that window manager thinks it's a - user-specified position and therefore honours it */ - - geometry = XtMalloc(256); - - sprintf(geometry, "%dx%d+%d+%d", - toplevelWidth, toplevelHeight, toplevelX, toplevelY); - XtVaSetValues(toplevel, XtNgeometry, geometry, NULL); - } - } + char *titleFormat; + char *title; + char *geometry; + int h = si.framebufferHeight; + int w = si.framebufferWidth; + + check_tall(); + if (appData.yCrop < 0) { + appData.yCrop = guessCrop(); + fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop); + if (appData.yCrop > 0) { + h = appData.yCrop; + } + } + + XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL); + title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1); + sprintf(title, titleFormat, desktopName); + XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL); + + if (appData.scale != NULL) { + /* switched to not scaled */ + double frac_x, frac_y; + get_scale_values(&frac_x, &frac_y); + if (frac_x > 0.0) { + w = scale_round(w, frac_x); + h = scale_round(h, frac_y); + } + } + XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL); + + dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); + dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); + + if (appData.fullScreen) { + /* full screen - set position to 0,0, but defer size calculation until widgets are realized */ + + if (!net_wm_supported()) { + XtVaSetValues(toplevel, XtNoverrideRedirect, True, XtNgeometry, "+0+0", NULL); + } else { + fullscreen_startup = 1; + } + + } else { + + /* not full screen - work out geometry for middle of screen unless specified by user */ + + XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL); + + if (geometry == NULL) { + Dimension toplevelX, toplevelY; + Dimension toplevelWidth = w; + Dimension toplevelHeight = h; + + if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) { + toplevelWidth = dpyWidth - appData.wmDecorationWidth; + } + + if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) { + toplevelHeight = dpyHeight - appData.wmDecorationHeight; + } + + toplevelX = (dpyWidth - toplevelWidth - appData.wmDecorationWidth) / 2; + toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2; + + /* set position via "geometry" so that window manager thinks it's a + user-specified position and therefore honours it */ + + geometry = XtMalloc(256); + + sprintf(geometry, "%dx%d+%d+%d", toplevelWidth, toplevelHeight, toplevelX, toplevelY); + fprintf(stderr, "geometry: %s ycrop: %d\n", geometry, appData.yCrop); + XtVaSetValues(toplevel, XtNgeometry, geometry, NULL); + } + } /* Test if the keyboard is grabbed. If so, it's probably because the XDM login window is up, so try iconifying it to release the grab */ - if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync, - GrabModeSync, CurrentTime) == GrabSuccess) { - XUngrabKeyboard(dpy, CurrentTime); - } else { - wmState = XInternAtom(dpy, "WM_STATE", False); - - if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) { - xloginIconified = True; - XSync(dpy, False); - sleep(1); - } - } - - /* Set handlers for signals and X errors to perform cleanup */ - - signal(SIGHUP, CleanupSignalHandler); - signal(SIGINT, CleanupSignalHandler); - signal(SIGTERM, CleanupSignalHandler); - defaultXErrorHandler = XSetErrorHandler(CleanupXErrorHandler); - defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler); - defaultXtErrorHandler = XtAppSetErrorHandler(appContext, - CleanupXtErrorHandler); + if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync, GrabModeSync, CurrentTime) == GrabSuccess) { + XUngrabKeyboard(dpy, CurrentTime); + } else { + wmState = XInternAtom(dpy, "WM_STATE", False); + if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) { + xloginIconified = True; + XSync(dpy, False); + sleep(1); + } + } + + /* Set handlers for signals and X errors to perform cleanup */ + signal(SIGHUP, CleanupSignalHandler); + signal(SIGINT, CleanupSignalHandler); + signal(SIGTERM, CleanupSignalHandler); + defaultXErrorHandler = XSetErrorHandler(CleanupXErrorHandler); + defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler); + defaultXtErrorHandler = XtAppSetErrorHandler(appContext, CleanupXtErrorHandler); } @@ -141,14 +159,22 @@ void ToplevelInitAfterRealization() { - if (appData.fullScreen) { - FullScreenOn(); - } - - wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1); - XtOverrideTranslations - (toplevel, XtParseTranslationTable ("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 +183,7 @@ * CurrentTime if the event has no time field. */ -Time -TimeFromEvent(XEvent *ev) -{ +Time TimeFromEvent(XEvent *ev) { switch (ev->type) { case KeyPress: case KeyRelease: @@ -192,18 +216,15 @@ * generated by SendRFBEvent. */ -void -Pause(Widget w, XEvent *event, String *params, Cardinal *num_params) -{ - int msec; +void Pause(Widget w, XEvent *event, String *params, Cardinal *num_params) { + int msec; - if (*num_params == 0) { - msec = 100; - } else { - msec = atoi(params[0]); - } - - usleep(msec * 1000); + if (*num_params == 0) { + msec = 100; + } else { + msec = atoi(params[0]); + } + usleep(msec * 1000); } @@ -264,11 +285,9 @@ * Quit action - called when we get a "delete window" message. */ -void -Quit(Widget w, XEvent *event, String *params, Cardinal *num_params) -{ - Cleanup(); - exit(0); +void Quit(Widget w, XEvent *event, String *params, Cardinal *num_params) { + Cleanup(); + exit(0); } @@ -276,49 +295,90 @@ * Cleanup - perform any cleanup operations prior to exiting. */ -void -Cleanup() -{ - if (xloginIconified) { - IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True); - XFlush(dpy); - } +void Cleanup() { + + if (appData.chatActive) { + appData.chatActive = False; + fprintf(stderr,"Sending SendTextChatClose()\n"); + SendTextChatClose(); + SendTextChatFinished(); + } + + if (xloginIconified) { + IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True); + XFlush(dpy); + } #ifdef MITSHM - if (appData.useShm) - ShmCleanup(); + if (appData.useShm) { + ShmCleanup(); + } #endif + + releaseAllPressedModifiers(); + + fprintf(stderr,"\nVNC Viewer exiting.\n\n"); + if (listenSpecified) { + if (listenParent != 0 && getenv("SSVNC_LISTEN_ONCE") && listenParent != getpid()) { + fprintf(stderr, "SSVNC_LISTEN_ONCE: Trying to kill Listening Parent: %d\n", (int) listenParent); + fprintf(stderr, "SSVNC_LISTEN_ONCE: Press Ctrl-C if it continues to Listen.\n\n"); + kill(listenParent, SIGTERM); + } else { + fprintf(stderr,"(NOTE: You may need to Press Ctrl-C to make the Viewer Stop Listening.)\n\n"); + } + } +} + +static void check_dbg(void) { + if (getenv("SSVNC_EXIT_DEBUG")) { + fprintf(stderr, "Press any key to continue: "); + getc(stdin); + } } static int CleanupXErrorHandler(Display *dpy, XErrorEvent *error) { - fprintf(stderr,"CleanupXErrorHandler called\n"); - Cleanup(); - return (*defaultXErrorHandler)(dpy, error); + if (XError_ign) { + char str[4096]; + XError_ign++; + fprintf(stderr,"XError_ign called.\n"); + str[0] = '\0'; + if (XGetErrorText(dpy, error->error_code, str, 4096)) { + fprintf(stderr, "%s", str); + } + return; + } + fprintf(stderr,"CleanupXErrorHandler called\n"); + check_dbg(); + Cleanup(); + return (*defaultXErrorHandler)(dpy, error); } static int CleanupXIOErrorHandler(Display *dpy) { - fprintf(stderr,"CleanupXIOErrorHandler called\n"); - Cleanup(); - return (*defaultXIOErrorHandler)(dpy); + fprintf(stderr,"CleanupXIOErrorHandler called\n"); + check_dbg(); + Cleanup(); + return (*defaultXIOErrorHandler)(dpy); } static void CleanupXtErrorHandler(String message) { - fprintf(stderr,"CleanupXtErrorHandler called\n"); - Cleanup(); - (*defaultXtErrorHandler)(message); + fprintf(stderr,"CleanupXtErrorHandler called\n"); + check_dbg(); + Cleanup(); + (*defaultXtErrorHandler)(message); } static void CleanupSignalHandler(int sig) { - fprintf(stderr,"CleanupSignalHandler called\n"); - Cleanup(); - exit(1); + fprintf(stderr,"CleanupSignalHandler called\n"); + check_dbg(); + Cleanup(); + exit(1); } diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup.c vnc_unixsrc/vncviewer/popup.c --- vnc_unixsrc.orig/vncviewer/popup.c 2000-06-11 08:00:53.000000000 -0400 +++ vnc_unixsrc/vncviewer/popup.c 2008-10-26 15:52:08.000000000 -0400 @@ -25,22 +25,56 @@ #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 +86,544 @@ }; 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 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); +} 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 2008-10-15 08:00:20.000000000 -0400 @@ -23,6 +23,7 @@ * rfbproto.c - functions to deal with client side of RFB protocol. */ +#include #include #include #include @@ -57,6 +58,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 +106,13 @@ static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, int compressedLen); +extern int currentMsg; +extern double scale_factor_x; +extern double scale_factor_y; + +int sent_FBU = 0; +int skip_XtUpdate = 0; +int skip_XtUpdateAll = 0; int rfbsock; char *desktopName; @@ -177,6 +223,9 @@ 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"); } @@ -187,21 +236,117 @@ 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; - } - - rfbsock = ConnectToTcpAddr(host, port); + 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; + } + } + } - if (rfbsock < 0) { - fprintf(stderr,"Unable to connect to VNC server\n"); - return False; - } + if (cmd != NULL) { + int sfd[2]; + char *q, *cmd2 = strdup(cmd); + pid_t pid; + + q = strstr(cmd2, "pw="); + if (q) { + q += strlen("pw="); + while (*q != '\0' && !isspace(*q)) { + *q = '*'; + q++; + } + } + + fprintf(stderr, "exec-cmd: %s\n", cmd2); + free(cmd2); + + if (! SocketPair(sfd)) { + return False; + } + 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) { + fprintf(stderr,"Unable to connect to exec'd command: %s\n", cmd); + return False; + } + } else if (strstr(hostname, "fd=") == hostname) { + rfbsock = atoi(hostname + strlen("fd=")); + } else if (strchr(hostname, '/') && stat(hostname, &sb) == 0) { + /* assume unix domain socket */ + char *thost = strdup(hostname); + + rfbsock = ConnectToUnixSocket(thost); + free(thost); + + if (rfbsock < 0) { + fprintf(stderr,"Unable to connect to VNC server (unix-domain socket: %s)\n", hostname); + return False; + } + + } else { + if (!StringToIPAddr(hostname, &host)) { + fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname); + return False; + } + + rfbsock = ConnectToTcpAddr(host, port); + + if (rfbsock < 0) { + fprintf(stderr,"Unable to connect to VNC server (%s:%d)\n", hostname, port); + return False; + } + } - return SetNonBlocking(rfbsock); + setnb = SetNonBlocking(rfbsock); + return setnb; } @@ -212,211 +357,307 @@ Bool InitialiseRFBConnection(void) { - rfbProtocolVersionMsg pv; - int server_major, server_minor; - int viewer_major, viewer_minor; - rfbClientInitMsg ci; - int secType; + rfbProtocolVersionMsg pv; + int server_major, server_minor; + int viewer_major, viewer_minor; + rfbClientInitMsg ci; + int secType; - /* 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; + if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) { + return False; + } - errorMessageOnReadFailure = True; + errorMessageOnReadFailure = True; - pv[sz_rfbProtocolVersionMsg] = 0; + pv[sz_rfbProtocolVersionMsg] = 0; - if (sscanf(pv, rfbProtocolVersionFormat, - &server_major, &server_minor) != 2) { - fprintf(stderr,"Not a valid VNC server\n"); - 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) { + fprintf(stderr, "\n"); + fprintf(stderr, "***************************************************************\n"); + fprintf(stderr, "To work around UltraVNC SC III SSL dropping after a few minutes\n"); + fprintf(stderr, "you may need to set STUNNEL_EXTRA_OPTS_USER='options = ALL'.\n"); + fprintf(stderr, "***************************************************************\n"); + fprintf(stderr, "\n"); + } + if (strstr(pv, "ID:") == pv) { + goto check_ID_string; + } + if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) == 2) { + goto ultra_vnc_nonsense; + } + } + fprintf(stderr,"Not a valid VNC server: '%s'\n", pv); + return False; + } - 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; - } + 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) { + fprintf(stderr,"Not a valid VNC server: '%s'\n", pv); + return False; + } + } - fprintf(stderr, "Connected to RFB server, using protocol version %d.%d\n", - viewer_major, viewer_minor); + ultra_vnc_nonsense: + fprintf(stderr,"Proto: %s\n", pv); - sprintf(pv, rfbProtocolVersionFormat, viewer_major, viewer_minor); + viewer_major = rfbProtocolMajorVersion; - if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) - return False; + if (appData.rfbVersion != NULL && sscanf(appData.rfbVersion, "%d.%d", &viewer_major, &viewer_minor) == 2) { + fprintf(stderr,"Setting RFB version to %d.%d from -rfbversion.\n", viewer_major, viewer_minor); + } else if (getenv("SSVNC_RFB_VERSION") != NULL && sscanf(getenv("SSVNC_RFB_VERSION"), "%d.%d", &viewer_major, &viewer_minor) == 2) { + fprintf(stderr,"Setting RFB version to %d.%d from SSVNC_RFB_VERSION.\n", viewer_major, viewer_minor); + } else if (server_major == 3 && (server_minor == 14 || server_minor == 16)) { + /* hack for UltraVNC Single Click. They misuse rfb proto version */ + fprintf(stderr,"Setting RFB version to 3.3 for UltraVNC Single Click.\n"); + viewer_minor = rfbProtocolFallbackMinorVersion; + } else 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; + } - /* Read or select the security type. */ - if (viewer_minor == rfbProtocolMinorVersion) { - secType = SelectSecurityType(); - } else { - secType = ReadSecurityType(); - } - if (secType == rfbSecTypeInvalid) - return False; + fprintf(stderr, "\nConnected to RFB server, using protocol version %d.%d\n", viewer_major, viewer_minor); - 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; - } + sprintf(pv, rfbProtocolVersionFormat, viewer_major, viewer_minor); - ci.shared = (appData.shareDesktop ? 1 : 0); + if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) { + return False; + } - if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) - return False; + /* Read or select the security type. */ + if (viewer_minor == rfbProtocolMinorVersion) { + secType = SelectSecurityType(); + } else { + secType = ReadSecurityType(); + } + if (secType == rfbSecTypeInvalid) { + return False; + } - if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) - return False; + switch (secType) { + case rfbSecTypeNone: + fprintf(stderr, "No authentication needed\n\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; + } - 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; - } + ci.shared = (appData.shareDesktop ? 1 : 0); - if (!ReadFromRFBServer(desktopName, si.nameLength)) return False; + if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) { + return False; + } - desktopName[si.nameLength] = 0; + if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) { + return False; + } - fprintf(stderr,"Desktop name \"%s\"\n",desktopName); + 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; + } - fprintf(stderr,"VNC server default format:\n"); - PrintPixelFormat(&si.format); + /* 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 (tightVncProtocol) { - /* Read interaction capabilities (protocol 3.7t) */ - if (!ReadInteractionCaps()) - return False; - } + if (!ReadFromRFBServer(desktopName, si.nameLength)) { + return False; + } - return True; + desktopName[si.nameLength] = 0; + + fprintf(stderr,"Desktop name \"%s\"\n\n", desktopName); + + fprintf(stderr,"VNC server default format:\n"); + 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; + } - 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 && secType != rfbSecTypeVncAuth) { + fprintf(stderr, "Unknown security type from RFB server: %d\n", + (int)secType); + 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 secutiry types. */ + if (!ReadFromRFBServer((char *)&nSecTypes, sizeof(nSecTypes))) { + return rfbSecTypeInvalid; + } - 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; + } + + /* 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; + } + } + + /* 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; + } + } - free(secTypes); + free(secTypes); - if (secType == rfbSecTypeInvalid) - fprintf(stderr, "Server did not offer supported security type\n"); + if (secType == rfbSecTypeInvalid) { + fprintf(stderr, "Server did not offer supported security type\n"); + } - return (int)secType; + return (int)secType; } @@ -451,6 +692,9 @@ return True; } +static char *restart_session_pw = NULL; +static int restart_session_len = 0; + /* * Negotiate authentication scheme (protocol version 3.7t) @@ -459,56 +703,61 @@ 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 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; + } + } - fprintf(stderr, "No suitable authentication schemes offered by server\n"); - return False; + fprintf(stderr, "No suitable authentication schemes offered by server\n"); + return False; } @@ -519,80 +768,100 @@ 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 (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 (restart_session_pw != NULL) { + passwd = restart_session_pw; + restart_session_pw = NULL; + restart = 1; + } else 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 (getenv("VNCVIEWER_PASSWORD")) { + passwd = strdup(getenv("VNCVIEWER_PASSWORD")); + putenv("VNCVIEWER_PASSWORD=none"); + } else if (appData.passwordDialog) { + passwd = DoPasswordDialog(); + } else { + passwd = getpass("VNC Password: "); + } - 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) { + fprintf(stderr, "Reading password failed\n\n"); + 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)); +// /* Lose the password from memory */ +// memset(passwd, '\0', strlen(passwd)); - if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) - return False; + if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) { + return False; + } - if (!ReadFromRFBServer((char *)&authResult, 4)) - return False; + if (!ReadFromRFBServer((char *)&authResult, 4)) { + return False; + } - authResult = Swap32IfLE(authResult); + authResult = Swap32IfLE(authResult); - 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; - } + switch (authResult) { + case rfbVncAuthOK: + fprintf(stderr, "VNC authentication succeeded\n\n"); + break; + case rfbVncAuthFailed: + fprintf(stderr, "VNC authentication failed\n\n"); + return False; + case rfbVncAuthTooMany: + fprintf(stderr, "VNC authentication failed - too many tries\n\n"); + return False; + default: + fprintf(stderr, "Unknown VNC authentication result: %d\n\n", + (int)authResult); + return False; + } - return True; + return True; } /* @@ -602,68 +871,71 @@ 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) { + passwd = DoPasswordDialog(); + } else { + 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: + fprintf(stderr, "Authentication failed\n\n"); + return False; + case rfbVncAuthTooMany: + fprintf(stderr, "Authentication failed - too many tries\n\n"); + return False; + default: + fprintf(stderr, "Unknown authentication result: %d\n\n", + (int)authResult); + return False; + } - return True; + return True; } @@ -675,19 +947,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,17 +973,18 @@ 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; } @@ -729,6 +1003,11 @@ Bool requestCompressLevel = False; Bool requestQualityLevel = False; Bool requestLastRectEncoding = False; + Bool requestNewFBSizeEncoding = True; + Bool requestTextChatEncoding = True; + int dsm = 0; + +// fprintf(stderr, "SetFormatAndEncodings: sent_FBU state: %2d\n", sent_FBU); spf.type = rfbSetPixelFormat; spf.format = myFormat; @@ -736,12 +1015,18 @@ 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; @@ -754,11 +1039,17 @@ 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) @@ -767,16 +1058,33 @@ requestQualityLevel = True; } 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) { + } 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) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZYWRLE); + requestQualityLevel = True; + if (appData.qualityLevel < 3) { + zywrle_level = 3; + } else if (appData.qualityLevel < 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; @@ -797,7 +1105,7 @@ 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 +1114,14 @@ if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) { encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect); } + + if (se->nEncodings < MAX_ENCODINGS && requestNewFBSizeEncoding) { + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingNewFBSize); + } } else { if (SameMachine(rfbsock)) { - if (!tunnelSpecified) { + if (!tunnelSpecified && appData.useRawLocal) { fprintf(stderr,"Same machine: preferring raw encoding\n"); encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw); } else { @@ -818,13 +1130,15 @@ } 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) { + if (!dsm && appData.compressLevel >= 0 && appData.compressLevel <= 9) { encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0); } else if (!tunnelSpecified) { @@ -835,7 +1149,7 @@ encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCompressLevel1); } - if (appData.enableJPEG) { + if (!dsm && appData.enableJPEG) { if (appData.qualityLevel < 0 || appData.qualityLevel > 9) appData.qualityLevel = 5; encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + @@ -844,18 +1158,35 @@ 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 +1199,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; - 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 < 0) { + if (getenv("SSVNC_DEBUG_RECTS")) { + db = atoi(getenv("SSVNC_DEBUG_RECTS")); + } else { + db = 0; + } + } - if (!WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg)) - return False; + if (db) fprintf(stderr, "SendFramebufferUpdateRequest(%d, %d, %d, %d, incremental=%d)\n", x, y, w, h, (int) incremental); - return True; + 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 (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 +1289,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 (scale_factor_x > 0.0 && scale_factor_x != 1.0) { + x /= scale_factor_x; + } + if (scale_factor_y > 0.0 && scale_factor_y != 1.0) { + y /= scale_factor_y; + } + + if (x < 0) x = 0; + if (y < 0) y = 0; + + if (!appData.useX11Cursor) { + SoftCursorMove(x, y); + } - pe.type = rfbPointerEvent; - pe.buttonMask = buttonMask; - 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.x = Swap16IfLE(x); + pe.y = Swap16IfLE(y); + currentMsg = rfbPointerEvent; + return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg); } @@ -926,12 +1329,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 +1353,943 @@ Bool SendClientCutText(char *str, int len) { - rfbClientCutTextMsg cct; + rfbClientCutTextMsg cct; - if (serverCutText) - free(serverCutText); - serverCutText = NULL; - - cct.type = rfbClientCutText; - cct.length = Swap32IfLE(len); - return (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) && - WriteExact(rfbsock, str, len)); + 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; + } + + 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) { + + } - /* If RichCursor encoding is used, we should prevent collisions - between framebuffer updates and cursor drawing operations. */ - SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h); + len = (hdr[8] << 24) | (hdr[9] << 16) | (hdr[10] << 8) | hdr[11]; + if (db) fprintf(stderr, "Got rfbFileTransfer: len1 %u\n", len); + if (len > 0) { + 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); + } + } - switch (rect.encoding) { + len = (hdr[4] << 24) | (hdr[5] << 16) | (hdr[6] << 8) | hdr[7]; + if (db) fprintf(stderr, "Got rfbFileTransfer: len2 %u\n", len); - case rfbEncodingRaw: +#if 0 + if (hdr[1] == rfbFileHeader && len != rfbRErrorCmd) +#else + // the extra 4 bytes get send on rfbRErrorCmd as well. + if (hdr[1] == rfbFileHeader) { +#endif + int is_err = 0; + if (len == rfbRErrorCmd) { + is_err = 1; + } + if (db) fprintf(stderr, "Got rfbFileTransfer: rfbFileHeader\n"); + if (is_err && guess_x11vnc) { + fprintf(stderr, "rfbRErrorCmd x11vnc skip read 4 bytes.\n"); + goto read_no_more; + } + len = 4; + if (!ReadFromRFBServer(fxfer, len)) { + skip_XtUpdateAll = 0; + 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); + } + } - bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; - linesToRead = BUFFER_SIZE / bytesPerLine; + read_no_more: - while (rect.r.h > 0) { - if (linesToRead > rect.r.h) - linesToRead = rect.r.h; + if (filexfer_sock < 0) { + int stop = 0; + static time_t last_stop = 0; +#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); + } + } - if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) - return False; + if (db) fprintf(stderr, "Got rfbFileTransfer done.\n"); + skip_XtUpdateAll = 0; - CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, - linesToRead); + if (db) fprintf(stderr, "CFX: B\n"); + CheckFileXfer(); +//fprintf(stderr, "Out HandleFileXfer\n"); + return True; +} + +/* + * HandleRFBServerMessage. + */ - rect.r.h -= linesToRead; - rect.r.y += linesToRead; - } - break; +Bool +HandleRFBServerMessage() +{ + static int db = -1; + rfbServerToClientMsg msg; - 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 (db < 0) { + if (getenv("DEBUG_RFB_SMSG")) { + db = 1; + } else { + db = 0; + } } - XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY, - rect.r.w, rect.r.h, rect.r.x, rect.r.y); + if (!ReadFromRFBServer((char *)&msg, 1)) { + return False; + } + if (appData.ultraDSM) { + if (!ReadFromRFBServer((char *)&msg, 1)) { + return False; + } + } - break; - } +//fprintf(stderr, "msg.type: %d\n", msg.type); - 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 (msg.type == rfbFileTransfer) { + return HandleFileXfer(); } - 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; + switch (msg.type) { + + case rfbSetColourMapEntries: + { + int i; + CARD16 rgb[3]; + XColor xc; + + if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbSetColourMapEntriesMsg - 1)) { + return False; } - 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; + 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 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; + 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; + + 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; - } - 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; + int skip_incFBU = 0; + sent_FBU = -1; + + 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(); - } + 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 (rect.encoding == rfbEncodingXCursor || rect.encoding == rfbEncodingRichCursor) { + 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) { + 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) { + 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); + + 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; + + 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 +2297,165 @@ 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 + { + XSync(dpy, False); + } + + if (skip_XtUpdate || skip_incFBU) { + ; + } else if (!SendIncrementalFramebufferUpdateRequest()) { + return False; + } - if (!SendIncrementalFramebufferUpdateRequest()) - return False; - - break; + break; } case rfbBell: { - Window toplevelWin; + Window toplevelWin; - XBell(dpy, 0); + if (appData.useBell) { + 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 +2475,47 @@ #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; + #define BPP 8 #include "rre.c" #include "corre.c" #include "hextile.c" #include "zlib.c" #include "tight.c" +#include "zrle.c" #undef BPP + #define BPP 16 #include "rre.c" #include "corre.c" #include "hextile.c" #include "zlib.c" #include "tight.c" +#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" #include "tight.c" +#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 /* @@ -1358,9 +2558,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 +2662,3 @@ cinfo->src = &jpegSrcManager; } - diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rre.c vnc_unixsrc/vncviewer/rre.c --- vnc_unixsrc.orig/vncviewer/rre.c 2000-06-11 08:00:53.000000000 -0400 +++ vnc_unixsrc/vncviewer/rre.c 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/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 2008-10-10 12:26:07.000000000 -0400 @@ -33,68 +33,97 @@ void ShmCleanup() { - fprintf(stderr,"ShmCleanup called\n"); - if (needShmCleanup) { - shmdt(shminfo.shmaddr); - shmctl(shminfo.shmid, IPC_RMID, 0); - needShmCleanup = False; - } + fprintf(stderr,"ShmCleanup called\n"); + if (needShmCleanup) { + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + needShmCleanup = False; + } +} + +Bool UsingShm() { + return needShmCleanup; } static int ShmCreationXErrorHandler(Display *dpy, XErrorEvent *error) { - caughtShmError = True; - return 0; + caughtShmError = True; + return 0; } +int scale_round(int len, double fac); +extern int scale_x, scale_y; +extern double scale_factor_x, scale_factor_y; + XImage * -CreateShmImage() +CreateShmImage(int do_ycrop) { - 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); - - 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; - } - - shminfo.readOnly = True; - - oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler); - XShmAttach(dpy, &shminfo); - XSync(dpy, False); - XSetErrorHandler(oldXErrorHandler); - - if (caughtShmError) { - XDestroyImage(image); - shmdt(shminfo.shmaddr); - shmctl(shminfo.shmid, IPC_RMID, 0); - return NULL; - } + 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 2008-10-15 08:30:41.000000000 -0400 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -56,22 +57,366 @@ */ 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 +xfrsockReadyCallback(XtPointer clientData, int *fd, XtInputId *id) +{ + 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; + static void ProcessXtEvents() { - rfbsockReady = False; - XtAppAddInput(appContext, rfbsock, (XtPointer)XtInputReadMask, - rfbsockReadyCallback, NULL); - while (!rfbsockReady) { - XtAppProcessEvent(appContext, XtIMAll); - } + 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 @@ -151,6 +496,8 @@ } +int currentMsg = -1; + /* * Write an exact number of bytes, and don't return until you've sent them. */ @@ -158,37 +505,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 +594,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 +625,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 +653,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 +682,8 @@ * ListenAtTcpPort starts listening at the given TCP port. */ +int use_loopback = 0; + int ListenAtTcpPort(int port) { @@ -279,10 +691,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); 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/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/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 2008-10-29 08:24:43.000000000 -0400 @@ -0,0 +1,717 @@ +'\" 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-2008 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 "October 2008" "" "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. 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\-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. +Note that scaling is done in software and can be slow +and requires more memory. "str" can also be set by +the env. var. SSVNC_SCALE. +.TP +\fB\-ycrop\fR n +Only show the top n rows of the framebuffer. For +use with x11vnc \fB\-ncache\fR client caching option +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\-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\-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\-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'. + +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/ZRLE: ~ -encodings ... + Toggle ZRLE/ZYWRLE: ~ -encodings zywrle... + Quality Level ~ -quality (both Tight and ZYWRLE) + Compress Level ~ -compresslevel + Disable JPEG: ~ -nojpeg (Tight) + Full Color ~ as many colors as local screen allows. + Grey scale (16 & 8-bpp) ~ -grey, for low colors 16/8bpp modes. + 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 a single window. + (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. + +.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. + +\fBMan page authors:\fR +.br +Marcus Brinkmann , +.br +Terran Melconian , +.br +Tim Waugh , +.br +Constantin Kaplinsky +.br +Karl 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 2008-10-27 10:28:50.000000000 -0400 @@ -22,6 +22,7 @@ */ #include "vncviewer.h" +#include char *programName; XtAppContext appContext; @@ -29,11 +30,190 @@ Widget toplevel; +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++; + } +} + +#include +#include +#include + +void unixpw(char *instr) { + char *str, *q, *infile = NULL; + FILE *in; + int i, rmfile = 0; + struct stat sb; + int N = 99; + char username[100], passwd[100]; + + 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; + 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; + 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 (! 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 main(int argc, char **argv) { - int i; - programName = argv[0]; + int i, save_sbw; + char *pw_loc = NULL; + programName = argv[0]; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-env") == 0) { + 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 +225,1391 @@ 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 (strstr(argv[i], " pw=") != NULL) { + pw_loc = strstr(argv[i], " pw=") + 1; + } + } + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-listen") == 0) { + listenForIncomingConnections(&argc, argv, i); + break; + } + if (strcmp(argv[i], "-multilisten") == 0) { + putenv("SSVNC_MULTIPLE_LISTEN=1"); + listenForIncomingConnections(&argc, argv, i); + break; + } + if (strcmp(argv[i], "-tunnel") == 0 || strcmp(argv[i], "-via") == 0) { + if (!createTunnel(&argc, argv, i)) { + exit(1); + } + break; + } + if (strcmp(argv[i], "-printres") == 0 || strcmp(argv[i], "-res") == 0) { + 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); + 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 (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); + } else if (getenv("SSVNC_UNIXPW")) { + unixpw(getenv("SSVNC_UNIXPW")); + } /* 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(); + 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; +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(); + 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; + 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(); +} + +/* + * 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); + } +} + +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) +{ + 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; + 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; + } +} + +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; + int fs = 0; + if (appData.scale != NULL && !strcmp(s, appData.scale)) { + return; + } + if (!strcasecmp(s, "none")) { + appData.scale = NULL; + } else if (!strcmp(s, "1.0")) { + appData.scale = NULL; + } else if (!strcmp(s, "1")) { + appData.scale = NULL; + } else { + appData.scale = strdup(s); + } + if (appData.fullScreen) { + fs = 1; + FullScreenOff(); + } + rescale_image(); + if (fs) { + FullScreenOn(); + } + } +} + +void +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(); + } +} + +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 +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); + } +} - Cleanup(); +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); + } +} - return 0; +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); + } +} + +void +SetZRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + static int first = 1; + if (first && appData.encodingsString) { + char *t, *z, *w; + t = strstr(appData.encodingsString, "tight"); + z = strstr(appData.encodingsString, "zrle"); + w = strstr(appData.encodingsString, "zywrle"); + if (t) { + if (z) { + if (w) { + if (t < z && t < w) { + usingZRLE = False; + } else { + usingZRLE = True; + } + if (z < w) { + usingZYWRLE = False; + } else { + usingZYWRLE = True; + } + } else { + if (t < z) { + usingZRLE = False; + } else { + usingZRLE = True; + } + usingZYWRLE = False; + } + } else { + if (w) { + if (t < w) { + usingZRLE = False; + } else { + usingZRLE = True; + } + usingZYWRLE = True; + } else { + usingZRLE = False; + usingZYWRLE = False; + } + } + } else { + if (z) { + if (w) { + usingZRLE = True; + if (z < w) { + usingZYWRLE = False; + } else { + usingZYWRLE = True; + } + } else { + usingZRLE = True; + usingZYWRLE = False; + } + } else { + if (w) { + usingZRLE = True; + usingZYWRLE = True; + } else { + usingZRLE = False; + usingZYWRLE = False; + } + } + } + } + first = 0; + + if (usingZRLE) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +void +SetZYWRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params) +{ + if (usingZYWRLE) { + XtVaSetValues(w, XtNstate, True, NULL); + } else { + XtVaSetValues(w, XtNstate, False, NULL); + } +} + +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 +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 2008-10-25 22:51:22.000000000 -0400 @@ -51,7 +51,7 @@ (((l) & 0x0000ff00) << 8) | \ (((l) & 0x000000ff) << 24)) : (l)) -#define MAX_ENCODINGS 20 +#define MAX_ENCODINGS 24 #define FLASH_PORT_OFFSET 5400 #define LISTEN_PORT_OFFSET 5500 @@ -65,59 +65,95 @@ (DEFAULT_SSH_CMD " -f -L %L:%H:%R %G sleep 20") -/* 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; - - 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 *repeaterUltra; + Bool ultraDSM; + char *rfbVersion; + + char *passwordFile; + Bool passwordDialog; + + 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 escapeActive; } 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 +166,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(); @@ -157,13 +194,52 @@ 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 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(); @@ -181,6 +257,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 +279,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 +292,20 @@ Cardinal *num_params); extern void CreatePopup(); +extern void HideScaleN(Widget w, XEvent *event, String *params, + Cardinal *num_params); +extern void CreateScaleN(); + +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); /* rfbproto.c */ extern int rfbsock; @@ -229,8 +328,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 +351,9 @@ /* shm.c */ -extern XImage *CreateShmImage(); +extern XImage *CreateShmImage(int do_ycrop); extern void ShmCleanup(); +extern Bool UsingShm(); /* sockets.c */ @@ -253,8 +364,11 @@ 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 Bool SameMachine(int sock); @@ -271,3 +385,69 @@ extern XtAppContext appContext; extern Display* dpy; extern Widget toplevel; + +extern void GotChatText(char *str, int len); + +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 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 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 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 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 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 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 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 2008-10-29 08:24:43.000000000 -0400 @@ -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-2008 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 "October 2008" "" "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 @@ -168,6 +185,313 @@ \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\-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. +Note that scaling is done in software and can be slow +and requires more memory. "str" can also be set by +the env. var. SSVNC_SCALE. +.TP +\fB\-ycrop\fR n +Only show the top n rows of the framebuffer. For +use with x11vnc \fB\-ncache\fR client caching option +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\-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\-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\-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'. + +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/ZRLE: ~ -encodings ... + Toggle ZRLE/ZYWRLE: ~ -encodings zywrle... + Quality Level ~ -quality (both Tight and ZYWRLE) + Compress Level ~ -compresslevel + Disable JPEG: ~ -nojpeg (Tight) + Full Color ~ as many colors as local screen allows. + Grey scale (16 & 8-bpp) ~ -grey, for low colors 16/8bpp modes. + 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 a single window. + (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. + .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 +562,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,8 +697,8 @@ .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 @@ -380,3 +713,5 @@ Tim Waugh , .br Constantin Kaplinsky +.br +Karl 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 2008-10-08 00:04:43.000000000 -0400 @@ -0,0 +1,618 @@ +/* + * 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; + 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; + 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 +1035,8 @@ rfbFileDownloadDataMsg fdd; rfbFileUploadCancelMsg fuc; rfbFileDownloadFailedMsg fdf; + rfbRestartConnectionMsg rc; + rfbTextChatMsg tc; } rfbServerToClientMsg; @@ -1221,6 +1290,41 @@ #define sz_rfbFileCreateDirRequestMsg 4 +/* ultra */ +typedef struct _rfbSetScaleMsg { + CARD8 type; /* always rfbSetScale */ + CARD8 scale; /* Scale value 1server messages. */ @@ -1241,4 +1345,9 @@ rfbFileDownloadCancelMsg fdc; rfbFileUploadFailedMsg fuf; rfbFileCreateDirRequestMsg fcdr; + rfbSetScaleMsg ssc; + rfbPalmVNCSetScaleFactorMsg pssf; + rfbSetServerInputMsg sim; + rfbSetSWMsg sw; + rfbTextChatMsg tc; } rfbClientToServerMsg;