| 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:\ |
| <Enter>: SelectionToVNC()\n\ |
| <Leave>: 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:\ |
| <Key>F8: ShowPopup()\n\ |
| + <Key>F9: ToggleFullScreen()\n\ |
| <ButtonPress>: SendRFBEvent()\n\ |
| <ButtonRelease>: SendRFBEvent()\n\ |
| <Motion>: SendRFBEvent()\n\ |
| <KeyPress>: SendRFBEvent()\n\ |
| <KeyRelease>: SendRFBEvent() |
| |
| +*viewport.horizontal.translations: #override\n\ |
| + <KeyPress>Right: StartScroll(Forward)\n\ |
| + <KeyRelease>Right: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Left: StartScroll(Backward)\n\ |
| + <KeyRelease>Left: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Next: StartScroll(Forward)\n\ |
| + <KeyRelease>Next: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Prior: StartScroll(Backward)\n\ |
| + <KeyRelease>Prior: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>z: StartScroll(Forward)\n\ |
| + <KeyRelease>z: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>a: StartScroll(Backward)\n\ |
| + <KeyRelease>a: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>f: StartScroll(Forward)\n\ |
| + <KeyRelease>f: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>b: StartScroll(Backward)\n\ |
| + <KeyRelease>b: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Down: StartScroll(Forward)\n\ |
| + <KeyRelease>Down: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Up: StartScroll(Backward)\n\ |
| + <KeyRelease>Up: NotifyScroll(FullLength) EndScroll() |
| + |
| +*viewport.vertical.translations: #override\n\ |
| + <KeyPress>Down: StartScroll(Forward)\n\ |
| + <KeyRelease>Down: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Up: StartScroll(Backward)\n\ |
| + <KeyRelease>Up: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Next: StartScroll(Forward)\n\ |
| + <KeyRelease>Next: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Prior: StartScroll(Backward)\n\ |
| + <KeyRelease>Prior: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>z: StartScroll(Forward)\n\ |
| + <KeyRelease>z: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>a: StartScroll(Backward)\n\ |
| + <KeyRelease>a: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>f: StartScroll(Forward)\n\ |
| + <KeyRelease>f: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>b: StartScroll(Backward)\n\ |
| + <KeyRelease>b: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Right: StartScroll(Forward)\n\ |
| + <KeyRelease>Right: NotifyScroll(FullLength) EndScroll()\n\ |
| + <KeyPress>Left: StartScroll(Backward)\n\ |
| + <KeyRelease>Left: NotifyScroll(FullLength) EndScroll() |
| + |
| |
| ! |
| ! Dialog boxes |
| ! |
| |
| *serverDialog.dialog.label: VNC server: |
| + |
| *serverDialog.dialog.value: |
| + |
| *serverDialog.dialog.value.translations: #override\n\ |
| - <Key>Return: ServerDialogDone() |
| + <Key>Return: ServerDialogDone() |
| + |
| +*ycropDialog.dialog.label: Y Crop (max-height in pixels): |
| + |
| +*ycropDialog.dialog.value: |
| + |
| +*ycropDialog.dialog.value.translations: #override\n\ |
| + <Key>Return: YCropDialogDone() |
| + |
| +*scbarDialog.dialog.label: Scroll Bars width: |
| + |
| +*scbarDialog.dialog.value: |
| + |
| +*scbarDialog.dialog.value.translations: #override\n\ |
| + <Key>Return: ScbarDialogDone() |
| + |
| +*scaleDialog.dialog.label: Integer n for 1/n server scaling: |
| + |
| +*scaleDialog.dialog.value: |
| + |
| +*scaleDialog.dialog.value.translations: #override\n\ |
| + <Key>Return: ScaleDialogDone() |
| |
| *passwordDialog.dialog.label: Password: |
| + |
| *passwordDialog.dialog.value: |
| + |
| *passwordDialog.dialog.value.AsciiSink.echo: False |
| + |
| *passwordDialog.dialog.value.translations: #override\n\ |
| - <Key>Return: PasswordDialogDone() |
| + <Key>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 <Message>WM_PROTOCOLS: HidePopup() |
| + |
| *popup.buttonForm.translations: #override\n\ |
| - <KeyPress>: SendRFBEvent() HidePopup() |
| + <KeyPress>: SendRFBEvent() HidePopup() |
| |
| |
| ! |
| ! Popup buttons |
| ! |
| |
| -*popupButtonCount: 8 |
| +*popupButtonCount: 38 |
| + |
| +*popupButtonBreak: 19 |
| |
| *popup*button1.label: Dismiss popup |
| + |
| *popup*button1.translations: #override\n\ |
| - <Btn1Down>,<Btn1Up>: HidePopup() |
| + <Btn1Down>,<Btn1Up>: HidePopup() |
| |
| *popup*button2.label: Quit viewer |
| + |
| *popup*button2.translations: #override\n\ |
| - <Btn1Down>,<Btn1Up>: Quit() |
| + <Btn1Down>,<Btn1Up>: Quit() |
| + |
| +*popup*button3.label: Full screen (also F9) |
| |
| -*popup*button3.label: Full screen |
| *popup*button3.type: toggle |
| + |
| *popup*button3.translations: #override\n\ |
| - <Visible>: SetFullScreenState()\n\ |
| - <Btn1Down>,<Btn1Up>: toggle() HidePopup() ToggleFullScreen() |
| + <Visible>: SetFullScreenState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleFullScreen() HidePopup() |
| |
| *popup*button4.label: Clipboard: local -> remote |
| + |
| *popup*button4.translations: #override\n\ |
| - <Btn1Down>,<Btn1Up>: SelectionToVNC(always) HidePopup() |
| + <Btn1Down>,<Btn1Up>: SelectionToVNC(always) HidePopup() |
| |
| *popup*button5.label: Clipboard: local <- remote |
| + |
| *popup*button5.translations: #override\n\ |
| - <Btn1Down>,<Btn1Up>: SelectionFromVNC(always) HidePopup() |
| + <Btn1Down>,<Btn1Up>: SelectionFromVNC(always) HidePopup() |
| |
| *popup*button6.label: Request refresh |
| + |
| *popup*button6.translations: #override\n\ |
| - <Btn1Down>,<Btn1Up>: SendRFBEvent(fbupdate) HidePopup() |
| + <Btn1Down>,<Btn1Up>: SendRFBEvent(fbupdate) HidePopup() |
| |
| *popup*button7.label: Send ctrl-alt-del |
| + |
| *popup*button7.translations: #override\n\ |
| - <Btn1Down>,<Btn1Up>: SendRFBEvent(keydown,Control_L)\ |
| - SendRFBEvent(keydown,Alt_L)\ |
| - SendRFBEvent(key,Delete)\ |
| - SendRFBEvent(keyup,Alt_L)\ |
| - SendRFBEvent(keyup,Control_L)\ |
| - HidePopup() |
| + <Btn1Down>,<Btn1Up>: 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\ |
| - <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F8) HidePopup() |
| + <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F8) HidePopup() |
| + |
| +*popup*button9.label: Send F9 |
| + |
| +*popup*button9.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F9) HidePopup() |
| + |
| +*popup*button10.label: ViewOnly |
| + |
| +*popup*button10.type: toggle |
| + |
| +*popup*button10.translations: #override\n\ |
| + <Visible>: SetViewOnlyState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleViewOnly() HidePopup() |
| + |
| +*popup*button11.label: Disable Bell |
| + |
| +*popup*button11.type: toggle |
| + |
| +*popup*button11.translations: #override\n\ |
| + <Visible>: SetBellState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleBell() HidePopup() |
| + |
| +*popup*button12.label: Cursor Shape |
| + |
| +*popup*button12.type: toggle |
| + |
| +*popup*button12.translations: #override\n\ |
| + <Visible>: SetCursorShapeState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleCursorShape() HidePopup() |
| + |
| +*popup*button13.label: X11 Cursor |
| + |
| +*popup*button13.type: toggle |
| + |
| +*popup*button13.translations: #override\n\ |
| + <Visible>: SetX11CursorState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleX11Cursor() HidePopup() |
| + |
| +*popup*button14.label: Cursor Alphablend |
| + |
| +*popup*button14.type: toggle |
| + |
| +*popup*button14.translations: #override\n\ |
| + <Visible>: SetCursorAlphaState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleCursorAlpha() HidePopup() |
| + |
| +*popup*button15.label: Toggle Tight/ZRLE |
| + |
| +*popup*button15.type: toggle |
| + |
| +*popup*button15.translations: #override\n\ |
| + <Visible>: SetZRLEState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleTightZRLE() HidePopup() |
| + |
| +*popup*button16.label: Toggle ZRLE/ZYWRLE |
| + |
| +*popup*button16.type: toggle |
| + |
| +*popup*button16.translations: #override\n\ |
| + <Visible>: SetZYWRLEState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleZRLEZYWRLE() HidePopup() |
| + |
| +*popup*button17.label: Quality Level |
| + |
| +*popup*button17.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() ShowQuality() |
| + |
| +*popup*button18.label: Compress Level |
| + |
| +*popup*button18.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() ShowCompress() |
| + |
| +*popup*button19.label: Disable JPEG |
| + |
| +*popup*button19.type: toggle |
| + |
| +*popup*button19.translations: #override\n\ |
| + <Visible>: SetNOJPEGState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleJPEG() HidePopup() |
| + |
| +*popup*button20.label: Full Color |
| + |
| +*popup*button20.type: toggle |
| + |
| +*popup*button20.translations: #override\n\ |
| + <Visible>: SetFullColorState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleFullColor() HidePopup() |
| + |
| +*popup*button21.label: Grey Scale (16 & 8-bpp) |
| + |
| +*popup*button21.type: toggle |
| + |
| +*popup*button21.translations: #override\n\ |
| + <Visible>: SetGreyScaleState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleGreyScale() HidePopup() |
| + |
| +*popup*button22.label: 16 bit color (BGR565) |
| + |
| +*popup*button22.type: toggle |
| + |
| +*popup*button22.translations: #override\n\ |
| + <Visible>: Set16bppState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle16bpp() HidePopup() |
| + |
| +*popup*button23.label: 8 bit color (BGR233) |
| + |
| +*popup*button23.type: toggle |
| + |
| +*popup*button23.translations: #override\n\ |
| + <Visible>: Set8bppState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle8bpp() HidePopup() |
| + |
| +*popup*button24.label: - 256 colors |
| + |
| +*popup*button24.type: toggle |
| + |
| +*popup*button24.translations: #override\n\ |
| + <Visible>: Set256ColorsState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle256Colors() HidePopup() |
| + |
| +*popup*button25.label: - 64 colors |
| + |
| +*popup*button25.type: toggle |
| + |
| +*popup*button25.translations: #override\n\ |
| + <Visible>: Set64ColorsState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle64Colors() HidePopup() |
| + |
| +*popup*button26.label: - 8 colors |
| + |
| +*popup*button26.type: toggle |
| + |
| +*popup*button26.translations: #override\n\ |
| + <Visible>: Set8ColorsState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle8Colors() HidePopup() |
| + |
| +*popup*button27.label: Set Y Crop (y-max) |
| + |
| +*popup*button27.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() SetYCrop() |
| + |
| +*popup*button28.label: Set Scrollbar Width |
| + |
| +*popup*button28.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() SetScbar() |
| + |
| +*popup*button29.label: UltraVNC Extensions: |
| + |
| +*popup*button29.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() |
| + |
| +*popup*button30.label: - Set 1/n Server Scale |
| + |
| +*popup*button30.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() ShowScaleN() |
| + |
| +*popup*button31.label: - Text Chat |
| + |
| +*popup*button31.type: toggle |
| + |
| +*popup*button31.translations: #override\n\ |
| + <Visible>: SetTextChatState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleTextChat() HidePopup() |
| + |
| +*popup*button32.label: - File Transfer |
| + |
| +*popup*button32.type: toggle |
| + |
| +*popup*button32.translations: #override\n\ |
| + <Visible>: SetFileXferState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleFileXfer() HidePopup() |
| + |
| +*popup*button33.label: - Single Window |
| + |
| +*popup*button33.type: toggle |
| + |
| +*popup*button33.translations: #override\n\ |
| + <Visible>: SetSingleWindowState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleSingleWindow() HidePopup() |
| + |
| +*popup*button34.label: - Disable Remote Input |
| + |
| +*popup*button34.type: toggle |
| + |
| +*popup*button34.translations: #override\n\ |
| + <Visible>: SetServerInputState()\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleServerInput() HidePopup() |
| + |
| +*popup*button35.label: |
| + |
| +*popup*button36.label: |
| + |
| +*popup*button37.label: |
| + |
| +*popup*button38.label: |
| + |
| +*scaleN*button0.label: Dismiss |
| + |
| +*scaleN*button0.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HideScaleN() |
| + |
| +*scaleN*button1.label: 1/1 |
| + |
| +*scaleN*button1.translations: #override\n\ |
| + <Visible>: SetScaleNState(1)\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(1) HideScaleN() |
| + |
| +*scaleN*button2.label: 1/2 |
| + |
| +*scaleN*button2.translations: #override\n\ |
| + <Visible>: SetScaleNState(2)\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(2) HideScaleN() |
| + |
| +*scaleN*button3.label: 1/3 |
| + |
| +*scaleN*button3.translations: #override\n\ |
| + <Visible>: SetScaleNState(3)\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(3) HideScaleN() |
| + |
| +*scaleN*button4.label: 1/4 |
| + |
| +*scaleN*button4.translations: #override\n\ |
| + <Visible>: SetScaleNState(4)\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(4) HideScaleN() |
| + |
| +*scaleN*button5.label: 1/5 |
| + |
| +*scaleN*button5.translations: #override\n\ |
| + <Visible>: SetScaleNState(5)\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(5) HideScaleN() |
| + |
| +*scaleN*button6.label: Other |
| + |
| +*scaleN*button6.translations: #override\n\ |
| + <Visible>: SetScaleNState(6)\n\ |
| + <Btn1Down>,<Btn1Up>: HideScaleN() DoServerScale() |
| + |
| +*quality*buttonD.label: Dismiss |
| + |
| +*quality*buttonD.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HideQuality() |
| + |
| +*quality*button0.label: 0 |
| + |
| +*quality*button0.type: toggle |
| + |
| +*quality*button0.translations: #override\n\ |
| + <Visible>: SetQualityState(0)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(0) HideQuality() |
| + |
| +*quality*button1.label: 1 |
| + |
| +*quality*button1.type: toggle |
| + |
| +*quality*button1.translations: #override\n\ |
| + <Visible>: SetQualityState(1)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(1) HideQuality() |
| + |
| +*quality*button2.label: 2 |
| + |
| +*quality*button2.type: toggle |
| + |
| +*quality*button2.translations: #override\n\ |
| + <Visible>: SetQualityState(2)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(2) HideQuality() |
| + |
| +*quality*button3.label: 3 |
| + |
| +*quality*button3.type: toggle |
| + |
| +*quality*button3.translations: #override\n\ |
| + <Visible>: SetQualityState(3)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(3) HideQuality() |
| + |
| +*quality*button4.label: 4 |
| + |
| +*quality*button4.type: toggle |
| + |
| +*quality*button4.translations: #override\n\ |
| + <Visible>: SetQualityState(4)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(4) HideQuality() |
| + |
| +*quality*button5.label: 5 |
| + |
| +*quality*button5.type: toggle |
| + |
| +*quality*button5.translations: #override\n\ |
| + <Visible>: SetQualityState(5)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(5) HideQuality() |
| + |
| +*quality*button6.label: 6 |
| + |
| +*quality*button6.type: toggle |
| + |
| +*quality*button6.translations: #override\n\ |
| + <Visible>: SetQualityState(6)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(6) HideQuality() |
| + |
| +*quality*button7.label: 7 |
| + |
| +*quality*button7.type: toggle |
| + |
| +*quality*button7.translations: #override\n\ |
| + <Visible>: SetQualityState(7)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(7) HideQuality() |
| + |
| +*quality*button8.label: 8 |
| + |
| +*quality*button8.type: toggle |
| + |
| +*quality*button8.translations: #override\n\ |
| + <Visible>: SetQualityState(8)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(8) HideQuality() |
| + |
| +*quality*button9.label: 9 |
| + |
| +*quality*button9.type: toggle |
| + |
| +*quality*button9.translations: #override\n\ |
| + <Visible>: SetQualityState(9)\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(9) HideQuality() |
| + |
| +*compress*buttonD.label: Dismiss |
| + |
| +*compress*buttonD.translations: #override\n\ |
| + <Btn1Down>,<Btn1Up>: HideCompress() |
| + |
| +*compress*button0.label: 0 |
| + |
| +*compress*button0.translations: #override\n\ |
| + <Visible>: SetCompressState(0)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(0) HideCompress() |
| + |
| +*compress*button1.label: 1 |
| + |
| +*compress*button1.translations: #override\n\ |
| + <Visible>: SetCompressState(1)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(1) HideCompress() |
| + |
| +*compress*button2.label: 2 |
| + |
| +*compress*button2.translations: #override\n\ |
| + <Visible>: SetCompressState(2)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(2) HideCompress() |
| + |
| +*compress*button3.label: 3 |
| + |
| +*compress*button3.translations: #override\n\ |
| + <Visible>: SetCompressState(3)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(3) HideCompress() |
| + |
| +*compress*button4.label: 4 |
| + |
| +*compress*button4.translations: #override\n\ |
| + <Visible>: SetCompressState(4)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(4) HideCompress() |
| + |
| +*compress*button5.label: 5 |
| + |
| +*compress*button5.translations: #override\n\ |
| + <Visible>: SetCompressState(5)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(5) HideCompress() |
| + |
| +*compress*button6.label: 6 |
| + |
| +*compress*button6.translations: #override\n\ |
| + <Visible>: SetCompressState(6)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(6) HideCompress() |
| + |
| +*compress*button7.label: 7 |
| + |
| +*compress*button7.translations: #override\n\ |
| + <Visible>: SetCompressState(7)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(7) HideCompress() |
| + |
| +*compress*button8.label: 8 |
| + |
| +*compress*button8.translations: #override\n\ |
| + <Visible>: SetCompressState(8)\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(8) HideCompress() |
| + |
| +*compress*button9.label: 9 |
| + |
| +*compress*button9.translations: #override\n\ |
| + <Visible>: SetCompressState(9)\n\ |
| + <Btn1Down>,<Btn1Up>: 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 2010-04-18 12:39:55.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:\ |
| <Enter>: SelectionToVNC()\\n\ |
| <Leave>: 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\ |
| + <KeyPress>Right: StartScroll(Forward)\\n\ |
| + <KeyRelease>Right: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Left: StartScroll(Backward)\\n\ |
| + <KeyRelease>Left: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Next: StartScroll(Forward)\\n\ |
| + <KeyRelease>Next: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Prior: StartScroll(Backward)\\n\ |
| + <KeyRelease>Prior: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>z: StartScroll(Forward)\\n\ |
| + <KeyRelease>z: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>a: StartScroll(Backward)\\n\ |
| + <KeyRelease>a: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>f: StartScroll(Forward)\\n\ |
| + <KeyRelease>f: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>b: StartScroll(Backward)\\n\ |
| + <KeyRelease>b: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Down: StartScroll(Forward)\\n\ |
| + <KeyRelease>Down: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Up: StartScroll(Backward)\\n\ |
| + <KeyRelease>Up: NotifyScroll(FullLength) EndScroll()", |
| + |
| + "*viewport.vertical.translations: #override\\n\ |
| + <KeyPress>Down: StartScroll(Forward)\\n\ |
| + <KeyRelease>Down: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Up: StartScroll(Backward)\\n\ |
| + <KeyRelease>Up: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Next: StartScroll(Forward)\\n\ |
| + <KeyRelease>Next: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Prior: StartScroll(Backward)\\n\ |
| + <KeyRelease>Prior: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>z: StartScroll(Forward)\\n\ |
| + <KeyRelease>z: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>a: StartScroll(Backward)\\n\ |
| + <KeyRelease>a: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>f: StartScroll(Forward)\\n\ |
| + <KeyRelease>f: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>b: StartScroll(Backward)\\n\ |
| + <KeyRelease>b: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Right: StartScroll(Forward)\\n\ |
| + <KeyRelease>Right: NotifyScroll(FullLength) EndScroll()\\n\ |
| + <KeyPress>Left: StartScroll(Backward)\\n\ |
| + <KeyRelease>Left: NotifyScroll(FullLength) EndScroll()", |
| + |
| "*desktop.baseTranslations:\ |
| - <Key>F8: ShowPopup()\\n\ |
| + <KeyPress>F8: ShowPopup()\\n\ |
| + <KeyRelease>F8: Noop()\\n\ |
| + <KeyPress>F9: ToggleFullScreen()\\n\ |
| + <KeyRelease>F9: Noop()\\n\ |
| <ButtonPress>: SendRFBEvent()\\n\ |
| <ButtonRelease>: SendRFBEvent()\\n\ |
| <Motion>: SendRFBEvent()\\n\ |
| @@ -55,26 +107,137 @@ |
| |
| "*serverDialog.dialog.label: VNC server:", |
| "*serverDialog.dialog.value:", |
| + "*serverDialog.dialog.value.width: 150", |
| "*serverDialog.dialog.value.translations: #override\\n\ |
| <Key>Return: ServerDialogDone()", |
| |
| - "*passwordDialog.dialog.label: Password:", |
| + "*userDialog.dialog.label: SSVNC: Enter Username", |
| + "*userDialog.dialog.value:", |
| + "*userDialog.dialog.value.width: 150", |
| + "*userDialog.dialog.value.translations: #override\\n\ |
| + <Key>Return: UserDialogDone()", |
| + |
| + "*scaleDialog.dialog.label: Scale: Enter 'none' (same as '1' or '1.0'),\\na geometry WxH (e.g. 1280x1024), or\\na fraction (e.g. 0.75 or 3/4).\\nUse 'fit' for full screen size.\\nUse 'auto' to match window size.\\nCurrent value:", |
| + "*scaleDialog.dialog.value:", |
| + "*scaleDialog.dialog.value.translations: #override\\n\ |
| + <KeyRelease>Return: ScaleDialogDone()", |
| + |
| + "*escapeDialog.dialog.label: Escape Keys: Enter a comma separated list of modifier keys to be the\\n" |
| + "'escape sequence'. When these keys are held down, the next keystroke is\\n" |
| + "interpreted locally to invoke a special action instead of being sent to\\n" |
| + "the remote VNC server. In other words, a set of 'Hot Keys'.\\n" |
| + "\\n" |
| + "To enable or disable this, click on 'Escape Keys: Toggle' in the Popup.\\n" |
| + "\\n" |
| + "Here is the list of hot-key mappings to special actions:\\n" |
| + "\\n" |
| + " r: refresh desktop b: toggle bell c: toggle full-color\\n" |
| + " f: file transfer x: x11cursor z: toggle Tight/ZRLE\\n" |
| + " l: full screen g: graball e: escape keys dialog\\n" |
| + " s: scale dialog +: scale up (=) -: scale down (_)\\n" |
| + " t: text chat a: alphablend cursor\\n" |
| + " V: toggle viewonly Q: quit viewer 1 2 3 4 5 6: UltraVNC scale 1/n\\n" |
| + "\\n" |
| + " Arrow keys: pan the viewport about 10% for each keypress.\\n" |
| + " PageUp / PageDown: pan the viewport by a screenful vertically.\\n" |
| + " Home / End: pan the viewport by a screenful horizontally.\\n" |
| + " KeyPad Arrow keys: pan the viewport by 1 pixel for each keypress.\\n" |
| + " Dragging the Mouse with Button1 pressed also pans the viewport.\\n" |
| + " Clicking Mouse Button3 brings up the Popup Menu.\\n" |
| + "\\n" |
| + "The above mappings are *always* active in ViewOnly mode, unless you set the\\n" |
| + "Escape Keys value to 'never'.\\n" |
| + "\\n" |
| + "x11vnc -appshare hot-keys: x11vnc has a simple application sharing mode\\n" |
| + "that enables the viewer-side to move, resize, or raise the remote toplevel\\n" |
| + "windows. To enable it, hold down Shift + the Escape Keys and press these:\\n" |
| + "\\n" |
| + " Arrow keys: move the remote window around in its desktop.\\n" |
| + " PageUp/PageDn/Home/End: resize the remote window.\\n" |
| + " +/- raise or lower the remote window.\\n" |
| + " M or Button1 move win to local position; D or Button3: delete remote win.\\n" |
| + "\\n" |
| + "If the Escape Keys value below is set to 'default' then a fixed list of\\n" |
| + "modifier keys is used. For Unix it is: Alt_L,Super_L and for MacOSX it is\\n" |
| + "Control_L,Meta_L. Note: the Super_L key usually has a Windows(TM) Flag.\\n" |
| + "Also note the _L and _R mean the key is on the LEFT or RIGHT side of keyboard.\\n" |
| + "\\n" |
| + "On Unix the default is Alt and Windows keys on Left side of keyboard.\\n" |
| + "On MacOSX the default is Control and Command keys on Left side of keyboard.\\n" |
| + "\\n" |
| + "Example: Press and hold the Alt and Windows keys on the LEFT side of the\\n" |
| + "keyboard and then press 'c' to toggle the full-color state. Or press 't'\\n" |
| + "to toggle the ultravnc Text Chat window, etc.\\n" |
| + "\\n" |
| + "To use something besides the default, supply a comma separated list (or a\\n" |
| + "single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L\\n" |
| + "Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch.\\n" |
| + "\\n" |
| + "Current Escape Keys Value:", |
| + "*escapeDialog.dialog.value:", |
| + "*escapeDialog.dialog.value.width: 280", |
| + "*escapeDialog.dialog.value.translations: #override\\n\ |
| + <KeyRelease>Return: EscapeDialogDone()", |
| + |
| + "*ycropDialog.dialog.label: Y Crop (max-height in pixels):", |
| + "*ycropDialog.dialog.value:", |
| + "*ycropDialog.dialog.value.translations: #override\\n\ |
| + <KeyRelease>Return: YCropDialogDone()", |
| + |
| + "*scbarDialog.dialog.label: Scroll Bars width:", |
| + "*scbarDialog.dialog.value:", |
| + "*scbarDialog.dialog.value.translations: #override\\n\ |
| + <KeyRelease>Return: ScbarDialogDone()", |
| + |
| + "*scaleNDialog.dialog.label: Integer n for 1/n server scaling:", |
| + "*scaleNDialog.dialog.value:", |
| + "*scaleNDialog.dialog.value.translations: #override\\n\ |
| + <KeyRelease>Return: ScaleNDialogDone()", |
| + |
| + "*passwordDialog.dialog.label: SSVNC: Enter Password", |
| "*passwordDialog.dialog.value:", |
| + "*passwordDialog.dialog.value.width: 150", |
| "*passwordDialog.dialog.value.AsciiSink.echo: False", |
| "*passwordDialog.dialog.value.translations: #override\\n\ |
| <Key>Return: PasswordDialogDone()", |
| |
| - "*popup.title: TightVNC popup", |
| + "*popup.title: SSVNC popup", |
| "*popup*background: grey", |
| - "*popup*font: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-*", |
| - "*popup.buttonForm.Command.borderWidth: 0", |
| - "*popup.buttonForm.Toggle.borderWidth: 0", |
| + "*popup*font_old: -*-helvetica-bold-r-*-*-16-*-*-*-*-*-*-*", |
| + "*popup*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", |
| + "*popup.buttonForm*.Command.borderWidth: 0", |
| + "*popup.buttonForm*.Toggle.borderWidth: 0", |
| + |
| + "*scaleN.title: 1/n scale", |
| + "*scaleN*background: grey", |
| + "*scaleN*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", |
| + "*scaleN.buttonForm.Command.borderWidth: 0", |
| + "*scaleN.buttonForm.Toggle.borderWidth: 0", |
| + |
| + "*turboVNC.title: TurboVNC", |
| + "*turboVNC*background: grey", |
| + "*turboVNC*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", |
| + "*turboVNC.buttonForm.Command.borderWidth: 0", |
| + "*turboVNC.buttonForm.Toggle.borderWidth: 0", |
| + |
| + "*quality.title: quality", |
| + "*quality*background: grey", |
| + "*quality*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", |
| + "*quality.buttonForm.Command.borderWidth: 0", |
| + "*quality.buttonForm.Toggle.borderWidth: 0", |
| + |
| + "*compress.title: compress", |
| + "*compress*background: grey", |
| + "*compress*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*", |
| + "*compress.buttonForm.Command.borderWidth: 0", |
| + "*compress.buttonForm.Toggle.borderWidth: 0", |
| |
| "*popup.translations: #override <Message>WM_PROTOCOLS: HidePopup()", |
| "*popup.buttonForm.translations: #override\\n\ |
| <KeyPress>: SendRFBEvent() HidePopup()", |
| |
| - "*popupButtonCount: 8", |
| + "*popupButtonCount: 44", |
| + "*popupButtonBreak: 22", |
| |
| "*popup*button1.label: Dismiss popup", |
| "*popup*button1.translations: #override\\n\ |
| @@ -84,7 +247,7 @@ |
| "*popup*button2.translations: #override\\n\ |
| <Btn1Down>,<Btn1Up>: Quit()", |
| |
| - "*popup*button3.label: Full screen", |
| + "*popup*button3.label: Full screen (also F9)", |
| "*popup*button3.type: toggle", |
| "*popup*button3.translations: #override\\n\ |
| <Visible>: SetFullScreenState()\\n\ |
| @@ -105,16 +268,426 @@ |
| "*popup*button7.label: Send ctrl-alt-del", |
| "*popup*button7.translations: #override\\n\ |
| <Btn1Down>,<Btn1Up>: 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\ |
| <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F8) HidePopup()", |
| |
| + "*popup*button9.label: Send F9", |
| + "*popup*button9.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SendRFBEvent(key,F9) HidePopup()", |
| + |
| + "*popup*button10.label: ViewOnly", |
| + "*popup*button10.type: toggle", |
| + "*popup*button10.translations: #override\\n\ |
| + <Visible>: SetViewOnlyState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleViewOnly() HidePopup()", |
| + |
| + "*popup*button11.label: Disable Bell", |
| + "*popup*button11.type: toggle", |
| + "*popup*button11.translations: #override\\n\ |
| + <Visible>: SetBellState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleBell() HidePopup()", |
| + |
| + "*popup*button12.label: Cursor Shape", |
| + "*popup*button12.type: toggle", |
| + "*popup*button12.translations: #override\\n\ |
| + <Visible>: SetCursorShapeState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleCursorShape() HidePopup()", |
| + |
| + "*popup*button13.label: X11 Cursor", |
| + "*popup*button13.type: toggle", |
| + "*popup*button13.translations: #override\\n\ |
| + <Visible>: SetX11CursorState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleX11Cursor() HidePopup()", |
| + |
| + "*popup*button14.label: Cursor Alphablend", |
| + "*popup*button14.type: toggle", |
| + "*popup*button14.translations: #override\\n\ |
| + <Visible>: SetCursorAlphaState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleCursorAlpha() HidePopup()", |
| + |
| + "*popup*button15.label: Toggle Tight/Hextile", |
| + "*popup*button15.type: toggle", |
| + "*popup*button15.translations: #override\\n\ |
| + <Visible>: SetHextileState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleTightHextile() HidePopup()", |
| + |
| + "*popup*button16.label: Toggle Tight/ZRLE", |
| + "*popup*button16.type: toggle", |
| + "*popup*button16.translations: #override\\n\ |
| + <Visible>: SetZRLEState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleTightZRLE() HidePopup()", |
| + |
| + "*popup*button17.label: Toggle ZRLE/ZYWRLE", |
| + "*popup*button17.type: toggle", |
| + "*popup*button17.translations: #override\\n\ |
| + <Visible>: SetZYWRLEState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleZRLEZYWRLE() HidePopup()", |
| + |
| + "*popup*button18.label: Quality Level", |
| + "*popup*button18.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() ShowQuality()", |
| + |
| + "*popup*button19.label: Compress Level", |
| + "*popup*button19.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() ShowCompress()", |
| + |
| + "*popup*button20.label: Disable JPEG", |
| + "*popup*button20.type: toggle", |
| + "*popup*button20.translations: #override\\n\ |
| + <Visible>: SetNOJPEGState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleJPEG() HidePopup()", |
| + |
| + "*popup*button21.label: TurboVNC Settings", |
| + "*popup*button21.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() ShowTurboVNC()", |
| + |
| + "*popup*button22.label: Pipeline Updates", |
| + "*popup*button22.type: toggle", |
| + "*popup*button22.translations: #override\\n\ |
| + <Visible>: SetPipelineUpdates()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() TogglePipelineUpdates() HidePopup()", |
| + |
| + "*popup*button23.label: Full Color", |
| + "*popup*button23.type: toggle", |
| + "*popup*button23.translations: #override\\n\ |
| + <Visible>: SetFullColorState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleFullColor() HidePopup()", |
| + |
| + "*popup*button24.label: Grey Scale (16 & 8-bpp)", |
| + "*popup*button24.type: toggle", |
| + "*popup*button24.translations: #override\\n\ |
| + <Visible>: SetGreyScaleState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleGreyScale() HidePopup()", |
| + |
| + "*popup*button25.label: 16 bit color (BGR565)", |
| + "*popup*button25.type: toggle", |
| + "*popup*button25.translations: #override\\n\ |
| + <Visible>: Set16bppState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle16bpp() HidePopup()", |
| + |
| + "*popup*button26.label: 8 bit color (BGR233)", |
| + "*popup*button26.type: toggle", |
| + "*popup*button26.translations: #override\\n\ |
| + <Visible>: Set8bppState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle8bpp() HidePopup()", |
| + |
| + "*popup*button27.label: - 256 colors", |
| + "*popup*button27.type: toggle", |
| + "*popup*button27.translations: #override\\n\ |
| + <Visible>: Set256ColorsState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle256Colors() HidePopup()", |
| + |
| + "*popup*button28.label: - 64 colors", |
| + "*popup*button28.type: toggle", |
| + "*popup*button28.translations: #override\\n\ |
| + <Visible>: Set64ColorsState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle64Colors() HidePopup()", |
| + |
| + "*popup*button29.label: - 8 colors", |
| + "*popup*button29.type: toggle", |
| + "*popup*button29.translations: #override\\n\ |
| + <Visible>: Set8ColorsState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() Toggle8Colors() HidePopup()", |
| + |
| + "*popup*button30.label: Scale Viewer", |
| + "*popup*button30.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() SetScale()", |
| + |
| + "*popup*button31.label: Escape Keys: Toggle", |
| + "*popup*button31.type: toggle", |
| + "*popup*button31.translations: #override\\n\ |
| + <Visible>: SetEscapeKeysState()\\n\ |
| + <Btn1Down>, <Btn1Up>: toggle() ToggleEscapeActive() HidePopup()", |
| + |
| + "*popup*button32.label: Escape Keys: Help+Set", |
| + "*popup*button32.translations: #override\\n\ |
| + <Btn1Down>, <Btn1Up>: HidePopup() SetEscapeKeys()", |
| + |
| + "*popup*button33.label: Set Y Crop (y-max)", |
| + "*popup*button33.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() SetYCrop()", |
| + |
| + "*popup*button34.label: Set Scrollbar Width", |
| + "*popup*button34.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() SetScbar()", |
| + |
| + "*popup*button35.label: XGrabServer", |
| + "*popup*button35.type: toggle", |
| + "*popup*button35.translations: #override\\n\ |
| + <Visible>: SetXGrabState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleXGrab() HidePopup()", |
| + |
| + "*popup*button36.label: UltraVNC Extensions:", |
| + "*popup*button36.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup()", |
| + |
| + "*popup*button37.label: - Set 1/n Server Scale", |
| + "*popup*button37.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HidePopup() ShowScaleN()", |
| + |
| + "*popup*button38.label: - Text Chat", |
| + "*popup*button38.type: toggle", |
| + "*popup*button38.translations: #override\\n\ |
| + <Visible>: SetTextChatState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleTextChat() HidePopup()", |
| + |
| + "*popup*button39.label: - File Transfer", |
| + "*popup*button39.type: toggle", |
| + "*popup*button39.translations: #override\\n\ |
| + <Visible>: SetFileXferState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleFileXfer() HidePopup()", |
| + |
| + "*popup*button40.label: - Single Window", |
| + "*popup*button40.type: toggle", |
| + "*popup*button40.translations: #override\\n\ |
| + <Visible>: SetSingleWindowState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleSingleWindow() HidePopup()", |
| + |
| + "*popup*button41.label: - Disable Remote Input", |
| + "*popup*button41.type: toggle", |
| + "*popup*button41.translations: #override\\n\ |
| + <Visible>: SetServerInputState()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleServerInput() HidePopup()", |
| + |
| + "*popup*button42.label: Send Clipboard not Primary", |
| + "*popup*button42.type: toggle", |
| + "*popup*button42.translations: #override\\n\ |
| + <Visible>: SetSendClipboard()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleSendClipboard() HidePopup()", |
| + |
| + "*popup*button43.label: Send Selection Every time", |
| + "*popup*button43.type: toggle", |
| + "*popup*button43.translations: #override\\n\ |
| + <Visible>: SetSendAlways()\\n\ |
| + <Btn1Down>,<Btn1Up>: toggle() ToggleSendAlways() HidePopup()", |
| + |
| + "*popup*button44.label: ", |
| + |
| + "*turboVNC*button0.label: Dismiss", |
| + "*turboVNC*button0.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HideTurboVNC()", |
| + |
| + "*turboVNC*button1.label: High Quality (LAN)", |
| + "*turboVNC*button1.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(1)", |
| + |
| + "*turboVNC*button2.label: Medium Quality", |
| + "*turboVNC*button2.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(2)", |
| + |
| + "*turboVNC*button3.label: Low Quality (WAN)", |
| + "*turboVNC*button3.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(3)", |
| + |
| + "*turboVNC*button4.label: Lossless (Gigabit)", |
| + "*turboVNC*button4.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(4)", |
| + |
| + "*turboVNC*button5.label: Lossless Zlib (WAN)", |
| + "*turboVNC*button5.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(5)", |
| + |
| + "*turboVNC*button6.label: Subsampling:", |
| + |
| + "*turboVNC*button7.label: - None", |
| + "*turboVNC*button7.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(6)", |
| + |
| + "*turboVNC*button8.label: - 2X", |
| + "*turboVNC*button8.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(7)", |
| + |
| + "*turboVNC*button9.label: - 4X", |
| + "*turboVNC*button9.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(8)", |
| + |
| + "*turboVNC*button10.label: - Gray", |
| + "*turboVNC*button10.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(9)", |
| + |
| + "*turboVNC*button11.label: Lossless Refresh", |
| + "*turboVNC*button11.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SetTurboVNC(10)", |
| + |
| + "*turboVNC*button12.label: Lossy Refresh", |
| + "*turboVNC*button12.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: SendRFBEvent(fbupdate)", |
| + |
| + "*turboVNC*buttonNone.label: Not Compiled with\\nTurboVNC Support.", |
| + "*turboVNC*buttonNone.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HideTurboVNC()", |
| + |
| + "*qualLabel.label: JPEG Image Quality:", |
| + "*qualBar.length: 100", |
| + "*qualBar.width: 130", |
| + "*qualBar.orientation: horizontal", |
| + "*qualBar.translations: #override\\n\ |
| + <Btn1Down>: StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ |
| + <Btn1Motion>: MoveThumb() NotifyThumb()\\n\ |
| + <Btn3Down>: StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\ |
| + <Btn3Motion>: MoveThumb() NotifyThumb()", |
| + |
| + "*qualText.label: 000", |
| + |
| + "*scaleN*button0.label: Dismiss", |
| + "*scaleN*button0.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HideScaleN()", |
| + |
| + "*scaleN*button1.label: 1/1", |
| + "*scaleN*button1.translations: #override\\n\ |
| + <Visible>: SetScaleNState(1)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(1) HideScaleN()", |
| + |
| + "*scaleN*button2.label: 1/2", |
| + "*scaleN*button2.translations: #override\\n\ |
| + <Visible>: SetScaleNState(2)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(2) HideScaleN()", |
| + |
| + "*scaleN*button3.label: 1/3", |
| + "*scaleN*button3.translations: #override\\n\ |
| + <Visible>: SetScaleNState(3)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(3) HideScaleN()", |
| + |
| + "*scaleN*button4.label: 1/4", |
| + "*scaleN*button4.translations: #override\\n\ |
| + <Visible>: SetScaleNState(4)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(4) HideScaleN()", |
| + |
| + "*scaleN*button5.label: 1/5", |
| + "*scaleN*button5.translations: #override\\n\ |
| + <Visible>: SetScaleNState(5)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetScaleN(5) HideScaleN()", |
| + |
| + "*scaleN*button6.label: Other", |
| + "*scaleN*button6.translations: #override\\n\ |
| + <Visible>: SetScaleNState(6)\\n\ |
| + <Btn1Down>,<Btn1Up>: HideScaleN() DoServerScale()", |
| + |
| + "*quality*buttonD.label: Dismiss", |
| + "*quality*buttonD.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HideQuality()", |
| + |
| + "*quality*button0.label: 0", |
| + "*quality*button0.type: toggle", |
| + "*quality*button0.translations: #override\\n\ |
| + <Visible>: SetQualityState(0)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(0) HideQuality()", |
| + |
| + "*quality*button1.label: 1", |
| + "*quality*button1.type: toggle", |
| + "*quality*button1.translations: #override\\n\ |
| + <Visible>: SetQualityState(1)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(1) HideQuality()", |
| + |
| + "*quality*button2.label: 2", |
| + "*quality*button2.type: toggle", |
| + "*quality*button2.translations: #override\\n\ |
| + <Visible>: SetQualityState(2)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(2) HideQuality()", |
| + |
| + "*quality*button3.label: 3", |
| + "*quality*button3.type: toggle", |
| + "*quality*button3.translations: #override\\n\ |
| + <Visible>: SetQualityState(3)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(3) HideQuality()", |
| + |
| + "*quality*button4.label: 4", |
| + "*quality*button4.type: toggle", |
| + "*quality*button4.translations: #override\\n\ |
| + <Visible>: SetQualityState(4)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(4) HideQuality()", |
| + |
| + "*quality*button5.label: 5", |
| + "*quality*button5.type: toggle", |
| + "*quality*button5.translations: #override\\n\ |
| + <Visible>: SetQualityState(5)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(5) HideQuality()", |
| + |
| + "*quality*button6.label: 6", |
| + "*quality*button6.type: toggle", |
| + "*quality*button6.translations: #override\\n\ |
| + <Visible>: SetQualityState(6)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(6) HideQuality()", |
| + |
| + "*quality*button7.label: 7", |
| + "*quality*button7.type: toggle", |
| + "*quality*button7.translations: #override\\n\ |
| + <Visible>: SetQualityState(7)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(7) HideQuality()", |
| + |
| + "*quality*button8.label: 8", |
| + "*quality*button8.type: toggle", |
| + "*quality*button8.translations: #override\\n\ |
| + <Visible>: SetQualityState(8)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(8) HideQuality()", |
| + |
| + "*quality*button9.label: 9", |
| + "*quality*button9.type: toggle", |
| + "*quality*button9.translations: #override\\n\ |
| + <Visible>: SetQualityState(9)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetQuality(9) HideQuality()", |
| + |
| + "*compress*buttonD.label: Dismiss", |
| + "*compress*buttonD.translations: #override\\n\ |
| + <Btn1Down>,<Btn1Up>: HideCompress()", |
| + |
| + "*compress*button0.label: 0", |
| + "*compress*button0.translations: #override\\n\ |
| + <Visible>: SetCompressState(0)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(0) HideCompress()", |
| + |
| + "*compress*button1.label: 1", |
| + "*compress*button1.translations: #override\\n\ |
| + <Visible>: SetCompressState(1)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(1) HideCompress()", |
| + |
| + "*compress*button2.label: 2", |
| + "*compress*button2.translations: #override\\n\ |
| + <Visible>: SetCompressState(2)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(2) HideCompress()", |
| + |
| + "*compress*button3.label: 3", |
| + "*compress*button3.translations: #override\\n\ |
| + <Visible>: SetCompressState(3)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(3) HideCompress()", |
| + |
| + "*compress*button4.label: 4", |
| + "*compress*button4.translations: #override\\n\ |
| + <Visible>: SetCompressState(4)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(4) HideCompress()", |
| + |
| + "*compress*button5.label: 5", |
| + "*compress*button5.translations: #override\\n\ |
| + <Visible>: SetCompressState(5)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(5) HideCompress()", |
| + |
| + "*compress*button6.label: 6", |
| + "*compress*button6.translations: #override\\n\ |
| + <Visible>: SetCompressState(6)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(6) HideCompress()", |
| + |
| + "*compress*button7.label: 7", |
| + "*compress*button7.translations: #override\\n\ |
| + <Visible>: SetCompressState(7)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(7) HideCompress()", |
| + |
| + "*compress*button8.label: 8", |
| + "*compress*button8.translations: #override\\n\ |
| + <Visible>: SetCompressState(8)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(8) HideCompress()", |
| + |
| + "*compress*button9.label: 9", |
| + "*compress*button9.translations: #override\\n\ |
| + <Visible>: SetCompressState(9)\\n\ |
| + <Btn1Down>,<Btn1Up>: SetCompress(9) HideCompress()", |
| + |
| NULL |
| }; |
| |
| @@ -124,7 +697,7 @@ |
| * from a dialog box. |
| */ |
| |
| -char vncServerHost[256]; |
| +char vncServerHost[1024]; |
| int vncServerPort = 0; |
| |
| |
| @@ -135,6 +708,7 @@ |
| */ |
| |
| AppData appData; |
| +AppData appDataNew; |
| |
| static XtResource appDataResourceList[] = { |
| {"shareDesktop", "ShareDesktop", XtRBool, sizeof(Bool), |
| @@ -155,14 +729,44 @@ |
| {"userLogin", "UserLogin", XtRString, sizeof(String), |
| XtOffsetOf(AppData, userLogin), XtRImmediate, (XtPointer) 0}, |
| |
| + {"unixPW", "UnixPW", XtRString, sizeof(String), |
| + XtOffsetOf(AppData, unixPW), XtRImmediate, (XtPointer) 0}, |
| + |
| + {"msLogon", "MSLogon", XtRString, sizeof(String), |
| + XtOffsetOf(AppData, msLogon), XtRImmediate, (XtPointer) 0}, |
| + |
| + {"repeaterUltra", "RepeaterUltra", XtRString, sizeof(String), |
| + XtOffsetOf(AppData, repeaterUltra), XtRImmediate, (XtPointer) 0}, |
| + |
| + {"ultraDSM", "UltraDSM", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, ultraDSM), XtRImmediate, (XtPointer) False}, |
| + |
| + {"acceptPopup", "AcceptPopup", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, acceptPopup), XtRImmediate, (XtPointer) False}, |
| + |
| + {"rfbVersion", "RfbVersion", XtRString, sizeof(String), |
| + XtOffsetOf(AppData, rfbVersion), XtRImmediate, (XtPointer) 0}, |
| + |
| {"passwordDialog", "PasswordDialog", XtRBool, sizeof(Bool), |
| XtOffsetOf(AppData, passwordDialog), XtRImmediate, (XtPointer) False}, |
| |
| {"encodings", "Encodings", XtRString, sizeof(String), |
| XtOffsetOf(AppData, encodingsString), XtRImmediate, (XtPointer) 0}, |
| |
| - {"useBGR233", "UseBGR233", XtRBool, sizeof(Bool), |
| - XtOffsetOf(AppData, useBGR233), XtRImmediate, (XtPointer) False}, |
| + {"useBGR233", "UseBGR233", XtRInt, sizeof(int), |
| + XtOffsetOf(AppData, useBGR233), XtRImmediate, (XtPointer) 0}, |
| + |
| + {"useBGR565", "UseBGR565", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, useBGR565), XtRImmediate, (XtPointer) False}, |
| + |
| + {"useGreyScale", "UseGreyScale", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, useGreyScale), XtRImmediate, (XtPointer) False}, |
| + |
| + {"yCrop", "yCrop", XtRInt, sizeof(int), |
| + XtOffsetOf(AppData, yCrop), XtRImmediate, (XtPointer) 0}, |
| + |
| + {"sbWidth", "sbWidth", XtRInt, sizeof(int), |
| + XtOffsetOf(AppData, sbWidth), XtRImmediate, (XtPointer) 2}, |
| |
| {"nColours", "NColours", XtRInt, sizeof(int), |
| XtOffsetOf(AppData, nColours), XtRImmediate, (XtPointer) 256}, |
| @@ -179,9 +783,12 @@ |
| {"requestedDepth", "RequestedDepth", XtRInt, sizeof(int), |
| XtOffsetOf(AppData, requestedDepth), XtRImmediate, (XtPointer) 0}, |
| |
| - {"useSharedMemory", "UseSharedMemory", XtRBool, sizeof(Bool), |
| + {"useShm", "UseShm", XtRBool, sizeof(Bool), |
| XtOffsetOf(AppData, useShm), XtRImmediate, (XtPointer) True}, |
| |
| + {"termChat", "TermChat", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, termChat), XtRImmediate, (XtPointer) False}, |
| + |
| {"wmDecorationWidth", "WmDecorationWidth", XtRInt, sizeof(int), |
| XtOffsetOf(AppData, wmDecorationWidth), XtRImmediate, (XtPointer) 4}, |
| |
| @@ -191,6 +798,9 @@ |
| {"popupButtonCount", "PopupButtonCount", XtRInt, sizeof(int), |
| XtOffsetOf(AppData, popupButtonCount), XtRImmediate, (XtPointer) 0}, |
| |
| + {"popupButtonBreak", "PopupButtonBreak", XtRInt, sizeof(int), |
| + XtOffsetOf(AppData, popupButtonBreak), XtRImmediate, (XtPointer) 0}, |
| + |
| {"debug", "Debug", XtRBool, sizeof(Bool), |
| XtOffsetOf(AppData, debug), XtRImmediate, (XtPointer) False}, |
| |
| @@ -206,11 +816,13 @@ |
| {"bumpScrollPixels", "BumpScrollPixels", XtRInt, sizeof(int), |
| XtOffsetOf(AppData, bumpScrollPixels), XtRImmediate, (XtPointer) 20}, |
| |
| + /* hardwired compress -1 vs . 7 */ |
| {"compressLevel", "CompressionLevel", XtRInt, sizeof(int), |
| XtOffsetOf(AppData, compressLevel), XtRImmediate, (XtPointer) -1}, |
| |
| + /* hardwired quality was 6 */ |
| {"qualityLevel", "QualityLevel", XtRInt, sizeof(int), |
| - XtOffsetOf(AppData, qualityLevel), XtRImmediate, (XtPointer) 6}, |
| + XtOffsetOf(AppData, qualityLevel), XtRImmediate, (XtPointer) -1}, |
| |
| {"enableJPEG", "EnableJPEG", XtRBool, sizeof(Bool), |
| XtOffsetOf(AppData, enableJPEG), XtRImmediate, (XtPointer) True}, |
| @@ -218,14 +830,97 @@ |
| {"useRemoteCursor", "UseRemoteCursor", XtRBool, sizeof(Bool), |
| XtOffsetOf(AppData, useRemoteCursor), XtRImmediate, (XtPointer) True}, |
| |
| + {"useCursorAlpha", "UseCursorAlpha", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, useCursorAlpha), XtRImmediate, (XtPointer) False}, |
| + |
| + {"useRawLocal", "UseRawLocal", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, useRawLocal), XtRImmediate, (XtPointer) False}, |
| + |
| + {"notty", "NoTty", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, notty), XtRImmediate, (XtPointer) False}, |
| + |
| {"useX11Cursor", "UseX11Cursor", XtRBool, sizeof(Bool), |
| XtOffsetOf(AppData, useX11Cursor), XtRImmediate, (XtPointer) False}, |
| |
| + {"useBell", "UseBell", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, useBell), XtRImmediate, (XtPointer) True}, |
| + |
| {"grabKeyboard", "GrabKeyboard", XtRBool, sizeof(Bool), |
| - XtOffsetOf(AppData, grabKeyboard), XtRImmediate, (XtPointer) False}, |
| + XtOffsetOf(AppData, grabKeyboard), XtRImmediate, (XtPointer) True}, |
| |
| {"autoPass", "AutoPass", XtRBool, sizeof(Bool), |
| - XtOffsetOf(AppData, autoPass), XtRImmediate, (XtPointer) False} |
| + XtOffsetOf(AppData, autoPass), XtRImmediate, (XtPointer) False}, |
| + |
| + {"grabAll", "GrabAll", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, grabAll), XtRImmediate, (XtPointer) False}, |
| + |
| + {"useXserverBackingStore", "UseXserverBackingStore", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, useXserverBackingStore), XtRImmediate, (XtPointer) False}, |
| + |
| + {"overrideRedir", "OverrideRedir", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, overrideRedir), XtRImmediate, (XtPointer) True}, |
| + |
| + {"serverInput", "ServerInput", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, serverInput), XtRImmediate, (XtPointer) True}, |
| + |
| + {"singleWindow", "SingleWindow", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, singleWindow), XtRImmediate, (XtPointer) False}, |
| + |
| + {"serverScale", "ServerScale", XtRInt, sizeof(int), |
| + XtOffsetOf(AppData, serverScale), XtRImmediate, (XtPointer) 1}, |
| + |
| + {"chatActive", "ChatActive", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, chatActive), XtRImmediate, (XtPointer) False}, |
| + |
| + {"chatOnly", "ChatOnly", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, chatOnly), XtRImmediate, (XtPointer) False}, |
| + |
| + {"fileActive", "FileActive", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, fileActive), XtRImmediate, (XtPointer) False}, |
| + |
| + {"popupFix", "PopupFix", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, popupFix), XtRImmediate, (XtPointer) False}, |
| + |
| + {"scale", "Scale", XtRString, sizeof(String), |
| + XtOffsetOf(AppData, scale), XtRImmediate, (XtPointer) 0}, |
| + |
| + {"pipelineUpdates", "PipelineUpdates", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, pipelineUpdates), XtRImmediate, (XtPointer) |
| +#ifdef TURBOVNC |
| + True}, |
| +#else |
| +#if 0 |
| + False}, |
| +#else |
| + True}, |
| +#endif |
| +#endif |
| + |
| + {"noipv4", "noipv4", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, noipv4), XtRImmediate, (XtPointer) False}, |
| + |
| + {"noipv6", "noipv6", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, noipv6), XtRImmediate, (XtPointer) False}, |
| + |
| + {"sendClipboard", "SendClipboard", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, sendClipboard), XtRImmediate, (XtPointer) False}, |
| + |
| + {"sendAlways", "SendAlways", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, sendAlways), XtRImmediate, (XtPointer) False}, |
| + |
| + {"recvText", "RecvText", XtRString, sizeof(String), |
| + XtOffsetOf(AppData, recvText), XtRImmediate, (XtPointer) 0}, |
| + |
| + {"appShare", "AppShare", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, appShare), XtRImmediate, (XtPointer) False}, |
| + |
| + {"escapeKeys", "EscapeKeys", XtRString, sizeof(String), |
| + XtOffsetOf(AppData, escapeKeys), XtRImmediate, (XtPointer) 0}, |
| + |
| + {"escapeActive", "EscapeActive", XtRBool, sizeof(Bool), |
| + XtOffsetOf(AppData, escapeActive), XtRImmediate, (XtPointer) False} |
| + |
| + /* check commas */ |
| }; |
| |
| |
| @@ -242,8 +937,29 @@ |
| {"-noraiseonbeep", "*raiseOnBeep", XrmoptionNoArg, "False"}, |
| {"-passwd", "*passwordFile", XrmoptionSepArg, 0}, |
| {"-user", "*userLogin", XrmoptionSepArg, 0}, |
| + {"-unixpw", "*unixPW", XrmoptionSepArg, 0}, |
| + {"-mslogon", "*msLogon", XrmoptionSepArg, 0}, |
| + {"-repeater", "*repeaterUltra", XrmoptionSepArg, 0}, |
| + {"-ultradsm", "*ultraDSM", XrmoptionNoArg, "True"}, |
| + {"-acceptpopup", "*acceptPopup", XrmoptionNoArg, "True"}, |
| + {"-acceptpopupsc", "*acceptPopup", XrmoptionNoArg, "True"}, |
| + {"-rfbversion", "*rfbVersion", XrmoptionSepArg, 0}, |
| {"-encodings", "*encodings", XrmoptionSepArg, 0}, |
| - {"-bgr233", "*useBGR233", XrmoptionNoArg, "True"}, |
| + {"-bgr233", "*useBGR233", XrmoptionNoArg, "256"}, |
| + {"-use64", "*useBGR233", XrmoptionNoArg, "64"}, |
| + {"-bgr222", "*useBGR233", XrmoptionNoArg, "64"}, |
| + {"-use8", "*useBGR233", XrmoptionNoArg, "8"}, |
| + {"-bgr111", "*useBGR233", XrmoptionNoArg, "8"}, |
| + {"-16bpp", "*useBGR565", XrmoptionNoArg, "True"}, |
| + {"-bgr565", "*useBGR565", XrmoptionNoArg, "True"}, |
| + {"-grey", "*useGreyScale", XrmoptionNoArg, "True"}, |
| + {"-gray", "*useGreyScale", XrmoptionNoArg, "True"}, |
| + {"-sbwidth", "*sbwidth", XrmoptionSepArg, 0}, |
| + {"-env", "*envDummy", XrmoptionSepArg, 0}, |
| + {"-ycrop", "*yCrop", XrmoptionSepArg, 0}, |
| + {"-rawlocal", "*useRawLocal", XrmoptionNoArg, "True"}, |
| + {"-notty", "*notty", XrmoptionNoArg, "True"}, |
| + {"-alpha", "*useCursorAlpha", XrmoptionNoArg, "True"}, |
| {"-owncmap", "*forceOwnCmap", XrmoptionNoArg, "True"}, |
| {"-truecolor", "*forceTrueColour", XrmoptionNoArg, "True"}, |
| {"-truecolour", "*forceTrueColour", XrmoptionNoArg, "True"}, |
| @@ -253,8 +969,30 @@ |
| {"-nojpeg", "*enableJPEG", XrmoptionNoArg, "False"}, |
| {"-nocursorshape", "*useRemoteCursor", XrmoptionNoArg, "False"}, |
| {"-x11cursor", "*useX11Cursor", XrmoptionNoArg, "True"}, |
| - {"-autopass", "*autoPass", XrmoptionNoArg, "True"} |
| - |
| + {"-nobell", "*useBell", XrmoptionNoArg, "False"}, |
| + {"-autopass", "*autoPass", XrmoptionNoArg, "True"}, |
| + {"-graball", "*grabAll", XrmoptionNoArg, "True"}, |
| + {"-grabkbd", "*grabKeyboard", XrmoptionNoArg, "True"}, |
| + {"-nograbkbd", "*grabKeyboard", XrmoptionNoArg, "False"}, |
| + {"-grabkeyboard", "*grabKeyboard", XrmoptionNoArg, "True"}, |
| + {"-nograbkeyboard","*grabKeyboard", XrmoptionNoArg, "False"}, |
| + {"-nooverride", "*overrideRedir", XrmoptionNoArg, "False"}, |
| + {"-bs", "*useXserverBackingStore", XrmoptionNoArg, "True"}, |
| + {"-nobs", "*useXserverBackingStore", XrmoptionNoArg, "False"}, |
| + {"-popupfix", "*popupFix", XrmoptionNoArg, "True"}, |
| + {"-noshm", "*useShm", XrmoptionNoArg, "False"}, |
| + {"-termchat", "*termChat", XrmoptionNoArg, "True"}, |
| + {"-chatonly", "*chatOnly", XrmoptionNoArg, "True"}, |
| + {"-scale", "*scale", XrmoptionSepArg, 0}, |
| + {"-appshare", "*appShare", XrmoptionNoArg, "True"}, |
| + {"-escape", "*escapeKeys", XrmoptionSepArg, 0}, |
| + {"-sendclipboard", "*sendClipboard", XrmoptionNoArg, "True"}, |
| + {"-sendalways", "*sendAlways", XrmoptionNoArg, "True"}, |
| + {"-recvtext", "*recvText", XrmoptionSepArg, 0}, |
| + {"-pipeline", "*pipelineUpdates", XrmoptionNoArg, "True"}, |
| + {"-nopipeline", "*pipelineUpdates", XrmoptionNoArg, "False"}, |
| + {"-noipv4", "*noipv4", XrmoptionNoArg, "True"}, |
| + {"-noipv6", "*noipv6", XrmoptionNoArg, "True"} |
| }; |
| |
| int numCmdLineOptions = XtNumber(cmdLineOptions); |
| @@ -267,16 +1005,100 @@ |
| static XtActionsRec actions[] = { |
| {"SendRFBEvent", SendRFBEvent}, |
| {"ShowPopup", ShowPopup}, |
| + {"Noop", Noop}, |
| {"HidePopup", HidePopup}, |
| + {"HideScaleN", HideScaleN}, |
| + {"HideTurboVNC", HideTurboVNC}, |
| + {"HideQuality", HideQuality}, |
| + {"HideCompress", HideCompress}, |
| {"ToggleFullScreen", ToggleFullScreen}, |
| + {"JumpLeft", JumpLeft}, |
| + {"JumpRight", JumpRight}, |
| + {"JumpUp", JumpUp}, |
| + {"JumpDown", JumpDown}, |
| {"SetFullScreenState", SetFullScreenState}, |
| {"SelectionFromVNC", SelectionFromVNC}, |
| {"SelectionToVNC", SelectionToVNC}, |
| {"ServerDialogDone", ServerDialogDone}, |
| + {"UserDialogDone", UserDialogDone}, |
| + {"YCropDialogDone", YCropDialogDone}, |
| + {"ScbarDialogDone", ScbarDialogDone}, |
| + {"ScaleNDialogDone", ScaleNDialogDone}, |
| + {"ScaleDialogDone", ScaleDialogDone}, |
| {"PasswordDialogDone", PasswordDialogDone}, |
| {"Pause", Pause}, |
| {"RunCommand", RunCommand}, |
| {"Quit", Quit}, |
| + {"HideChat", HideChat}, |
| + {"Toggle8bpp", Toggle8bpp}, |
| + {"Toggle16bpp", Toggle16bpp}, |
| + {"ToggleFullColor", ToggleFullColor}, |
| + {"Toggle256Colors", Toggle256Colors}, |
| + {"Toggle64Colors", Toggle64Colors}, |
| + {"Toggle8Colors", Toggle8Colors}, |
| + {"ToggleGreyScale", ToggleGreyScale}, |
| + {"ToggleTightZRLE", ToggleTightZRLE}, |
| + {"ToggleTightHextile", ToggleTightHextile}, |
| + {"ToggleZRLEZYWRLE", ToggleZRLEZYWRLE}, |
| + {"ToggleViewOnly", ToggleViewOnly}, |
| + {"ToggleJPEG", ToggleJPEG}, |
| + {"ToggleCursorShape", ToggleCursorShape}, |
| + {"ToggleCursorAlpha", ToggleCursorAlpha}, |
| + {"ToggleX11Cursor", ToggleX11Cursor}, |
| + {"ToggleBell", ToggleBell}, |
| + {"ToggleRawLocal", ToggleRawLocal}, |
| + {"ToggleServerInput", ToggleServerInput}, |
| + {"TogglePipelineUpdates", TogglePipelineUpdates}, |
| + {"ToggleSendClipboard", ToggleSendClipboard}, |
| + {"ToggleSendAlways", ToggleSendAlways}, |
| + {"ToggleSingleWindow", ToggleSingleWindow}, |
| + {"ToggleTextChat", ToggleTextChat}, |
| + {"ToggleFileXfer", ToggleFileXfer}, |
| + {"ToggleXGrab", ToggleXGrab}, |
| + {"DoServerScale", DoServerScale}, |
| + {"SetScale", SetScale}, |
| + {"SetYCrop", SetYCrop}, |
| + {"SetScbar", SetScbar}, |
| + {"ShowScaleN", ShowScaleN}, |
| + {"ShowTurboVNC", ShowTurboVNC}, |
| + {"ShowQuality", ShowQuality}, |
| + {"ShowCompress", ShowCompress}, |
| + {"SetScaleN", SetScaleN}, |
| + {"SetTurboVNC", SetTurboVNC}, |
| + {"SetQuality", SetQuality}, |
| + {"SetCompress", SetCompress}, |
| + {"Set8bppState", Set8bppState}, |
| + {"Set16bppState", Set16bppState}, |
| + {"SetFullColorState", SetFullColorState}, |
| + {"Set256ColorsState", Set256ColorsState}, |
| + {"Set64ColorsState", Set64ColorsState}, |
| + {"Set8ColorsState", Set8ColorsState}, |
| + {"SetGreyScaleState", SetGreyScaleState}, |
| + {"SetZRLEState", SetZRLEState}, |
| + {"SetHextileState", SetHextileState}, |
| + {"SetZYWRLEState", SetZYWRLEState}, |
| + {"SetNOJPEGState", SetNOJPEGState}, |
| + {"SetScaleNState", SetScaleNState}, |
| + {"SetQualityState", SetQualityState}, |
| + {"SetCompressState", SetCompressState}, |
| + {"SetViewOnlyState", SetViewOnlyState}, |
| + {"SetCursorShapeState", SetCursorShapeState}, |
| + {"SetCursorAlphaState", SetCursorAlphaState}, |
| + {"SetX11CursorState", SetX11CursorState}, |
| + {"SetBellState", SetBellState}, |
| + {"SetRawLocalState", SetRawLocalState}, |
| + {"SetServerInputState", SetServerInputState}, |
| + {"SetPipelineUpdates", SetPipelineUpdates}, |
| + {"SetSendClipboard", SetSendClipboard}, |
| + {"SetSendAlways", SetSendAlways}, |
| + {"SetSingleWindowState", SetSingleWindowState}, |
| + {"SetTextChatState", SetTextChatState}, |
| + {"SetFileXferState", SetFileXferState}, |
| + {"SetXGrabState", SetXGrabState}, |
| + {"SetEscapeKeysState", SetEscapeKeysState}, |
| + {"ToggleEscapeActive", ToggleEscapeActive}, |
| + {"EscapeDialogDone", EscapeDialogDone}, |
| + {"SetEscapeKeys", SetEscapeKeys} |
| }; |
| |
| |
| @@ -302,11 +1124,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 [<OPTIONS>] [<HOST>][:<DISPLAY#>]\n" |
| " %s [<OPTIONS>] [<HOST>][::<PORT#>]\n" |
| + " %s [<OPTIONS>] exec=[CMD ARGS...]\n" |
| + " %s [<OPTIONS>] fd=n\n" |
| + " %s [<OPTIONS>] /path/to/unix/socket\n" |
| " %s [<OPTIONS>] -listen [<DISPLAY#>]\n" |
| " %s -help\n" |
| "\n" |
| @@ -319,7 +1144,7 @@ |
| " -noraiseonbeep\n" |
| " -passwd <PASSWD-FILENAME> (standard VNC authentication)\n" |
| " -user <USERNAME> (Unix login authentication)\n" |
| - " -encodings <ENCODING-LIST> (e.g. \"tight copyrect\")\n" |
| + " -encodings <ENCODING-LIST> (e.g. \"tight,copyrect\")\n" |
| " -bgr233\n" |
| " -owncmap\n" |
| " -truecolour\n" |
| @@ -332,10 +1157,390 @@ |
| " -autopass\n" |
| "\n" |
| "Option names may be abbreviated, e.g. -bgr instead of -bgr233.\n" |
| - "See the manual page for more information." |
| - "\n", programName, programName, programName, programName); |
| + "See the manual page for more information.\n" |
| + "\n" |
| + "\n" |
| + "Enhanced TightVNC viewer (SSVNC) options:\n" |
| + "\n" |
| + " URL http://www.karlrunge.com/x11vnc/ssvnc.html\n" |
| + "\n" |
| + " Note: ZRLE and ZYWRLE encodings are now supported.\n" |
| + "\n" |
| + " Note: F9 is shortcut to Toggle FullScreen mode.\n" |
| + "\n" |
| + " Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1\n" |
| + " to allow more than one incoming VNC server at a time.\n" |
| + " This is the same as -multilisten described below. Set\n" |
| + " SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than \"n\"\n" |
| + " simultaneous reverse connections.\n" |
| + "\n" |
| + " Note: If the host:port is specified as \"exec=command args...\"\n" |
| + " then instead of making a TCP/IP socket connection to the\n" |
| + " remote VNC server, \"command args...\" is executed and the\n" |
| + " viewer is attached to its stdio. This enables tunnelling\n" |
| + " established via an external command, e.g. an stunnel(8)\n" |
| + " that does not involve a listening socket. This mode does\n" |
| + " not work for -listen reverse connections.\n" |
| + "\n" |
| + " If the host:port is specified as \"fd=n\" then it is assumed\n" |
| + " n is an already opened file descriptor to the socket. (i.e\n" |
| + " the parent did fork+exec)\n" |
| + "\n" |
| + " If the host:port contains a '/' it is interpreted as a\n" |
| + " unix-domain socket (AF_LOCAL insead of AF_INET)\n" |
| + "\n" |
| + " -multilisten As in -listen (reverse connection listening) except\n" |
| + " allow more than one incoming VNC server to be connected\n" |
| + " at a time. The default for -listen of only one at a\n" |
| + " time tries to play it safe by not allowing anyone on\n" |
| + " the network to put (many) desktops on your screen over\n" |
| + " a long window of time. Use -multilisten for no limit.\n" |
| + "\n" |
| + " -acceptpopup In -listen (reverse connection listening) mode when\n" |
| + " a reverse VNC connection comes in show a popup asking\n" |
| + " whether to Accept or Reject the connection. The IP\n" |
| + " address of the connecting host is shown. Same as\n" |
| + " setting the env. var. SSVNC_ACCEPT_POPUP=1.\n" |
| + "\n" |
| + " -acceptpopupsc As in -acceptpopup except assume UltraVNC Single\n" |
| + " Click (SC) server. Retrieve User and ComputerName\n" |
| + " info from UltraVNC Server and display in the Popup.\n" |
| + "\n" |
| + " -use64 In -bgr233 mode, use 64 colors instead of 256.\n" |
| + " -bgr222 Same as -use64.\n" |
| + "\n" |
| + " -use8 In -bgr233 mode, use 8 colors instead of 256.\n" |
| + " -bgr111 Same as -use8.\n" |
| + "\n" |
| + " -16bpp If the vnc viewer X display is depth 24 at 32bpp\n" |
| + " request a 16bpp format from the VNC server to cut\n" |
| + " network traffic by up to 2X, then tranlate the\n" |
| + " pixels to 32bpp locally.\n" |
| + " -bgr565 Same as -16bpp.\n" |
| + "\n" |
| + " -grey Use a grey scale for the 16- and 8-bpp modes.\n" |
| + "\n" |
| + " -alpha Use alphablending transparency for local cursors\n" |
| + " requires: x11vnc server, both client and server\n" |
| + " must be 32bpp and same endianness.\n" |
| + "\n" |
| + " -scale str Scale the desktop locally. The string \"str\" can\n" |
| + " a floating point ratio, e.g. \"0.9\", or a fraction,\n" |
| + " e.g. \"3/4\", or WxH, e.g. 1280x1024. Use \"fit\"\n" |
| + " to fit in the current screen size. Use \"auto\" to\n" |
| + " fit in the window size. \"str\" can also be set by\n" |
| + " the env. var. SSVNC_SCALE.\n" |
| + "\n" |
| + " If you observe mouse trail painting errors, enable\n" |
| + " X11 Cursor mode (either via Popup or -x11cursor.)\n" |
| + "\n" |
| + " Note that scaling is done in software and so can be\n" |
| + " slow and requires more memory. Some speedup Tips:\n" |
| + "\n" |
| + " ZRLE is faster than Tight in this mode. When\n" |
| + " scaling is first detected, the encoding will\n" |
| + " be automatically switched to ZRLE. Use the\n" |
| + " Popup menu if you want to go back to Tight.\n" |
| + " Set SSVNC_PRESERVE_ENCODING=1 to disable this.\n" |
| + "\n" |
| + " Use a solid background on the remote side.\n" |
| + " (e.g. manually or via x11vnc -solid ...)\n" |
| + "\n" |
| + " If the remote server is x11vnc, try client\n" |
| + " side caching: x11vnc -ncache 10 ...\n" |
| + "\n" |
| + " -ycrop n Only show the top n rows of the framebuffer. For\n" |
| + " use with x11vnc -ncache client caching option\n" |
| + " to help \"hide\" the pixel cache region.\n" |
| + " Use a negative value (e.g. -1) for autodetection.\n" |
| + " Autodetection will always take place if the remote\n" |
| + " fb height is more than 2 times the width.\n" |
| + "\n" |
| + " -sbwidth n Scrollbar width for x11vnc -ncache mode (-ycrop),\n" |
| + " default is very narrow: 2 pixels, it is narrow to\n" |
| + " avoid distraction in -ycrop mode.\n" |
| + "\n" |
| + " -nobell Disable bell.\n" |
| + "\n" |
| + " -rawlocal Prefer raw encoding for localhost, default is\n" |
| + " no, i.e. assumes you have a SSH tunnel instead.\n" |
| + "\n" |
| + " -notty Try to avoid using the terminal for interactive\n" |
| + " responses: use windows for messages and prompting\n" |
| + " instead. Messages will also be printed to terminal.\n" |
| + "\n" |
| + " -sendclipboard Send the X CLIPBOARD selection (i.e. Ctrl+C,\n" |
| + " Ctrl+V) instead of the X PRIMARY selection (mouse\n" |
| + " select and middle button paste.)\n" |
| + "\n" |
| + " -sendalways Whenever the mouse enters the VNC viewer main\n" |
| + " window, send the selection to the VNC server even if\n" |
| + " it has not changed. This is like the Xt resource\n" |
| + " translation SelectionToVNC(always)\n" |
| + "\n" |
| + " -recvtext str When cut text is received from the VNC server,\n" |
| + " ssvncviewer will set both the X PRIMARY and the\n" |
| + " X CLIPBOARD local selections. To control which\n" |
| + " is set, specify 'str' as 'primary', 'clipboard',\n" |
| + " or 'both' (the default.)\n" |
| + "\n" |
| + " -graball Grab the entire X server when in fullscreen mode,\n" |
| + " needed by some old window managers like fvwm2.\n" |
| + "\n" |
| + " -popupfix Warp the popup back to the pointer position,\n" |
| + " needed by some old window managers like fvwm2.\n" |
| + " -sendclipboard Send the X CLIPBOARD selection (i.e. Ctrl+C,\n" |
| + " Ctrl+V) instead of the X PRIMARY selection (mouse\n" |
| + " select and middle button paste.)\n" |
| + "\n" |
| + " -sendalways Whenever the mouse enters the VNC viewer main\n" |
| + " window, send the selection to the VNC server even if\n" |
| + " it has not changed. This is like the Xt resource\n" |
| + " translation SelectionToVNC(always)\n" |
| + "\n" |
| + " -recvtext str When cut text is received from the VNC server,\n" |
| + " ssvncviewer will set both the X PRIMARY and the\n" |
| + " X CLIPBOARD local selections. To control which\n" |
| + " is set, specify 'str' as 'primary', 'clipboard',\n" |
| + " or 'both' (the default.)\n" |
| + "\n" |
| + " -graball Grab the entire X server when in fullscreen mode,\n" |
| + " needed by some old window managers like fvwm2.\n" |
| + "\n" |
| + " -popupfix Warp the popup back to the pointer position,\n" |
| + " needed by some old window managers like fvwm2.\n" |
| + "\n" |
| + " -grabkbd Grab the X keyboard when in fullscreen mode,\n" |
| + " needed by some window managers. Same as -grabkeyboard.\n" |
| + " -grabkbd is the default, use -nograbkbd to disable.\n" |
| + "\n" |
| + " -bs, -nobs Whether or not to use X server Backingstore for the\n" |
| + " main viewer window. The default is to not, mainly\n" |
| + " because most Linux, etc, systems X servers disable\n" |
| + " *all* Backingstore by default. To re-enable it put\n" |
| + "\n" |
| + " Option \"Backingstore\"\n" |
| + "\n" |
| + " in the Device section of /etc/X11/xorg.conf.\n" |
| + " In -bs mode with no X server backingstore, whenever an\n" |
| + " area of the screen is re-exposed it must go out to the\n" |
| + " VNC server to retrieve the pixels. This is too slow.\n" |
| + "\n" |
| + " In -nobs mode, memory is allocated by the viewer to\n" |
| + " provide its own backing of the main viewer window. This\n" |
| + " actually makes some activities faster (changes in large\n" |
| + " regions) but can appear to \"flash\" too much.\n" |
| + "\n" |
| + " -noshm Disable use of MIT shared memory extension (not recommended)\n" |
| + "\n" |
| + " -termchat Do the UltraVNC chat in the terminal vncviewer is in\n" |
| + " instead of in an independent window.\n" |
| + "\n" |
| + " -unixpw str Useful for logging into x11vnc in -unixpw mode. \"str\" is a\n" |
| + " string that allows many ways to enter the Unix Username\n" |
| + " and Unix Password. These characters: username, newline,\n" |
| + " password, newline are sent to the VNC server after any VNC\n" |
| + " authentication has taken place. Under x11vnc they are\n" |
| + " used for the -unixpw login. Other VNC servers could do\n" |
| + " something similar.\n" |
| + "\n" |
| + " You can also indicate \"str\" via the environment\n" |
| + " variable SSVNC_UNIXPW.\n" |
| + "\n" |
| + " Note that the Escape key is actually sent first to tell\n" |
| + " x11vnc to not echo the Unix Username back to the VNC\n" |
| + " viewer. Set SSVNC_UNIXPW_NOESC=1 to override this.\n" |
| + "\n" |
| + " If str is \".\", then you are prompted at the command line\n" |
| + " for the username and password in the normal way. If str is\n" |
| + " \"-\" the stdin is read via getpass(3) for username@password.\n" |
| + " Otherwise if str is a file, it is opened and the first line\n" |
| + " read is taken as the Unix username and the 2nd as the\n" |
| + " password. If str prefixed by \"rm:\" the file is removed\n" |
| + " after reading. Otherwise, if str has a \"@\" character,\n" |
| + " it is taken as username@password. Otherwise, the program\n" |
| + " exits with an error. Got all that?\n" |
| + "\n" |
| + " -repeater str This is for use with UltraVNC repeater proxy described\n" |
| + " here: http://www.uvnc.com/addons/repeater.html. The \"str\"\n" |
| + " is the ID string to be sent to the repeater. E.g. ID:1234\n" |
| + " It can also be the hostname and port or display of the VNC\n" |
| + " server, e.g. 12.34.56.78:0 or snoopy.com:1. Note that when\n" |
| + " using -repeater, the host:dpy on the cmdline is the repeater\n" |
| + " server, NOT the VNC server. The repeater will connect you.\n" |
| + "\n" |
| + " Example: vncviewer ... -repeater ID:3333 repeat.host:5900\n" |
| + " Example: vncviewer ... -repeater vhost:0 repeat.host:5900\n" |
| + "\n" |
| + " Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a\n" |
| + " Single Click III (SSL) repeater (repeater_SSL.exe) and you\n" |
| + " are passing the SSL part of the connection through stunnel,\n" |
| + " socat, etc. This way the magic UltraVNC string 'testB'\n" |
| + " needed to work with the repeater is sent to it.\n" |
| + "\n" |
| + " -rfbversion str Set the advertised RFB version. E.g.: -rfbversion 3.6\n" |
| + " For some servers, e.g. UltraVNC this needs to be done.\n" |
| + "\n" |
| + " -ultradsm UltraVNC has symmetric private key encryption DSM plugins:\n" |
| + " http://www.uvnc.com/features/encryption.html. It is assumed\n" |
| + " you are using a unix program (e.g. our ultravnc_dsm_helper)\n" |
| + " to encrypt and decrypt the UltraVNC DSM stream. IN ADDITION\n" |
| + " TO THAT supply -ultradsm to tell THIS viewer to modify the\n" |
| + " RFB data sent so as to work with the UltraVNC Server. For\n" |
| + " some reason, each RFB msg type must be sent twice under DSM.\n" |
| + "\n" |
| + " -mslogon user Use Windows MS Logon to an UltraVNC server. Supply the\n" |
| + " username or \"1\" to be prompted. The default is to\n" |
| + " autodetect the UltraVNC MS Logon server and prompt for\n" |
| + " the username and password.\n" |
| + "\n" |
| + " IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman\n" |
| + " exchange is very weak and can be brute forced to recover\n" |
| + " your username and password in a few seconds of CPU time.\n" |
| + " To be safe, be sure to use an additional encrypted tunnel\n" |
| + " (e.g. SSL or SSH) for the entire VNC session.\n" |
| + "\n" |
| + " -chatonly Try to be a client that only does UltraVNC text chat. This\n" |
| + " mode is used by x11vnc to present a chat window on the\n" |
| + " physical X11 console (i.e. chat with the person at the\n" |
| + " display).\n" |
| + "\n" |
| + " -env VAR=VALUE To save writing a shell script to set environment variables,\n" |
| + " specify as many as you need on the command line. For\n" |
| + " example, -env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi\n" |
| + "\n" |
| + " -noipv6 Disable all IPv6 sockets. Same as VNCVIEWER_NO_IPV6=1.\n" |
| + "\n" |
| + " -noipv4 Disable all IPv4 sockets. Same as VNCVIEWER_NO_IPV4=1.\n" |
| + "\n" |
| + " -printres Print out the Ssvnc X resources (appdefaults) and then exit\n" |
| + " You can save them to a file and customize them (e.g. the\n" |
| + " keybindings and Popup menu) Then point to the file via\n" |
| + " XENVIRONMENT or XAPPLRESDIR.\n" |
| + "\n" |
| + " -pipeline Like TurboVNC, request the next framebuffer update as soon\n" |
| + " as possible instead of waiting until the end of the current\n" |
| + " framebuffer update coming in. Helps 'pipeline' the updates.\n" |
| + " This is currently the default, use -nopipeline to disable.\n" |
| + "\n" |
| + " -appshare Enable features for use with x11vnc's -appshare mode where\n" |
| + " instead of sharing the full desktop only the application's\n" |
| + " windows are shared. Viewer multilisten mode is used to\n" |
| + " create the multiple windows: -multilisten is implied.\n" |
| + " See 'x11vnc -appshare -help' more information on the mode.\n" |
| + "\n" |
| + " Features enabled in the viewer under -appshare are:\n" |
| + " Minimum extra text in the title, auto -ycrop is disabled,\n" |
| + " x11vnc -remote_prefix X11VNC_APPSHARE_CMD: message channel,\n" |
| + " x11vnc initial window position hints. See also Escape Keys\n" |
| + " below for additional key and mouse bindings.\n" |
| + "\n" |
| + " -escape str This sets the 'Escape Keys' modifier sequence and enables\n" |
| + " escape keys mode. When the modifier keys escape sequence\n" |
| + " is held down, the next keystroke is interpreted locally\n" |
| + " to perform a special action instead of being sent to the\n" |
| + " remote VNC server.\n" |
| + "\n" |
| + " Use '-escape default' for the default modifier sequence.\n" |
| + " (Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L)\n" |
| + "\n" |
| + " Here are the 'Escape Keys: Help+Set' instructions from the Popup Menu:\n" |
| + "\n" |
| + " Escape Keys: Enter a comma separated list of modifier keys to be the\n" |
| + " 'escape sequence'. When these keys are held down, the next keystroke is\n" |
| + " interpreted locally to invoke a special action instead of being sent to\n" |
| + " the remote VNC server. In other words, a set of 'Hot Keys'.\n" |
| + " \n" |
| + " To enable or disable this, click on 'Escape Keys: Toggle' in the Popup.\n" |
| + " \n" |
| + " Here is the list of hot-key mappings to special actions:\n" |
| + " \n" |
| + " r: refresh desktop b: toggle bell c: toggle full-color\n" |
| + " f: file transfer x: x11cursor z: toggle Tight/ZRLE\n" |
| + " l: full screen g: graball e: escape keys dialog\n" |
| + " s: scale dialog +: scale up (=) -: scale down (_)\n" |
| + " t: text chat a: alphablend cursor\n" |
| + " V: toggle viewonly Q: quit viewer 1 2 3 4 5 6: UltraVNC scale 1/n\n" |
| + " \n" |
| + " Arrow keys: pan the viewport about 10%% for each keypress.\n" |
| + " PageUp / PageDown: pan the viewport by a screenful vertically.\n" |
| + " Home / End: pan the viewport by a screenful horizontally.\n" |
| + " KeyPad Arrow keys: pan the viewport by 1 pixel for each keypress.\n" |
| + " Dragging the Mouse with Button1 pressed also pans the viewport.\n" |
| + " Clicking Mouse Button3 brings up the Popup Menu.\n" |
| + " \n" |
| + " The above mappings are *always* active in ViewOnly mode, unless you set the\n" |
| + " Escape Keys value to 'never'.\n" |
| + " \n" |
| + " If the Escape Keys value below is set to 'default' then a default list of\n" |
| + " of modifier keys is used. For Unix it is: Alt_L,Super_L and for MacOSX it\n" |
| + " is Control_L,Meta_L. Note: the Super_L key usually has a Windows(TM) Flag\n" |
| + " on it. Also note the _L and _R mean the key is on the LEFT or RIGHT side\n" |
| + " of the keyboard.\n" |
| + " \n" |
| + " On Unix the default is Alt and Windows keys on Left side of keyboard.\n" |
| + " On MacOSX the default is Control and Command keys on Left side of keyboard.\n" |
| + " \n" |
| + " Example: Press and hold the Alt and Windows keys on the LEFT side of the\n" |
| + " keyboard and then press 'c' to toggle the full-color state. Or press 't'\n" |
| + " to toggle the ultravnc Text Chat window, etc.\n" |
| + " \n" |
| + " To use something besides the default, supply a comma separated list (or a\n" |
| + " single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L\n" |
| + " Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch.\n" |
| + "\n" |
| + "\n" |
| + " New Popup actions:\n" |
| + "\n" |
| + " ViewOnly: ~ -viewonly\n" |
| + " Disable Bell: ~ -nobell\n" |
| + " Cursor Shape: ~ -nocursorshape\n" |
| + " X11 Cursor: ~ -x11cursor\n" |
| + " Cursor Alphablend: ~ -alpha\n" |
| + " Toggle Tight/Hextile: ~ -encodings hextile...\n" |
| + " Toggle Tight/ZRLE: ~ -encodings zrle...\n" |
| + " Toggle ZRLE/ZYWRLE: ~ -encodings zywrle...\n" |
| + " Quality Level ~ -quality (both Tight and ZYWRLE)\n" |
| + " Compress Level ~ -compresslevel\n" |
| + " Disable JPEG: ~ -nojpeg (Tight)\n" |
| + " Pipeline Updates ~ -pipeline\n" |
| + "\n" |
| + " Full Color as many colors as local screen allows.\n" |
| + " Grey scale (16 & 8-bpp) ~ -grey, for low colors 16/8bpp modes only.\n" |
| + " 16 bit color (BGR565) ~ -16bpp / -bgr565\n" |
| + " 8 bit color (BGR233) ~ -bgr233\n" |
| + " 256 colors ~ -bgr233 default # of colors.\n" |
| + " 64 colors ~ -bgr222 / -use64\n" |
| + " 8 colors ~ -bgr111 / -use8\n" |
| + " Scale Viewer ~ -scale\n" |
| + " Escape Keys: Toggle ~ -escape\n" |
| + " Escape Keys: Help+Set ~ -escape\n" |
| + " Set Y Crop (y-max) ~ -ycrop\n" |
| + " Set Scrollbar Width ~ -sbwidth\n" |
| + " XGrabServer ~ -graball\n" |
| + "\n" |
| + " UltraVNC Extensions:\n" |
| + "\n" |
| + " Set 1/n Server Scale Ultravnc ext. Scale desktop by 1/n.\n" |
| + " Text Chat Ultravnc ext. Do Text Chat.\n" |
| + " File Transfer Ultravnc ext. File xfer via Java helper.\n" |
| + " Single Window Ultravnc ext. Grab and view a single window.\n" |
| + " (select then click on the window you want).\n" |
| + " Disable Remote Input Ultravnc ext. Try to prevent input and\n" |
| + " viewing of monitor at physical display.\n" |
| + "\n" |
| + " Note: the Ultravnc extensions only apply to servers that support\n" |
| + " them. x11vnc/libvncserver supports some of them.\n" |
| + "\n" |
| + " Send Clipboard not Primary ~ -sendclipboard\n" |
| + " Send Selection Every time ~ -sendalways\n" |
| + "\n" |
| + "\n", programName, programName, programName, programName, programName, programName, programName); |
| exit(1); |
| } |
| +#if 0 |
| + " -nooverride Do not apply OverrideRedirect in fullscreen mode.\n" |
| +#endif |
| |
| |
| /* |
| @@ -343,77 +1548,247 @@ |
| * not already processed by XtVaAppInitialize(). It sets vncServerHost and |
| * vncServerPort and all the fields in appData. |
| */ |
| +extern int saw_appshare; |
| |
| void |
| GetArgsAndResources(int argc, char **argv) |
| { |
| - int i; |
| - char *vncServerName, *colonPos; |
| - int len, portOffset; |
| + char *vncServerName = NULL, *colonPos, *bracketPos; |
| + int len, portOffset; |
| + int disp; |
| |
| /* Turn app resource specs into our appData structure for the rest of the |
| program to use */ |
| |
| - XtGetApplicationResources(toplevel, &appData, appDataResourceList, |
| - XtNumber(appDataResourceList), 0, 0); |
| + XtGetApplicationResources(toplevel, &appData, appDataResourceList, |
| + XtNumber(appDataResourceList), 0, 0); |
| + |
| + /* |
| + * we allow setting of some by env, to avoid clash with other |
| + * viewer's cmdlines (e.g. change viewer in SSVNC). |
| + */ |
| + if (getenv("VNCVIEWER_ALPHABLEND")) { |
| + appData.useCursorAlpha = True; |
| + } |
| + if (getenv("VNCVIEWER_POPUP_FIX")) { |
| + if (getenv("NOPOPUPFIX")) { |
| + ; |
| + } else if (!strcmp(getenv("VNCVIEWER_POPUP_FIX"), "0")) { |
| + ; |
| + } else { |
| + appData.popupFix = True; |
| + } |
| + } |
| + if (getenv("VNCVIEWER_GRAB_SERVER")) { |
| + appData.grabAll = True; |
| + } |
| + if (getenv("VNCVIEWER_YCROP")) { |
| + int n = atoi(getenv("VNCVIEWER_YCROP")); |
| + if (n != 0) { |
| + appData.yCrop = n; |
| + } |
| + } |
| + if (getenv("VNCVIEWER_RFBVERSION") && strcmp(getenv("VNCVIEWER_RFBVERSION"), "")) { |
| + appData.rfbVersion = strdup(getenv("VNCVIEWER_RFBVERSION")); |
| + } |
| + if (getenv("VNCVIEWER_ENCODINGS") && strcmp(getenv("VNCVIEWER_ENCODINGS"), "")) { |
| + appData.encodingsString = strdup(getenv("VNCVIEWER_ENCODINGS")); |
| + } |
| + if (getenv("VNCVIEWER_NOBELL")) { |
| + appData.useBell = False; |
| + } |
| + if (getenv("VNCVIEWER_X11CURSOR")) { |
| + appData.useX11Cursor = True; |
| + } |
| + if (getenv("VNCVIEWER_RAWLOCAL")) { |
| + appData.useRawLocal = True; |
| + } |
| + if (getenv("VNCVIEWER_NOTTY") || getenv("SSVNC_VNCVIEWER_NOTTY")) { |
| + appData.notty = True; |
| + } |
| + if (getenv("VNCVIEWER_SBWIDTH")) { |
| + int n = atoi(getenv("VNCVIEWER_SBWIDTH")); |
| + if (n != 0) { |
| + appData.sbWidth = n; |
| + } |
| + } |
| + if (getenv("VNCVIEWER_ULTRADSM")) { |
| + appData.ultraDSM = True; |
| + } |
| + if (getenv("SSVNC_ULTRA_DSM") && strcmp(getenv("SSVNC_ULTRA_DSM"), "")) { |
| + appData.ultraDSM = True; |
| + } |
| + if (getenv("SSVNC_NO_ULTRA_DSM")) { |
| + appData.ultraDSM = False; |
| + } |
| + if (getenv("SSVNC_SCALE") && strcmp(getenv("SSVNC_SCALE"), "")) { |
| + if (appData.scale == NULL) { |
| + appData.scale = strdup(getenv("SSVNC_SCALE")); |
| + } |
| + } |
| + if (getenv("VNCVIEWER_ESCAPE") && strcmp(getenv("VNCVIEWER_ESCAPE"), "")) { |
| + if (appData.escapeKeys == NULL) { |
| + appData.escapeKeys = strdup(getenv("VNCVIEWER_ESCAPE")); |
| + } |
| + } |
| + if (saw_appshare) { |
| + appData.appShare = True; |
| + } |
| + if (appData.appShare && appData.escapeKeys == NULL) { |
| + appData.escapeKeys = strdup("default"); |
| + } |
| + if (appData.escapeKeys != NULL) { |
| + appData.escapeActive = True; |
| + } |
| + if (getenv("VNCVIEWER_SEND_CLIPBOARD")) { |
| + appData.sendClipboard = True; |
| + } |
| + if (getenv("VNCVIEWER_SEND_ALWAYS")) { |
| + appData.sendAlways = True; |
| + } |
| + if (getenv("VNCVIEWER_RECV_TEXT")) { |
| + char *s = getenv("VNCVIEWER_RECV_TEXT"); |
| + if (!strcasecmp(s, "clipboard")) { |
| + appData.recvText = strdup("clipboard"); |
| + } else if (!strcasecmp(s, "primary")) { |
| + appData.recvText = strdup("primary"); |
| + } else if (!strcasecmp(s, "both")) { |
| + appData.recvText = strdup("both"); |
| + } |
| + } |
| + if (getenv("VNCVIEWER_PIPELINE_UPDATES")) { |
| + appData.pipelineUpdates = True; |
| + } else if (getenv("VNCVIEWER_NO_PIPELINE_UPDATES")) { |
| + appData.pipelineUpdates = False; |
| + } |
| + |
| + if (getenv("VNCVIEWER_NO_IPV4")) { |
| + appData.noipv4 = True; |
| + } |
| + if (getenv("VNCVIEWER_NO_IPV6")) { |
| + appData.noipv6 = True; |
| + } |
| + |
| + if (appData.useBGR233 && appData.useBGR565) { |
| + appData.useBGR233 = 0; |
| + } |
| + |
| + if (getenv("SSVNC_ULTRA_FTP_JAR") == NULL && programName != NULL) { |
| + int len = strlen(programName) + 200; |
| + char *q, *jar = (char *) malloc(len); |
| + |
| + sprintf(jar, "%s", programName); |
| + q = strrchr(jar, '/'); |
| + if (q) { |
| + struct stat sb; |
| + *(q+1) = '\0'; |
| + strcat(jar, "../lib/ssvnc/util/ultraftp.jar"); |
| + if (stat(jar, &sb) == 0) { |
| + char *put = (char *) malloc(len); |
| + sprintf(put, "SSVNC_ULTRA_FTP_JAR=%s", jar); |
| + fprintf(stderr, "Setting: %s\n\n", put); |
| + putenv(put); |
| + } else { |
| + sprintf(jar, "%s", programName); |
| + q = strrchr(jar, '/'); |
| + *(q+1) = '\0'; |
| + strcat(jar, "util/ultraftp.jar"); |
| + if (stat(jar, &sb) == 0) { |
| + char *put = (char *) malloc(len); |
| + sprintf(put, "SSVNC_ULTRA_FTP_JAR=%s", jar); |
| + fprintf(stderr, "Setting: %s\n\n", put); |
| + putenv(put); |
| + } |
| + } |
| + } |
| + free(jar); |
| + } |
| + |
| |
| /* Add our actions to the actions table so they can be used in widget |
| resource specs */ |
| |
| - XtAppAddActions(appContext, actions, XtNumber(actions)); |
| + XtAppAddActions(appContext, actions, XtNumber(actions)); |
| |
| /* Check any remaining command-line arguments. If -listen was specified |
| there should be none. Otherwise the only argument should be the VNC |
| server name. If not given then pop up a dialog box and wait for the |
| server name to be entered. */ |
| |
| - if (listenSpecified) { |
| - if (argc != 1) { |
| - fprintf(stderr,"\n%s -listen: invalid command line argument: %s\n", |
| - programName, argv[1]); |
| - usage(); |
| - } |
| - return; |
| - } |
| - |
| - if (argc == 1) { |
| - vncServerName = DoServerDialog(); |
| - appData.passwordDialog = True; |
| - } else if (argc != 2) { |
| - usage(); |
| - } else { |
| - vncServerName = argv[1]; |
| - |
| - if (!isatty(0)) |
| - appData.passwordDialog = True; |
| - if (vncServerName[0] == '-') |
| - usage(); |
| - } |
| - |
| - if (strlen(vncServerName) > 255) { |
| - fprintf(stderr,"VNC server name too long\n"); |
| - exit(1); |
| - } |
| - |
| - colonPos = strchr(vncServerName, ':'); |
| - if (colonPos == NULL) { |
| - /* No colon -- use default port number */ |
| - strcpy(vncServerHost, vncServerName); |
| - vncServerPort = SERVER_PORT_OFFSET; |
| - } else { |
| - memcpy(vncServerHost, vncServerName, colonPos - vncServerName); |
| - vncServerHost[colonPos - vncServerName] = '\0'; |
| - len = strlen(colonPos + 1); |
| - portOffset = SERVER_PORT_OFFSET; |
| - if (colonPos[1] == ':') { |
| - /* Two colons -- interpret as a port number */ |
| - colonPos++; |
| - len--; |
| - portOffset = 0; |
| - } |
| - if (!len || strspn(colonPos + 1, "0123456789") != len) { |
| - usage(); |
| - } |
| - vncServerPort = atoi(colonPos + 1) + portOffset; |
| - } |
| + if (listenSpecified) { |
| + if (argc != 1) { |
| + fprintf(stderr,"\n%s -listen: invalid command line argument: %s\n", |
| + programName, argv[1]); |
| + usage(); |
| + } |
| + return; |
| + } |
| + |
| + if (argc == 1) { |
| + vncServerName = DoServerDialog(); |
| + if (!use_tty()) { |
| + appData.passwordDialog = True; |
| + } |
| + } else if (argc != 2) { |
| + usage(); |
| + } else { |
| + vncServerName = argv[1]; |
| + |
| + if (!use_tty()) { |
| + appData.passwordDialog = True; |
| + } |
| + if (vncServerName[0] == '-') { |
| + usage(); |
| + } |
| + } |
| + |
| + if (strlen(vncServerName) > 255) { |
| + fprintf(stderr,"VNC server name too long\n"); |
| + exit(1); |
| + } |
| + |
| + colonPos = strrchr(vncServerName, ':'); |
| + bracketPos = strrchr(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 if (bracketPos != NULL && colonPos < bracketPos) { |
| + strcpy(vncServerHost, vncServerName); |
| + vncServerPort = SERVER_PORT_OFFSET; |
| + } else { |
| + if (colonPos > vncServerName && *(colonPos - 1) == ':') { |
| + colonPos--; |
| + } |
| + 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") != (size_t) 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 2010-02-25 22:02:19.000000000 -0500 |
| @@ -31,9 +31,12 @@ |
| #define BGR233_SIZE 256 |
| unsigned long BGR233ToPixel[BGR233_SIZE]; |
| |
| +#define BGR565_SIZE 65536 |
| +unsigned long BGR565ToPixel[BGR565_SIZE]; |
| + |
| Colormap cmap; |
| Visual *vis; |
| -unsigned int visdepth, visbpp; |
| +unsigned int visdepth, visbpp, isLSB; |
| Bool allocColorFailed = False; |
| |
| static int nBGR233ColoursAllocated; |
| @@ -45,6 +48,8 @@ |
| static void AllocateExactBGR233Colours(); |
| static Bool AllocateBGR233Colour(int r, int g, int b); |
| |
| +static void SetupBGR565Map(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask); |
| + |
| |
| /* |
| * SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are |
| @@ -97,6 +102,44 @@ |
| visbpp = GetBPPForDepth(visdepth); |
| cmap = DefaultColormap(dpy,DefaultScreen(dpy)); |
| |
| + if (ImageByteOrder(dpy) == LSBFirst) { |
| + isLSB = 1; |
| + } else { |
| + isLSB = 0; |
| + } |
| + if (visbpp == 24) { |
| + if (!appData.useBGR233) { |
| + fprintf(stderr, "Warning: for 24bpp enabling -bgr565 -- Don't use FullColor!\n"); |
| + appData.useBGR565 = True; |
| + } else { |
| + fprintf(stderr, "Warning: for 24bpp using -bgr233 -- Don't use FullColor!\n"); |
| + } |
| + } |
| + |
| + if (appData.useBGR565) { |
| + if (visdepth < 24 || visbpp < 24 || vis->class != TrueColor) { |
| + fprintf(stderr, "disabling -16bpp BGR565 on non-depth 24 machine\n"); |
| + appData.useBGR565 = False; |
| + } else { |
| + myFormat.bitsPerPixel = 16; |
| + myFormat.depth = 16; |
| + myFormat.trueColour = 1; |
| + myFormat.bigEndian = 0; |
| + myFormat.redMax = 31; |
| + myFormat.greenMax = 63; |
| + myFormat.blueMax = 31; |
| + myFormat.redShift = 11; |
| + myFormat.greenShift = 5; |
| + myFormat.blueShift = 0; |
| + |
| + fprintf(stderr, "Using default colormap and translating from BGR565 (65536 colors). Pixel format:\n"); |
| + PrintPixelFormat(&myFormat); |
| + |
| + SetupBGR565Map(vis->red_mask, vis->green_mask, vis->blue_mask); |
| + return; |
| + } |
| + } |
| + |
| if (!appData.useBGR233 && (vis->class == TrueColor)) { |
| |
| myFormat.bitsPerPixel = visbpp; |
| @@ -116,21 +159,42 @@ |
| return; |
| } |
| |
| - appData.useBGR233 = True; |
| + if (appData.useBGR233 == 0) { |
| + appData.useBGR233 = 256; |
| + } |
| |
| myFormat.bitsPerPixel = 8; |
| myFormat.depth = 8; |
| myFormat.trueColour = 1; |
| myFormat.bigEndian = 0; |
| - myFormat.redMax = 7; |
| + myFormat.redMax = 7; |
| myFormat.greenMax = 7; |
| - myFormat.blueMax = 3; |
| - myFormat.redShift = 0; |
| + myFormat.blueMax = 3; |
| + myFormat.redShift = 0; |
| myFormat.greenShift = 3; |
| - myFormat.blueShift = 6; |
| + myFormat.blueShift = 6; |
| + |
| + if (appData.useBGR233 == 64) { |
| + /* BGR222 */ |
| + myFormat.redMax = 3; |
| + myFormat.greenMax = 3; |
| + myFormat.blueMax = 3; |
| + myFormat.redShift = 0; |
| + myFormat.greenShift = 2; |
| + myFormat.blueShift = 4; |
| + } |
| + if (appData.useBGR233 == 8) { |
| + /* BGR111 */ |
| + myFormat.redMax = 2; |
| + myFormat.greenMax = 2; |
| + myFormat.blueMax = 2; |
| + myFormat.redShift = 0; |
| + myFormat.greenShift = 1; |
| + myFormat.blueShift = 2; |
| + } |
| |
| fprintf(stderr, |
| - "Using default colormap and translating from BGR233. Pixel format:\n"); |
| + "Using default colormap and translating from BGR233 (%d colors). Pixel format:\n", appData.useBGR233); |
| PrintPixelFormat(&myFormat); |
| |
| SetupBGR233Map(); |
| @@ -282,8 +346,12 @@ |
| XFree(format); |
| |
| if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32) { |
| - fprintf(stderr,"Can't cope with %d bits-per-pixel. Sorry.\n", bpp); |
| - exit(1); |
| + if (bpp == 24) { |
| + fprintf(stderr,"Warning: 24 bits-per-pixel may have problems...\n"); |
| + } else { |
| + fprintf(stderr,"Can't cope with %d bits-per-pixel. Sorry.\n", bpp); |
| + exit(1); |
| + } |
| } |
| |
| return bpp; |
| @@ -374,7 +442,7 @@ |
| if (!exactBGR233[i] && |
| XAllocColor(dpy, cmap, &cmapEntry[i])) { |
| |
| - if (cmapEntry[i].pixel == i) { |
| + if ((long) cmapEntry[i].pixel == i) { |
| |
| shared[i] = True; /* probably shared */ |
| |
| @@ -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<<bs) | (g<<gs) | (r<<rs)] == INVALID_PIXEL) { |
| |
| unsigned long minDistance = ULONG_MAX; |
| |
| for (i = 0; i < cmapSize; i++) { |
| if (exactBGR233[i] || shared[i]) { |
| - unsigned long distance |
| - = (abs(cmapEntry[i].red - r * 65535 / 7) |
| - + abs(cmapEntry[i].green - g * 65535 / 7) |
| - + abs(cmapEntry[i].blue - b * 65535 / 3)); |
| + unsigned long distance; |
| + int r1, g1, b1; |
| + if (appData.useGreyScale) { |
| + int ave; |
| + ave = (r + g + 2*b)/3; |
| + r1 = ave; |
| + g1 = ave; |
| + b1 = ave/2; |
| + } else { |
| + r1 = r; |
| + g1 = g; |
| + b1 = b; |
| + } |
| + distance |
| + = ( abs(cmapEntry[i].red - r1 * 65535 / rm) |
| + + abs(cmapEntry[i].green - g1 * 65535 / gm) |
| + + abs(cmapEntry[i].blue - b1 * 65535 / bm)); |
| + |
| |
| if (distance < minDistance) { |
| minDistance = distance; |
| @@ -412,7 +507,7 @@ |
| } |
| } |
| |
| - BGR233ToPixel[(b<<6) | (g<<3) | r] = nearestPixel; |
| + BGR233ToPixel[(b<<bs) | (g<<gs) | (r<<rs)] = nearestPixel; |
| if (shared[nearestPixel] && !usedAsNearest[nearestPixel]) |
| nSharedUsed++; |
| usedAsNearest[nearestPixel] = True; |
| @@ -433,6 +528,59 @@ |
| } |
| } |
| |
| +static void |
| +SetupBGR565Map(unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask) |
| +{ |
| + int r, g, b; |
| + int r2, g2, b2; |
| + long idx; |
| + int cnt = 0; |
| + unsigned long pixel = 0; |
| + |
| + for (r = 0; r < 32; r++) { |
| + for (g = 0; g < 64; g++) { |
| + for (b = 0; b < 32; b++) { |
| + int bs = 0, gs = 5, rs = 11; |
| + int bm = 31, gm = 63, rm = 31; |
| + if ((b > bm || g > gm || r > rm)) { |
| + continue; |
| + } |
| + r2 = (255 * r) / rm; |
| + g2 = (255 * g) / gm; |
| + b2 = (255 * b) / bm; |
| + |
| + pixel = (r2 << 16) | (g2 << 8) | (b2 << 0); |
| + if (appData.useGreyScale) { |
| + int ave; |
| + int r1, g1, b1; |
| + ave = (2*r + g + 2*b)/3; |
| + r1 = ave/2; |
| + g1 = ave; |
| + b1 = ave/2; |
| + |
| + r2 = (255 * r1) / rm; |
| + g2 = (255 * g1) / gm; |
| + b2 = (255 * b1) / bm; |
| + |
| + pixel = (r2 << 16) | (g2 << 8) | (b2 << 0); |
| + } |
| + |
| + if (red_mask == 0xff) { |
| + idx = (r<<bs) | (g<<gs) | (b<<rs); |
| + } else { |
| + idx = (b<<bs) | (g<<gs) | (r<<rs); |
| + } |
| + if (0) fprintf(stderr, "cnt: %5d idx: %lu pixel: 0x%08x\n", cnt, idx, (unsigned int) pixel); |
| + BGR565ToPixel[idx] = pixel; |
| + cnt++; |
| + } |
| + } |
| + } |
| + green_mask = 0; |
| + blue_mask = 0; |
| +} |
| + |
| + |
| |
| /* |
| * AllocateExactBGR233Colours() attempts to allocate each of the colours in the |
| @@ -484,8 +632,13 @@ |
| ri = rn; |
| for (gi = 0; gi < gn; gi++) { |
| 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; |
| + } |
| } |
| } |
| rn++; |
| @@ -496,8 +649,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 +665,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 +692,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<<bs) | (g<<gs) | r] = c.pixel; |
| |
| nBGR233ColoursAllocated++; |
| |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/corre.c vnc_unixsrc/vncviewer/corre.c |
| --- vnc_unixsrc.orig/vncviewer/corre.c 2000-06-11 08:00:53.000000000 -0400 |
| +++ vnc_unixsrc/vncviewer/corre.c 2008-10-05 15:16:01.000000000 -0400 |
| @@ -29,6 +29,18 @@ |
| #define HandleCoRREBPP CONCAT2E(HandleCoRRE,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 |
| HandleCoRREBPP (int rx, int ry, int rw, int rh) |
| { |
| @@ -50,11 +62,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 |
| |
| if (!ReadFromRFBServer(buffer, hdr.nSubrects * (4 + (BPP / 8)))) |
| return False; |
| @@ -72,12 +92,22 @@ |
| #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 + x, ry + y, w, h); |
| +#else |
| + FillRectangle(rx + x, ry + y, w, h, gcv.foreground); |
| +#endif |
| } |
| |
| return True; |
| } |
| + |
| +#undef FillRectangle |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cp_it vnc_unixsrc/vncviewer/cp_it |
| --- vnc_unixsrc.orig/vncviewer/cp_it 1969-12-31 19:00:00.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/cp_it 2009-03-06 20:02:05.000000000 -0500 |
| @@ -0,0 +1,18 @@ |
| +#!/bin/sh |
| + |
| +dest=/dist/bin/vncviewerz-1.3dev5-resize |
| +suc "cp -p $dest $dest.back; mv $dest $dest.unlink; mv $dest.back $dest; rm $dest.unlink" |
| +strip ./vncviewer |
| +cat ./vncviewer > $dest |
| +touch -r ./vncviewer $dest |
| +yy=/dist/src/apps/VNC/etc/libvncserver_cvs/expts/etv/ssvnc/bin/Linux.i686/vncviewer |
| +mv $yy $yy.unlink |
| +cp -p ./vncviewer $yy |
| +mv $yy.turbovnc $yy.unlink.turbovnc |
| +cp -p ./vncviewer $HOME/etv_col/Linux.i686 |
| +cp -p ./vncviewer.turbovnc $yy.turbovnc |
| +cp -p ./vncviewer.turbovnc $HOME/etv_col/Linux.i686/vncviewer.turbovnc |
| +chmod 755 $yy* |
| + |
| +rm -f $yy.unlink* |
| +ls -l ./vncviewer* $dest $yy* $HOME/etv_col/Linux.i686/vncviewer* |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/cursor.c vnc_unixsrc/vncviewer/cursor.c |
| --- vnc_unixsrc.orig/vncviewer/cursor.c 2003-01-15 04:46:52.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/cursor.c 2010-02-25 22:04:28.000000000 -0500 |
| @@ -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) |
| { |
| @@ -124,7 +134,7 @@ |
| XQueryBestCursor(dpy, dr, width, height, &wret, &hret); |
| } |
| |
| - if (width * height == 0 || wret < width || hret < height) { |
| + if (width * height == 0 || (int) wret < width || (int) hret < height) { |
| /* Free resources */ |
| if (buf != NULL) |
| free(buf); |
| @@ -139,7 +149,7 @@ |
| fg.green = (unsigned short)colors.foreGreen << 8 | colors.foreGreen; |
| fg.blue = (unsigned short)colors.foreBlue << 8 | colors.foreBlue; |
| |
| - for (i = 0; i < bytesData * 2; i++) |
| + for (i = 0; (size_t) i < bytesData * 2; i++) |
| buf[i] = (char)_reverse_byte[(int)buf[i] & 0xFF]; |
| |
| source = XCreateBitmapFromData(dpy, dr, buf, width, 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,169 @@ |
| 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 = 0, ys = 0, ws = 0, hs = 0; |
| + 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) { |
| + 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 +650,182 @@ |
| int offset, bytesPerPixel; |
| char *pos; |
| |
| +#define alphahack |
| +#ifdef alphahack |
| + /* hack to have cursor transparency at 32bpp <runge@karlrunge.com> */ |
| + 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 2010-02-25 22:32:49.000000000 -0500 |
| @@ -28,28 +28,497 @@ |
| #include <X11/extensions/XShm.h> |
| #endif |
| |
| +#include <X11/cursorfont.h> |
| + |
| GC gc; |
| GC srcGC, dstGC; /* used for debugging copyrect */ |
| Window desktopWin; |
| -Cursor dotCursor; |
| +Cursor dotCursor3 = None; |
| +Cursor dotCursor4 = None; |
| +Cursor bogoCursor = None; |
| +Cursor waitCursor = None; |
| Widget form, viewport, desktop; |
| |
| +int appshare_0_hint = -10000; |
| +int appshare_x_hint = -10000; |
| +int appshare_y_hint = -10000; |
| + |
| static Bool modifierPressed[256]; |
| |
| -static XImage *image = NULL; |
| +XImage *image = NULL; |
| +XImage *image_ycrop = NULL; |
| +XImage *image_scale = NULL; |
| + |
| +int image_is_shm = 0; |
| |
| static Cursor CreateDotCursor(); |
| static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width,int height); |
| static void HandleBasicDesktopEvent(Widget w, XtPointer ptr, XEvent *ev, |
| Boolean *cont); |
| |
| +static void CopyBGR565ToScreen(CARD16 *buf, int x, int y, int width,int height); |
| + |
| static XtResource desktopBackingStoreResources[] = { |
| { |
| - XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0, |
| - XtRImmediate, (XtPointer) Always, |
| + XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof(int), 0, |
| + XtRImmediate, (XtPointer) Always, |
| }, |
| }; |
| |
| +double scale_factor_x = 0.0; |
| +double scale_factor_y = 0.0; |
| +int scale_x = 0, scale_y = 0; |
| +int scale_round(int len, double fac); |
| + |
| +double last_rescale = 0.0; |
| +double last_fullscreen = 0.0; |
| +double start_time = 0.0; |
| + |
| +int prev_fb_width = -1; |
| +int prev_fb_height = -1; |
| + |
| +void get_scale_values(double *fx, double *fy) { |
| + char *s = appData.scale; |
| + double f, frac_x = -1.0, frac_y = -1.0; |
| + int n, m; |
| + int xmax = si.framebufferWidth; |
| + int ymax = si.framebufferHeight; |
| + |
| + if (appData.yCrop > 0) { |
| + ymax = appData.yCrop; |
| + } |
| + |
| + if (sscanf(s, "%d/%d", &n, &m) == 2) { |
| + if (m == 0) { |
| + frac_x = 1.0; |
| + } else { |
| + frac_x = ((double) n) / ((double) m); |
| + } |
| + } |
| + if (sscanf(s, "%dx%d", &n, &m) == 2) { |
| + frac_x = ((double) n) / ((double) xmax); |
| + frac_y = ((double) m) / ((double) ymax); |
| + } |
| + if (!strcasecmp(s, "fit")) { |
| + frac_x = ((double) dpyWidth) / ((double) xmax); |
| + frac_y = ((double) dpyHeight) / ((double) ymax); |
| + } |
| + if (!strcasecmp(s, "auto")) { |
| + Dimension w, h; |
| + XtVaGetValues(toplevel, XtNheight, &h, XtNwidth, &w, NULL); |
| + fprintf(stderr, "auto: %dx%d\n", w, h); |
| + if (w > 32 && h > 32) { |
| + frac_x = ((double) w) / ((double) xmax); |
| + frac_y = ((double) h) / ((double) ymax); |
| + } |
| + } |
| + if (frac_x < 0.0 && sscanf(s, "%lf", &f) == 1) { |
| + if (f > 0.0) { |
| + frac_x = f; |
| + } |
| + } |
| + |
| + if (frac_y < 0.0) { |
| + frac_y = frac_x; |
| + } |
| + |
| + if (frac_y > 0.0 && frac_x > 0.0) { |
| + if (fx != NULL) { |
| + *fx = frac_x; |
| + } |
| + if (fy != NULL) { |
| + *fy = frac_y; |
| + } |
| + } else { |
| + if (appData.scale) { |
| + fprintf(stderr, "Invalid scale string: '%s'\n", appData.scale); |
| + } else { |
| + fprintf(stderr, "Invalid scale string.\n"); |
| + } |
| + appData.scale = NULL; |
| + } |
| +} |
| + |
| +void try_create_image(void); |
| +void put_image(int src_x, int src_y, int dst_x, int dst_y, int width, int height, int solid); |
| +void create_image(); |
| + |
| +/* toplevel -> form -> viewport -> desktop */ |
| + |
| +void adjust_Xt_win(int w, int h) { |
| + int x, y, dw, dh, h0 = h; |
| + int mw = w, mh = h; |
| + int autoscale = 0; |
| + |
| + if (!appData.fullScreen && appData.scale != NULL && !strcmp(appData.scale, "auto")) { |
| + autoscale = 1; |
| + mw = dpyWidth; |
| + mh = dpyHeight; |
| + } |
| + |
| + if (appData.yCrop > 0) { |
| + int ycrop = appData.yCrop; |
| + if (image_scale && scale_factor_y > 0.0) { |
| + ycrop = scale_round(ycrop, scale_factor_y); |
| + if (!autoscale) { |
| + mh = ycrop; |
| + } |
| + } |
| + XtVaSetValues(toplevel, XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, ycrop, NULL); |
| + XtVaSetValues(form, XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, ycrop, NULL); |
| + h0 = ycrop; |
| + } else { |
| + XtVaSetValues(toplevel, XtNmaxWidth, mw, XtNmaxHeight, mh, XtNwidth, w, XtNheight, h, NULL); |
| + } |
| + |
| + fprintf(stderr, "adjust_Xt_win: %dx%d & %dx%d\n", w, h, w, h0); |
| + |
| + XtVaSetValues(desktop, XtNwidth, w, XtNheight, h, NULL); |
| + |
| + XtResizeWidget(desktop, w, h, 0); |
| + |
| + if (!autoscale) { |
| + dw = appData.wmDecorationWidth; |
| + dh = appData.wmDecorationHeight; |
| + |
| + x = (dpyWidth - w - dw)/2; |
| + y = (dpyHeight - h0 - dh)/2; |
| + |
| + XtConfigureWidget(toplevel, x + dw, y + dh, w, h0, 0); |
| + } |
| +} |
| + |
| +void rescale_image(void) { |
| + double frac_x, frac_y; |
| + int w, h; |
| + |
| + if (image == NULL) { |
| + create_image(); |
| + return; |
| + } |
| + |
| + if (appData.useXserverBackingStore) { |
| + create_image(); |
| + return; |
| + } |
| + |
| + if (image == NULL && image_scale == NULL) { |
| + create_image(); |
| + return; |
| + } |
| + |
| + if (appData.scale == NULL) { |
| + /* switching to not scaled */ |
| + frac_x = frac_y = 1.0; |
| + } else { |
| + get_scale_values(&frac_x, &frac_y); |
| + if (frac_x < 0.0 || frac_y < 0.0) { |
| + create_image(); |
| + return; |
| + } |
| + } |
| + |
| + last_rescale = dnow(); |
| + |
| + SoftCursorLockArea(0, 0, si.framebufferWidth, si.framebufferHeight); |
| + |
| + if (image_scale == NULL) { |
| + /* switching from not scaled */ |
| + int i; |
| + int Bpl = image->bytes_per_line; |
| + char *dst, *src = image->data; |
| + |
| + image_scale = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, |
| + si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); |
| + |
| + image_scale->data = (char *) malloc(image_scale->bytes_per_line * image_scale->height); |
| + |
| + fprintf(stderr, "rescale_image: switching from not scaled. created image_scale %dx%d\n", image_scale->width, image_scale->height); |
| + fprintf(stderr, "rescale_image: copying image -> image_scale %dx%d -> %dx%d\n", image->width, image->height, image_scale->width, image_scale->height); |
| + |
| + dst = image_scale->data; |
| + |
| + /* copy from image->data */ |
| + for (i=0; i < image->height; i++) { |
| + memcpy(dst, src, Bpl); |
| + dst += Bpl; |
| + src += Bpl; |
| + } |
| + } |
| + |
| + /* now destroy image */ |
| + if (image && image->data) { |
| + if (UsingShm()) { |
| + ShmDetach(); |
| + } |
| + XDestroyImage(image); |
| + fprintf(stderr, "rescale_image: destroyed 'image'\n"); |
| + if (UsingShm()) { |
| + ShmCleanup(); |
| + } |
| + image = NULL; |
| + } |
| + if (image_ycrop && image_ycrop->data) { |
| + XDestroyImage(image_ycrop); |
| + fprintf(stderr, "rescale_image: destroyed 'image_ycrop'\n"); |
| + image_ycrop = NULL; |
| + } |
| + |
| + if (frac_x == 1.0 && frac_y == 1.0) { |
| + /* switching to not scaled */ |
| + fprintf(stderr, "rescale_image: switching to not scaled.\n"); |
| + w = si.framebufferWidth; |
| + h = si.framebufferHeight; |
| + |
| + scale_factor_x = 0.0; |
| + scale_factor_y = 0.0; |
| + scale_x = 0; |
| + scale_y = 0; |
| + } else { |
| + w = scale_round(si.framebufferWidth, frac_x); |
| + h = scale_round(si.framebufferHeight, frac_y); |
| + |
| + scale_factor_x = frac_x; |
| + scale_factor_y = frac_y; |
| + scale_x = w; |
| + scale_y = h; |
| + } |
| + |
| + adjust_Xt_win(w, h); |
| + |
| + fprintf(stderr, "rescale: %dx%d %.4f %.4f\n", w, h, scale_factor_x, scale_factor_y); |
| + |
| + try_create_image(); |
| + |
| + if (image && image->data && image_scale && frac_x == 1.0 && frac_y == 1.0) { |
| + /* switched to not scaled */ |
| + int i; |
| + int Bpl = image->bytes_per_line; |
| + char *dst = image->data; |
| + char *src = image_scale->data; |
| + |
| + fprintf(stderr, "rescale_image: switching to not scaled.\n"); |
| + |
| + for (i=0; i < image->height; i++) { |
| + memcpy(dst, src, Bpl); |
| + dst += Bpl; |
| + src += Bpl; |
| + } |
| + XDestroyImage(image_scale); |
| + fprintf(stderr, "rescale_image: destroyed 'image_scale'\n"); |
| + image_scale = NULL; |
| + } |
| + |
| + if (appData.yCrop > 0) { |
| + int ycrop = appData.yCrop; |
| + /* do the top part first so they can see it earlier */ |
| + put_image(0, 0, 0, 0, si.framebufferWidth, ycrop, 0); |
| + if (si.framebufferHeight > ycrop) { |
| + /* this is a big fb and so will take a long time */ |
| + if (waitCursor != None) { |
| + XDefineCursor(dpy, desktopWin, waitCursor); |
| + XSync(dpy, False); |
| + } |
| + put_image(0, 0, 0, 0, si.framebufferWidth, si.framebufferHeight - ycrop, 0); |
| + if (waitCursor != None) { |
| + Xcursors(1); |
| + if (appData.useX11Cursor) { |
| + XSetWindowAttributes attr; |
| + unsigned long valuemask = 0; |
| + if (appData.viewOnly) { |
| + attr.cursor = dotCursor4; |
| + } else { |
| + attr.cursor = dotCursor3; |
| + } |
| + valuemask |= CWCursor; |
| + XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); |
| + } |
| + } |
| + } |
| + } else { |
| + put_image(0, 0, 0, 0, si.framebufferWidth, si.framebufferHeight, 0); |
| + } |
| + |
| + SoftCursorUnlockScreen(); |
| + |
| + fprintf(stderr, "rescale: image_scale=%p image=%p image_ycrop=%p\n", (void *) image_scale, (void *) image, (void *) image_ycrop); |
| + last_rescale = dnow(); |
| + |
| +} |
| + |
| +void try_create_image(void) { |
| + |
| + image_is_shm = 0; |
| + if (appData.useShm) { |
| +#ifdef MITSHM |
| + image = CreateShmImage(0); |
| + if (!image) { |
| + if (appData.yCrop > 0) { |
| + if (appData.scale != NULL && scale_x > 0) { |
| + ; |
| + } else { |
| + image_ycrop = CreateShmImage(1); |
| + if (!image_ycrop) { |
| + appData.useShm = False; |
| + } else { |
| + fprintf(stderr, "created smaller image_ycrop shm image: %dx%d\n", |
| + image_ycrop->width, image_ycrop->height); |
| + } |
| + } |
| + } else { |
| + appData.useShm = False; |
| + } |
| + } else { |
| + image_is_shm = 1; |
| + fprintf(stderr, "created shm image: %dx%d\n", image->width, image->height); |
| + } |
| +#endif |
| + } |
| + |
| + if (!image) { |
| + fprintf(stderr, "try_create_image: shm image create fail: image == NULL\n"); |
| + if (scale_x > 0) { |
| + image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, |
| + scale_x, scale_y, BitmapPad(dpy), 0); |
| + } else { |
| + image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, |
| + si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); |
| + } |
| + |
| + image->data = malloc(image->bytes_per_line * image->height); |
| + |
| + if (!image->data) { |
| + fprintf(stderr, "try_create_image: malloc failed\n"); |
| + exit(1); |
| + } else { |
| + fprintf(stderr, "try_create_image: created *non-shm* image: %dx%d\n", image->width, image->height); |
| + } |
| + } |
| + fprintf(stderr, "try_create_image: image->bytes_per_line: %d\n", image->bytes_per_line); |
| +} |
| + |
| +void create_image() { |
| + image = NULL; |
| + image_ycrop = NULL; |
| + image_scale = NULL; |
| + |
| + fprintf(stderr, "create_image()\n"); |
| + |
| + if (CreateShmImage(-1) == NULL) { |
| + appData.useShm = False; |
| + } |
| + if (appData.scale != NULL) { |
| + if (appData.useXserverBackingStore) { |
| + fprintf(stderr, "Cannot scale when using X11 backingstore.\n"); |
| + } else { |
| + double frac_x = -1.0, frac_y = -1.0; |
| + |
| + get_scale_values(&frac_x, &frac_y); |
| + |
| + if (frac_x < 0.0 || frac_y < 0.0) { |
| + fprintf(stderr, "Cannot figure out scale factor!\n"); |
| + goto bork; |
| + } |
| + |
| + scale_factor_x = 0.0; |
| + scale_factor_y = 0.0; |
| + scale_x = 0; |
| + scale_y = 0; |
| + |
| + |
| + if (1) { |
| + int w, h, hyc; |
| + |
| + w = scale_round(si.framebufferWidth, frac_x); |
| + h = scale_round(si.framebufferHeight, frac_y); |
| + hyc = h; |
| + if (appData.yCrop > 0) { |
| + hyc = scale_round(appData.yCrop, frac_y); |
| + } |
| + |
| + /* image scale is full framebuffer */ |
| + image_scale = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, |
| + si.framebufferWidth, si.framebufferHeight, BitmapPad(dpy), 0); |
| + |
| + image_scale->data = (char *) malloc(image_scale->bytes_per_line * image_scale->height); |
| + |
| + fprintf(stderr, "create_image: created image_scale %dx%d\n", image_scale->width, image_scale->height); |
| + |
| + if (!image_scale->data) { |
| + fprintf(stderr, "create_image: malloc failed\n"); |
| + XDestroyImage(image_scale); |
| + fprintf(stderr, "create_image: destroyed 'image_scale'\n"); |
| + image_scale = NULL; |
| + } else { |
| + int h2; |
| + scale_factor_x = frac_x; |
| + scale_factor_y = frac_y; |
| + scale_x = w; |
| + scale_y = h; |
| + |
| + XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, hyc, NULL); |
| + |
| + h2 = scale_round(si.framebufferHeight, frac_y); |
| + XtVaSetValues(desktop, XtNwidth, w, XtNheight, h2, NULL); |
| + |
| + } |
| + fprintf(stderr, "create_image: scale: %dx%d %.4f %.4f\n", w, h, |
| + scale_factor_x, scale_factor_y); |
| + } |
| + } |
| + } |
| + bork: |
| + try_create_image(); |
| +} |
| + |
| +int old_width = 0; |
| +int old_height = 0; |
| + |
| +int guessCrop(void) { |
| + int w = si.framebufferWidth; |
| + |
| + if (w == 320) { |
| + return 240; |
| + } else if (w == 400) { |
| + return 300; |
| + } else if (w == 640) { |
| + return 480; |
| + } else if (w == 800) { |
| + return 600; |
| + } else if (w == 1024) { |
| + return 768; |
| + } else if (w == 1152) { |
| + return 864; |
| + } else if (w == 1280) { |
| + return 1024; |
| + } else if (w == 1440) { |
| + return 900; |
| + } else if (w == 1600) { |
| + return 1200; |
| + } else if (w == 1680) { |
| + return 1050; |
| + } else if (w == 1920) { |
| + return 1200; |
| + } else { |
| + int h = (3 * w) / 4; |
| + return h; |
| + } |
| +} |
| + |
| +void check_tall(void) { |
| + if (appData.appShare) { |
| + return; |
| + } |
| + if (! appData.yCrop) { |
| + int w = si.framebufferWidth; |
| + int h = si.framebufferHeight; |
| + if (h > 2 * w) { |
| + fprintf(stderr, "Tall display (%dx%d) suspect 'x11vnc -ncache' mode,\n", w, h); |
| + fprintf(stderr, " setting auto -ycrop detection.\n"); |
| + appData.yCrop = -1; |
| + } |
| + } |
| +} |
| |
| /* |
| * DesktopInitBeforeRealization creates the "desktop" widget and the viewport |
| @@ -59,91 +528,1023 @@ |
| void |
| DesktopInitBeforeRealization() |
| { |
| - int i; |
| + int i; |
| + int h = si.framebufferHeight; |
| + int w = si.framebufferWidth; |
| + double frac_x = 1.0, frac_y = 1.0; |
| + |
| + start_time = dnow(); |
| + |
| + prev_fb_width = si.framebufferWidth; |
| + prev_fb_height = si.framebufferHeight; |
| + |
| + if (appData.scale != NULL) { |
| + get_scale_values(&frac_x, &frac_y); |
| + if (frac_x > 0.0 && frac_y > 0.0) { |
| + w = scale_round(w, frac_x); |
| + h = scale_round(h, frac_y); |
| + } else { |
| + appData.scale = NULL; |
| + } |
| + } |
| |
| - form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel, |
| - XtNborderWidth, 0, |
| - XtNdefaultDistance, 0, NULL); |
| + form = XtVaCreateManagedWidget("form", formWidgetClass, toplevel, |
| + XtNborderWidth, 0, XtNdefaultDistance, 0, NULL); |
| |
| - viewport = XtVaCreateManagedWidget("viewport", viewportWidgetClass, form, |
| - XtNborderWidth, 0, |
| - NULL); |
| + viewport = XtVaCreateManagedWidget("viewport", viewportWidgetClass, form, |
| + XtNborderWidth, 0, NULL); |
| |
| - desktop = XtVaCreateManagedWidget("desktop", coreWidgetClass, viewport, |
| - XtNborderWidth, 0, |
| - NULL); |
| + desktop = XtVaCreateManagedWidget("desktop", coreWidgetClass, viewport, |
| + XtNborderWidth, 0, NULL); |
| |
| - XtVaSetValues(desktop, XtNwidth, si.framebufferWidth, |
| - XtNheight, si.framebufferHeight, NULL); |
| + XtVaSetValues(desktop, XtNwidth, w, XtNheight, h, NULL); |
| |
| - XtAddEventHandler(desktop, LeaveWindowMask|ExposureMask, |
| - True, HandleBasicDesktopEvent, NULL); |
| + XtAddEventHandler(desktop, LeaveWindowMask|EnterWindowMask|ExposureMask, |
| + True, HandleBasicDesktopEvent, NULL); |
| |
| - for (i = 0; i < 256; i++) |
| - modifierPressed[i] = False; |
| + if (appData.yCrop) { |
| + int 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; |
| - } |
| + hm *= frac_y; |
| + |
| + 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(); |
| +} |
| + |
| +#if 0 |
| +static Widget scrollbar_y = NULL; |
| +static int xsst = 2; |
| #endif |
| |
| - 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); |
| - } |
| - } |
| +#include <X11/Xaw/Scrollbar.h> |
| + |
| +#if 0 |
| +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); |
| + } |
| + if (closure) {} |
| } |
| |
| +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); |
| + } |
| + } |
| + if (closure) {} |
| +} |
| +#endif |
| + |
| +extern double dnow(void); |
| + |
| +void check_things() { |
| + 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 sb = appData.sbWidth; |
| + XtVaGetValues(wv, XtNwidth, &w0, XtNheight, &h0, XtNborderWidth, &b0, XtNx, &x0, XtNy, &y0, NULL); |
| + XtVaGetValues(wh, XtNwidth, &w1, XtNheight, &h1, XtNborderWidth, &b1, XtNx, &x1, XtNy, &y1, NULL); |
| + XtVaGetValues(wc, XtNwidth, &w2, XtNheight, &h2, XtNborderWidth, &b2, NULL); |
| + if (!sb) { |
| + sb = 2; |
| + } |
| + if (w0 != sb || h1 != sb) { |
| + fprintf(stderr, "Very tall (-ncache) fb, setting scrollbar thickness to: %d pixels (%d/%d)\n\n", sb, w0, h1); |
| + |
| + XtUnmanageChild(wv); |
| + XtUnmanageChild(wh); |
| + XtUnmanageChild(wc); |
| + |
| + XtVaSetValues(wv, XtNwidth, sb, XtNx, x0 + (w0 - sb), NULL); |
| + XtVaSetValues(wh, XtNheight, sb, XtNy, y1 + (h1 - sb), NULL); |
| + w2 = w2 + (w0 - sb); |
| + h2 = h2 + (h1 - sb); |
| + if (w2 > 10 && h2 > 10) { |
| + XtVaSetValues(wc, XtNwidth, w2, XtNheight, h2, NULL); |
| + } |
| + |
| + XtManageChild(wv); |
| + XtManageChild(wh); |
| + XtManageChild(wc); |
| + |
| + appData.sbWidth = sb; |
| + } |
| + } |
| + last_scrollbar = dnow(); |
| + } |
| + |
| + if (now <= last + 0.25) { |
| + return; |
| + } |
| + |
| + if (image_scale) { |
| + scale_check_zrle(); |
| + } |
| + |
| + /* e.g. xrandr resize */ |
| + dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); |
| + dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); |
| + |
| + if (appData.scale != NULL) { |
| + static Dimension last_w = 0, last_h = 0; |
| + static double last_resize = 0.0; |
| + Dimension w, h; |
| + if (last_w == 0) { |
| + XtVaGetValues(toplevel, XtNwidth, &last_w, XtNheight, &last_h, NULL); |
| + last_resize = now; |
| + } |
| + if (now < last_resize + 0.5) { |
| + ; |
| + } else if (appData.fullScreen) { |
| + ; |
| + } else if (!strcmp(appData.scale, "auto")) { |
| + XtVaGetValues(toplevel, XtNwidth, &w, XtNheight, &h, NULL); |
| + if (w < 32 || h < 32) { |
| + ; |
| + } else if (last_w != w || last_h != h) { |
| + Window rr, cr, r = DefaultRootWindow(dpy); |
| + int rx, ry, wx, wy; |
| + unsigned int mask; |
| + /* make sure mouse buttons not pressed */ |
| + if (XQueryPointer(dpy, r, &rr, &cr, &rx, &ry, &wx, &wy, &mask)) { |
| + if (mask == 0) { |
| + rescale_image(); |
| + last_w = w; |
| + last_h = h; |
| + last_resize = dnow(); |
| + } |
| + } |
| + } |
| + } |
| + } |
| + |
| + last = dnow(); |
| +} |
| |
| /* |
| * DesktopInitAfterRealization does things which require the X windows to |
| * exist. It creates some GCs and sets the dot cursor. |
| */ |
| |
| +void Xcursors(int set) { |
| + if (dotCursor3 == None) { |
| + dotCursor3 = CreateDotCursor(3); |
| + } |
| + if (dotCursor4 == None) { |
| + dotCursor4 = CreateDotCursor(4); |
| + } |
| + if (set) { |
| + XSetWindowAttributes attr; |
| + unsigned long valuemask = 0; |
| + |
| + if (!appData.useX11Cursor) { |
| + if (appData.viewOnly) { |
| + attr.cursor = dotCursor4; |
| + } else { |
| + attr.cursor = dotCursor3; |
| + } |
| + valuemask |= CWCursor; |
| + XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); |
| + } |
| + } |
| +} |
| + |
| void |
| DesktopInitAfterRealization() |
| { |
| - XGCValues gcv; |
| - XSetWindowAttributes attr; |
| - unsigned long valuemask; |
| - |
| - desktopWin = XtWindow(desktop); |
| - |
| - gc = XCreateGC(dpy,desktopWin,0,NULL); |
| - |
| - gcv.function = GXxor; |
| - gcv.foreground = 0x0f0f0f0f; |
| - srcGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv); |
| - gcv.foreground = 0xf0f0f0f0; |
| - dstGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv); |
| - |
| - XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore, |
| - NULL, 0); |
| - |
| - XtVaGetApplicationResources(desktop, (XtPointer)&attr.backing_store, |
| - desktopBackingStoreResources, 1, NULL); |
| - valuemask = CWBackingStore; |
| - |
| - if (!appData.useX11Cursor) { |
| - dotCursor = CreateDotCursor(); |
| - attr.cursor = dotCursor; |
| - valuemask |= CWCursor; |
| - } |
| + XGCValues gcv; |
| + XSetWindowAttributes attr; |
| + XWindowAttributes gattr; |
| + unsigned long valuemask = 0; |
| + |
| + desktopWin = XtWindow(desktop); |
| + |
| + gc = XCreateGC(dpy,desktopWin,0,NULL); |
| + |
| + gcv.function = GXxor; |
| + gcv.foreground = 0x0f0f0f0f; |
| + srcGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv); |
| + gcv.foreground = 0xf0f0f0f0; |
| + dstGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv); |
| + |
| + XtAddConverter(XtRString, XtRBackingStore, XmuCvtStringToBackingStore, |
| + NULL, 0); |
| + |
| + if (appData.useXserverBackingStore) { |
| + Screen *s = DefaultScreenOfDisplay(dpy); |
| + if (DoesBackingStore(s) != Always) { |
| + fprintf(stderr, "X server does not do backingstore, disabling it.\n"); |
| + appData.useXserverBackingStore = False; |
| + } |
| + } |
| + |
| + 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); |
| |
| - XChangeWindowAttributes(dpy, desktopWin, valuemask, &attr); |
| +void |
| +DesktopCursorOff() |
| +{ |
| + if (dotCursor3 == None) { |
| + dotCursor3 = CreateDotCursor(3); |
| + dotCursor4 = CreateDotCursor(4); |
| + } |
| + if (appData.viewOnly) { |
| + XDefineCursor(dpy, desktopWin, dotCursor4); |
| + } else { |
| + XDefineCursor(dpy, desktopWin, dotCursor3); |
| + } |
| + FreeX11Cursor(); |
| + FreeSoftCursor(); |
| +} |
| + |
| + |
| +#define CEIL(x) ( (double) ((int) (x)) == (x) ? \ |
| + (double) ((int) (x)) : (double) ((int) (x) + 1) ) |
| +#define FLOOR(x) ( (double) ((int) (x)) ) |
| + |
| +#if 0 |
| +static int nfix(int i, int n) { |
| + if (i < 0) { |
| + i = 0; |
| + } else if (i >= n) { |
| + i = n - 1; |
| + } |
| + return i; |
| } |
| +#else |
| +#define nfix(i, n) ( i < 0 ? 0 : ( (i >= n) ? (n - 1) : i ) ) |
| +#endif |
| + |
| +int scale_round(int len, double fac) { |
| + double eps = 0.000001; |
| + |
| + len = (int) (len * fac + eps); |
| + if (len < 1) { |
| + len = 1; |
| + } |
| + return len; |
| +} |
| + |
| +static void scale_rect(double factor_x, double factor_y, int blend, int interpolate, |
| + int *px, int *py, int *pw, int *ph, int solid) { |
| + |
| + int i, j, i1, i2, j1, j2; /* indices for scaled fb (dest) */ |
| + int I, J, I1, I2, J1, J2; /* indices for main fb (source) */ |
| + |
| + double w, wx, wy, wtot; /* pixel weights */ |
| + |
| + double x1 = 0, y1, x2 = 0, 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; |
| + |
| + 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; |
| +#if 0 |
| + double fmin = factor_x < factor_y ? factor_x : factor_y; |
| +#endif |
| + |
| + 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); |
| + |
| + if (mark && !shrink && blend) { |
| + /* |
| + * kludge: correct for interpolating blurring leaking |
| + * up or left 1 destination pixel. |
| + */ |
| + if (X1 > 0) X1--; |
| + if (Y1 > 0) Y1--; |
| + } |
| + |
| + /* |
| + * find the extent of the change the input rectangle induces in |
| + * the scaled framebuffer. |
| + */ |
| + |
| + /* Left edges: find largest i such that i * dx <= X1 */ |
| + i1 = FLOOR(X1/dx); |
| + |
| + /* Right edges: find smallest i such that (i+1) * dx >= X2+1 */ |
| + i2 = CEIL( (X2+1)/dx ) - 1; |
| + |
| + /* To be safe, correct any overflows: */ |
| + i1 = nfix(i1, nx); |
| + i2 = nfix(i2, nx) + 1; /* add 1 to make a rectangle upper boundary */ |
| + |
| + /* Repeat above for y direction: */ |
| + j1 = FLOOR(Y1/dy); |
| + j2 = CEIL( (Y2+1)/dy ) - 1; |
| + |
| + j1 = nfix(j1, ny); |
| + j2 = nfix(j2, ny) + 1; |
| + |
| + /* |
| + * special case integer magnification with no blending. |
| + * vision impaired magnification usage is interested in this case. |
| + */ |
| + if (mark && ! blend && mag_int && Bpp != 3) { |
| + int jmin, jmax, imin, imax; |
| + |
| + /* outer loop over *source* pixels */ |
| + for (J=Y1; J < Y2; J++) { |
| + jmin = J * mag_int; |
| + jmax = jmin + mag_int; |
| + for (I=X1; I < X2; I++) { |
| + /* extract value */ |
| + src = src_fb + J*src_bytes_per_line + I*Bpp; |
| + if (Bpp == 4) { |
| + ui = *((unsigned int *)src); |
| + } else if (Bpp == 2) { |
| + us = *((unsigned short *)src); |
| + } else if (Bpp == 1) { |
| + uc = *((unsigned char *)src); |
| + } |
| + imin = I * mag_int; |
| + imax = imin + mag_int; |
| + /* inner loop over *dest* pixels */ |
| + for (j=jmin; j<jmax; j++) { |
| + dest = dst_fb + j*dst_bytes_per_line + imin*Bpp; |
| + for (i=imin; i<imax; i++) { |
| + if (Bpp == 4) { |
| + *((unsigned int *)dest) = ui; |
| + } else if (Bpp == 2) { |
| + *((unsigned short *)dest) = us; |
| + } else if (Bpp == 1) { |
| + *((unsigned char *)dest) = uc; |
| + } |
| + dest += Bpp; |
| + } |
| + } |
| + } |
| + } |
| + goto markit; |
| + } |
| + |
| + /* set these all to 1.0 to begin with */ |
| + wx = 1.0; |
| + wy = 1.0; |
| + w = 1.0; |
| + |
| + /* |
| + * Loop over destination pixels in scaled fb: |
| + */ |
| + for (j=j1; j<j2; j++) { |
| + int jbdy = 1, I1_solid = 0; |
| + |
| + y1 = j * dy; /* top edge */ |
| + if (y1 > Ny - 1) { |
| + /* can go over with dy = 1/scale_fac */ |
| + y1 = Ny - 1; |
| + } |
| + y2 = y1 + dy; /* bottom edge */ |
| + |
| + /* Find main fb indices covered by this dest pixel: */ |
| + J1 = (int) FLOOR(y1); |
| + J1 = nfix(J1, Ny); |
| + |
| + if (shrink && ! interpolate) { |
| + J2 = (int) CEIL(y2) - 1; |
| + J2 = nfix(J2, Ny); |
| + } else { |
| + J2 = J1 + 1; /* simple interpolation */ |
| + ddy = y1 - J1; |
| + } |
| + |
| + /* destination char* pointer: */ |
| + dest = dst_fb + j*dst_bytes_per_line + i1*Bpp; |
| + |
| + if (solid) { |
| + if (j1+sbdy <= j && j < j2-sbdy) { |
| + jbdy = 0; |
| + x1 = (i1+sbdy) * dx; |
| + if (x1 > Nx - 1) { |
| + x1 = Nx - 1; |
| + } |
| + I1_solid = (int) FLOOR(x1); |
| + if (I1_solid >= Nx) I1_solid = Nx - 1; |
| + } |
| + } |
| + |
| + for (i=i1; i<i2; i++) { |
| + int solid_skip = 0; |
| + |
| + if (solid) { |
| + /* if the region is solid, we can use the noblend speedup */ |
| + if (!jbdy && i1+sbdy <= i && i < i2-sbdy) { |
| + solid_skip = 1; |
| + /* pixels all the same so use X1: */ |
| + I1 = I1_solid; |
| + goto jsolid; |
| + } |
| + } |
| + |
| + x1 = i * dx; /* left edge */ |
| + if (x1 > Nx - 1) { |
| + /* can go over with dx = 1/scale_fac */ |
| + x1 = Nx - 1; |
| + } |
| + x2 = x1 + dx; /* right edge */ |
| + |
| + /* Find main fb indices covered by this dest pixel: */ |
| + I1 = (int) FLOOR(x1); |
| + if (I1 >= Nx) I1 = Nx - 1; |
| + |
| + jsolid: |
| + cnt++; |
| + |
| + if ((!blend && use_noblend_shortcut) || solid_skip) { |
| + /* |
| + * The noblend case involves no weights, |
| + * and 1 pixel, so just copy the value |
| + * directly. |
| + */ |
| + src = src_fb + J1*src_bytes_per_line + I1*Bpp; |
| + if (Bpp == 4) { |
| + *((unsigned int *)dest) |
| + = *((unsigned int *)src); |
| + } else if (Bpp == 2) { |
| + *((unsigned short *)dest) |
| + = *((unsigned short *)src); |
| + } else if (Bpp == 1) { |
| + *(dest) = *(src); |
| + } else if (Bpp == 3) { |
| + /* rare case */ |
| + for (k=0; k<=2; k++) { |
| + *(dest+k) = *(src+k); |
| + } |
| + } |
| + dest += Bpp; |
| + continue; |
| + } |
| + |
| + if (shrink && ! interpolate) { |
| + I2 = (int) CEIL(x2) - 1; |
| + if (I2 >= Nx) I2 = Nx - 1; |
| + } else { |
| + I2 = I1 + 1; /* simple interpolation */ |
| + ddx = x1 - I1; |
| + } |
| +#if 0 |
| +if (first) fprintf(stderr, " I1=%d I2=%d J1=%d J2=%d\n", I1, I2, J1, J2); |
| +#endif |
| + |
| + /* Zero out accumulators for next pixel average: */ |
| + for (b=0; b<4; b++) { |
| + pixave[b] = 0.0; /* for RGB weighted sums */ |
| + } |
| + |
| + /* |
| + * wtot is for accumulating the total weight. |
| + * It should always sum to 1/(scale_fac * scale_fac). |
| + */ |
| + wtot = 0.0; |
| + |
| + /* |
| + * Loop over source pixels covered by this dest pixel. |
| + * |
| + * These "extra" loops over "J" and "I" make |
| + * the cache/cacheline performance unclear. |
| + * For example, will the data brought in from |
| + * src for j, i, and J=0 still be in the cache |
| + * after the J > 0 data have been accessed and |
| + * we are at j, i+1, J=0? The stride in J is |
| + * main_bytes_per_line, and so ~4 KB. |
| + * |
| + * Typical case when shrinking are 2x2 loop, so |
| + * just two lines to worry about. |
| + */ |
| + for (J=J1; J<=J2; J++) { |
| + /* see comments for I, x1, x2, etc. below */ |
| + if (constant_weights) { |
| + ; |
| + } else if (! blend) { |
| + if (J != J1) { |
| + continue; |
| + } |
| + wy = 1.0; |
| + |
| + /* interpolation scheme: */ |
| + } else if (! shrink || interpolate) { |
| + if (J >= Ny) { |
| + continue; |
| + } else if (J == J1) { |
| + wy = 1.0 - ddy; |
| + } else if (J != J1) { |
| + wy = ddy; |
| + } |
| + |
| + /* integration scheme: */ |
| + } else if (J < y1) { |
| + wy = J+1 - y1; |
| + } else if (J+1 > y2) { |
| + wy = y2 - J; |
| + } else { |
| + wy = 1.0; |
| + } |
| + |
| + src = src_fb + J*src_bytes_per_line + I1*Bpp; |
| + |
| + for (I=I1; I<=I2; I++) { |
| + |
| + /* Work out the weight: */ |
| + |
| + if (constant_weights) { |
| + ; |
| + } else if (! blend) { |
| + /* |
| + * Ugh, PseudoColor colormap is |
| + * bad news, to avoid random |
| + * colors just take the first |
| + * pixel. Or user may have |
| + * specified :nb to fraction. |
| + * The :fb will force blending |
| + * for this case. |
| + */ |
| + if (I != I1) { |
| + continue; |
| + } |
| + wx = 1.0; |
| + |
| + /* interpolation scheme: */ |
| + } else if (! shrink || interpolate) { |
| + if (I >= Nx) { |
| + continue; /* off edge */ |
| + } else if (I == I1) { |
| + wx = 1.0 - ddx; |
| + } else if (I != I1) { |
| + wx = ddx; |
| + } |
| + |
| + /* integration scheme: */ |
| + } else if (I < x1) { |
| + /* |
| + * source left edge (I) to the |
| + * left of dest left edge (x1): |
| + * fractional weight |
| + */ |
| + wx = I+1 - x1; |
| + } else if (I+1 > x2) { |
| + /* |
| + * source right edge (I+1) to the |
| + * right of dest right edge (x2): |
| + * fractional weight |
| + */ |
| + wx = x2 - I; |
| + } else { |
| + /* |
| + * source edges (I and I+1) completely |
| + * inside dest edges (x1 and x2): |
| + * full weight |
| + */ |
| + wx = 1.0; |
| + } |
| + |
| + w = wx * wy; |
| + wtot += w; |
| + |
| + /* |
| + * We average the unsigned char value |
| + * instead of char value: otherwise |
| + * the minimum (char 0) is right next |
| + * to the maximum (char -1)! This way |
| + * they are spread between 0 and 255. |
| + */ |
| + if (Bpp == 4) { |
| + /* unroll the loops, can give 20% */ |
| + pixave[0] += w * ((unsigned char) *(src )); |
| + pixave[1] += w * ((unsigned char) *(src+1)); |
| + pixave[2] += w * ((unsigned char) *(src+2)); |
| + pixave[3] += w * ((unsigned char) *(src+3)); |
| + } else if (Bpp == 2) { |
| + /* |
| + * 16bpp: trickier with green |
| + * split over two bytes, so we |
| + * use the masks: |
| + */ |
| + us = *((unsigned short *) src); |
| + pixave[0] += w*(us & main_red_mask); |
| + pixave[1] += w*(us & main_green_mask); |
| + pixave[2] += w*(us & main_blue_mask); |
| + } else if (Bpp == 1) { |
| + pixave[0] += w * |
| + ((unsigned char) *(src)); |
| + } else { |
| + for (b=0; b<Bpp; b++) { |
| + pixave[b] += w * |
| + ((unsigned char) *(src+b)); |
| + } |
| + } |
| + src += Bpp; |
| + } |
| + } |
| + |
| + if (wtot <= 0.0) { |
| + wtot = 1.0; |
| + } |
| + wtot = 1.0/wtot; /* normalization factor */ |
| + |
| + /* place weighted average pixel in the scaled fb: */ |
| + if (Bpp == 4) { |
| + *(dest ) = (char) (wtot * pixave[0]); |
| + *(dest+1) = (char) (wtot * pixave[1]); |
| + *(dest+2) = (char) (wtot * pixave[2]); |
| + *(dest+3) = (char) (wtot * pixave[3]); |
| + } else if (Bpp == 2) { |
| + /* 16bpp / 565 case: */ |
| + pixave[0] *= wtot; |
| + pixave[1] *= wtot; |
| + pixave[2] *= wtot; |
| + us = (main_red_mask & (int) pixave[0]) |
| + | (main_green_mask & (int) pixave[1]) |
| + | (main_blue_mask & (int) pixave[2]); |
| + *( (unsigned short *) dest ) = us; |
| + } else if (Bpp == 1) { |
| + *(dest) = (char) (wtot * pixave[0]); |
| + } else { |
| + for (b=0; b<Bpp; b++) { |
| + *(dest+b) = (char) (wtot * pixave[b]); |
| + } |
| + } |
| + dest += Bpp; |
| + } |
| + } |
| + markit: |
| +/* End taken from x11vnc scale: */ |
| + if (0) {} |
| +} |
| + |
| +void do_scale_stats(int width, int height) { |
| + static double calls = 0.0, sum = 0.0, var = 0.0, last = 0.0; |
| + double A = width * height; |
| + |
| + if (last == 0.0) { |
| + last = dnow(); |
| + } |
| + |
| + calls += 1.0; |
| + sum += A; |
| + var += A*A; |
| + |
| + if (dnow() > last + 4.0) { |
| + double cnt = calls; |
| + if (cnt <= 0.0) cnt = 1.0; |
| + var /= cnt; |
| + sum /= cnt; |
| + var = var - sum * sum; |
| + if (sum > 0.0) { |
| + var = var / (sum*sum); |
| + } |
| + fprintf(stderr, "scale_rect stats: %10d %10.1f ave: %10.3f var-rat: %10.3f\n", (int) calls, sum * cnt, sum, var); |
| + |
| + calls = 0.0; |
| + sum = 0.0; |
| + var = 0.0; |
| + last = dnow(); |
| + } |
| +} |
| + |
| +void put_image(int src_x, int src_y, int dst_x, int dst_y, int width, |
| + int height, int solid) { |
| + int db = 0; |
| + int xmax = si.framebufferWidth; |
| + int ymax = si.framebufferHeight; |
| + |
| +if (db || 0) fprintf(stderr, "put_image(%d %d %d %d %d %d)\n", src_x, src_y, dst_x, dst_y, width, height); |
| + |
| + if (image_scale) { |
| + int i; |
| + static int scale_stats = -1; |
| + |
| + for (i=0; i < 2; i++) { |
| + if (src_x > 0) src_x--; |
| + if (src_y > 0) src_y--; |
| + } |
| + for (i=0; i < 4; i++) { |
| + if (src_x + width < xmax) width++; |
| + if (src_y + height < ymax) height++; |
| + } |
| + |
| + if (db) fprintf(stderr, "put_image(%d %d %d %d %d %d)\n", src_x, src_y, dst_x, dst_y, width, height); |
| + if (db) fprintf(stderr, "scale_rect(%d %d %d %d)\n", src_x, src_y, width, height); |
| + |
| + if (scale_stats < 0) { |
| + if (getenv("SSVNC_SCALE_STATS")) { |
| + scale_stats = 1; |
| + } else { |
| + scale_stats = 0; |
| + } |
| + } |
| + if (scale_stats) { |
| + do_scale_stats(width, height); |
| + } |
| + |
| + scale_rect(scale_factor_x, scale_factor_y, 1, 0, &src_x, &src_y, &width, &height, solid); |
| + dst_x = src_x; |
| + dst_y = src_y; |
| + } |
| + |
| +#ifdef MITSHM |
| + if (appData.useShm) { |
| + double fac = image_scale ? scale_factor_y : 1.0; |
| + if (image_ycrop == NULL) { |
| + if (image_is_shm) { |
| + XShmPutImage(dpy, desktopWin, gc, image, src_x, src_y, |
| + dst_x, dst_y, width, height, False); |
| + } else { |
| + XPutImage(dpy, desktopWin, gc, image, src_x, src_y, |
| + dst_x, dst_y, width, height); |
| + } |
| + } else if ((width < 32 && height < 32) || height > appData.yCrop * fac) { |
| + XPutImage(dpy, desktopWin, gc, image, src_x, src_y, |
| + dst_x, dst_y, width, height); |
| + } else { |
| + char *src, *dst; |
| + int Bpp = image->bits_per_pixel / 8; |
| + int Bpl = image->bytes_per_line, h; |
| + int Bpl2 = image_ycrop->bytes_per_line; |
| + src = image->data + src_y * Bpl + src_x * Bpp; |
| + dst = image_ycrop->data; |
| + for (h = 0; h < height; h++) { |
| + memcpy(dst, src, width * Bpp); |
| + src += Bpl; |
| + dst += Bpl2; |
| + } |
| + XShmPutImage(dpy, desktopWin, gc, image_ycrop, 0, 0, |
| + dst_x, dst_y, width, height, False); |
| + } |
| + } else |
| +#endif |
| + { |
| + XPutImage(dpy, desktopWin, gc, image, src_x, src_y, |
| + dst_x, dst_y, width, height); |
| + } |
| +} |
| + |
| +#if 0 |
| +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); |
| +#endif |
| + |
| +void releaseAllPressedModifiers(void) { |
| + int i; |
| + static int debug_release = -1; |
| + if (debug_release < 0) { |
| + if (getenv("SSVNC_DEBUG_RELEASE")) { |
| + debug_release = 1; |
| + } else { |
| + debug_release = 0; |
| + } |
| + } |
| + if (debug_release) fprintf(stderr, "into releaseAllPressedModifiers()\n"); |
| + for (i = 0; i < 256; i++) { |
| + if (modifierPressed[i]) { |
| + SendKeyEvent(XKeycodeToKeysym(dpy, i, 0), False); |
| + modifierPressed[i] = False; |
| + if (debug_release) fprintf(stderr, "releasing[%d] %s\n", i, XKeysymToString(XKeycodeToKeysym(dpy, i, 0))); |
| + } |
| + } |
| +} |
| + |
| +#define PR_EXPOSE fprintf(stderr, "Expose: %04dx%04d+%04d+%04d %04d/%04d/%04d now: %8.4f rescale: %8.4f fullscreen: %8.4f\n", width, height, x, y, si.framebufferWidth, appData.yCrop, si.framebufferHeight, now - start_time, now - last_rescale, now - last_fullscreen); |
| |
| /* |
| * HandleBasicDesktopEvent - deal with expose and leave events. |
| @@ -152,42 +1553,529 @@ |
| static void |
| HandleBasicDesktopEvent(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont) |
| { |
| - int i; |
| + int x, y, width, height; |
| + double now = dnow(); |
| |
| - switch (ev->type) { |
| + if (w || ptr || cont) {} |
| + |
| + 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; |
| + case ClientMessage: |
| + if (ev->xclient.window == XtWindow(desktop) && ev->xclient.message_type == XA_INTEGER && |
| + ev->xclient.format == 8 && !strcmp(ev->xclient.data.b, "SendRFBUpdate")) { |
| + SendIncrementalFramebufferUpdateRequest(); |
| + } |
| + break; |
| } |
| + check_things(); |
| +} |
| + |
| +extern Position desktopX, desktopY; |
| + |
| +void x11vnc_appshare(char *cmd) { |
| + char send[200], str[100]; |
| + char *id = "cmd=id_cmd"; |
| + int m_big = 80, m_fine = 15; |
| + int resize = 100, db = 0; |
| + |
| + if (getenv("X11VNC_APPSHARE_DEBUG")) { |
| + db = atoi(getenv("X11VNC_APPSHARE_DEBUG")); |
| + } |
| + |
| + if (db) fprintf(stderr, "x11vnc_appshare: cmd=%s\n", cmd); |
| + |
| + str[0] = '\0'; |
| + |
| + if (!strcmp(cmd, "left")) { |
| + sprintf(str, "%s:move:-%d+0", id, m_big); |
| + } else if (!strcmp(cmd, "right")) { |
| + sprintf(str, "%s:move:+%d+0", id, m_big); |
| + } else if (!strcmp(cmd, "up")) { |
| + sprintf(str, "%s:move:+0-%d", id, m_big); |
| + } else if (!strcmp(cmd, "down")) { |
| + sprintf(str, "%s:move:+0+%d", id, m_big); |
| + } else if (!strcmp(cmd, "left-fine")) { |
| + sprintf(str, "%s:move:-%d+0", id, m_fine); |
| + } else if (!strcmp(cmd, "right-fine")) { |
| + sprintf(str, "%s:move:+%d+0", id, m_fine); |
| + } else if (!strcmp(cmd, "up-fine")) { |
| + sprintf(str, "%s:move:+0-%d", id, m_fine); |
| + } else if (!strcmp(cmd, "down-fine")) { |
| + sprintf(str, "%s:move:+0+%d", id, m_fine); |
| + } else if (!strcmp(cmd, "taller")) { |
| + sprintf(str, "%s:resize:+0+%d", id, resize); |
| + } else if (!strcmp(cmd, "shorter")) { |
| + sprintf(str, "%s:resize:+0-%d", id, resize); |
| + } else if (!strcmp(cmd, "wider")) { |
| + sprintf(str, "%s:resize:+%d+0", id, resize); |
| + } else if (!strcmp(cmd, "narrower")) { |
| + sprintf(str, "%s:resize:-%d+0", id, resize); |
| + } else if (!strcmp(cmd, "lower")) { |
| + sprintf(str, "%s:lower", id); |
| + } else if (!strcmp(cmd, "raise")) { |
| + sprintf(str, "%s:raise", id); |
| + } else if (!strcmp(cmd, "delete")) { |
| + sprintf(str, "%s:wm_delete", id); |
| + } else if (!strcmp(cmd, "position")) { |
| + Position x, y; |
| + int xi, yi; |
| + |
| + XtVaGetValues(toplevel, XtNx, &x, XtNy, &y, NULL); |
| + xi = (int) x; |
| + yi = (int) y; |
| + if (appData.scale) { |
| + double fx = 1.0, fy = 1.0; |
| + get_scale_values(&fx, &fy); |
| + if (fx > 0.0 && fy > 0.0) { |
| + xi /= fx; |
| + yi /= fx; |
| + } |
| + } |
| + sprintf(str, "%s:geom:0x0+%d+%d", id, xi, yi); |
| + fprintf(stderr, "str=%s\n", str); |
| + } |
| + if (strcmp(str, "")) { |
| + Bool vo = appData.viewOnly; |
| + strcpy(send, "X11VNC_APPSHARE_CMD:"); |
| + strcat(send, str); |
| + if (db) fprintf(stderr, "x11vnc_appshare: send=%s\n", send); |
| + if (vo) appData.viewOnly = False; |
| + SendClientCutText(send, strlen(send)); |
| + if (vo) appData.viewOnly = True; |
| + } |
| +} |
| + |
| +void scroll_desktop(int horiz, int vert, double amount) { |
| + Dimension h, w; |
| + Position x, y; |
| + Position x2, y2; |
| + static int db = -1; |
| + |
| + if (db < 0) { |
| + if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) { |
| + db = 1; |
| + } else { |
| + db = 0; |
| + } |
| + } |
| + |
| + XtVaGetValues(form, XtNheight, &h, XtNwidth, &w, NULL); |
| + XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL); |
| + |
| + x2 = -x; |
| + y2 = -y; |
| + |
| + if (amount == -1.0) { |
| + int dx = horiz; |
| + int dy = vert; |
| + if (dx == 0 && dy == 0) { |
| + return; |
| + } |
| + x2 -= dx; |
| + y2 -= dy; |
| + } else { |
| + if (horiz) { |
| + int dx = (int) (amount * w); |
| + if (dx < 0) dx = -dx; |
| + if (amount == 0.0) dx = 1; |
| + if (horiz > 0) { |
| + x2 += dx; |
| + } else { |
| + x2 -= dx; |
| + } |
| + if (x2 < 0) x2 = 0; |
| + } |
| + if (vert) { |
| + int dy = (int) (amount * h); |
| + if (amount == 0.0) dy = 1; |
| + if (dy < 0) dy = -dy; |
| + if (vert < 0) { |
| + y2 += dy; |
| + } else { |
| + y2 -= dy; |
| + } |
| + if (y2 < 0) y2 = 0; |
| + } |
| + } |
| + |
| + if (db) fprintf(stderr, "%d %d %f viewport(%dx%d): %d %d -> %d %d\n", horiz, vert, amount, w, h, -x, -y, x2, y2); |
| + XawViewportSetCoordinates(viewport, x2, y2); |
| + |
| + if (appData.fullScreen) { |
| + XSync(dpy, False); |
| + XtVaGetValues(desktop, XtNx, &x, XtNy, &y, NULL); |
| + desktopX = -x; |
| + desktopY = -y; |
| + } else if (amount == -1.0) { |
| + XSync(dpy, False); |
| + } |
| } |
| |
| +void scale_desktop(int bigger, double frac) { |
| + double current, new; |
| + char tmp[100]; |
| + char *s; |
| + int fs; |
| + |
| + if (appData.scale == NULL) { |
| + s = "1.0"; |
| + } else { |
| + s = appData.scale; |
| + } |
| + if (!strcmp(s, "auto")) { |
| + fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s); |
| + return; |
| + } else if (!strcmp(s, "fit")) { |
| + fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s); |
| + return; |
| + } else if (strstr(s, "x")) { |
| + fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s); |
| + return; |
| + } else if (!strcmp(s, "none")) { |
| + s = "1.0"; |
| + } |
| + |
| + if (sscanf(s, "%lf", ¤t) != 1) { |
| + fprintf(stderr, "scale_desktop: skipping scale mode '%s'\n", s); |
| + return; |
| + } |
| + if (bigger) { |
| + new = current * (1.0 + frac); |
| + } else { |
| + new = current / (1.0 + frac); |
| + } |
| + if (0.99 < new && new < 1.01) { |
| + new = 1.0; |
| + } |
| |
| + if (new > 5.0) { |
| + fprintf(stderr, "scale_desktop: not scaling > 5.0: %f\n", new); |
| + return; |
| + } else if (new < 0.05) { |
| + fprintf(stderr, "scale_desktop: not scaling < 0.05: %f\n", new); |
| + return; |
| + } |
| + sprintf(tmp, "%.16f", new); |
| + appData.scale = strdup(tmp); |
| + |
| + fs = 0; |
| + if (appData.fullScreen) { |
| + fs = 1; |
| + FullScreenOff(); |
| + } |
| + if (1) { |
| + double fx, fy; |
| + get_scale_values(&fx, &fy); |
| + if (fx > 0.0 && fy > 0.0) { |
| + rescale_image(); |
| + } |
| + } |
| + if (fs) { |
| + FullScreenOn(); |
| + } |
| +} |
| + |
| +static int escape_mods[8]; |
| +static int escape_drag_in_progress = 0, last_x = 0, last_y = 0; |
| +static double last_drag = 0.0; |
| +static double last_key = 0.0; |
| + |
| +static int escape_sequence_pressed(void) { |
| + static char *prev = NULL; |
| + char *str = "default"; |
| + int sum, i, init = 0, pressed; |
| + static int db = -1; |
| + |
| + if (db < 0) { |
| + if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) { |
| + db = 1; |
| + } else { |
| + db = 0; |
| + } |
| + } |
| + |
| + if (appData.escapeKeys != NULL) { |
| + str = appData.escapeKeys; |
| + } |
| + if (prev == NULL) { |
| + init = 1; |
| + prev = strdup(str); |
| + } else { |
| + if (strcmp(prev, str)) { |
| + init = 1; |
| + free(prev); |
| + prev = strdup(str); |
| + } |
| + } |
| + if (db) fprintf(stderr, "str: %s\n", str); |
| + |
| + if (init) { |
| + char *p, *s; |
| + KeySym ks; |
| + int k = 0, failed = 0; |
| + |
| + for (i = 0; i < 8; i++) { |
| + escape_mods[i] = -1; |
| + } |
| + |
| + if (!strcasecmp(str, "default")) { |
| +#if (defined(__MACH__) && defined(__APPLE__)) |
| + s = strdup("Control_L,Meta_L"); |
| +#else |
| + s = strdup("Alt_L,Super_L"); |
| +#endif |
| + } else { |
| + s = strdup(str); |
| + } |
| + |
| + p = strtok(s, ",+ "); |
| + while (p) { |
| + ks = XStringToKeysym(p); |
| + if (ks == XK_Shift_L || ks == XK_Shift_R) { |
| + putenv("NO_X11VNC_APPSHARE=1"); |
| + } |
| + if (k >= 8) { |
| + fprintf(stderr, "EscapeKeys: more than 8 modifier keys.\n"); |
| + failed = 1; |
| + break; |
| + } |
| + if (ks == NoSymbol) { |
| + fprintf(stderr, "EscapeKeys: failed lookup for '%s'\n", p); |
| + failed = 1; |
| + break; |
| + } else if (!IsModifierKey(ks)) { |
| + fprintf(stderr, "EscapeKeys: not a modifier key '%s'\n", p); |
| + failed = 1; |
| + break; |
| + } else { |
| + KeyCode kc = XKeysymToKeycode(dpy, ks); |
| + if (kc == NoSymbol) { |
| + fprintf(stderr, "EscapeKeys: no keycode for modifier key '%s'\n", p); |
| + failed = 1; |
| + break; |
| + } |
| + if (db) fprintf(stderr, "set: %d %d\n", k, kc); |
| + escape_mods[k++] = kc; |
| + } |
| + |
| + p = strtok(NULL, ",+ "); |
| + } |
| + free(s); |
| + |
| + if (failed) { |
| + for (i = 0; i < 8; i++) { |
| + escape_mods[i] = -1; |
| + } |
| + } |
| + } |
| + |
| + pressed = 1; |
| + sum = 0; |
| + for (i = 0; i < 8; i++) { |
| + int kc = escape_mods[i]; |
| + if (kc != -1 && kc < 256) { |
| + if (db) fprintf(stderr, "try1: %d %d = %d\n", i, kc, modifierPressed[kc]); |
| + if (!modifierPressed[kc]) { |
| + pressed = 0; |
| + break; |
| + } else { |
| + sum++; |
| + } |
| + } |
| + } |
| + if (sum == 0) pressed = 0; |
| + |
| + if (!pressed) { |
| + /* user may have dragged mouse outside of toplevel window */ |
| + int i, k; |
| + int keystate[256]; |
| + char keys[32]; |
| + |
| + /* so query server instead of modifierPressed[] */ |
| + XQueryKeymap(dpy, keys); |
| + for (i=0; i<32; i++) { |
| + char c = keys[i]; |
| + |
| + for (k=0; k < 8; k++) { |
| + if (c & 0x1) { |
| + keystate[8*i + k] = 1; |
| + } else { |
| + keystate[8*i + k] = 0; |
| + } |
| + c = c >> 1; |
| + } |
| + } |
| + |
| + /* check again using keystate[] */ |
| + pressed = 2; |
| + sum = 0; |
| + for (i = 0; i < 8; i++) { |
| + int kc = escape_mods[i]; |
| + if (kc != -1 && kc < 256) { |
| + if (db) fprintf(stderr, "try2: %d %d = %d\n", i, kc, keystate[kc]); |
| + if (!keystate[kc]) { |
| + pressed = 0; |
| + break; |
| + } else { |
| + sum++; |
| + } |
| + } |
| + } |
| + if (sum == 0) pressed = 0; |
| + } |
| + |
| + return pressed; |
| +} |
| + |
| +static int shift_is_down(void) { |
| + int shift_down = 0; |
| + KeyCode kc; |
| + |
| + if (appData.viewOnly) { |
| + int i, k; |
| + char keys[32]; |
| + int keystate[256]; |
| + |
| + XQueryKeymap(dpy, keys); |
| + for (i=0; i<32; i++) { |
| + char c = keys[i]; |
| + |
| + for (k=0; k < 8; k++) { |
| + if (c & 0x1) { |
| + keystate[8*i + k] = 1; |
| + } else { |
| + keystate[8*i + k] = 0; |
| + } |
| + c = c >> 1; |
| + } |
| + } |
| + |
| + kc = XKeysymToKeycode(dpy, XK_Shift_L); |
| + if (kc != NoSymbol && keystate[kc]) { |
| + shift_down = 1; |
| + } else { |
| + kc = XKeysymToKeycode(dpy, XK_Shift_R); |
| + if (kc != NoSymbol && keystate[kc]) { |
| + shift_down = 1; |
| + } |
| + } |
| + return shift_down; |
| + } else { |
| + kc = XKeysymToKeycode(dpy, XK_Shift_L); |
| + if (kc != NoSymbol && modifierPressed[kc]) { |
| + shift_down = 1; |
| + } else { |
| + kc = XKeysymToKeycode(dpy, XK_Shift_R); |
| + if (kc != NoSymbol && modifierPressed[kc]) { |
| + shift_down = 1; |
| + } |
| + } |
| + return shift_down; |
| + } |
| +} |
| + |
| /* |
| * SendRFBEvent is an action which sends an RFB event. It can be used in two |
| * ways. Without any parameters it simply sends an RFB event corresponding to |
| @@ -201,127 +2089,406 @@ |
| * button2 down, 3 for both, etc). |
| */ |
| |
| +extern Bool selectingSingleWindow; |
| + |
| +extern Cursor dotCursor3; |
| +extern Cursor dotCursor4; |
| + |
| +extern void set_server_scale(int); |
| + |
| void |
| SendRFBEvent(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| { |
| - KeySym ks; |
| - char keyname[256]; |
| - int buttonMask, x, y; |
| - |
| - if (appData.fullScreen && ev->type == MotionNotify) { |
| - if (BumpScroll(ev)) |
| - return; |
| - } |
| + KeySym ks; |
| + char keyname[256]; |
| + int buttonMask, x, y; |
| + int do_escape; |
| + static int db = -1; |
| + char *ek = appData.escapeKeys; |
| + |
| + if (db < 0) { |
| + if (getenv("SSVNC_DEBUG_ESCAPE_KEYS")) { |
| + db = 1; |
| + } else { |
| + db = 0; |
| + } |
| + } |
| + |
| + if (ev->type == MotionNotify || ev->type == KeyRelease) { |
| + static double last = 0.0; |
| + double now = dnow(); |
| + if (now > last + 0.25) { |
| + check_things(); |
| + last = now; |
| + } |
| + } |
| + |
| + if (selectingSingleWindow && ev->type == ButtonPress) { |
| + selectingSingleWindow = False; |
| + SendSingleWindow(ev->xbutton.x, ev->xbutton.y); |
| + if (appData.viewOnly) { |
| + XDefineCursor(dpy, desktopWin, dotCursor4); |
| + } else { |
| + XDefineCursor(dpy, desktopWin, dotCursor3); |
| + } |
| + return; |
| + } |
| |
| - if (appData.viewOnly) return; |
| + if (appData.fullScreen && ev->type == MotionNotify && !escape_drag_in_progress) { |
| + if (BumpScroll(ev)) { |
| + return; |
| + } |
| + } |
| + |
| + do_escape = 0; |
| + if (ek != NULL && (ek[0] == 'n' || ek[0] == 'N') && !strcasecmp(ek, "never")) { |
| + ; |
| + } else if (appData.viewOnly) { |
| + do_escape = 1; |
| + } else if (appData.escapeActive) { |
| + int skip = 0, is_key = 0; |
| + |
| + if (ev->type == KeyPress || ev->type == KeyRelease) { |
| + is_key = 1; |
| + XLookupString(&ev->xkey, keyname, 256, &ks, NULL); |
| + if (IsModifierKey(ks)) { |
| + skip = 1; |
| + } |
| + } |
| + if (!skip) { |
| + int es = escape_sequence_pressed(); |
| + if (es == 1) { |
| + do_escape = 1; |
| + } else if (es == 2) { |
| + if (is_key) { |
| + if (dnow() < last_key + 5.0) { |
| + do_escape = 1; |
| + } |
| + } else { |
| + if (dnow() < last_drag + 5.0) { |
| + do_escape = 1; |
| + } |
| + } |
| + } |
| + } |
| + } |
| + if (!do_escape) { |
| + escape_drag_in_progress = 0; |
| + } |
| + if (db) fprintf(stderr, "do_escape: %d\n", do_escape); |
| + |
| + if (do_escape) { |
| + int W = si.framebufferWidth; |
| + int H = si.framebufferHeight; |
| + int shift_down = 0; |
| + |
| + if (!getenv("NO_X11VNC_APPSHARE")) { |
| + shift_down = shift_is_down(); |
| + } |
| + if (db) fprintf(stderr, "shift_down: %d\n", shift_down); |
| + |
| + if (*num_params != 0) { |
| + if (strcasecmp(params[0],"fbupdate") == 0) { |
| + SendFramebufferUpdateRequest(0, 0, W, H, False); |
| + } |
| + } |
| + if (ev->type == ButtonRelease) { |
| + XButtonEvent *b = (XButtonEvent *) ev; |
| + if (db) fprintf(stderr, "ButtonRelease: %d %d %d\n", b->x_root, b->y_root, b->state); |
| + if (b->button == 3) { |
| + if (shift_down) { |
| + x11vnc_appshare("delete"); |
| + } else { |
| + ShowPopup(w, ev, params, num_params); |
| + } |
| + } else if (escape_drag_in_progress && b->button == 1) { |
| + escape_drag_in_progress = 0; |
| + } |
| + } else if (ev->type == ButtonPress) { |
| + XButtonEvent *b = (XButtonEvent *) ev; |
| + if (db) fprintf(stderr, "ButtonPress: %d %d %d\n", b->x_root, b->y_root, b->state); |
| + if (b->button == 1) { |
| + if (shift_down) { |
| + x11vnc_appshare("position"); |
| + } else { |
| + escape_drag_in_progress = 1; |
| + last_x = b->x_root; |
| + last_y = b->y_root; |
| + } |
| + } else { |
| + escape_drag_in_progress = 0; |
| + } |
| + } else if (ev->type == MotionNotify) { |
| + XMotionEvent *m = (XMotionEvent *) ev; |
| + if (escape_drag_in_progress) { |
| + if (db) fprintf(stderr, "MotionNotify: %d %d %d\n", m->x_root, m->y_root, m->state); |
| + scroll_desktop(m->x_root - last_x, m->y_root - last_y, -1.0); |
| + last_x = m->x_root; |
| + last_y = m->y_root; |
| + } |
| + } else if (ev->type == KeyRelease) { |
| + int did = 1; |
| + |
| + XLookupString(&ev->xkey, keyname, 256, &ks, NULL); |
| + if (ks == XK_1 || ks == XK_KP_1) { |
| + set_server_scale(1); |
| + } else if (ks == XK_2 || ks == XK_KP_2) { |
| + set_server_scale(2); |
| + } else if (ks == XK_3 || ks == XK_KP_3) { |
| + set_server_scale(3); |
| + } else if (ks == XK_4 || ks == XK_KP_4) { |
| + set_server_scale(4); |
| + } else if (ks == XK_5 || ks == XK_KP_5) { |
| + set_server_scale(5); |
| + } else if (ks == XK_6 || ks == XK_KP_6) { |
| + set_server_scale(6); |
| + } else if (ks == XK_r || ks == XK_R) { |
| + SendFramebufferUpdateRequest(0, 0, W, H, False); |
| + } else if (ks == XK_b || ks == XK_B) { |
| + ToggleBell(w, ev, params, num_params); |
| + } else if (ks == XK_c || ks == XK_C) { |
| + Toggle8bpp(w, ev, params, num_params); |
| + } else if (ks == XK_x || ks == XK_X) { |
| + ToggleX11Cursor(w, ev, params, num_params); |
| + } else if (ks == XK_z || ks == XK_Z) { |
| + ToggleTightZRLE(w, ev, params, num_params); |
| + } else if (ks == XK_h || ks == XK_H) { |
| + ToggleTightHextile(w, ev, params, num_params); |
| + } else if (ks == XK_f || ks == XK_F) { |
| + ToggleFileXfer(w, ev, params, num_params); |
| + } else if (ks == XK_V) { |
| + ToggleViewOnly(w, ev, params, num_params); |
| + } else if (ks == XK_Q) { |
| + Quit(w, ev, params, num_params); |
| + } else if (ks == XK_l || ks == XK_L) { |
| + ToggleFullScreen(w, ev, params, num_params); |
| + } else if (ks == XK_a || ks == XK_A) { |
| + ToggleCursorAlpha(w, ev, params, num_params); |
| + } else if (ks == XK_s || ks == XK_S) { |
| + SetScale(w, ev, params, num_params); |
| + } else if (ks == XK_t || ks == XK_T) { |
| + ToggleTextChat(w, ev, params, num_params); |
| + } else if (ks == XK_e || ks == XK_E) { |
| + SetEscapeKeys(w, ev, params, num_params); |
| + } else if (ks == XK_g || ks == XK_G) { |
| + ToggleXGrab(w, ev, params, num_params); |
| + } else if (ks == XK_D) { |
| + if (shift_down || appData.appShare) { |
| + x11vnc_appshare("delete"); |
| + } |
| + } else if (ks == XK_M) { |
| + if (shift_down || appData.appShare) { |
| + x11vnc_appshare("position"); |
| + } |
| + } else if (ks == XK_Left) { |
| + if (shift_down) { |
| + x11vnc_appshare("left"); |
| + } else { |
| + scroll_desktop(-1, 0, 0.1); |
| + } |
| + } else if (ks == XK_Right) { |
| + if (shift_down) { |
| + x11vnc_appshare("right"); |
| + } else { |
| + scroll_desktop(+1, 0, 0.1); |
| + } |
| + } else if (ks == XK_Up) { |
| + if (shift_down) { |
| + x11vnc_appshare("up"); |
| + } else { |
| + scroll_desktop(0, +1, 0.1); |
| + } |
| + } else if (ks == XK_Down) { |
| + if (shift_down) { |
| + x11vnc_appshare("down"); |
| + } else { |
| + scroll_desktop(0, -1, 0.1); |
| + } |
| + } else if (ks == XK_KP_Left) { |
| + if (shift_down) { |
| + x11vnc_appshare("left-fine"); |
| + } else { |
| + scroll_desktop(-1, 0, 0.0); |
| + } |
| + } else if (ks == XK_KP_Right) { |
| + if (shift_down) { |
| + x11vnc_appshare("right-fine"); |
| + } else { |
| + scroll_desktop(+1, 0, 0.0); |
| + } |
| + } else if (ks == XK_KP_Up) { |
| + if (shift_down) { |
| + x11vnc_appshare("up-fine"); |
| + } else { |
| + scroll_desktop(0, +1, 0.0); |
| + } |
| + } else if (ks == XK_KP_Down) { |
| + if (shift_down) { |
| + x11vnc_appshare("down-fine"); |
| + } else { |
| + scroll_desktop(0, -1, 0.0); |
| + } |
| + } else if (ks == XK_Next || ks == XK_KP_Next) { |
| + if (shift_down && ks == XK_Next) { |
| + x11vnc_appshare("shorter"); |
| + } else { |
| + scroll_desktop(0, -1, 1.0); |
| + } |
| + } else if (ks == XK_Prior || ks == XK_KP_Prior) { |
| + if (shift_down && ks == XK_Prior) { |
| + x11vnc_appshare("taller"); |
| + } else { |
| + scroll_desktop(0, +1, 1.0); |
| + } |
| + } else if (ks == XK_End || ks == XK_KP_End) { |
| + if (shift_down && ks == XK_End) { |
| + x11vnc_appshare("narrower"); |
| + } else { |
| + scroll_desktop(+1, 0, 1.0); |
| + } |
| + } else if (ks == XK_Home || ks == XK_KP_Home) { |
| + if (shift_down && ks == XK_Home) { |
| + x11vnc_appshare("wider"); |
| + } else { |
| + scroll_desktop(-1, 0, 1.0); |
| + } |
| + } else if (ks == XK_equal || ks == XK_plus) { |
| + if (shift_down) { |
| + x11vnc_appshare("raise"); |
| + } else { |
| + scale_desktop(1, 0.1); |
| + } |
| + } else if (ks == XK_underscore || ks == XK_minus) { |
| + if (shift_down) { |
| + x11vnc_appshare("lower"); |
| + } else { |
| + scale_desktop(0, 0.1); |
| + } |
| + } else { |
| + did = 0; |
| + } |
| + if (did) { |
| + last_key = dnow(); |
| + } |
| + } |
| + if (escape_drag_in_progress) { |
| + last_drag = dnow(); |
| + } |
| + return; |
| + } |
| + if (appData.viewOnly) { |
| + return; |
| + } |
| + |
| + if (*num_params != 0) { |
| + if (strncasecmp(params[0],"key",3) == 0) { |
| + if (*num_params != 2) { |
| + fprintf(stderr, "Invalid params: " |
| + "SendRFBEvent(key|keydown|keyup,<keysym>)\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,<buttonMask>)\n"); |
| + return; |
| + } |
| + buttonMask = atoi(params[1]); |
| + SendPointerEvent(x, y, buttonMask); |
| + } else { |
| + fprintf(stderr, "Invalid params: " |
| + "SendRFBEvent(ptr,<x>,<y>,<buttonMask>)\n" |
| + " or SendRFBEvent(ptr,<buttonMask>)\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,<keysym>)\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,<buttonMask>)\n"); |
| - return; |
| - } |
| - buttonMask = atoi(params[1]); |
| - SendPointerEvent(x, y, buttonMask); |
| - } else { |
| - fprintf(stderr, |
| - "Invalid params: SendRFBEvent(ptr,<x>,<y>,<buttonMask>)\n" |
| - " or SendRFBEvent(ptr,<buttonMask>)\n"); |
| - return; |
| - } |
| - |
| - } else { |
| - fprintf(stderr,"Invalid event '%s' passed to SendRFBEvent\n", params[0]); |
| - } |
| - return; |
| - } |
| - |
| - switch (ev->type) { |
| + XLookupString(&ev->xkey, keyname, 256, &ks, NULL); |
| |
| - case MotionNotify: |
| - while (XCheckTypedWindowEvent(dpy, desktopWin, MotionNotify, ev)) |
| - ; /* discard all queued motion notify events */ |
| - |
| - SendPointerEvent(ev->xmotion.x, ev->xmotion.y, |
| - (ev->xmotion.state & 0x1f00) >> 8); |
| - return; |
| - |
| - case ButtonPress: |
| - SendPointerEvent(ev->xbutton.x, ev->xbutton.y, |
| - (((ev->xbutton.state & 0x1f00) >> 8) | |
| - (1 << (ev->xbutton.button - 1)))); |
| - return; |
| - |
| - case ButtonRelease: |
| - SendPointerEvent(ev->xbutton.x, ev->xbutton.y, |
| - (((ev->xbutton.state & 0x1f00) >> 8) & |
| - ~(1 << (ev->xbutton.button - 1)))); |
| - return; |
| - |
| - case KeyPress: |
| - case KeyRelease: |
| - XLookupString(&ev->xkey, keyname, 256, &ks, NULL); |
| - |
| - if (IsModifierKey(ks)) { |
| - ks = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0); |
| - modifierPressed[ev->xkey.keycode] = (ev->type == KeyPress); |
| - } |
| + if (IsModifierKey(ks)) { |
| + ks = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0); |
| + modifierPressed[ev->xkey.keycode] = (ev->type == KeyPress); |
| + } |
| |
| - SendKeyEvent(ks, (ev->type == KeyPress)); |
| - return; |
| + SendKeyEvent(ks, (ev->type == KeyPress)); |
| + return; |
| |
| - default: |
| - fprintf(stderr,"Invalid event passed to SendRFBEvent\n"); |
| - } |
| + default: |
| + fprintf(stderr,"Invalid event passed to SendRFBEvent\n"); |
| + } |
| } |
| |
| |
| @@ -329,68 +2496,255 @@ |
| * CreateDotCursor. |
| */ |
| |
| +#ifndef very_small_dot_cursor |
| static Cursor |
| -CreateDotCursor() |
| +CreateDotCursor(int which) |
| { |
| - 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 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; |
| + return cursor; |
| } |
| +#else |
| +static Cursor |
| +CreateDotCursor() |
| +{ |
| + Cursor cursor; |
| + Pixmap src, msk; |
| + static char srcBits[] = { 0, 14, 0 }; |
| + static char mskBits[] = { 14,31,14 }; |
| + XColor fg, bg; |
| + |
| + src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits, 3, 3); |
| + msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits, 3, 3); |
| + XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "black", |
| + &fg, &fg); |
| + XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "white", |
| + &bg, &bg); |
| + cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 1, 1); |
| + XFreePixmap(dpy, src); |
| + XFreePixmap(dpy, msk); |
| |
| + return cursor; |
| +} |
| +#endif |
| |
| +int skip_maybe_sync = 0; |
| +void maybe_sync(int width, int height) { |
| + static int singles = 0, always_skip = -1; |
| + int singles_max = 64; |
| + |
| + if (always_skip < 0) { |
| + if (getenv("SSVNC_NO_MAYBE_SYNC")) { |
| + always_skip = 1; |
| + } else { |
| + always_skip = 0; |
| + } |
| + } |
| + if (skip_maybe_sync || always_skip) { |
| + return; |
| + } |
| +#if 0 |
| + if (width > 1 || height > 1) { |
| + XSync(dpy, False); |
| + singles = 0; |
| + } else { |
| + if (++singles >= singles_max) { |
| + singles = 0; |
| + XSync(dpy, False); |
| + } |
| + } |
| +#else |
| + if (width * height >= singles_max) { |
| + XSync(dpy, False); |
| + singles = 0; |
| + } else { |
| + singles += width * height; |
| + if (singles >= singles_max) { |
| + XSync(dpy, False); |
| + singles = 0; |
| + } |
| + } |
| +#endif |
| +} |
| /* |
| - * CopyDataToScreen. |
| + * FillImage. |
| */ |
| |
| void |
| -CopyDataToScreen(char *buf, int x, int y, int width, int height) |
| +FillScreen(int x, int y, int width, int height, unsigned long fill) |
| { |
| - if (appData.rawDelay != 0) { |
| - XFillRectangle(dpy, desktopWin, gc, x, y, width, height); |
| + 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; |
| |
| - XSync(dpy,False); |
| +#if 0 |
| +fprintf(stderr, "FillImage bpp=%d %04dx%04d+%04d+%04d -- 0x%x\n", bpp, width, height, x, y, fill); |
| +#endif |
| + if (appData.chatOnly) { |
| + return; |
| + } |
| |
| - usleep(appData.rawDelay * 1000); |
| - } |
| + 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; |
| + } |
| |
| - 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); |
| - } |
| + 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; |
| + } |
| + } |
| |
| -#ifdef MITSHM |
| - if (appData.useShm) { |
| - XShmPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height, False); |
| - return; |
| - } |
| + 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; |
| + |
| +#if 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); |
| #endif |
| - XPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height); |
| + 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; |
| + } |
| +} |
| + |
| + |
| +/* |
| + * CopyDataToScreen. |
| + */ |
| + |
| +void |
| +CopyDataToScreen(char *buf, int x, int y, int width, int height) |
| +{ |
| + 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) { |
| + 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; |
| + char *scr; |
| + XImage *im = image_scale ? image_scale : image; |
| + |
| + if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line; |
| + |
| + scr = (im->data + y * scrWidthInBytes |
| + + x * myFormat.bitsPerPixel / 8); |
| + |
| + for (h = 0; h < height; h++) { |
| + memcpy(scr, buf, widthInBytes); |
| + buf += widthInBytes; |
| + scr += scrWidthInBytes; |
| + } |
| + } |
| + |
| + put_image(x, y, x, y, width, height, 0); |
| + maybe_sync(width, height); |
| } |
| |
| |
| @@ -401,62 +2755,338 @@ |
| static void |
| CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width, int height) |
| { |
| - int p, q; |
| - int xoff = 7 - (x & 7); |
| - int xcur; |
| - int fbwb = si.framebufferWidth / 8; |
| - CARD8 *scr1 = ((CARD8 *)image->data) + y * fbwb + x / 8; |
| - CARD8 *scrt; |
| - CARD8 *scr8 = ((CARD8 *)image->data) + y * si.framebufferWidth + x; |
| - CARD16 *scr16 = ((CARD16 *)image->data) + y * si.framebufferWidth + x; |
| - CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x; |
| + XImage *im = image_scale ? image_scale : image; |
| + int p, q; |
| + int xoff = 7 - (x & 7); |
| + int xcur; |
| + int fbwb = si.framebufferWidth / 8; |
| + int src_width8 = im->bytes_per_line/1; |
| + int src_width16 = im->bytes_per_line/2; |
| + int src_width32 = im->bytes_per_line/4; |
| + CARD8 *src1 = ((CARD8 *)im->data) + y * fbwb + x / 8; |
| + CARD8 *srct; |
| + CARD8 *src8 = ( (CARD8 *)im->data) + y * src_width8 + x; |
| + CARD16 *src16 = ((CARD16 *)im->data) + y * src_width16 + x; |
| + CARD32 *src32 = ((CARD32 *)im->data) + y * src_width32 + x; |
| + int b0, b1, b2; |
| |
| - switch (visbpp) { |
| + switch (visbpp) { |
| |
| /* thanks to Chris Hooper for single bpp support */ |
| |
| - case 1: |
| - for (q = 0; q < height; q++) { |
| - xcur = xoff; |
| - scrt = scr1; |
| - for (p = 0; p < width; p++) { |
| - *scrt = ((*scrt & ~(1 << xcur)) |
| - | (BGR233ToPixel[*(buf++)] << xcur)); |
| - |
| - if (xcur-- == 0) { |
| - xcur = 7; |
| - scrt++; |
| - } |
| - } |
| - scr1 += fbwb; |
| - } |
| - break; |
| - |
| - case 8: |
| - for (q = 0; q < height; q++) { |
| - for (p = 0; p < width; p++) { |
| - *(scr8++) = BGR233ToPixel[*(buf++)]; |
| - } |
| - scr8 += si.framebufferWidth - width; |
| - } |
| - break; |
| - |
| - case 16: |
| - for (q = 0; q < height; q++) { |
| - for (p = 0; p < width; p++) { |
| - *(scr16++) = BGR233ToPixel[*(buf++)]; |
| - } |
| - scr16 += si.framebufferWidth - width; |
| - } |
| - break; |
| - |
| - case 32: |
| - for (q = 0; q < height; q++) { |
| - for (p = 0; p < width; p++) { |
| - *(scr32++) = BGR233ToPixel[*(buf++)]; |
| - } |
| - scr32 += si.framebufferWidth - width; |
| - } |
| - break; |
| - } |
| + case 1: |
| + for (q = 0; q < height; q++) { |
| + xcur = xoff; |
| + srct = src1; |
| + for (p = 0; p < width; p++) { |
| + *srct = ((*srct & ~(1 << xcur)) |
| + | (BGR233ToPixel[*(buf++)] << xcur)); |
| + |
| + if (xcur-- == 0) { |
| + xcur = 7; |
| + srct++; |
| + } |
| + } |
| + src1 += fbwb; |
| + } |
| + break; |
| + |
| + case 8: |
| + for (q = 0; q < height; q++) { |
| + for (p = 0; p < width; p++) { |
| + *(src8++) = BGR233ToPixel[*(buf++)]; |
| + } |
| + src8 += src_width8 - width; |
| + } |
| + break; |
| + |
| + case 16: |
| + for (q = 0; q < height; q++) { |
| + for (p = 0; p < width; p++) { |
| + *(src16++) = BGR233ToPixel[*(buf++)]; |
| + } |
| + src16 += src_width16 - width; |
| + } |
| + break; |
| + |
| + case 24: |
| + if (isLSB) { |
| + b0 = 0; b1 = 1; b2 = 2; |
| + } else { |
| + b0 = 2; b1 = 1; b2 = 0; |
| + } |
| + src8 = ((CARD8 *)im->data) + (y * si.framebufferWidth + x) * 3; |
| + for (q = 0; q < height; q++) { |
| + for (p = 0; p < width; p++) { |
| + CARD32 v = BGR233ToPixel[*(buf++)]; |
| + *(src8 + b0) = (unsigned char) ((v & 0x0000ff) >> 0); |
| + *(src8 + b1) = (unsigned char) ((v & 0x00ff00) >> 8); |
| + *(src8 + b2) = (unsigned char) ((v & 0xff0000) >> 16); |
| + src8 += 3; |
| + } |
| + src8 += (si.framebufferWidth - width) * 3; |
| + } |
| + break; |
| + |
| + case 32: |
| + for (q = 0; q < height; q++) { |
| + for (p = 0; p < width; p++) { |
| + *(src32++) = BGR233ToPixel[*(buf++)]; |
| + } |
| + src32 += src_width32 - width; |
| + } |
| + break; |
| + } |
| +} |
| + |
| +static void |
| +BGR565_24bpp(CARD16 *buf, int x, int y, int width, int height) |
| +{ |
| + int p, q; |
| + int b0, b1, b2; |
| + XImage *im = image_scale ? image_scale : image; |
| + unsigned char *src= (unsigned char *)im->data + (y * si.framebufferWidth + x) * 3; |
| + |
| + if (isLSB) { |
| + b0 = 0; b1 = 1; b2 = 2; |
| + } else { |
| + b0 = 2; b1 = 1; b2 = 0; |
| + } |
| + |
| + /* case 24: */ |
| + for (q = 0; q < height; q++) { |
| + for (p = 0; p < width; p++) { |
| + CARD32 v = BGR565ToPixel[*(buf++)]; |
| + *(src + b0) = (unsigned char) ((v & 0x0000ff) >> 0); |
| + *(src + b1) = (unsigned char) ((v & 0x00ff00) >> 8); |
| + *(src + b2) = (unsigned char) ((v & 0xff0000) >> 16); |
| + src += 3; |
| + } |
| + src += (si.framebufferWidth - width) * 3; |
| + } |
| +} |
| + |
| +static void |
| +CopyBGR565ToScreen(CARD16 *buf, int x, int y, int width, int height) |
| +{ |
| + int p, q; |
| + XImage *im = image_scale ? image_scale : image; |
| + int src_width32 = im->bytes_per_line/4; |
| + CARD32 *src32 = ((CARD32 *)im->data) + y * src_width32 + x; |
| + |
| + if (visbpp == 24) { |
| + BGR565_24bpp(buf, x, y, width, height); |
| + return; |
| + } |
| + |
| + /* case 32: */ |
| + for (q = 0; q < height; q++) { |
| + for (p = 0; p < width; p++) { |
| + *(src32++) = BGR565ToPixel[*(buf++)]; |
| + } |
| + src32 += src_width32 - width; |
| + } |
| +} |
| + |
| +static void reset_image(void) { |
| + if (UsingShm()) { |
| + ShmDetach(); |
| + } |
| + if (image && image->data) { |
| + XDestroyImage(image); |
| + fprintf(stderr, "reset_image: destroyed 'image'\n"); |
| + } |
| + image = NULL; |
| + if (image_ycrop && image_ycrop->data) { |
| + XDestroyImage(image_ycrop); |
| + fprintf(stderr, "reset_image: destroyed 'image_ycrop'\n"); |
| + } |
| + image_ycrop = NULL; |
| + if (image_scale && image_scale->data) { |
| + XDestroyImage(image_scale); |
| + fprintf(stderr, "reset_image: destroyed 'image_scale'\n"); |
| + } |
| + image_scale = NULL; |
| + |
| + if (UsingShm()) { |
| + ShmCleanup(); |
| + } |
| + create_image(); |
| + XFlush(dpy); |
| +} |
| + |
| +void ReDoDesktop(void) { |
| + int w, w0, h, h0, x, y, dw, dh; |
| + int fs = 0; |
| + int autoscale = 0; |
| + Position x_orig, y_orig; |
| + Dimension w_orig, h_orig; |
| + |
| + if (!appData.fullScreen && appData.scale != NULL && !strcmp(appData.scale, "auto")) { |
| + autoscale = 1; |
| + } |
| + |
| + fprintf(stderr, "ReDoDesktop: ycrop: %d\n", appData.yCrop); |
| + |
| + XtVaGetValues(toplevel, XtNx, &x_orig, XtNy, &y_orig, NULL); |
| + XtVaGetValues(toplevel, XtNheight, &h_orig, XtNwidth, &w_orig, NULL); |
| + |
| + check_tall(); |
| + |
| + if (appData.yCrop) { |
| + if (appData.yCrop < 0 || old_width <= 0) { |
| + appData.yCrop = guessCrop(); |
| + fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop); |
| + } else { |
| + int w1 = si.framebufferWidth; |
| + appData.yCrop = (w1 * appData.yCrop) / old_width; |
| + if (appData.yCrop <= 100) { |
| + appData.yCrop = guessCrop(); |
| + fprintf(stderr, "Set small -ycrop to: %d\n", appData.yCrop); |
| + } |
| + } |
| + fprintf(stderr, "Using -ycrop: %d\n", appData.yCrop); |
| + } |
| + |
| + old_width = si.framebufferWidth; |
| + old_height = si.framebufferHeight; |
| + |
| + if (appData.fullScreen) { |
| + if (prev_fb_width != si.framebufferWidth || prev_fb_height != si.framebufferHeight) { |
| + int xmax = si.framebufferWidth; |
| + int ymax = si.framebufferHeight; |
| + if (appData.yCrop > 0) { |
| + ymax = appData.yCrop; |
| + } |
| + if (scale_x > 0) { |
| + xmax = scale_round(xmax, scale_factor_x); |
| + ymax = scale_round(ymax, scale_factor_y); |
| + } |
| + if (xmax < dpyWidth || ymax < dpyHeight) { |
| + FullScreenOff(); |
| + fs = 1; |
| + } |
| + } |
| + } |
| + |
| + prev_fb_width = si.framebufferWidth; |
| + prev_fb_height = si.framebufferHeight; |
| + |
| + if (appData.fullScreen) { |
| + |
| + int xmax = si.framebufferWidth; |
| + int ymax = si.framebufferHeight; |
| + if (scale_x > 0) { |
| + xmax = scale_round(xmax, scale_factor_x); |
| + ymax = scale_round(ymax, scale_factor_y); |
| + } |
| + |
| + if (image && image->data) { |
| + int len; |
| + int h = image->height; |
| + int w = image->width; |
| + len = image->bytes_per_line * image->height; |
| + /* black out window first: */ |
| + memset(image->data, 0, len); |
| + XPutImage(dpy, XtWindow(desktop), gc, image, 0, 0, 0, 0, w, h); |
| + XFlush(dpy); |
| + } |
| + |
| + /* XXX scaling?? */ |
| + XtResizeWidget(desktop, xmax, ymax, 0); |
| + |
| + XSync(dpy, False); |
| + usleep(100*1000); |
| + FullScreenOn(); |
| + XSync(dpy, False); |
| + usleep(100*1000); |
| + reset_image(); |
| + return; |
| + } |
| + |
| + dw = appData.wmDecorationWidth; |
| + dh = appData.wmDecorationHeight; |
| + |
| + w = si.framebufferWidth; |
| + h = si.framebufferHeight; |
| + w0 = w; |
| + h0 = h; |
| + if (appData.yCrop > 0) { |
| + h = appData.yCrop; |
| + } |
| + if (image_scale) { |
| + w = scale_round(w, scale_factor_x); |
| + h = scale_round(h, scale_factor_y); |
| + w0 = scale_round(w0, scale_factor_x); |
| + h0 = scale_round(h0, scale_factor_y); |
| + } |
| + |
| + if (w + dw >= dpyWidth) { |
| + w = dpyWidth - dw; |
| + } |
| + if (h + dh >= dpyHeight) { |
| + h = dpyHeight - dh; |
| + } |
| + |
| + if (!autoscale) { |
| + XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL); |
| + } else { |
| + XtVaSetValues(toplevel, XtNmaxWidth, dpyWidth, XtNmaxHeight, dpyHeight, NULL); |
| + } |
| + |
| + XtVaSetValues(desktop, XtNwidth, w0, XtNheight, h0, NULL); |
| + |
| + XtResizeWidget(desktop, w0, h0, 0); |
| + |
| + if (appData.yCrop > 0) { |
| + int ycrop = appData.yCrop; |
| + if (image_scale) { |
| + ycrop *= scale_factor_y; |
| + } |
| + XtVaSetValues(toplevel, XtNmaxHeight, ycrop, NULL); |
| + XtVaSetValues(form, XtNmaxHeight, ycrop, NULL); |
| + } |
| + |
| + x = (dpyWidth - w - dw)/2; |
| + y = (dpyHeight - h - dh)/2; |
| + |
| + if (!autoscale) { |
| + |
| + if (!getenv("VNCVIEWER_ALWAYS_RECENTER")) { |
| + int x_cm_old, y_cm_old; |
| + int x_cm_new, y_cm_new; |
| + int x_try, y_try; |
| + |
| + x_cm_old = (int) x_orig + ((int) w_orig)/2; |
| + y_cm_old = (int) y_orig + ((int) h_orig)/2; |
| + |
| + x_cm_new = dpyWidth/2; |
| + y_cm_new = dpyHeight/2; |
| + |
| + x_try = x + (x_cm_old - x_cm_new); |
| + y_try = y + (y_cm_old - y_cm_new); |
| + if (x_try < 0) { |
| + x_try = 0; |
| + } |
| + if (y_try < 0) { |
| + y_try = 0; |
| + } |
| + if (x_try + w + dw > dpyWidth) { |
| + x_try = dpyWidth - w - dw; |
| + } |
| + if (y_try + h + dh > dpyHeight) { |
| + y_try = dpyHeight - h - dh; |
| + } |
| + x = x_try; |
| + y = y_try; |
| + } |
| + |
| + XtConfigureWidget(toplevel, x + dw, y + dh, w, h, 0); |
| + } |
| + |
| + reset_image(); |
| + |
| + if (fs) { |
| + FullScreenOn(); |
| + } |
| } |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/dialogs.c vnc_unixsrc/vncviewer/dialogs.c |
| --- vnc_unixsrc.orig/vncviewer/dialogs.c 2000-10-26 15:19:19.000000000 -0400 |
| +++ vnc_unixsrc/vncviewer/dialogs.c 2010-02-25 22:33:06.000000000 -0500 |
| @@ -25,75 +25,564 @@ |
| #include <X11/Xaw/Dialog.h> |
| |
| static Bool serverDialogDone = False; |
| +static Bool userDialogDone = False; |
| static Bool passwordDialogDone = False; |
| +static Bool ycropDialogDone = False; |
| +static Bool scaleDialogDone = False; |
| +static Bool escapeDialogDone = False; |
| +static Bool scbarDialogDone = False; |
| +static Bool scaleNDialogDone = False; |
| +static Bool qualityDialogDone = False; |
| +static Bool compressDialogDone = False; |
| + |
| +extern void popupFixer(Widget wid); |
| + |
| +int use_tty(void) { |
| + if (appData.notty) { |
| + return 0; |
| + } else if (!isatty(0)) { |
| + return 0; |
| + } |
| + return 1; |
| +} |
| + |
| +void |
| +ScaleDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + scaleDialogDone = True; |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +void |
| +EscapeDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + escapeDialogDone = True; |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +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, "<Message>WM_PROTOCOLS: %s", func); |
| + XtOverrideTranslations(w, XtParseTranslationTable (str)); |
| + } |
| +} |
| + |
| +static void xtmove(Widget w) { |
| + XtMoveWidget(w, WidthOfScreen(XtScreen(w))*2/5, HeightOfScreen(XtScreen(w))*2/5); |
| +} |
| + |
| +char * |
| +DoScaleDialog() |
| +{ |
| + Widget pshell, dialog; |
| + char *scaleValue; |
| + char *valueString; |
| + |
| + pshell = XtVaCreatePopupShell("scaleDialog", transientShellWidgetClass, |
| + toplevel, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + |
| + dialog_over(pshell); |
| + |
| + if (0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (appData.scale != NULL) { |
| + String label; |
| + char tmp[410]; |
| + XtVaGetValues(dialog, XtNlabel, &label, NULL); |
| + if (strlen(label) + strlen(appData.scale) < 400) { |
| + sprintf(tmp, "%s %s", label, appData.scale); |
| + XtVaSetValues(dialog, XtNlabel, tmp, NULL); |
| + } |
| + } |
| + |
| + |
| + if (1 && appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| + dialog_input(pshell); |
| + wm_delete(pshell, "ScaleDialogDone()"); |
| + |
| + scaleDialogDone = False; |
| + |
| + while (!scaleDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + scaleValue = XtNewString(valueString); |
| + |
| + XtPopdown(pshell); |
| + return scaleValue; |
| +} |
| + |
| +char * |
| +DoEscapeKeysDialog() |
| +{ |
| + Widget pshell, dialog; |
| + char *escapeValue; |
| + char *valueString; |
| + char *curr = appData.escapeKeys ? appData.escapeKeys : "default"; |
| + |
| + pshell = XtVaCreatePopupShell("escapeDialog", transientShellWidgetClass, |
| + toplevel, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + |
| + dialog_over(pshell); |
| + |
| + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (curr != NULL) { |
| + String label; |
| + char tmp[3010]; |
| + XtVaGetValues(dialog, XtNlabel, &label, NULL); |
| + if (strlen(label) + strlen(curr) < 3000) { |
| + sprintf(tmp, "%s %s", label, curr); |
| + XtVaSetValues(dialog, XtNlabel, tmp, NULL); |
| + } |
| + } |
| + |
| + if (appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + /* too big */ |
| + if (0) xtmove(pshell); |
| + } |
| + dialog_input(pshell); |
| + wm_delete(pshell, "EscapeDialogDone()"); |
| + |
| + escapeDialogDone = False; |
| + |
| + while (!escapeDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + escapeValue = XtNewString(valueString); |
| + |
| + XtPopdown(pshell); |
| + return escapeValue; |
| +} |
| + |
| +void |
| +YCropDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + ycropDialogDone = True; |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +char * |
| +DoYCropDialog() |
| +{ |
| + Widget pshell, dialog; |
| + char *ycropValue; |
| + char *valueString; |
| + |
| + pshell = XtVaCreatePopupShell("ycropDialog", transientShellWidgetClass, |
| + toplevel, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + |
| + dialog_over(pshell); |
| + |
| + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (1 && appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| + dialog_input(pshell); |
| + wm_delete(pshell, "YCropDialogDone()"); |
| + |
| + ycropDialogDone = False; |
| + |
| + while (!ycropDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + ycropValue = XtNewString(valueString); |
| + |
| + XtPopdown(pshell); |
| + return ycropValue; |
| +} |
| + |
| +void |
| +ScbarDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + scbarDialogDone = True; |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +char * |
| +DoScbarDialog() |
| +{ |
| + Widget pshell, dialog; |
| + char *scbarValue; |
| + char *valueString; |
| + |
| + pshell = XtVaCreatePopupShell("scbarDialog", transientShellWidgetClass, |
| + toplevel, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + |
| + dialog_over(pshell); |
| + |
| + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (1 && appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| + dialog_input(pshell); |
| + wm_delete(pshell, "ScbarDialogDone()"); |
| + |
| + scbarDialogDone = False; |
| + |
| + while (!scbarDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + scbarValue = XtNewString(valueString); |
| + |
| + XtPopdown(pshell); |
| + return scbarValue; |
| +} |
| + |
| +void |
| +ScaleNDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + scaleNDialogDone = True; |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +char * |
| +DoScaleNDialog() |
| +{ |
| + Widget pshell, dialog; |
| + char *scaleNValue; |
| + char *valueString; |
| + |
| + pshell = XtVaCreatePopupShell("scaleNDialog", transientShellWidgetClass, |
| + toplevel, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + |
| + dialog_over(pshell); |
| + wm_delete(pshell, "ScaleNDialogDone()"); |
| + |
| + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| + dialog_input(pshell); |
| + wm_delete(pshell, "ScaleNDialogDone()"); |
| + |
| + scaleNDialogDone = False; |
| + |
| + while (!scaleNDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + scaleNValue = XtNewString(valueString); |
| + |
| + XtPopdown(pshell); |
| + return scaleNValue; |
| +} |
| + |
| +void |
| +QualityDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + qualityDialogDone = True; |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +char * |
| +DoQualityDialog() |
| +{ |
| + Widget pshell, dialog; |
| + char *qualityValue; |
| + char *valueString; |
| + |
| + pshell = XtVaCreatePopupShell("qualityDialog", transientShellWidgetClass, |
| + toplevel, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + |
| + dialog_over(pshell); |
| + |
| + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (1 && appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| + dialog_input(pshell); |
| + wm_delete(pshell, "QualityDialogDone() HideQuality()"); |
| + |
| + qualityDialogDone = False; |
| + |
| + while (!qualityDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + qualityValue = XtNewString(valueString); |
| + |
| + XtPopdown(pshell); |
| + return qualityValue; |
| +} |
| + |
| +void |
| +CompressDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + compressDialogDone = True; |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +char * |
| +DoCompressDialog() |
| +{ |
| + Widget pshell, dialog; |
| + char *compressValue; |
| + char *valueString; |
| + |
| + fprintf(stderr, "compress start:\n"); |
| + |
| + pshell = XtVaCreatePopupShell("compressDialog", transientShellWidgetClass, |
| + toplevel, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + |
| + dialog_over(pshell); |
| + |
| + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (1 && appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| + dialog_input(pshell); |
| + wm_delete(pshell, "CompressDialogDone() HideCompress()"); |
| + |
| + compressDialogDone = False; |
| + |
| + while (!compressDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + compressValue = XtNewString(valueString); |
| + |
| + fprintf(stderr, "compress done: %s\n", compressValue); |
| + |
| + XtPopdown(pshell); |
| + return compressValue; |
| +} |
| |
| void |
| ServerDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| { |
| - serverDialogDone = True; |
| + serverDialogDone = True; |
| + if (w || event || params || num_params) {} |
| } |
| |
| char * |
| DoServerDialog() |
| { |
| - Widget pshell, dialog; |
| - char *vncServerName; |
| - char *valueString; |
| + Widget pshell, dialog; |
| + char *vncServerName; |
| + char *valueString; |
| |
| - pshell = XtVaCreatePopupShell("serverDialog", transientShellWidgetClass, |
| + pshell = XtVaCreatePopupShell("serverDialog", transientShellWidgetClass, |
| toplevel, NULL); |
| - dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| |
| - XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, |
| - HeightOfScreen(XtScreen(pshell))*2/5); |
| - XtPopup(pshell, XtGrabNonexclusive); |
| - XtRealizeWidget(pshell); |
| + dialog_over(pshell); |
| |
| - serverDialogDone = False; |
| + if (0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (0 && appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| +#if 0 |
| + dialog_input(pshell); |
| +#endif |
| + wm_delete(pshell, "ServerDialogDone()"); |
| + |
| + serverDialogDone = False; |
| + |
| + while (!serverDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + vncServerName = XtNewString(valueString); |
| |
| - while (!serverDialogDone) { |
| - XtAppProcessEvent(appContext, XtIMAll); |
| - } |
| + XtPopdown(pshell); |
| + return vncServerName; |
| +} |
| |
| - valueString = XawDialogGetValueString(dialog); |
| - vncServerName = XtNewString(valueString); |
| +void |
| +UserDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + userDialogDone = True; |
| + if (w || event || params || num_params) {} |
| +} |
| |
| - XtPopdown(pshell); |
| - return vncServerName; |
| +char * |
| +DoUserDialog() |
| +{ |
| + Widget pshell, dialog; |
| + char *userName; |
| + char *valueString; |
| + |
| + pshell = XtVaCreatePopupShell("userDialog", transientShellWidgetClass, |
| + toplevel, NULL); |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| + |
| + dialog_over(pshell); |
| + |
| + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (0 && appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| +#if 0 |
| + dialog_input(pshell); |
| +#endif |
| + wm_delete(pshell, "UserDialogDone()"); |
| + |
| + userDialogDone = False; |
| + |
| + while (!userDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + userName = XtNewString(valueString); |
| + |
| + XtPopdown(pshell); |
| + return userName; |
| } |
| |
| void |
| -PasswordDialogDone(Widget w, XEvent *event, String *params, |
| - Cardinal *num_params) |
| +PasswordDialogDone(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| { |
| - passwordDialogDone = True; |
| + passwordDialogDone = True; |
| + if (w || event || params || num_params) {} |
| } |
| |
| char * |
| DoPasswordDialog() |
| { |
| - Widget pshell, dialog; |
| - char *password; |
| - char *valueString; |
| + Widget pshell, dialog; |
| + char *password; |
| + char *valueString; |
| |
| - pshell = XtVaCreatePopupShell("passwordDialog", transientShellWidgetClass, |
| + pshell = XtVaCreatePopupShell("passwordDialog", transientShellWidgetClass, |
| toplevel, NULL); |
| - dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| - |
| - XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, |
| - HeightOfScreen(XtScreen(pshell))*2/5); |
| - XtPopup(pshell, XtGrabNonexclusive); |
| - XtRealizeWidget(pshell); |
| - |
| - passwordDialogDone = False; |
| + dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass, pshell, NULL); |
| |
| - while (!passwordDialogDone) { |
| - XtAppProcessEvent(appContext, XtIMAll); |
| - } |
| + dialog_over(pshell); |
| |
| - valueString = XawDialogGetValueString(dialog); |
| - password = XtNewString(valueString); |
| + if(0) XtMoveWidget(pshell, WidthOfScreen(XtScreen(pshell))*2/5, HeightOfScreen(XtScreen(pshell))*2/5); |
| + XtPopup(pshell, XtGrabNonexclusive); |
| + XtRealizeWidget(pshell); |
| + |
| + if (0 && appData.popupFix) { |
| + popupFixer(pshell); |
| + } else { |
| + xtmove(pshell); |
| + } |
| +#if 0 |
| + dialog_input(pshell); |
| +#endif |
| + wm_delete(pshell, "PasswordDialogDone()"); |
| + |
| + passwordDialogDone = False; |
| + |
| + while (!passwordDialogDone) { |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + |
| + valueString = XawDialogGetValueString(dialog); |
| + rmNL(valueString); |
| + password = XtNewString(valueString); |
| |
| - XtPopdown(pshell); |
| - return password; |
| + XtPopdown(pshell); |
| + return password; |
| } |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/fullscreen.c vnc_unixsrc/vncviewer/fullscreen.c |
| --- vnc_unixsrc.orig/vncviewer/fullscreen.c 2003-10-09 05:23:49.000000000 -0400 |
| +++ vnc_unixsrc/vncviewer/fullscreen.c 2010-02-25 22:37:49.000000000 -0500 |
| @@ -22,20 +22,24 @@ |
| */ |
| |
| #include <vncviewer.h> |
| +#include <time.h> |
| #include <X11/Xaw/Form.h> |
| #include <X11/Xaw/Viewport.h> |
| #include <X11/Xaw/Toggle.h> |
| |
| 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 +82,456 @@ |
| * 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; |
| +#if 0 |
| + int _NET_WM_STATE_TOGGLE = 2; |
| +#endif |
| + 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); |
| +#if 0 |
| + XtVaSetValues(viewport, XtNoverrideRedirect, True, NULL); |
| + XtVaSetValues(desktop, XtNoverrideRedirect, True, NULL); |
| +#endif |
| + 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. */ |
| + |
| +#if 0 |
| + XtVaSetValues(toplevel, XtNwidth, toplevelWidth, XtNheight, toplevelHeight, NULL); |
| + XtResizeWidget(toplevel, toplevelWidth, toplevelHeight, 0); |
| +#endif |
| + 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 +553,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 +607,42 @@ |
| 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); |
| +#if 0 |
| + XtVaSetValues(viewport, XtNoverrideRedirect, False, NULL); |
| + XtVaSetValues(desktop, XtNoverrideRedirect, False, NULL); |
| +#endif |
| + 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 +654,12 @@ |
| 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); |
| + } |
| + if (w || ev || params || num_params) {} |
| } |
| |
| |
| @@ -278,11 +670,12 @@ |
| void |
| ToggleFullScreen(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| { |
| - if (appData.fullScreen) { |
| - FullScreenOff(); |
| - } else { |
| - FullScreenOn(); |
| - } |
| + if (appData.fullScreen) { |
| + FullScreenOff(); |
| + } else { |
| + FullScreenOn(); |
| + } |
| + if (w || ev || params || num_params) {} |
| } |
| |
| |
| @@ -294,84 +687,226 @@ |
| 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(); |
| + if (clientData || id) {} |
| +} |
| + |
| +/* 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(); |
| + if (clientData || id) {} |
| +} |
| +void JumpRight(Widget w, XEvent *ev, String *params, Cardinal *num_params) { |
| + JumpScroll(1, 0); |
| + if (w || ev || params || num_params) {} |
| +} |
| +void JumpLeft(Widget w, XEvent *ev, String *params, Cardinal *num_params) { |
| + JumpScroll(0, 0); |
| + if (w || ev || params || num_params) {} |
| +} |
| +void JumpUp(Widget w, XEvent *ev, String *params, Cardinal *num_params) { |
| + JumpScroll(1, 1); |
| + if (w || ev || params || num_params) {} |
| } |
| +void JumpDown(Widget w, XEvent *ev, String *params, Cardinal *num_params) { |
| + JumpScroll(0, 1); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| + |
| 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 (<HELP>) { |
| + $_ =~ s/&/&/g; |
| + $_ =~ s/</</g; |
| + $_ =~ s/>/>/g; |
| + print; |
| +} |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/hextile.c vnc_unixsrc/vncviewer/hextile.c |
| --- vnc_unixsrc.orig/vncviewer/hextile.c 2007-02-17 22:33:46.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/hextile.c 2009-10-16 22:54:40.000000000 -0400 |
| @@ -30,6 +30,21 @@ |
| #define CARDBPP CONCAT2E(CARD,BPP) |
| #define GET_PIXEL CONCAT2E(GET_PIXEL,BPP) |
| |
| +#define FillRectangle(x, y, w, h, color) \ |
| + { \ |
| + XGCValues _gcv; \ |
| + _gcv.foreground = color; \ |
| + if (!appData.useXserverBackingStore) { \ |
| + FillScreen(x, y, w, h, _gcv.foreground); \ |
| + } else { \ |
| + XChangeGC(dpy, gc, GCForeground, &_gcv); \ |
| + XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \ |
| + } \ |
| + } |
| + |
| +extern int skip_maybe_sync; |
| +extern void maybe_sync(int w, int h); |
| + |
| static Bool |
| HandleHextileBPP (int rx, int ry, int rw, int rh) |
| { |
| @@ -41,21 +56,43 @@ |
| int sx, sy, sw, sh; |
| CARD8 subencoding; |
| CARD8 nSubrects; |
| + int irect = 0, nrects = (rw * rh) / (16 * 16); |
| + static int nosync_ycrop = -1; |
| + |
| + if (nosync_ycrop < 0) { |
| + nosync_ycrop = 0; |
| + if (getenv("HEXTILE_YCROP_TOO")) { |
| + nosync_ycrop = 1; |
| + } |
| + } |
| |
| for (y = ry; y < ry+rh; y += 16) { |
| for (x = rx; x < rx+rw; x += 16) { |
| w = h = 16; |
| - if (rx+rw - x < 16) |
| + if (rx+rw - x < 16) { |
| w = rx+rw - x; |
| - if (ry+rh - y < 16) |
| + } |
| + if (ry+rh - y < 16) { |
| h = ry+rh - y; |
| + } |
| + |
| + if (nrects > 400 && (appData.yCrop == 0 || nosync_ycrop)) { |
| + skip_maybe_sync = 0; |
| + if (irect++ % 2000 != 0) { |
| + if (x < rx+rw-16 || y < ry+rh-16) { |
| + skip_maybe_sync = 1; |
| + } |
| + } |
| + } |
| |
| - if (!ReadFromRFBServer((char *)&subencoding, 1)) |
| + if (!ReadFromRFBServer((char *)&subencoding, 1)) { |
| return False; |
| + } |
| |
| if (subencoding & rfbHextileRaw) { |
| - if (!ReadFromRFBServer(buffer, w * h * (BPP / 8))) |
| + if (!ReadFromRFBServer(buffer, w * h * (BPP / 8))) { |
| return False; |
| + } |
| |
| CopyDataToScreen(buffer, x, y, w, h); |
| continue; |
| @@ -66,14 +103,25 @@ |
| return False; |
| |
| #if (BPP == 8) |
| - if (appData.useBGR233) |
| + if (appData.useBGR233) { |
| gcv.foreground = BGR233ToPixel[bg]; |
| - else |
| + } else |
| +#endif |
| +#if (BPP == 16) |
| + if (appData.useBGR565) { |
| + gcv.foreground = BGR565ToPixel[bg]; |
| + } else |
| #endif |
| + { |
| gcv.foreground = bg; |
| + } |
| |
| - XChangeGC(dpy, gc, GCForeground, &gcv); |
| - XFillRectangle(dpy, desktopWin, gc, x, y, w, h); |
| +#if 0 |
| + XChangeGC(dpy, gc, GCForeground, &gcv); |
| + XFillRectangle(dpy, desktopWin, gc, x, y, w, h); |
| +#else |
| + FillRectangle(x, y, w, h, gcv.foreground); |
| +#endif |
| |
| if (subencoding & rfbHextileForegroundSpecified) |
| if (!ReadFromRFBServer((char *)&fg, sizeof(fg))) |
| @@ -101,14 +149,25 @@ |
| sh = rfbHextileExtractH(*ptr); |
| ptr++; |
| #if (BPP == 8) |
| - if (appData.useBGR233) |
| + if (appData.useBGR233) { |
| gcv.foreground = BGR233ToPixel[fg]; |
| - else |
| + } else |
| #endif |
| +#if (BPP == 16) |
| + if (appData.useBGR565) { |
| + gcv.foreground = BGR565ToPixel[fg]; |
| + } else |
| +#endif |
| + { |
| gcv.foreground = fg; |
| + } |
| |
| - XChangeGC(dpy, gc, GCForeground, &gcv); |
| - XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh); |
| +#if 0 |
| + XChangeGC(dpy, gc, GCForeground, &gcv); |
| + XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh); |
| +#else |
| + FillRectangle(x+sx, y+sy, sw, sh, gcv.foreground); |
| +#endif |
| } |
| |
| } else { |
| @@ -116,13 +175,22 @@ |
| return False; |
| |
| #if (BPP == 8) |
| - if (appData.useBGR233) |
| + if (appData.useBGR233) { |
| gcv.foreground = BGR233ToPixel[fg]; |
| - else |
| + } else |
| #endif |
| +#if (BPP == 16) |
| + if (appData.useBGR565) { |
| + gcv.foreground = BGR565ToPixel[fg]; |
| + } else |
| +#endif |
| + { |
| gcv.foreground = fg; |
| + } |
| |
| +#if 0 |
| XChangeGC(dpy, gc, GCForeground, &gcv); |
| +#endif |
| |
| for (i = 0; i < nSubrects; i++) { |
| sx = rfbHextileExtractX(*ptr); |
| @@ -131,7 +199,11 @@ |
| sw = rfbHextileExtractW(*ptr); |
| sh = rfbHextileExtractH(*ptr); |
| ptr++; |
| +#if 0 |
| XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh); |
| +#else |
| + FillRectangle(x+sx, y+sy, sw, sh, gcv.foreground); |
| +#endif |
| } |
| } |
| } |
| @@ -139,3 +211,5 @@ |
| |
| return True; |
| } |
| + |
| +#undef FillRectangle |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/listen.c vnc_unixsrc/vncviewer/listen.c |
| --- vnc_unixsrc.orig/vncviewer/listen.c 2001-01-16 03:07:57.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/listen.c 2010-04-11 23:14:21.000000000 -0400 |
| @@ -32,14 +32,88 @@ |
| #define FLASHDELAY 1 /* seconds */ |
| |
| Bool listenSpecified = False; |
| +pid_t listenParent = 0; |
| int listenPort = 0, flashPort = 0; |
| |
| +#if 0 |
| static Font flashFont; |
| - |
| static void getFlashFont(Display *d); |
| static void flashDisplay(Display *d, char *user); |
| +#endif |
| + |
| static Bool AllXEventsPredicate(Display *d, XEvent *ev, char *arg); |
| |
| +void raiseme(int force); |
| + |
| +static int accept_popup_check(int *argc, char **argv, char *sip, char *sih) { |
| + char line[16]; |
| + char msg[1000]; |
| + int dopopup = 1; |
| + |
| + if (!getenv("SSVNC_ACCEPT_POPUP")) { |
| + return 1; |
| + } |
| + |
| + if (!dopopup && use_tty()) { |
| + raiseme(1); |
| + fprintf(stderr, "Accept VNC connection? y/[n] "); |
| + fgets(line, sizeof(line), stdin); |
| + if (!strchr(line, 'y') && !strchr(line, 'Y')) { |
| + fprintf(stderr, "Refusing connection.\n"); |
| + return 0; |
| + } else { |
| + fprintf(stderr, "Accepting connection.\n"); |
| + return 1; |
| + } |
| + } else { |
| + int pid, pid2, accept_it = 0; |
| + |
| + pid = fork(); |
| + if (pid == -1) { |
| + perror("fork"); |
| + exit(1); |
| + } |
| + if (pid == 0) { |
| + char *geometry = "2x2+0+0"; |
| + String fb[] = { "*message.Scroll: whenNeeded", NULL}; |
| + close(rfbsock); |
| + |
| + toplevel = XtAppInitialize(&appContext, "Ssvnc", cmdLineOptions, numCmdLineOptions, |
| + argc, argv, fb, NULL, 0); |
| + XtVaSetValues(toplevel, XtNmaxWidth, 2, XtNmaxHeight, 2, NULL); |
| + XtVaSetValues(toplevel, XtNgeometry, geometry, NULL); |
| + XtRealizeWidget(toplevel); |
| + dpy = XtDisplay(toplevel); |
| + sprintf(msg, "\n(LISTEN) Reverse VNC connection from IP: %s\n Hostname: %s\n\n", sip, sih); |
| + strcat(msg, "Accept or Reject VNC connection?"); |
| + if (CreateMsg(msg, 2)) { |
| + XCloseDisplay(dpy); |
| + exit(0); |
| + } else { |
| + XCloseDisplay(dpy); |
| + exit(1); |
| + } |
| + } else { |
| + int status; |
| + pid2 = waitpid(pid, &status, 0); |
| + fprintf(stderr, "waitpid: %d/%d status: %d\n", pid, pid2, status); |
| + if (pid2 == pid) { |
| + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { |
| + accept_it = 1; |
| + } |
| + } |
| + } |
| + if (accept_it) { |
| + fprintf(stderr, "Accepting connection.\n"); |
| + return 1; |
| + } else { |
| + fprintf(stderr, "Refusing connection.\n"); |
| + return 0; |
| + } |
| + } |
| + return 0; |
| +} |
| + |
| /* |
| * listenForIncomingConnections() - listen for incoming connections from |
| * servers, and fork a new process to deal with each connection. We must do |
| @@ -47,145 +121,291 @@ |
| * cope with forking very well. |
| */ |
| |
| +extern char *accept6_hostname; |
| +extern char *accept6_ipaddr; |
| + |
| void |
| listenForIncomingConnections(int *argc, char **argv, int listenArgIndex) |
| { |
| - Display *d; |
| - XEvent ev; |
| - int listenSocket, flashSocket, sock; |
| - fd_set fds; |
| - char flashUser[256]; |
| - int n; |
| - int i; |
| - char *displayname = NULL; |
| - |
| - listenSpecified = True; |
| - |
| - for (i = 1; i < *argc; i++) { |
| - if (strcmp(argv[i], "-display") == 0 && i+1 < *argc) { |
| - displayname = argv[i+1]; |
| - } |
| - } |
| + Display *d; |
| + XEvent ev; |
| + int listenSocket, listenSocket6, flashSocket, sock; |
| + fd_set fds; |
| + char flashUser[256]; |
| + 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) { |
| + displayname = argv[i+1]; |
| + } |
| + } |
| + if (sock || flashUser || n) {} |
| |
| - if (listenArgIndex+1 < *argc && argv[listenArgIndex+1][0] >= '0' && |
| + if (listenArgIndex+1 < *argc && argv[listenArgIndex+1][0] >= '0' && |
| argv[listenArgIndex+1][0] <= '9') { |
| |
| - listenPort = LISTEN_PORT_OFFSET + atoi(argv[listenArgIndex+1]); |
| - flashPort = FLASH_PORT_OFFSET + atoi(argv[listenArgIndex+1]); |
| - removeArgs(argc, argv, listenArgIndex, 2); |
| + listenPort = LISTEN_PORT_OFFSET + atoi(argv[listenArgIndex+1]); |
| + flashPort = FLASH_PORT_OFFSET + atoi(argv[listenArgIndex+1]); |
| + removeArgs(argc, argv, listenArgIndex, 2); |
| |
| - } else { |
| + } else { |
| |
| - char *display; |
| - char *colonPos; |
| - struct utsname hostinfo; |
| + char *display; |
| + char *colonPos; |
| + struct utsname hostinfo; |
| |
| - removeArgs(argc, argv, listenArgIndex, 1); |
| + removeArgs(argc, argv, listenArgIndex, 1); |
| |
| - display = XDisplayName(displayname); |
| - colonPos = strchr(display, ':'); |
| + display = XDisplayName(displayname); |
| + colonPos = strchr(display, ':'); |
| |
| - uname(&hostinfo); |
| + uname(&hostinfo); |
| |
| - if (colonPos && ((colonPos == display) || |
| - (strncmp(hostinfo.nodename, display, |
| - strlen(hostinfo.nodename)) == 0))) { |
| + if (colonPos && ((colonPos == display) || |
| + (strncmp(hostinfo.nodename, display, |
| + strlen(hostinfo.nodename)) == 0))) { |
| |
| - listenPort = LISTEN_PORT_OFFSET + atoi(colonPos+1); |
| - flashPort = FLASH_PORT_OFFSET + atoi(colonPos+1); |
| + listenPort = LISTEN_PORT_OFFSET + atoi(colonPos+1); |
| + flashPort = FLASH_PORT_OFFSET + atoi(colonPos+1); |
| |
| - } else { |
| - fprintf(stderr,"%s: cannot work out which display number to " |
| - "listen on.\n", programName); |
| - fprintf(stderr,"Please specify explicitly with -listen <num>\n"); |
| - exit(1); |
| - } |
| - } |
| + } else { |
| + fprintf(stderr,"%s: cannot work out which display number to " |
| + "listen on.\n", programName); |
| + fprintf(stderr,"Please specify explicitly with -listen <num>\n"); |
| + exit(1); |
| + } |
| |
| - if (!(d = XOpenDisplay(displayname))) { |
| - fprintf(stderr,"%s: unable to open display %s\n", |
| - programName, XDisplayName(displayname)); |
| - exit(1); |
| - } |
| + } |
| |
| - getFlashFont(d); |
| + if (!(d = XOpenDisplay(displayname))) { |
| + fprintf(stderr,"%s: unable to open display %s\n", |
| + programName, XDisplayName(displayname)); |
| + exit(1); |
| + } |
| |
| - listenSocket = ListenAtTcpPort(listenPort); |
| - flashSocket = ListenAtTcpPort(flashPort); |
| +#if 0 |
| + getFlashFont(d); |
| +#endif |
| |
| - if ((listenSocket < 0) || (flashSocket < 0)) exit(1); |
| + listenSocket = ListenAtTcpPort(listenPort); |
| + listenSocket6 = ListenAtTcpPort6(listenPort); |
| + |
| +#if 0 |
| + flashSocket = ListenAtTcpPort(flashPort); |
| +#endif |
| + flashSocket = 1234; |
| + |
| + if (listenSocket < 0 && listenSocket6 < 0) { |
| + fprintf(stderr,"%s -listen: could not obtain a listening socket on port %d\n", |
| + programName, listenPort); |
| + 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 ipv4_fd: %d ipv6_fd: %d\n", |
| + programName, listenPort, listenSocket, listenSocket6); |
| + fprintf(stderr,"%s -listen: Cmdline errors are not reported until " |
| "a connection comes in.\n", programName); |
| |
| - while (True) { |
| + /* this will only work if X events drives this loop -- they don't */ |
| + if (getenv("SSVNC_MAX_LISTEN")) { |
| + maxconn = atoi(getenv("SSVNC_MAX_LISTEN")); |
| + } |
| |
| - /* reap any zombies */ |
| - int status, pid; |
| - while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0); |
| - |
| - /* discard any X events */ |
| - while (XCheckIfEvent(d, &ev, AllXEventsPredicate, NULL)) |
| - ; |
| - |
| - FD_ZERO(&fds); |
| - |
| - FD_SET(flashSocket, &fds); |
| - FD_SET(listenSocket, &fds); |
| - FD_SET(ConnectionNumber(d), &fds); |
| - |
| - select(FD_SETSIZE, &fds, NULL, NULL, NULL); |
| - |
| - if (FD_ISSET(flashSocket, &fds)) { |
| - |
| - sock = AcceptTcpConnection(flashSocket); |
| - if (sock < 0) exit(1); |
| - n = read(sock, flashUser, 255); |
| - if (n > 0) { |
| - flashUser[n] = 0; |
| - flashDisplay(d, flashUser); |
| - } else { |
| - flashDisplay(d, NULL); |
| - } |
| - close(sock); |
| - } |
| + while (True) { |
| + int lsock = -1; |
| |
| - if (FD_ISSET(listenSocket, &fds)) { |
| - rfbsock = AcceptTcpConnection(listenSocket); |
| - if (rfbsock < 0) exit(1); |
| - if (!SetNonBlocking(rfbsock)) exit(1); |
| + /* reap any zombies */ |
| + int status, pid; |
| + 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); |
| + } |
| + } |
| + } |
| |
| - XCloseDisplay(d); |
| + /* discard any X events */ |
| + while (XCheckIfEvent(d, &ev, AllXEventsPredicate, NULL)) { |
| + ; |
| + } |
| |
| - /* Now fork off a new process to deal with it... */ |
| + FD_ZERO(&fds); |
| |
| - switch (fork()) { |
| +#if 0 |
| + FD_SET(flashSocket, &fds); |
| +#endif |
| + if (listenSocket >= 0) { |
| + FD_SET(listenSocket, &fds); |
| + } |
| + if (listenSocket6 >= 0) { |
| + FD_SET(listenSocket6, &fds); |
| + } |
| + FD_SET(ConnectionNumber(d), &fds); |
| |
| - case -1: |
| - perror("fork"); |
| - exit(1); |
| + select(FD_SETSIZE, &fds, NULL, NULL, NULL); |
| |
| - case 0: |
| - /* child - return to caller */ |
| - close(listenSocket); |
| - close(flashSocket); |
| - return; |
| + 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); |
| + } |
| + } |
| + } |
| |
| - default: |
| - /* parent - go round and listen again */ |
| - close(rfbsock); |
| - if (!(d = XOpenDisplay(displayname))) { |
| - fprintf(stderr,"%s: unable to open display %s\n", |
| - programName, XDisplayName(displayname)); |
| - exit(1); |
| +#if 0 |
| + if (FD_ISSET(flashSocket, &fds)) { |
| + sock = AcceptTcpConnection(flashSocket); |
| + if (sock < 0) exit(1); |
| + n = read(sock, flashUser, 255); |
| + if (n > 0) { |
| + flashUser[n] = 0; |
| + flashDisplay(d, flashUser); |
| + } else { |
| + flashDisplay(d, NULL); |
| + } |
| + close(sock); |
| + } |
| +#endif |
| + |
| + lsock = -1; |
| + if (listenSocket >= 0 && FD_ISSET(listenSocket, &fds)) { |
| + lsock = listenSocket; |
| + } else if (listenSocket6 >= 0 && FD_ISSET(listenSocket6, &fds)) { |
| + lsock = listenSocket6; |
| + } |
| + |
| + if (lsock >= 0) { |
| + int multi_ok = 0; |
| + char *sml = getenv("SSVNC_MULTIPLE_LISTEN"); |
| + char *sip = NULL; |
| + char *sih = NULL; |
| + |
| + if (lsock == listenSocket) { |
| + rfbsock = AcceptTcpConnection(lsock); |
| + } else { |
| + rfbsock = AcceptTcpConnection6(lsock); |
| + } |
| + |
| + 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; |
| + } |
| + |
| + if (lsock == listenSocket) { |
| + sip = get_peer_ip(rfbsock); |
| + if (strlen(sip) > 100) sip = "0.0.0.0"; |
| + sih = ip2host(sip); |
| + if (strlen(sih) > 300) sih = "unknown"; |
| + } else { |
| + if (accept6_hostname != NULL) { |
| + sip = accept6_ipaddr; |
| + accept6_ipaddr = NULL; |
| + sih = accept6_hostname; |
| + accept6_hostname = NULL; |
| + } else { |
| + sip = "unknown"; |
| + sih = "unknown"; |
| + } |
| + } |
| + |
| + fprintf(stderr, "\n"); |
| + fprintf(stderr, "(LISTEN) Reverse VNC connection from IP: %s\n", sip); |
| + fprintf(stderr, " Hostname: %s\n\n", sih); |
| + |
| + if (sml == NULL && !accept_popup_check(argc, argv, sip, sih)) { |
| + close(rfbsock); |
| + rfbsock = -1; |
| + continue; |
| + } |
| + |
| + totalconn++; |
| + |
| + XCloseDisplay(d); |
| + |
| + /* Now fork off a new process to deal with it... */ |
| + |
| + switch (fork()) { |
| + |
| + case -1: |
| + perror("fork"); |
| + exit(1); |
| + |
| + case 0: |
| + /* child - return to caller */ |
| + close(listenSocket); |
| +#if 0 |
| + close(flashSocket); |
| +#endif |
| + if (sml != NULL && !accept_popup_check(argc, argv, sip, sih)) { |
| + close(rfbsock); |
| + rfbsock = -1; |
| + exit(0); |
| + } |
| + return; |
| + |
| + default: |
| + /* parent - go round and listen again */ |
| + children++; |
| + close(rfbsock); |
| + if (!(d = XOpenDisplay(displayname))) { |
| + fprintf(stderr,"%s: unable to open display %s\n", |
| + programName, XDisplayName(displayname)); |
| + exit(1); |
| + } |
| +#if 0 |
| + getFlashFont(d); |
| +#endif |
| + 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; |
| + } |
| } |
| - getFlashFont(d); |
| - break; |
| - } |
| } |
| - } |
| } |
| |
| |
| @@ -193,9 +413,16 @@ |
| * getFlashFont |
| */ |
| |
| +#if 0 |
| static void |
| getFlashFont(Display *d) |
| { |
| + |
| +#if 1 |
| + /* no longer used */ |
| + if (d) {} |
| + return; |
| +#else |
| char fontName[256]; |
| char **fontNames; |
| int nFontNames; |
| @@ -209,6 +436,9 @@ |
| sprintf(fontName,"fixed"); |
| } |
| flashFont = XLoadFont(d, fontName); |
| + |
| +#endif |
| + |
| } |
| |
| |
| @@ -219,6 +449,11 @@ |
| static void |
| flashDisplay(Display *d, char *user) |
| { |
| +#if 1 |
| + /* no longer used */ |
| + if (d || user) {} |
| + return; |
| +#else |
| Window w1, w2, w3, w4; |
| XSetWindowAttributes attr; |
| |
| @@ -284,7 +519,11 @@ |
| XDestroyWindow(d, w3); |
| XDestroyWindow(d, w4); |
| XFlush(d); |
| + |
| +#endif |
| + |
| } |
| +#endif |
| |
| /* |
| * AllXEventsPredicate is needed to make XCheckIfEvent return all events. |
| @@ -293,5 +532,6 @@ |
| static Bool |
| AllXEventsPredicate(Display *d, XEvent *ev, char *arg) |
| { |
| - return True; |
| + if (d || ev || arg) {} |
| + return True; |
| } |
| 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 2010-02-25 22:44:09.000000000 -0500 |
| @@ -23,6 +23,7 @@ |
| |
| #include <vncviewer.h> |
| #include <signal.h> |
| +#include <sys/wait.h> |
| #include <fcntl.h> |
| |
| static void CleanupSignalHandler(int sig); |
| @@ -33,12 +34,20 @@ |
| |
| 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; |
| + |
| +void check_tall(void); |
| +int guessCrop(void); |
| +void get_scale_values(double *fx, double *fy); |
| +int scale_round(int n, double factor); |
| +Bool SendTextChatFinished(void); |
| |
| /* |
| * ToplevelInitBeforeRealization sets the title, geometry and other resources |
| @@ -48,87 +57,122 @@ |
| void |
| ToplevelInitBeforeRealization() |
| { |
| - char *titleFormat; |
| - char *title; |
| - char *geometry; |
| - |
| - XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL); |
| - title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1); |
| - sprintf(title, titleFormat, desktopName); |
| - XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL); |
| - |
| - XtVaSetValues(toplevel, XtNmaxWidth, si.framebufferWidth, |
| - XtNmaxHeight, si.framebufferHeight, NULL); |
| - |
| - dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); |
| - dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); |
| - |
| - if (appData.fullScreen) { |
| - |
| - /* full screen - set position to 0,0, but defer size calculation until |
| - widgets are realized */ |
| - |
| - XtVaSetValues(toplevel, XtNoverrideRedirect, True, |
| - XtNgeometry, "+0+0", NULL); |
| - |
| - } else { |
| - |
| - /* not full screen - work out geometry for middle of screen unless |
| - specified by user */ |
| - |
| - XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL); |
| - |
| - if (geometry == NULL) { |
| - Dimension toplevelX, toplevelY; |
| - Dimension toplevelWidth = si.framebufferWidth; |
| - Dimension toplevelHeight = si.framebufferHeight; |
| - |
| - if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) |
| - toplevelWidth = dpyWidth - appData.wmDecorationWidth; |
| - |
| - if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) |
| - toplevelHeight = dpyHeight - appData.wmDecorationHeight; |
| - |
| - toplevelX = (dpyWidth - toplevelWidth - appData.wmDecorationWidth) / 2; |
| - |
| - toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2; |
| - |
| - /* set position via "geometry" so that window manager thinks it's a |
| - user-specified position and therefore honours it */ |
| - |
| - geometry = XtMalloc(256); |
| - |
| - sprintf(geometry, "%dx%d+%d+%d", |
| - toplevelWidth, toplevelHeight, toplevelX, toplevelY); |
| - XtVaSetValues(toplevel, XtNgeometry, geometry, NULL); |
| - } |
| - } |
| + char *titleFormat; |
| + char *title; |
| + char *geometry; |
| + int h = si.framebufferHeight; |
| + int w = si.framebufferWidth; |
| + |
| + check_tall(); |
| + if (appData.yCrop < 0) { |
| + appData.yCrop = guessCrop(); |
| + fprintf(stderr, "Set -ycrop to: %d\n", appData.yCrop); |
| + if (appData.yCrop > 0) { |
| + h = appData.yCrop; |
| + } |
| + } |
| + |
| + XtVaGetValues(toplevel, XtNtitle, &titleFormat, NULL); |
| + title = XtMalloc(strlen(titleFormat) + strlen(desktopName) + 1); |
| + sprintf(title, titleFormat, desktopName); |
| + XtVaSetValues(toplevel, XtNtitle, title, XtNiconName, title, NULL); |
| + |
| + if (appData.scale != NULL) { |
| + /* switched to not scaled */ |
| + double frac_x, frac_y; |
| + get_scale_values(&frac_x, &frac_y); |
| + if (frac_x > 0.0 && frac_y > 0.0) { |
| + w = scale_round(w, frac_x); |
| + h = scale_round(h, frac_y); |
| + } |
| + } |
| + XtVaSetValues(toplevel, XtNmaxWidth, w, XtNmaxHeight, h, NULL); |
| + |
| + dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); |
| + dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); |
| + |
| + if (appData.fullScreen) { |
| + /* full screen - set position to 0,0, but defer size calculation until widgets are realized */ |
| + |
| + if (!net_wm_supported()) { |
| + XtVaSetValues(toplevel, XtNoverrideRedirect, True, XtNgeometry, "+0+0", NULL); |
| + } else { |
| + fullscreen_startup = 1; |
| + } |
| + |
| + } else { |
| + |
| + /* not full screen - work out geometry for middle of screen unless specified by user */ |
| + |
| + XtVaGetValues(toplevel, XtNgeometry, &geometry, NULL); |
| + |
| + if (geometry == NULL) { |
| + Dimension toplevelX, toplevelY; |
| + Dimension toplevelWidth = w; |
| + Dimension toplevelHeight = h; |
| + |
| + if ((toplevelWidth + appData.wmDecorationWidth) >= dpyWidth) { |
| + toplevelWidth = dpyWidth - appData.wmDecorationWidth; |
| + } |
| + |
| + if ((toplevelHeight + appData.wmDecorationHeight) >= dpyHeight) { |
| + toplevelHeight = dpyHeight - appData.wmDecorationHeight; |
| + } |
| + |
| + toplevelX = (dpyWidth - toplevelWidth - appData.wmDecorationWidth) / 2; |
| + toplevelY = (dpyHeight - toplevelHeight - appData.wmDecorationHeight) /2; |
| + |
| + if (appData.appShare) { |
| + int X = appshare_x_hint; |
| + int Y = appshare_y_hint; |
| + if (appData.scale) { |
| + double fx = 1.0, fy = 1.0; |
| + get_scale_values(&fx, &fy); |
| + if (fx > 0.0 && fy > 0.0) { |
| + X *= fx; |
| + Y *= fy; |
| + } |
| + } |
| + if (appshare_x_hint != appshare_0_hint) { |
| + toplevelX = X; |
| + } |
| + if (appshare_y_hint != appshare_0_hint) { |
| + toplevelY = Y; |
| + } |
| + } |
| + |
| + /* set position via "geometry" so that window manager thinks it's a |
| + user-specified position and therefore honours it */ |
| + |
| + geometry = XtMalloc(256); |
| + |
| + sprintf(geometry, "%dx%d+%d+%d", toplevelWidth, toplevelHeight, toplevelX, toplevelY); |
| + fprintf(stderr, "geometry: %s ycrop: %d\n", geometry, appData.yCrop); |
| + XtVaSetValues(toplevel, XtNgeometry, geometry, NULL); |
| + } |
| + } |
| |
| /* Test if the keyboard is grabbed. If so, it's probably because the |
| XDM login window is up, so try iconifying it to release the grab */ |
| |
| - if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync, |
| - GrabModeSync, CurrentTime) == GrabSuccess) { |
| - XUngrabKeyboard(dpy, CurrentTime); |
| - } else { |
| - wmState = XInternAtom(dpy, "WM_STATE", False); |
| - |
| - if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) { |
| - xloginIconified = True; |
| - XSync(dpy, False); |
| - sleep(1); |
| - } |
| - } |
| - |
| - /* Set handlers for signals and X errors to perform cleanup */ |
| - |
| - signal(SIGHUP, CleanupSignalHandler); |
| - signal(SIGINT, CleanupSignalHandler); |
| - signal(SIGTERM, CleanupSignalHandler); |
| - defaultXErrorHandler = XSetErrorHandler(CleanupXErrorHandler); |
| - defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler); |
| - defaultXtErrorHandler = XtAppSetErrorHandler(appContext, |
| - CleanupXtErrorHandler); |
| + if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), False, GrabModeSync, GrabModeSync, CurrentTime) == GrabSuccess) { |
| + XUngrabKeyboard(dpy, CurrentTime); |
| + } else { |
| + wmState = XInternAtom(dpy, "WM_STATE", False); |
| + if (IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", False)) { |
| + xloginIconified = True; |
| + XSync(dpy, False); |
| + sleep(1); |
| + } |
| + } |
| + |
| + /* Set handlers for signals and X errors to perform cleanup */ |
| + signal(SIGHUP, CleanupSignalHandler); |
| + signal(SIGINT, CleanupSignalHandler); |
| + signal(SIGTERM, CleanupSignalHandler); |
| + defaultXErrorHandler = XSetErrorHandler(CleanupXErrorHandler); |
| + defaultXIOErrorHandler = XSetIOErrorHandler(CleanupXIOErrorHandler); |
| + defaultXtErrorHandler = XtAppSetErrorHandler(appContext, CleanupXtErrorHandler); |
| } |
| |
| |
| @@ -141,14 +185,22 @@ |
| void |
| ToplevelInitAfterRealization() |
| { |
| - if (appData.fullScreen) { |
| - FullScreenOn(); |
| - } |
| - |
| - wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
| - XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1); |
| - XtOverrideTranslations |
| - (toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); |
| + if (appData.fullScreen) { |
| + FullScreenOn(); |
| + if (net_wm_supported()) { |
| + /* problem with scroll bars sticking: */ |
| + XSync(dpy, False); |
| + usleep(50 * 1000); |
| + FullScreenOff(); |
| + XSync(dpy, False); |
| + usleep(50 * 1000); |
| + FullScreenOn(); |
| + } |
| + } |
| + |
| + wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
| + XSetWMProtocols(dpy, XtWindow(toplevel), &wmDeleteWindow, 1); |
| + XtOverrideTranslations(toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); |
| } |
| |
| |
| @@ -157,9 +209,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 +242,16 @@ |
| * 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); |
| + if (w || event || params || num_params) {} |
| } |
| |
| |
| @@ -256,6 +304,7 @@ |
| /* Wait for Child 1 to die */ |
| wait(&childstatus); |
| |
| + if (w || event || params || num_params) {} |
| return; |
| } |
| |
| @@ -264,11 +313,10 @@ |
| * 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(); |
| + if (w || event || params || num_params) {} |
| + exit(0); |
| } |
| |
| |
| @@ -276,49 +324,94 @@ |
| * Cleanup - perform any cleanup operations prior to exiting. |
| */ |
| |
| -void |
| -Cleanup() |
| -{ |
| - if (xloginIconified) { |
| - IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True); |
| - XFlush(dpy); |
| - } |
| +void Cleanup() { |
| + |
| + if (appData.chatActive) { |
| + appData.chatActive = False; |
| + fprintf(stderr,"Sending SendTextChatClose()\n"); |
| + SendTextChatClose(); |
| + SendTextChatFinished(); |
| + } |
| + |
| + if (xloginIconified) { |
| + IconifyNamedWindow(DefaultRootWindow(dpy), "xlogin", True); |
| + XFlush(dpy); |
| + } |
| #ifdef MITSHM |
| - if (appData.useShm) |
| - ShmCleanup(); |
| + if (appData.useShm) { |
| + if (UsingShm()) { |
| + ShmDetach(); |
| + } |
| + ShmCleanup(); |
| + } |
| #endif |
| + |
| + releaseAllPressedModifiers(); |
| + |
| + fprintf(stderr,"\nVNC Viewer exiting.\n\n"); |
| + if (listenSpecified) { |
| + if (listenParent != 0 && getenv("SSVNC_LISTEN_ONCE") && listenParent != getpid()) { |
| + fprintf(stderr, "SSVNC_LISTEN_ONCE: Trying to kill Listening Parent: %d\n", (int) listenParent); |
| + fprintf(stderr, "SSVNC_LISTEN_ONCE: Press Ctrl-C if it continues to Listen.\n\n"); |
| + kill(listenParent, SIGTERM); |
| + } else { |
| + fprintf(stderr,"(NOTE: You may need to Press Ctrl-C to make the Viewer Stop Listening.)\n\n"); |
| + } |
| + } |
| +} |
| + |
| +static void check_dbg(void) { |
| + if (getenv("SSVNC_EXIT_DEBUG")) { |
| + fprintf(stderr, "Press any key to continue: "); |
| + getc(stdin); |
| + } |
| } |
| |
| static int |
| CleanupXErrorHandler(Display *dpy, XErrorEvent *error) |
| { |
| - fprintf(stderr,"CleanupXErrorHandler called\n"); |
| - Cleanup(); |
| - return (*defaultXErrorHandler)(dpy, error); |
| + if (XError_ign) { |
| + char str[4096]; |
| + XError_ign++; |
| + fprintf(stderr,"XError_ign called.\n"); |
| + str[0] = '\0'; |
| + if (XGetErrorText(dpy, error->error_code, str, 4096)) { |
| + fprintf(stderr, "%s", str); |
| + } |
| + return 0; |
| + } |
| + 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(); |
| + if (sig) {} |
| + exit(1); |
| } |
| |
| |
| @@ -362,7 +455,7 @@ |
| if (!XQueryTree(dpy, w, &dummy, &dummy, &children, &nchildren)) |
| return False; |
| |
| - for (i = 0; i < nchildren; i++) { |
| + for (i = 0; i < (int) nchildren; i++) { |
| if (IconifyNamedWindow(children[i], name, undo)) { |
| XFree ((char *)children); |
| return True; |
| 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 2010-04-11 22:03:32.000000000 -0400 |
| @@ -22,25 +22,69 @@ |
| */ |
| |
| #include "vncviewer.h" |
| +#include <time.h> |
| +#include <sys/wait.h> |
| |
| #include <X11/Xaw/Form.h> |
| #include <X11/Xaw/Command.h> |
| +#include <X11/Xaw/AsciiText.h> |
| #include <X11/Xaw/Toggle.h> |
| |
| +#include <X11/Xaw/Box.h> |
| +#include <X11/Xaw/Scrollbar.h> |
| + |
| Widget popup, fullScreenToggle; |
| |
| +Bool SendTextChatFinished(void); |
| + |
| +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) { |
| + if (0) fprintf(stderr, "No-op\n"); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| 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 ("<Message>WM_PROTOCOLS: HidePopup()")); |
| + if (w || event || params || num_params) {} |
| } |
| |
| 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); |
| + if (w || event || params || num_params) {} |
| } |
| |
| |
| @@ -52,42 +96,808 @@ |
| }; |
| |
| void |
| -CreatePopup() |
| +CreatePopup() { |
| + Widget buttonForm1, buttonForm2, twoForm, button = 0, 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 ("<Message>WM_PROTOCOLS: HideScaleN()")); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +void |
| +HideScaleN(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + XtPopdown(scaleN); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| + |
| +void |
| +CreateScaleN() |
| { |
| Widget buttonForm, button, prevButton = NULL; |
| int i; |
| - char buttonName[12]; |
| + char buttonName[32]; |
| String buttonType; |
| |
| - popup = XtVaCreatePopupShell("popup", transientShellWidgetClass, toplevel, |
| + scaleN = XtVaCreatePopupShell("scaleN", transientShellWidgetClass, toplevel, |
| NULL); |
| |
| - buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, popup, |
| + buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, scaleN, |
| NULL); |
| |
| - if (appData.popupButtonCount > 100) { |
| - fprintf(stderr,"Too many popup buttons\n"); |
| - exit(1); |
| - } |
| - |
| - for (i = 1; i <= appData.popupButtonCount; i++) { |
| + for (i = 0; i <= 6; i++) { |
| sprintf(buttonName, "button%d", i); |
| XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName, |
| "Button", resources, 1, NULL); |
| |
| - if (strcmp(buttonType, "command") == 0) { |
| - button = XtVaCreateManagedWidget(buttonName, commandWidgetClass, |
| + button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, |
| buttonForm, NULL); |
| - XtVaSetValues(button, XtNfromVert, prevButton, |
| + XtVaSetValues(button, XtNfromVert, prevButton, |
| XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); |
| - } else if (strcmp(buttonType, "toggle") == 0) { |
| - button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, |
| + prevButton = button; |
| + } |
| +} |
| + |
| +Widget turbovncW; |
| + |
| +static Widget turboButtons[32]; |
| + |
| +Widget qualtext, qualslider; |
| + |
| +void UpdateQualSlider(void) { |
| +#ifdef TURBOVNC |
| + char text[16]; |
| + XawScrollbarSetThumb(qualslider, (float)appData.qualityLevel/100., 0.); |
| + sprintf(text, "%3d", appData.qualityLevel); |
| + XtVaSetValues(qualtext, XtNlabel, text, NULL); |
| +#endif |
| +} |
| + |
| +void qualScrollProc(Widget w, XtPointer client, XtPointer p) { |
| +#ifdef TURBOVNC |
| + float size, val; int qual, pos=(int)p; |
| + XtVaGetValues(w, XtNshown, &size, XtNtopOfThumb, &val, 0); |
| + if(pos<0) val-=.1; else val+=.1; |
| + qual=(int)(val*100.); if(qual<1) qual=1; if(qual>100) qual=100; |
| + XawScrollbarSetThumb(w, val, 0.); |
| + appData.qualityLevel=qual; |
| + UpdateQual(); |
| +#endif |
| + if (w || client || p) {} |
| +} |
| + |
| +void qualJumpProc(Widget w, XtPointer client, XtPointer p) { |
| +#ifdef TURBOVNC |
| + float val=*(float *)p; int qual; |
| + qual=(int)(val*100.); if(qual<1) qual=1; if(qual>100) qual=100; |
| + appData.qualityLevel=qual; |
| + UpdateQual(); |
| +#endif |
| + if (w || client || p) {} |
| +} |
| + |
| +void UpdateSubsampButtons(void) { |
| +#ifdef TURBOVNC |
| + int i; |
| + for (i=7; i <= 10; i++) { |
| + XtVaSetValues(turboButtons[i], XtNstate, 0, NULL); |
| + } |
| + if (appData.subsampLevel==TVNC_1X) { |
| + i = 7; |
| + } else if (appData.subsampLevel==TVNC_2X) { |
| + i = 8; |
| + } else if (appData.subsampLevel==TVNC_4X) { |
| + i = 9; |
| + } else if (appData.subsampLevel==TVNC_GRAY) { |
| + i = 10; |
| + } else { |
| + return; |
| + } |
| + XtVaSetValues(turboButtons[i], XtNstate, 1, NULL); |
| +#endif |
| +} |
| + |
| +void |
| +ShowTurboVNC(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + UpdateSubsampButtons(); |
| + UpdateQualSlider(); |
| + if (appData.popupFix) { |
| + popupFixer(turbovncW); |
| + } else { |
| + XtMoveWidget(turbovncW, event->xbutton.x_root, event->xbutton.y_root); |
| + XtPopup(turbovncW, XtGrabNone); |
| + } |
| + if (appData.grabAll) { |
| + XRaiseWindow(dpy, XtWindow(turbovncW)); |
| + } |
| + XSetWMProtocols(dpy, XtWindow(turbovncW), &wmDeleteWindow, 1); |
| + XtOverrideTranslations(turbovncW, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideTurboVNC()")); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +void |
| +HideTurboVNC(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + XtPopdown(turbovncW); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +void |
| +CreateTurboVNC() { |
| + Widget buttonForm, button, prevButton = NULL; |
| + Widget label; |
| + int i; |
| + char buttonName[32]; |
| + String buttonType; |
| + |
| + turbovncW = XtVaCreatePopupShell("turboVNC", transientShellWidgetClass, toplevel, NULL); |
| + |
| + buttonForm = XtVaCreateManagedWidget("buttonForm", formWidgetClass, turbovncW, NULL); |
| + |
| + for (i = 0; i <= 12; i++) { |
| + sprintf(buttonName, "button%d", i); |
| +#ifndef TURBOVNC |
| + if (i == 0) { |
| + sprintf(buttonName, "buttonNone"); |
| + } else if (i > 0) { |
| + return; |
| + } |
| +#endif |
| + XtVaGetSubresources(buttonForm, (XtPointer)&buttonType, buttonName, |
| + "Button", resources, 1, NULL); |
| + |
| + button = XtVaCreateManagedWidget(buttonName, toggleWidgetClass, |
| + buttonForm, NULL); |
| + turboButtons[i] = button; |
| + XtVaSetValues(button, XtNfromVert, prevButton, |
| + XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); |
| + prevButton = button; |
| + } |
| + |
| + label = XtCreateManagedWidget("qualLabel", toggleWidgetClass, buttonForm, NULL, 0); |
| + XtVaSetValues(label, XtNfromVert, prevButton, XtNleft, XawChainLeft, XtNright, XawChainRight, NULL); |
| + |
| + qualslider = XtCreateManagedWidget("qualBar", scrollbarWidgetClass, buttonForm, NULL, 0); |
| + XtVaSetValues(qualslider, XtNfromVert, label, XtNleft, XawChainLeft, NULL); |
| + XtAddCallback(qualslider, XtNscrollProc, qualScrollProc, NULL) ; |
| + XtAddCallback(qualslider, XtNjumpProc, qualJumpProc, NULL) ; |
| + |
| + qualtext = XtCreateManagedWidget("qualText", labelWidgetClass, buttonForm, NULL, 0); |
| + XtVaSetValues(qualtext, XtNfromVert, label, XtNfromHoriz, qualslider, XtNright, XawChainRight, NULL); |
| +} |
| + |
| +Widget qualityW; |
| + |
| +void |
| +ShowQuality(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.popupFix) { |
| + popupFixer(qualityW); |
| + } else { |
| + XtMoveWidget(qualityW, event->xbutton.x_root, event->xbutton.y_root); |
| + XtPopup(qualityW, XtGrabNone); |
| + } |
| + if (appData.grabAll) { |
| + XRaiseWindow(dpy, XtWindow(qualityW)); |
| + } |
| + XSetWMProtocols(dpy, XtWindow(qualityW), &wmDeleteWindow, 1); |
| + XtOverrideTranslations(qualityW, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideQuality()")); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +void |
| +HideQuality(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + XtPopdown(qualityW); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| + |
| +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 ("<Message>WM_PROTOCOLS: HideCompress()")); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +void |
| +HideCompress(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| +{ |
| + XtPopdown(compressW); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| + |
| +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; |
| + } |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +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) { |
| + sock = ListenAtTcpPort6(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; |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +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 ("<Message>WM_PROTOCOLS: Quit()")); |
| + } else { |
| + XtOverrideTranslations(chat, XtParseTranslationTable ("<Message>WM_PROTOCOLS: HideChat()")); |
| + } |
| + XSync(dpy, False); |
| + usleep(200 * 1000); |
| + } |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +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(); |
| + if (w || event || params || num_params) {} |
| +} |
| + |
| +void dismiss_proc(Widget w, XtPointer client_data, XtPointer call_data) { |
| + SendTextChatClose(); |
| + SendTextChatFinished(); |
| + hidechat(); |
| + if (w || client_data || call_data) {} |
| +} |
| + |
| +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(); |
| + if (clientData || id) {} |
| +} |
| + |
| +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) { |
| + XawTextPosition beg, end; |
| + static XawTextPosition pos = 0; |
| + XawTextBlock txt; |
| + |
| + if (appData.termChat) { |
| + return; |
| + } |
| + |
| + XawTextSetInsertionPoint(text, pos); |
| + beg = XawTextGetInsertionPoint(text); |
| + end = beg; |
| +#if 0 |
| + fprintf(stderr, "AppendChatInput: pos=%d in= '%s'\n", beg, in); |
| +#endif |
| + |
| + 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); |
| +#if 0 |
| + fprintf(stderr, "AppendChatInput done pos=%d\n", pos); |
| +#endif |
| +} |
| + |
| +#if 0 |
| +static char errorbuf[1] = {0}; |
| +#endif |
| + |
| +void CreateChat(void) { |
| + |
| + Widget myform, dismiss; |
| + Dimension w = 400, h = 300; |
| + |
| + chat = XtVaCreatePopupShell("chat", topLevelShellWidgetClass, toplevel, XtNmappedWhenManaged, False, NULL); |
| + |
| + myform = XtVaCreateManagedWidget("myform", formWidgetClass, chat, NULL); |
| + |
| + text = XtVaCreateManagedWidget("text", asciiTextWidgetClass, myform, |
| + XtNresize, XawtextResizeBoth, XtNresizable, True, XtNwrap, XawtextWrapWord, |
| + XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollAlways, |
| + XtNwidth, w, XtNheight, h, XtNdisplayCaret, False, |
| + XtNeditType, XawtextAppend, XtNtype, XawAsciiString, |
| + XtNuseStringInPlace, False, NULL); |
| + |
| + entry = XtVaCreateManagedWidget("entry", asciiTextWidgetClass, myform, |
| + XtNresize, XawtextResizeWidth, XtNresizable, True, XtNwrap, XawtextWrapNever, |
| + XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollNever, |
| + XtNheight, 20, XtNwidth, 400, XtNfromVert, text, XtNeditType, XawtextEdit, |
| + XtNdisplayCaret, True, XtNeditType, XawtextEdit, NULL); |
| + |
| + dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "Close Chat", XtNfromVert, entry, NULL); |
| + |
| + AppendChatInput(""); |
| + |
| + XtAddCallback(dismiss, XtNcallback, dismiss_proc, NULL); |
| + |
| + XtRealizeWidget(chat); |
| + |
| + XtSetKeyboardFocus(chat, entry); |
| +} |
| + |
| +Widget msgwin, msgtext; |
| + |
| +void AppendMsg(char *in) { |
| + XawTextPosition beg, end; |
| + static XawTextPosition pos = 0; |
| + XawTextBlock txt; |
| + |
| + XawTextSetInsertionPoint(msgtext, pos); |
| + beg = XawTextGetInsertionPoint(msgtext); |
| + end = beg; |
| + |
| + txt.firstPos = 0; |
| + txt.length = strlen(in); |
| + txt.ptr = in; |
| + txt.format = FMT8BIT; |
| + |
| + XawTextReplace(msgtext, beg, end, &txt); |
| + XawTextSetInsertionPoint(msgtext, beg + txt.length); |
| + |
| + pos = XawTextGetInsertionPoint(msgtext); |
| +} |
| + |
| +static int msg_visible = 0; |
| +static int msg_NO_clicked = 0; |
| + |
| +void msg_dismiss_proc(Widget w, XtPointer client_data, XtPointer call_data) { |
| + XtPopdown(msgwin); |
| + msg_visible = 0; |
| + XSync(dpy, False); |
| + usleep(200 * 1000); |
| + if (w || client_data || call_data) {} |
| +} |
| + |
| +void msg_NO_proc(Widget w, XtPointer client_data, XtPointer call_data) { |
| + XtPopdown(msgwin); |
| + msg_visible = 0; |
| + msg_NO_clicked = 1; |
| + XSync(dpy, False); |
| + usleep(200 * 1000); |
| + if (w || client_data || call_data) {} |
| +} |
| + |
| +int CreateMsg(char *msg, int wait) { |
| + |
| + Widget myform, dismiss, reject; |
| + char *p; |
| + int n, run, wmax = 0; |
| + int ret = 1; |
| + Dimension w, h; |
| + |
| + |
| + n = 0; |
| + run = 0; |
| + p = msg; |
| + while (*p != '\0') { |
| + if (*p == '\n') { |
| + run = 0; |
| + n++; |
| + } |
| + run++; |
| + if (run > wmax) wmax = run; |
| + p++; |
| + } |
| + if (wmax > 80) { |
| + if (wmax > 120) n++; |
| + if (wmax > 80) n++; |
| + wmax = 80; |
| + } |
| + h = (Dimension) (n+2) * 14; |
| + w = (Dimension) (wmax+10) * 8; |
| + |
| + msgwin = XtVaCreatePopupShell("Message", topLevelShellWidgetClass, toplevel, XtNmappedWhenManaged, False, NULL); |
| + |
| + myform = XtVaCreateManagedWidget("myform", formWidgetClass, msgwin, NULL); |
| + |
| + msgtext = XtVaCreateManagedWidget("msgtext", asciiTextWidgetClass, myform, |
| + XtNresize, XawtextResizeBoth, XtNresizable, True, XtNwrap, XawtextWrapWord, |
| + XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical, XawtextScrollAlways, |
| + XtNwidth, w, XtNheight, h, XtNdisplayCaret, False, |
| + XtNeditType, XawtextAppend, XtNtype, XawAsciiString, |
| + XtNuseStringInPlace, False, NULL); |
| + |
| + if (wait == 2) { |
| + msg_NO_clicked = 0; |
| + |
| + dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "Accept", XtNfromVert, msgtext, NULL); |
| + XtAddCallback(dismiss, XtNcallback, msg_dismiss_proc, NULL); |
| + |
| + reject = XtVaCreateManagedWidget("reject", commandWidgetClass, myform, XtNlabel, "Reject", XtNfromVert, dismiss, NULL); |
| + XtAddCallback(reject, XtNcallback, msg_NO_proc, NULL); |
| + } else { |
| + dismiss = XtVaCreateManagedWidget("dismiss", commandWidgetClass, myform, XtNlabel, "OK", XtNfromVert, msgtext, NULL); |
| + XtAddCallback(dismiss, XtNcallback, msg_dismiss_proc, NULL); |
| + |
| + } |
| + |
| + AppendMsg(""); |
| + AppendMsg(msg); |
| + |
| + XtRealizeWidget(msgwin); |
| + |
| + XtPopup(msgwin, XtGrabNone); |
| + |
| + XSync(dpy, False); |
| + msg_visible = 1; |
| + while (wait && msg_visible) { |
| + if (0) fprintf(stderr, "mv: %d\n", msg_visible); |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + if (wait == 2) { |
| + if (msg_NO_clicked) { |
| + ret = 0; |
| + } else { |
| + ret = 1; |
| + } |
| + } |
| + return ret; |
| +} |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/popup_ad vnc_unixsrc/vncviewer/popup_ad |
| --- vnc_unixsrc.orig/vncviewer/popup_ad 1969-12-31 19:00:00.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/popup_ad 2008-02-17 13:32:34.000000000 -0500 |
| @@ -0,0 +1,20 @@ |
| +#!/usr/bin/perl |
| + |
| +$ok = 0; |
| + |
| +open(A, "<argsresources.c") || die; |
| + |
| +while (<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 2010-04-17 22:34:38.000000000 -0400 |
| @@ -23,7 +23,10 @@ |
| * rfbproto.c - functions to deal with client side of RFB protocol. |
| */ |
| |
| +#include <sys/stat.h> |
| #include <unistd.h> |
| +#include <time.h> |
| +#include <ctype.h> |
| #include <errno.h> |
| #include <pwd.h> |
| #include <vncviewer.h> |
| @@ -31,6 +34,9 @@ |
| #include <zlib.h> |
| #include <jpeglib.h> |
| |
| +int server_major = 0, server_minor = 0; |
| +int viewer_major = 0, viewer_minor = 0; |
| + |
| static void InitCapabilities(void); |
| static Bool SetupTunneling(void); |
| static int ReadSecurityType(void); |
| @@ -57,6 +63,47 @@ |
| 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); |
| + |
| +extern Bool HandleCursorPos(int x, int y); |
| +extern void printChat(char *, Bool); |
| + |
| +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 +114,25 @@ |
| static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData, |
| int compressedLen); |
| |
| +extern void deskey(unsigned char *, int); |
| +extern void des(unsigned char *, unsigned char *); |
| + |
| +extern int currentMsg; |
| +extern double scale_factor_x; |
| +extern double scale_factor_y; |
| + |
| +extern int skip_maybe_sync; |
| + |
| +int sent_FBU = 0; |
| +int skip_XtUpdate = 0; |
| +int skip_XtUpdateAll = 0; |
| + |
| +static double dt_out = 0.0; |
| +static double dt_out_sc = 0.0; |
| +double latency = 0.0; |
| +double connect_time = 0.0; |
| + |
| +void raiseme(int force); |
| |
| int rfbsock; |
| char *desktopName; |
| @@ -75,6 +141,14 @@ |
| char *serverCutText = NULL; |
| Bool newServerCutText = False; |
| |
| +/* ultravnc mslogon */ |
| +#define rfbUltraVncMsLogon 0xfffffffa |
| +static Bool AuthUltraVncMsLogon(void); |
| +extern void UvncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd); |
| +extern void UvncEncryptBytes2(unsigned char *where, int length, unsigned char *key); |
| +extern void UvncDecryptBytes2(unsigned char *where, int length, unsigned char *key); |
| +extern unsigned int urandom(void); |
| + |
| int endianTest = 1; |
| |
| static Bool tightVncProtocol = False; |
| @@ -177,8 +251,26 @@ |
| sig_rfbEncodingPointerPos, "Pointer position update"); |
| CapsAdd(encodingCaps, rfbEncodingLastRect, rfbTightVncVendor, |
| sig_rfbEncodingLastRect, "LastRect protocol extension"); |
| + |
| + CapsAdd(encodingCaps, rfbEncodingNewFBSize, rfbTightVncVendor, |
| + sig_rfbEncodingNewFBSize, "New FB size protocol extension"); |
| + |
| +#ifdef TURBOVNC |
| + CapsAdd(encodingCaps, rfbJpegQualityLevel1, rfbTurboVncVendor, |
| + sig_rfbEncodingNewFBSize, "TurboJPEG quality level"); |
| + CapsAdd(encodingCaps, rfbJpegSubsamp1X, rfbTurboVncVendor, |
| + sig_rfbEncodingNewFBSize, "TurboJPEG subsampling level"); |
| +#endif |
| } |
| |
| +static char msgbuf[10000]; |
| + |
| +static void wmsg(char *msg, int wait) { |
| + fprintf(stderr, "%s", msg); |
| + if (!use_tty() && !getenv("SSVNC_NO_MESSAGE_POPUP")) { |
| + CreateMsg(msg, wait); |
| + } |
| +} |
| |
| /* |
| * ConnectToRFBServer. |
| @@ -187,24 +279,179 @@ |
| 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; |
| - } |
| + char *q, *cmd = NULL; |
| + Bool setnb; |
| + struct stat sb; |
| + |
| + if (strstr(hostname, "exec=") == hostname) { |
| + cmd = strdup(hostname); |
| + q = strchr(cmd, '='); |
| + *q = ' '; |
| + if (getenv("SSVNC_BASEDIR")) { |
| + char *base = getenv("SSVNC_BASEDIR"); |
| + char *newcmd = (char *)malloc(strlen(base) + strlen(cmd) + 1000); |
| + sprintf(newcmd, "%s/unwrap.so", base); |
| + if (stat(newcmd, &sb) == 0) { |
| +#if (defined(__MACH__) && defined(__APPLE__)) |
| + sprintf(newcmd, "DYLD_FORCE_FLAT_NAMESPACE=1; export DYLD_FORCE_FLAT_NAMESPACE; DYLD_INSERT_LIBRARIES='%s/unwrap.so'; export DYLD_INSERT_LIBRARIES; %s", base, cmd); |
| +#else |
| + sprintf(newcmd, "LD_PRELOAD='%s/unwrap.so'; export LD_PRELOAD; %s", base, cmd); |
| +#endif |
| + cmd = newcmd; |
| + } |
| + } |
| + } |
| |
| - rfbsock = ConnectToTcpAddr(host, port); |
| + if (cmd != NULL) { |
| + int sfd[2]; |
| + char *q, *cmd2 = strdup(cmd); |
| + pid_t pid; |
| + |
| + q = strstr(cmd2, "pw="); |
| + if (q && !getenv("SSVNC_SHOW_ULTRAVNC_DSM_PASSWORD")) { |
| + q += strlen("pw="); |
| + while (*q != '\0' && !isspace(*q)) { |
| + *q = '*'; |
| + q++; |
| + } |
| + } |
| + |
| + fprintf(stderr, "exec-cmd: %s\n\n", cmd2); |
| + free(cmd2); |
| + |
| + if (! SocketPair(sfd)) { |
| + return False; |
| + } |
| + if (0) { |
| + fprintf(stderr, "sfd: %d %d\n", sfd[0], sfd[1]); |
| + fflush(stderr); |
| + } |
| + |
| + pid = fork(); |
| + if (pid == -1) { |
| + perror("fork"); |
| + return False; |
| + } |
| + if (pid == 0) { |
| + char *args[4]; |
| + int d; |
| + args[0] = "/bin/sh"; |
| + args[1] = "-c"; |
| + args[2] = cmd; |
| + args[3] = NULL; |
| + |
| + close(sfd[1]); |
| + dup2(sfd[0], 0); |
| + dup2(sfd[0], 1); |
| + for (d=3; d < 256; d++) { |
| + if (d != sfd[0]) { |
| + close(d); |
| + } |
| + } |
| + execvp(args[0], args); |
| + perror("exec"); |
| + exit(1); |
| + } else { |
| + close(sfd[0]); |
| + rfbsock = sfd[1]; |
| + } |
| + if (rfbsock < 0) { |
| + sprintf(msgbuf,"Unable to connect to exec'd command: %s\n", cmd); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + } else if (strstr(hostname, "fd=") == hostname) { |
| + rfbsock = atoi(hostname + strlen("fd=")); |
| + } else if (strchr(hostname, '/') && stat(hostname, &sb) == 0) { |
| + /* assume unix domain socket */ |
| + char *thost = strdup(hostname); |
| + |
| + rfbsock = ConnectToUnixSocket(thost); |
| + free(thost); |
| + |
| + if (rfbsock < 0) { |
| + sprintf(msgbuf,"Unable to connect to VNC server (unix-domain socket: %s)\n", hostname); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + |
| + } else { |
| + rfbsock = ConnectToTcpAddr(hostname, port); |
| + |
| + if (rfbsock < 0 && !appData.noipv4) { |
| + char *q, *hosttmp; |
| + if (hostname[0] == '[') { |
| + hosttmp = strdup(hostname+1); |
| + } else { |
| + hosttmp = strdup(hostname); |
| + } |
| + q = strrchr(hosttmp, ']'); |
| + if (q) *q = '\0'; |
| + if (strstr(hosttmp, "::ffff:") == hosttmp || strstr(hosttmp, "::FFFF:") == hosttmp) { |
| + char *host = hosttmp + strlen("::ffff:"); |
| + if (dotted_ip(host, 0)) { |
| + fprintf(stderr, "ConnectToTcpAddr[ipv4]: re-trying connection using '%s'\n", host); |
| + rfbsock = ConnectToTcpAddr(host, port); |
| + } |
| + } |
| + free(hosttmp); |
| + } |
| + |
| + if (rfbsock < 0) { |
| + sprintf(msgbuf,"Unable to connect to VNC server (%s:%d)\n", hostname, port); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + } |
| |
| - if (rfbsock < 0) { |
| - fprintf(stderr,"Unable to connect to VNC server\n"); |
| - return False; |
| - } |
| + setnb = SetNonBlocking(rfbsock); |
| + return setnb; |
| +} |
| |
| - return SetNonBlocking(rfbsock); |
| +static void printFailureReason(void) { |
| + CARD32 reasonLen; |
| + ReadFromRFBServer((char *)&reasonLen, 4); |
| + reasonLen = Swap32IfLE(reasonLen); |
| + if (reasonLen < 4096) { |
| + char *reason = (char *) malloc(reasonLen+1); |
| + memset(reason, 0, reasonLen+1); |
| + ReadFromRFBServer(reason, reasonLen); |
| + sprintf(msgbuf, "Reason: %s\n", reason); |
| + wmsg(msgbuf, 1); |
| + free(reason); |
| + } |
| } |
| |
| +static char *pr_sec_type(int type) { |
| + char *str = "unknown"; |
| + if (type == rfbSecTypeInvalid) str = "rfbSecTypeInvalid"; |
| + if (type == rfbSecTypeNone) str = "rfbSecTypeNone"; |
| + if (type == rfbSecTypeVncAuth) str = "rfbSecTypeVncAuth"; |
| + if (type == rfbSecTypeRA2) str = "rfbSecTypeRA2"; |
| + if (type == rfbSecTypeRA2ne) str = "rfbSecTypeRA2ne"; |
| + if (type == rfbSecTypeTight) str = "rfbSecTypeTight"; |
| + if (type == rfbSecTypeUltra) str = "rfbSecTypeUltra"; |
| + |
| + if (type == rfbSecTypeAnonTls) str = "rfbSecTypeAnonTls"; |
| + if (type == rfbSecTypeVencrypt) str = "rfbSecTypeVencrypt"; |
| + |
| + if (type == (int) rfbUltraVncMsLogon) str = "rfbUltraVncMsLogon"; |
| + return str; |
| +} |
| + |
| +static char *pr_sec_subtype(int type) { |
| + char *str = "unknown"; |
| + if (type == rfbVencryptPlain) str = "rfbVencryptPlain"; |
| + if (type == rfbVencryptTlsNone) str = "rfbVencryptTlsNone"; |
| + if (type == rfbVencryptTlsVnc) str = "rfbVencryptTlsVnc"; |
| + if (type == rfbVencryptTlsPlain) str = "rfbVencryptTlsPlain"; |
| + if (type == rfbVencryptX509None) str = "rfbVencryptX509None"; |
| + if (type == rfbVencryptX509Vnc) str = "rfbVencryptX509Vnc"; |
| + if (type == rfbVencryptX509Plain) str = "rfbVencryptX509Plain"; |
| + return str; |
| +} |
| |
| +extern void ProcessXtEvents(void); |
| /* |
| * InitialiseRFBConnection. |
| */ |
| @@ -212,211 +459,654 @@ |
| Bool |
| InitialiseRFBConnection(void) |
| { |
| - rfbProtocolVersionMsg pv; |
| - int server_major, server_minor; |
| - int viewer_major, viewer_minor; |
| - rfbClientInitMsg ci; |
| - int secType; |
| + rfbProtocolVersionMsg pv; |
| + rfbClientInitMsg ci; |
| + int i, secType, anon_dh = 0, accept_uvnc = 0; |
| + FILE *pd; |
| + char *hsfile = NULL; |
| + char *hsparam[128]; |
| + char *envsetsec = getenv("SSVNC_SET_SECURITY_TYPE"); |
| + char line[128]; |
| + double dt = 0.0; |
| |
| - /* if the connection is immediately closed, don't report anything, so |
| - that pmw's monitor can make test connections */ |
| + /* if the connection is immediately closed, don't report anything, so |
| + that pmw's monitor can make test connections */ |
| |
| - if (listenSpecified) |
| - errorMessageOnReadFailure = False; |
| + if (listenSpecified) { |
| + errorMessageOnReadFailure = False; |
| + } |
| |
| - if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) |
| - return False; |
| + for (i=0; i < 128; i++) { |
| + hsparam[i] = NULL; |
| + } |
| |
| - errorMessageOnReadFailure = True; |
| + skip_XtUpdateAll = 1; |
| + ProcessXtEvents(); |
| + skip_XtUpdateAll = 0; |
| + |
| + if (getenv("SSVNC_PREDIGESTED_HANDSHAKE")) { |
| + double start = dnow(); |
| + hsfile = getenv("SSVNC_PREDIGESTED_HANDSHAKE"); |
| + while (dnow() < start + 10.0) { |
| + int done = 0; |
| + usleep(100 * 1000); |
| + if ((pd = fopen(hsfile, "r")) != NULL) { |
| + while (fgets(line, 128, pd) != NULL) { |
| + if (strstr(line, "done") == line) { |
| + done = 1; |
| + usleep(100 * 1000); |
| + break; |
| + } |
| + } |
| + fclose(pd); |
| + } |
| + if (done) { |
| + break; |
| + } |
| + } |
| + if ((pd = fopen(hsfile, "r")) != NULL) { |
| + i = 0; |
| + while (fgets(line, 128, pd) != NULL) { |
| + hsparam[i] = strdup(line); |
| + fprintf(stderr, "%s", line); |
| + if (i++ > 100) break; |
| + } |
| + fclose(pd); |
| + } |
| + unlink(hsfile); |
| + } |
| |
| - pv[sz_rfbProtocolVersionMsg] = 0; |
| + if (getenv("SSVNC_SKIP_RFB_PROTOCOL_VERSION")) { |
| + viewer_major = 3; |
| + viewer_minor = 8; |
| + goto end_of_proto_msg; |
| + } else if (hsfile) { |
| + int k = 0; |
| + while (hsparam[k] != NULL) { |
| + char *str = hsparam[k++]; |
| + if (strstr(str, "server=") == str) { |
| + sprintf(pv, "%s", str + strlen("server=")); |
| + goto readed_pv; |
| + } |
| + } |
| + } |
| |
| - if (sscanf(pv, rfbProtocolVersionFormat, |
| - &server_major, &server_minor) != 2) { |
| - fprintf(stderr,"Not a valid VNC server\n"); |
| - return False; |
| - } |
| + dt = dnow(); |
| + if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) { |
| + return False; |
| + } |
| + if (getenv("PRINT_DELAY1")) fprintf(stderr, "delay1: %.3f ms\n", (dnow() - dt) * 1000); |
| + dt = 0.0; |
| |
| - viewer_major = rfbProtocolMajorVersion; |
| - if (server_major == 3 && server_minor >= rfbProtocolMinorVersion) { |
| - /* the server supports at least the standard protocol 3.7 */ |
| - viewer_minor = rfbProtocolMinorVersion; |
| - } else { |
| - /* any other server version, request the standard 3.3 */ |
| - viewer_minor = rfbProtocolFallbackMinorVersion; |
| - } |
| + readed_pv: |
| |
| - fprintf(stderr, "Connected to RFB server, using protocol version %d.%d\n", |
| - viewer_major, viewer_minor); |
| + errorMessageOnReadFailure = True; |
| |
| - sprintf(pv, rfbProtocolVersionFormat, viewer_major, viewer_minor); |
| + pv[sz_rfbProtocolVersionMsg] = 0; |
| |
| - if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) |
| - return False; |
| + if (strstr(pv, "ID:") == pv) { |
| + ; |
| + } else if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) != 2) { |
| + if (strstr(pv, "test") == pv) { |
| + /* now some hacks for ultraVNC SC III (SSL) ... testA, etc */ |
| + int i; |
| + char *se = NULL; |
| + |
| + fprintf(stderr,"Trying UltraVNC Single Click III workaround: %s\n", pv); |
| + for (i=0; i < 7 ; i++) { |
| + pv[i] = pv[i+5]; |
| + } |
| + if (!ReadFromRFBServer(pv+7, 5)) { |
| + return False; |
| + } |
| + |
| + se = getenv("STUNNEL_EXTRA_OPTS"); |
| + if (se == NULL) { |
| + se = getenv("STUNNEL_EXTRA_OPTS_USER"); |
| + } |
| + if (se != NULL) { |
| + if (strstr(se, "options")) { |
| + if (strstr(se, "ALL") || strstr(se, "DONT_INSERT_EMPTY_FRAGMENTS")) { |
| + ; /* good */ |
| + } else { |
| + se = NULL; |
| + } |
| + } else { |
| + se = NULL; |
| + } |
| + } |
| + if (se == NULL) { |
| + msgbuf[0] = '\0'; |
| + strcat(msgbuf, "\n"); |
| + strcat(msgbuf, "***************************************************************\n"); |
| + strcat(msgbuf, "To work around UltraVNC SC III SSL dropping after a few minutes\n"); |
| + strcat(msgbuf, "you may need to set STUNNEL_EXTRA_OPTS_USER='options = ALL'.\n"); |
| + strcat(msgbuf, "***************************************************************\n"); |
| + strcat(msgbuf, "\n"); |
| + wmsg(msgbuf, 0); |
| + } |
| + if (strstr(pv, "ID:") == pv) { |
| + goto check_ID_string; |
| + } |
| + if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) == 2) { |
| + goto ultra_vnc_nonsense; |
| + } |
| + } |
| + sprintf(msgbuf, "Not a valid VNC server: '%s'\n", pv); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| |
| - /* Read or select the security type. */ |
| - if (viewer_minor == rfbProtocolMinorVersion) { |
| - secType = SelectSecurityType(); |
| - } else { |
| - secType = ReadSecurityType(); |
| - } |
| - if (secType == rfbSecTypeInvalid) |
| - return False; |
| + check_ID_string: |
| + if (strstr(pv, "ID:") == pv) { |
| + char tmp[256]; |
| + fprintf(stderr, "UltraVNC Repeater string detected: %s\n", pv); |
| + fprintf(stderr, "Pretending to be UltraVNC repeater: reading 250 bytes...\n\n"); |
| + if (!ReadFromRFBServer(tmp, 250 - 12)) { |
| + return False; |
| + } |
| + if (!ReadFromRFBServer(pv, 12)) { |
| + return False; |
| + } |
| + if (sscanf(pv, rfbProtocolVersionFormat, &server_major, &server_minor) != 2) { |
| + sprintf(msgbuf,"Not a valid VNC server: '%s'\n", pv); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + } |
| |
| - switch (secType) { |
| - case rfbSecTypeNone: |
| - fprintf(stderr, "No authentication needed\n"); |
| - break; |
| - case rfbSecTypeVncAuth: |
| - if (!AuthenticateVNC()) |
| - return False; |
| - break; |
| - case rfbSecTypeTight: |
| - tightVncProtocol = True; |
| - InitCapabilities(); |
| - if (!SetupTunneling()) |
| - return False; |
| - if (!PerformAuthenticationTight()) |
| - return False; |
| - break; |
| - default: /* should never happen */ |
| - fprintf(stderr, "Internal error: Invalid security type\n"); |
| - return False; |
| - } |
| + ultra_vnc_nonsense: |
| + fprintf(stderr,"\nProto: %s\n", pv); |
| |
| - ci.shared = (appData.shareDesktop ? 1 : 0); |
| + viewer_major = 3; |
| |
| - if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) |
| - return False; |
| + if (appData.rfbVersion != NULL && sscanf(appData.rfbVersion, "%d.%d", &viewer_major, &viewer_minor) == 2) { |
| + fprintf(stderr,"Setting RFB version to %d.%d from -rfbversion.\n\n", viewer_major, viewer_minor); |
| |
| - if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) |
| - return False; |
| + } else if (getenv("SSVNC_RFB_VERSION") != NULL && sscanf(getenv("SSVNC_RFB_VERSION"), "%d.%d", &viewer_major, &viewer_minor) == 2) { |
| + fprintf(stderr,"Setting RFB version to %d.%d from SSVNC_RFB_VERSION.\n\n", viewer_major, viewer_minor); |
| + |
| + } else if (server_major > 3) { |
| + viewer_minor = 8; |
| + } else if (server_major == 3 && (server_minor == 14 || server_minor == 16)) { |
| + /* hack for UltraVNC Single Click. They misuse rfb proto version */ |
| + fprintf(stderr,"Setting RFB version to 3.3 for UltraVNC Single Click.\n\n"); |
| + viewer_minor = 3; |
| + |
| + } else if (server_major == 3 && server_minor >= 8) { |
| + /* the server supports at least the standard protocol 3.8 */ |
| + viewer_minor = 8; |
| + |
| + } else if (server_major == 3 && server_minor == 7) { |
| + /* the server supports at least the standard protocol 3.7 */ |
| + viewer_minor = 7; |
| + |
| + } else { |
| + /* any other server version, request the standard 3.3 */ |
| + viewer_minor = 3; |
| + } |
| + /* n.b. Apple Remote Desktop uses 003.889, but we should be OK with 3.8 */ |
| |
| - si.framebufferWidth = Swap16IfLE(si.framebufferWidth); |
| - si.framebufferHeight = Swap16IfLE(si.framebufferHeight); |
| - si.format.redMax = Swap16IfLE(si.format.redMax); |
| - si.format.greenMax = Swap16IfLE(si.format.greenMax); |
| - si.format.blueMax = Swap16IfLE(si.format.blueMax); |
| - si.nameLength = Swap32IfLE(si.nameLength); |
| - |
| - /* FIXME: Check arguments to malloc() calls. */ |
| - desktopName = malloc(si.nameLength + 1); |
| - if (!desktopName) { |
| - fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n", |
| - (unsigned long)si.nameLength); |
| - return False; |
| - } |
| + if (appData.msLogon) { |
| + if (server_minor == 4) { |
| + fprintf(stderr,"Setting RFB version to 3.4 for UltraVNC MS Logon.\n\n"); |
| + viewer_minor = 4; |
| + } |
| + } |
| + if (getenv("SSVNC_ACCEPT_POPUP_SC")) { |
| + if (server_minor == -4 || server_minor == -6 || server_minor == 14 || server_minor == 16) { |
| + /* 4 and 6 work too? */ |
| + viewer_minor = server_minor; |
| + accept_uvnc = 1; |
| + fprintf(stderr,"Reset RFB version to 3.%d for UltraVNC SSVNC_ACCEPT_POPUP_SC.\n\n", viewer_minor); |
| + } |
| + } |
| |
| - if (!ReadFromRFBServer(desktopName, si.nameLength)) return False; |
| + fprintf(stderr, "Connected to RFB server, using protocol version %d.%d\n", viewer_major, viewer_minor); |
| |
| - desktopName[si.nameLength] = 0; |
| + if (hsfile) { |
| + int k = 0; |
| + while (hsparam[k] != NULL) { |
| + char *str = hsparam[k++]; |
| + if (strstr(str, "latency=") == str) { |
| + latency = 1000. * atof(str + strlen("latency=")); |
| + } |
| + } |
| + k = 0; |
| + while (hsparam[k] != NULL) { |
| + char *str = hsparam[k++]; |
| + int v1, v2; |
| + if (sscanf(str, "viewer=RFB %d.%d\n", &v1, &v2) == 2) { |
| + viewer_major = v1; |
| + viewer_minor = v2; |
| + fprintf(stderr, "\nPre-Handshake set protocol version to: %d.%d Latency: %.2f ms\n", viewer_major, viewer_minor, latency); |
| + goto end_of_proto_msg; |
| + } |
| + } |
| + } |
| + sprintf(pv, rfbProtocolVersionFormat, viewer_major, viewer_minor); |
| |
| - fprintf(stderr,"Desktop name \"%s\"\n",desktopName); |
| + if (!appData.appShare) { |
| + usleep(100*1000); |
| + } |
| + dt = dnow(); |
| + if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) { |
| + return False; |
| + } |
| |
| - fprintf(stderr,"VNC server default format:\n"); |
| - PrintPixelFormat(&si.format); |
| + end_of_proto_msg: |
| |
| - if (tightVncProtocol) { |
| - /* Read interaction capabilities (protocol 3.7t) */ |
| - if (!ReadInteractionCaps()) |
| - return False; |
| - } |
| + if (envsetsec) { |
| + secType = atoi(getenv("SSVNC_SET_SECURITY_TYPE")); |
| + goto sec_type; |
| + } |
| + if (hsfile) { |
| + int k = 0; |
| + while (hsparam[k] != NULL) { |
| + char *str = hsparam[k++]; |
| + int st; |
| + if (sscanf(str, "sectype=%d\n", &st) == 1) { |
| + secType = st; |
| + fprintf(stderr, "Pre-Handshake set Security-Type to: %d (%s)\n", st, pr_sec_type(st)); |
| + if (secType == rfbSecTypeVencrypt) { |
| + goto sec_type; |
| + } else if (secType == rfbSecTypeAnonTls) { |
| + break; |
| + } |
| + } |
| + } |
| + } |
| |
| - return True; |
| + if (accept_uvnc) { |
| + unsigned int msg_sz = 0; |
| + unsigned int nimmer = 0; |
| + char msg[3000]; |
| + char *msg_buf, *sip = NULL, *sih = NULL; |
| + |
| + if (!ReadFromRFBServer((char *) &msg_sz, 4)) { |
| + return False; |
| + } |
| + dt_out_sc = dnow(); |
| + msg_sz = Swap32IfBE(msg_sz); |
| + if (msg_sz > 1024) { |
| + fprintf(stderr, "UVNC msg size too big: %d\n", msg_sz); |
| + exit(1); |
| + } |
| + msg_buf = (char *)calloc(msg_sz + 100, 1); |
| + if (!ReadFromRFBServer(msg_buf, msg_sz)) { |
| + return False; |
| + } |
| + |
| + if (0) { |
| + fprintf(stderr, "msg_buf: "); |
| + write(2, msg_buf, msg_sz); |
| + fprintf(stderr, "\n"); |
| + } |
| + |
| + sip = get_peer_ip(rfbsock); |
| + if (strlen(sip) > 100) sip = "0.0.0.0"; |
| + sih = ip2host(sip); |
| + if (strlen(sih) > 300) sih = "unknown"; |
| + |
| + sprintf(msg, "\n(LISTEN) Reverse VNC connection from IP: %s\n Hostname: %s\n\n", sip, sih); |
| + strcat(msg, "UltraVNC Server Message:\n"); |
| + strcat(msg, msg_buf); |
| + free(msg_buf); |
| + strcat(msg, "\n\n"); |
| + strcat(msg, "Accept or Reject VNC connection?"); |
| + if (CreateMsg(msg, 2)) { |
| + nimmer = 1; |
| + fprintf(stderr, "Accepting connection.\n\n"); |
| + } else { |
| + nimmer = 0; |
| + fprintf(stderr, "Refusing connection.\n\n"); |
| + } |
| + if (!WriteExact(rfbsock, (char *) &nimmer, 4)) { |
| + return False; |
| + } |
| + } |
| + |
| + /* Read or select the security type. */ |
| + dt_out = 0.0; |
| + |
| + skip_XtUpdateAll = 1; |
| + if (viewer_minor >= 7 && !accept_uvnc) { |
| + secType = SelectSecurityType(); |
| + } else { |
| + secType = ReadSecurityType(); |
| + } |
| + skip_XtUpdateAll = 0; |
| + |
| + if (accept_uvnc) { |
| + dt_out = dt_out_sc; |
| + } |
| + |
| + if (dt > 0.0 && dt_out > dt) { |
| + latency = (dt_out - dt) * 1000; |
| + } |
| + |
| + fprintf(stderr, "Security-Type: %d (%s) Latency: %.2f ms\n", (int) secType, pr_sec_type(secType), latency); |
| + if (secType == rfbSecTypeInvalid) { |
| + return False; |
| + } |
| + |
| + sec_type: |
| + |
| + if (hsfile) { |
| + int subsectype = 0; |
| + int k = 0; |
| + while (hsparam[k] != NULL) { |
| + char *str = hsparam[k++]; |
| + int st; |
| + if (sscanf(str, "subtype=%d\n", &st) == 1) { |
| + subsectype = st; |
| + fprintf(stderr, "Pre-Handshake set Sub-Security-Type to: %d (%s)\n\n", st, pr_sec_subtype(st)); |
| + break; |
| + } |
| + } |
| + |
| + if (!subsectype) { |
| + ; |
| + } else if (secType == rfbSecTypeVencrypt) { |
| + if (subsectype == rfbVencryptTlsNone) { |
| + anon_dh = 1; |
| + secType = rfbSecTypeNone; |
| + } else if (subsectype == rfbVencryptTlsVnc) { |
| + anon_dh = 1; |
| + secType = rfbSecTypeVncAuth; |
| + } else if (subsectype == rfbVencryptTlsPlain) { |
| + anon_dh = 1; |
| + secType = rfbSecTypeNone; |
| + } else if (subsectype == rfbVencryptX509None) { |
| + secType = rfbSecTypeNone; |
| + } else if (subsectype == rfbVencryptX509Vnc) { |
| + secType = rfbSecTypeVncAuth; |
| + } else if (subsectype == rfbVencryptX509Plain) { |
| + secType = rfbSecTypeNone; |
| + } |
| + if (subsectype == rfbVencryptTlsPlain || subsectype == rfbVencryptX509Plain) { |
| + usleep(300*1000); |
| + } |
| + if (subsectype == rfbVencryptTlsNone || subsectype == rfbVencryptTlsVnc || subsectype == rfbVencryptTlsPlain) { |
| + char tmp[1000], line[100]; |
| + tmp[0] = '\0'; |
| + strcat(tmp, "\n"); |
| + sprintf(line, "WARNING: Anonymous Diffie-Hellman TLS used (%s),\n", pr_sec_subtype(subsectype)); |
| + strcat(tmp, line); |
| + strcat(tmp, "WARNING: there will be *NO* Authentication of the VNC Server.\n"); |
| + strcat(tmp, "WARNING: I.e. a Man-In-The-Middle attack is possible.\n"); |
| + strcat(tmp, "WARNING: Configure the server to use X509 certs and verify them.\n\n"); |
| + wmsg(tmp, 1); |
| + } |
| + if (subsectype == rfbVencryptTlsPlain || subsectype == rfbVencryptX509Plain) { |
| + fprintf(stderr, "\nVeNCrypt Plain (username + passwd) selected.\n\n"); |
| + if (appData.unixPW != NULL) { |
| + unixpw(appData.unixPW, 1); |
| + } else if (getenv("SSVNC_UNIXPW")) { |
| + unixpw(getenv("SSVNC_UNIXPW"), 1); |
| + } else { |
| + unixpw(".", 1); |
| + } |
| + } |
| + } |
| + } |
| + |
| + switch (secType) { |
| + case rfbSecTypeNone: |
| + fprintf(stderr, "No VNC authentication needed\n"); |
| + if (viewer_minor >= 8) { |
| + CARD32 authResult; |
| + |
| + if (!ReadFromRFBServer((char *)&authResult, 4)) { |
| + return False; |
| + } |
| + |
| + authResult = Swap32IfLE(authResult); |
| + |
| + if (authResult == rfbVncAuthOK) { |
| + fprintf(stderr, "VNC authentication succeeded (%d) for rfbSecTypeNone (RFB 3.8)\n", (int) authResult); |
| + } else { |
| + sprintf(msgbuf, "VNC authentication failed (%d) for rfbSecTypeNone (RFB 3.8)\n\n", (int) authResult); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + } |
| + fprintf(stderr, "\n"); |
| + break; |
| + case rfbSecTypeVncAuth: |
| + if (!AuthenticateVNC()) { |
| + return False; |
| + } |
| + break; |
| + case rfbSecTypeTight: |
| + tightVncProtocol = True; |
| + InitCapabilities(); |
| + if (!SetupTunneling()) { |
| + return False; |
| + } |
| + if (!PerformAuthenticationTight()) { |
| + return False; |
| + } |
| + break; |
| + case rfbUltraVncMsLogon: |
| + if (!AuthUltraVncMsLogon()) { |
| + return False; |
| + } |
| + break; |
| + default: /* should never happen */ |
| + sprintf(msgbuf, "Internal error: Invalid security type: %d\n", secType); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + |
| + connect_time = dnow(); |
| + |
| + ci.shared = (appData.shareDesktop ? 1 : 0); |
| + |
| + if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) { |
| + return False; |
| + } |
| + |
| + if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) { |
| + return False; |
| + } |
| + |
| + si.framebufferWidth = Swap16IfLE(si.framebufferWidth); |
| + si.framebufferHeight = Swap16IfLE(si.framebufferHeight); |
| + si.format.redMax = Swap16IfLE(si.format.redMax); |
| + si.format.greenMax = Swap16IfLE(si.format.greenMax); |
| + si.format.blueMax = Swap16IfLE(si.format.blueMax); |
| + si.nameLength = Swap32IfLE(si.nameLength); |
| + |
| + if (appData.chatOnly) { |
| + si.framebufferWidth = 32; |
| + si.framebufferHeight = 32; |
| + } |
| + |
| + /* FIXME: Check arguments to malloc() calls. */ |
| + desktopName = malloc(si.nameLength + 1); |
| + memset(desktopName, 0, si.nameLength + 1); |
| + if (!desktopName) { |
| + fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n", |
| + (unsigned long)si.nameLength); |
| + return False; |
| + } |
| + |
| + if (!ReadFromRFBServer(desktopName, si.nameLength)) { |
| + return False; |
| + } |
| + |
| + desktopName[si.nameLength] = 0; |
| + |
| + if (appData.appShare) { |
| + int x_hint, y_hint; |
| + char *p, *q = NULL; |
| + p = desktopName; |
| + while (*p != '\0') { |
| + char *t = strstr(p, " XY="); |
| + if (t) q = t; |
| + p++; |
| + } |
| + if (q) { |
| + int ok = 1; |
| + p = q + strlen(" XY="); |
| + while (*p != '\0') { |
| + if (!strpbrk(p, "0123456789,+-")) { |
| + ok = 0; |
| + } |
| + p++; |
| + } |
| + if (ok && sscanf(q+1, "XY=%d,%d", &x_hint, &y_hint) == 2) { |
| + fprintf(stderr,"Using x11vnc appshare position: %s\n\n", q); |
| + *q = '\0'; |
| + appshare_x_hint = x_hint; |
| + appshare_y_hint = y_hint; |
| + } |
| + } |
| + } |
| + |
| + fprintf(stderr,"Desktop name \"%s\"\n\n", desktopName); |
| + |
| + fprintf(stderr,"VNC server default format:\n"); |
| + PrintPixelFormat(&si.format); |
| + |
| + if (tightVncProtocol) { |
| + /* Read interaction capabilities (protocol 3.7t) */ |
| + if (!ReadInteractionCaps()) { |
| + return False; |
| + } |
| + } |
| + |
| + return True; |
| } |
| |
| |
| /* |
| - * Read security type from the server (protocol version 3.3) |
| + * Read security type from the server (protocol 3.3) |
| */ |
| |
| static int |
| ReadSecurityType(void) |
| { |
| - CARD32 secType; |
| + CARD32 secType; |
| |
| - /* Read the security type */ |
| - if (!ReadFromRFBServer((char *)&secType, sizeof(secType))) |
| - return rfbSecTypeInvalid; |
| + /* Read the security type */ |
| + if (!ReadFromRFBServer((char *)&secType, sizeof(secType))) { |
| + return rfbSecTypeInvalid; |
| + } |
| + dt_out = dnow(); |
| |
| - secType = Swap32IfLE(secType); |
| + secType = Swap32IfLE(secType); |
| |
| - if (secType == rfbSecTypeInvalid) { |
| - ReadConnFailedReason(); |
| - return rfbSecTypeInvalid; |
| - } |
| + if (secType == rfbSecTypeInvalid) { |
| + ReadConnFailedReason(); |
| + return rfbSecTypeInvalid; |
| + } |
| |
| - if (secType != rfbSecTypeNone && secType != rfbSecTypeVncAuth) { |
| - fprintf(stderr, "Unknown security type from RFB server: %d\n", |
| - (int)secType); |
| - return rfbSecTypeInvalid; |
| - } |
| + if (secType == rfbSecTypeNone) { |
| + ; /* OK */ |
| + } else if (secType == rfbSecTypeVncAuth) { |
| + ; /* OK */ |
| + } else if (secType == rfbUltraVncMsLogon) { |
| + ; /* OK */ |
| + } else { |
| + sprintf(msgbuf, "Unknown security type from RFB server: %d\n", (int)secType); |
| + wmsg(msgbuf, 1); |
| + return rfbSecTypeInvalid; |
| + } |
| |
| - return (int)secType; |
| + return (int)secType; |
| } |
| |
| |
| /* |
| - * Select security type from the server's list (protocol version 3.7) |
| + * Select security type from the server's list (protocol 3.7) |
| */ |
| |
| static int |
| SelectSecurityType(void) |
| { |
| - CARD8 nSecTypes; |
| - char *secTypeNames[] = {"None", "VncAuth"}; |
| - CARD8 knownSecTypes[] = {rfbSecTypeNone, rfbSecTypeVncAuth}; |
| - int nKnownSecTypes = sizeof(knownSecTypes); |
| - CARD8 *secTypes; |
| - CARD8 secType = rfbSecTypeInvalid; |
| - int i, j; |
| - |
| - /* Read the list of secutiry types. */ |
| - if (!ReadFromRFBServer((char *)&nSecTypes, sizeof(nSecTypes))) |
| - return rfbSecTypeInvalid; |
| - |
| - if (nSecTypes == 0) { |
| - ReadConnFailedReason(); |
| - return rfbSecTypeInvalid; |
| - } |
| + CARD8 nSecTypes; |
| + char *secTypeNames[] = {"None", "VncAuth"}; |
| + CARD8 knownSecTypes[] = {rfbSecTypeNone, rfbSecTypeVncAuth}; |
| + int nKnownSecTypes = sizeof(knownSecTypes); |
| + CARD8 *secTypes; |
| + CARD8 secType = rfbSecTypeInvalid; |
| + int i, j; |
| + |
| + if (secTypeNames) {} |
| + |
| + /* Read the list of security types. */ |
| + if (!ReadFromRFBServer((char *)&nSecTypes, sizeof(nSecTypes))) { |
| + return rfbSecTypeInvalid; |
| + } |
| + dt_out = dnow(); |
| |
| - secTypes = malloc(nSecTypes); |
| - if (!ReadFromRFBServer((char *)secTypes, nSecTypes)) |
| - return rfbSecTypeInvalid; |
| - |
| - /* Find out if the server supports TightVNC protocol extensions */ |
| - for (j = 0; j < (int)nSecTypes; j++) { |
| - if (secTypes[j] == rfbSecTypeTight) { |
| - free(secTypes); |
| - secType = rfbSecTypeTight; |
| - if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) |
| - return rfbSecTypeInvalid; |
| - fprintf(stderr, "Enabling TightVNC protocol extensions\n"); |
| - return rfbSecTypeTight; |
| - } |
| - } |
| + if (nSecTypes == 0) { |
| + ReadConnFailedReason(); |
| + return rfbSecTypeInvalid; |
| + } |
| |
| - /* Find first supported security type */ |
| - for (j = 0; j < (int)nSecTypes; j++) { |
| - for (i = 0; i < nKnownSecTypes; i++) { |
| - if (secTypes[j] == knownSecTypes[i]) { |
| - secType = secTypes[j]; |
| - if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) { |
| - free(secTypes); |
| - return rfbSecTypeInvalid; |
| - } |
| - break; |
| - } |
| - } |
| - if (secType != rfbSecTypeInvalid) break; |
| - } |
| + secTypes = malloc(nSecTypes); |
| + if (!ReadFromRFBServer((char *)secTypes, nSecTypes)) { |
| + return rfbSecTypeInvalid; |
| + } |
| + |
| + if (getenv("SSVNC_DEBUG_SEC_TYPES")) { |
| + for (j = 0; j < (int)nSecTypes; j++) { |
| + fprintf(stderr, "sec-type[%d] %d\n", j, (int) secTypes[j]); |
| + } |
| + } |
| + |
| + /* Find out if the server supports TightVNC protocol extensions */ |
| + for (j = 0; j < (int)nSecTypes; j++) { |
| + if (getenv("VNCVIEWER_NO_SEC_TYPE_TIGHT")) { |
| + break; |
| + } |
| + if (getenv("SSVNC_NO_SEC_TYPE_TIGHT")) { |
| + break; |
| + } |
| +#ifdef TURBOVNC |
| + break; |
| +#endif |
| + if (secTypes[j] == rfbSecTypeTight) { |
| + free(secTypes); |
| + secType = rfbSecTypeTight; |
| + if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) { |
| + return rfbSecTypeInvalid; |
| + } |
| + fprintf(stderr, "Enabling TightVNC protocol extensions\n"); |
| + return rfbSecTypeTight; |
| + } |
| + } |
| + |
| + /* Find first supported security type */ |
| + for (j = 0; j < (int)nSecTypes; j++) { |
| + for (i = 0; i < nKnownSecTypes; i++) { |
| + if (secTypes[j] == knownSecTypes[i]) { |
| + secType = secTypes[j]; |
| + if (!WriteExact(rfbsock, (char *)&secType, sizeof(secType))) { |
| + free(secTypes); |
| + return rfbSecTypeInvalid; |
| + } |
| + break; |
| + } |
| + } |
| + if (secType != rfbSecTypeInvalid) { |
| + break; |
| + } |
| + } |
| |
| - free(secTypes); |
| + if (secType == rfbSecTypeInvalid) { |
| + fprintf(stderr, "Server did not offer supported security type:\n"); |
| + for (j = 0; j < (int)nSecTypes; j++) { |
| + fprintf(stderr, " sectype[%d] %d\n", j, (int) secTypes[j]); |
| + } |
| + } |
| |
| - if (secType == rfbSecTypeInvalid) |
| - fprintf(stderr, "Server did not offer supported security type\n"); |
| + free(secTypes); |
| |
| - return (int)secType; |
| + return (int)secType; |
| } |
| |
| |
| @@ -451,6 +1141,9 @@ |
| return True; |
| } |
| |
| +static char *restart_session_pw = NULL; |
| +static int restart_session_len = 0; |
| + |
| |
| /* |
| * Negotiate authentication scheme (protocol version 3.7t) |
| @@ -459,58 +1152,406 @@ |
| static Bool |
| PerformAuthenticationTight(void) |
| { |
| - rfbAuthenticationCapsMsg caps; |
| - CARD32 authScheme; |
| - int i; |
| + rfbAuthenticationCapsMsg caps; |
| + CARD32 authScheme; |
| + int i; |
| |
| - /* In the protocol version 3.7t, the server informs us about supported |
| - authentication schemes. Here we read this information. */ |
| + /* In the protocol version 3.7t, the server informs us about supported |
| + authentication schemes. Here we read this information. */ |
| |
| - if (!ReadFromRFBServer((char *)&caps, sz_rfbAuthenticationCapsMsg)) |
| - return False; |
| + if (!ReadFromRFBServer((char *)&caps, sz_rfbAuthenticationCapsMsg)) { |
| + return False; |
| + } |
| |
| - caps.nAuthTypes = Swap32IfLE(caps.nAuthTypes); |
| + caps.nAuthTypes = Swap32IfLE(caps.nAuthTypes); |
| |
| - if (!caps.nAuthTypes) { |
| - fprintf(stderr, "No authentication needed\n"); |
| - return True; |
| - } |
| + if (!caps.nAuthTypes) { |
| + fprintf(stderr, "No VNC authentication needed\n\n"); |
| + if (viewer_minor >= 8) { |
| + CARD32 authResult; |
| + |
| + if (!ReadFromRFBServer((char *)&authResult, 4)) { |
| + return False; |
| + } |
| + |
| + authResult = Swap32IfLE(authResult); |
| + |
| + if (authResult == rfbVncAuthOK) { |
| + fprintf(stderr, "VNC authentication succeeded (%d) for PerformAuthenticationTight rfbSecTypeNone (RFB 3.8)\n", (int) authResult); |
| + } else { |
| + sprintf(msgbuf, "VNC authentication failed (%d) for PerformAuthenticationTight rfbSecTypeNone (RFB 3.8)\n\n", (int) authResult); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + } |
| + 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; |
| + sprintf(msgbuf, "No suitable authentication schemes offered by server\n"); |
| + wmsg(msgbuf, 1); |
| + return False; |
| +} |
| + |
| +#if 0 |
| +unsigned char encPasswd[8]; |
| +unsigned char encPasswd_MSLOGON[32]; |
| +char clearPasswd_MSLOGIN[256]; |
| +static Bool old_ultravnc_mslogon_code(void) { |
| + char *passwd = NULL; |
| + CARD8 challenge_mslogon[CHALLENGESIZE_MSLOGON]; |
| + |
| + /* code from the old uvnc way (1.0.2?) that would go into AuthenticateVNC() template */ |
| + |
| + if (appData.msLogon != NULL) { |
| + raiseme(1); |
| + if (!strcmp(appData.msLogon, "1")) { |
| + char tmp[256]; |
| + fprintf(stderr, "\nUltraVNC MS Logon Username[@Domain]: "); |
| + if (fgets(tmp, 256, stdin) == NULL) { |
| + exit(1); |
| + } |
| + appData.msLogon = strdup(tmp); |
| + } |
| + passwd = getpass("UltraVNC MS Logon Password: "); |
| + if (! passwd) { |
| + exit(1); |
| + } |
| + fprintf(stderr, "\n"); |
| + |
| + UvncEncryptPasswd_MSLOGON(encPasswd_MSLOGON, passwd); |
| + } |
| + if (appData.msLogon) { |
| + if (!ReadFromRFBServer((char *)challenge_mslogon, CHALLENGESIZE_MSLOGON)) { |
| + return False; |
| + } |
| + } |
| + if (appData.msLogon) { |
| + int i; |
| + char tmp[256]; |
| + char *q, *domain = "."; |
| + for (i=0; i < 32; i++) { |
| + challenge_mslogon[i] = encPasswd_MSLOGON[i] ^ challenge_mslogon[i]; |
| + } |
| + q = strchr(appData.msLogon, '@'); |
| + if (q) { |
| + *q = '\0'; |
| + domain = strdup(q+1); |
| + } |
| + memset(tmp, 0, sizeof(tmp)); |
| + strcat(tmp, appData.msLogon); |
| + if (!WriteExact(rfbsock, tmp, 256)) { |
| + return False; |
| + } |
| + memset(tmp, 0, sizeof(tmp)); |
| + strcat(tmp, domain); |
| + if (!WriteExact(rfbsock, tmp, 256)) { |
| + return False; |
| + } |
| + memset(tmp, 0, sizeof(tmp)); |
| + strcat(tmp, passwd); |
| + if (!WriteExact(rfbsock, tmp, CHALLENGESIZE_MSLOGON)) { |
| + return False; |
| + } |
| + } |
| } |
| +#endif |
| |
| +static void hexprint(char *label, char *data, int len) { |
| + int i; |
| + fprintf(stderr, "%s: ", label); |
| + for (i=0; i < len; i++) { |
| + unsigned char c = (unsigned char) data[i]; |
| + fprintf(stderr, "%02x ", (int) c); |
| + if ((i+1) % 20 == 0) { |
| + fprintf(stderr, "\n%s: ", label); |
| + } |
| + } |
| + fprintf(stderr, "\n"); |
| +} |
| + |
| +#define DH_MAX_BITS 31 |
| +static unsigned long long max_dh = ((unsigned long long) 1) << DH_MAX_BITS; |
| + |
| +static unsigned long long bytes_to_uint64(char *bytes) { |
| + unsigned long long result = 0; |
| + int i; |
| + |
| + for (i=0; i < 8; i++) { |
| + result <<= 8; |
| + result += (unsigned char) bytes[i]; |
| + } |
| + return result; |
| +} |
| + |
| +static void uint64_to_bytes(unsigned long long n, char *bytes) { |
| + int i; |
| + |
| + for (i=0; i < 8; i++) { |
| + bytes[i] = (unsigned char) (n >> (8 * (7 - i))); |
| + } |
| +} |
| + |
| +static void try_invert(char *wireuser, char *wirepass, unsigned long long actual_key) { |
| + if (wireuser || wirepass || actual_key) {} |
| + return; |
| +} |
| + |
| + |
| +static unsigned long long XpowYmodN(unsigned long long x, unsigned long long y, unsigned long long N) { |
| + unsigned long long result = 1; |
| + unsigned long long oneShift63 = ((unsigned long long) 1) << 63; |
| + int i; |
| + |
| + for (i = 0; i < 64; y <<= 1, i++) { |
| + result = result * result % N; |
| + if (y & oneShift63) { |
| + result = result * x % N; |
| + } |
| + } |
| + return result; |
| +} |
| + |
| +/* |
| + * UltraVNC MS-Logon authentication (for v1.0.5 and later.) |
| + */ |
| + |
| +/* |
| + * NOTE: The UltraVNC MS-Logon username and password exchange is |
| + * VERY insecure. It can be brute forced in ~2e+9 operations. |
| + * It's not clear we should support it... It is only worth using |
| + * in an environment where no one is sniffing the network, in which |
| + * case all of this DH exchange secrecy is unnecessary... |
| + */ |
| + |
| +static Bool AuthUltraVncMsLogon(void) { |
| + CARD32 authResult; |
| + char gen[8], mod[8], pub[8], rsp[8]; |
| + char user[256], passwd[64], *gpw; |
| + unsigned char key[8]; |
| + unsigned long long ugen, umod, ursp, upub, uprv, ukey; |
| + double now = dnow(); |
| + int db = 0; |
| + |
| + if (getenv("SSVNC_DEBUG_MSLOGON")) { |
| + db = atoi(getenv("SSVNC_DEBUG_MSLOGON")); |
| + } |
| + |
| + fprintf(stderr, "\nAuthUltraVncMsLogon()\n"); |
| + |
| + if (!ReadFromRFBServer(gen, sizeof(gen))) { |
| + return False; |
| + } |
| + if (db) hexprint("gen", gen, sizeof(gen)); |
| + |
| + if (!ReadFromRFBServer(mod, sizeof(mod))) { |
| + return False; |
| + } |
| + if (db) hexprint("mod", mod, sizeof(mod)); |
| + |
| + if (!ReadFromRFBServer(rsp, sizeof(rsp))) { |
| + return False; |
| + } |
| + if (db) hexprint("rsp", rsp, sizeof(rsp)); |
| + |
| + ugen = bytes_to_uint64(gen); |
| + umod = bytes_to_uint64(mod); |
| + ursp = bytes_to_uint64(rsp); |
| + |
| + if (db) { |
| + fprintf(stderr, "ugen: 0x%016llx %12llu\n", ugen, ugen); |
| + fprintf(stderr, "umod: 0x%016llx %12llu\n", umod, umod); |
| + fprintf(stderr, "ursp: 0x%016llx %12llu\n", ursp, ursp); |
| + } |
| + |
| + if (ugen > max_dh) { |
| + fprintf(stderr, "ugen: too big: 0x%016llx\n", ugen); |
| + return False; |
| + } |
| + |
| + if (umod > max_dh) { |
| + fprintf(stderr, "umod: too big: 0x%016llx\n", umod); |
| + return False; |
| + } |
| + |
| + /* make a random long long: */ |
| + uprv = 0xffffffff * (now - (unsigned int) now); |
| + uprv = uprv << 32; |
| + uprv |= (unsigned long long) urandom(); |
| + uprv = uprv % max_dh; |
| + |
| + if (db) fprintf(stderr, "uprv: 0x%016llx %12llu\n", uprv, uprv); |
| + |
| + upub = XpowYmodN(ugen, uprv, umod); |
| + |
| + if (db) fprintf(stderr, "upub: 0x%016llx %12llu\n", upub, upub); |
| + |
| + uint64_to_bytes(upub, pub); |
| + |
| + if (db) hexprint("pub", pub, sizeof(pub)); |
| + |
| + if (!WriteExact(rfbsock, (char *)pub, sizeof(pub))) { |
| + return False; |
| + } |
| + if (db) fprintf(stderr, "wrote pub.\n"); |
| + |
| + if (ursp > max_dh) { |
| + fprintf(stderr, "ursp: too big: 0x%016llx\n", ursp); |
| + return False; |
| + } |
| + |
| + ukey = XpowYmodN(ursp, uprv, umod); |
| + |
| + if (db) fprintf(stderr, "ukey: 0x%016llx %12llu\n", ukey, ukey); |
| + |
| + if (1) { |
| + char tmp[10000]; |
| + tmp[0] = '\0'; |
| + strcat(tmp, "\n"); |
| + strcat(tmp, "WARNING: The UltraVNC Diffie-Hellman Key is weak (key < 2e+9, i.e. 31 bits)\n"); |
| + strcat(tmp, "WARNING: and so an eavesdropper could recover your MS-Logon username and\n"); |
| + strcat(tmp, "WARNING: password via brute force in a few seconds of CPU time. \n"); |
| + strcat(tmp, "WARNING: If this connection is NOT being tunnelled through a separate SSL or\n"); |
| + strcat(tmp, "WARNING: SSH encrypted tunnel, consider things carefully before proceeding...\n"); |
| + strcat(tmp, "WARNING: Do not enter an important username+password when prompted below if\n"); |
| + strcat(tmp, "WARNING: there is a risk of an eavesdropper sniffing this connection.\n"); |
| + strcat(tmp, "WARNING: UltraVNC MSLogon encryption is VERY weak. You've been warned!\n"); |
| + wmsg(tmp, 1); |
| + } |
| + |
| + uint64_to_bytes(ukey, (char *) key); |
| + |
| + if (appData.msLogon == NULL || !strcmp(appData.msLogon, "1")) { |
| + char tmp[256], *q, *s; |
| + if (!use_tty()) { |
| + fprintf(stderr, "\nEnter UltraVNC MS-Logon Username[@Domain] in the popup.\n"); |
| + s = DoUserDialog(); |
| + } else { |
| + raiseme(1); |
| + fprintf(stderr, "\nUltraVNC MS-Logon Username[@Domain]: "); |
| + if (fgets(tmp, 256, stdin) == NULL) { |
| + exit(1); |
| + } |
| + s = strdup(tmp); |
| + } |
| + q = strchr(s, '\n'); |
| + if (q) *q = '\0'; |
| + appData.msLogon = strdup(s); |
| + } |
| + |
| + if (!use_tty()) { |
| + gpw = DoPasswordDialog(); |
| + } else { |
| + raiseme(1); |
| + gpw = getpass("UltraVNC MS-Logon Password: "); |
| + } |
| + if (! gpw) { |
| + return False; |
| + } |
| + fprintf(stderr, "\n"); |
| + |
| + memset(user, 0, sizeof(user)); |
| + strncpy(user, appData.msLogon, 255); |
| + |
| + memset(passwd, 0, sizeof(passwd)); |
| + strncpy(passwd, gpw, 63); |
| + |
| + if (db > 1) { |
| + fprintf(stderr, "user='%s'\n", user); |
| + fprintf(stderr, "pass='%s'\n", passwd); |
| + } |
| + |
| + UvncEncryptBytes2((unsigned char *) user, sizeof(user), key); |
| + UvncEncryptBytes2((unsigned char *) passwd, sizeof(passwd), key); |
| + |
| + if (getenv("TRY_INVERT")) { |
| + try_invert(user, passwd, ukey); |
| + exit(0); |
| + } |
| + |
| + if (db) { |
| + hexprint("user", user, sizeof(user)); |
| + hexprint("pass", passwd, sizeof(passwd)); |
| + } |
| + |
| + if (!WriteExact(rfbsock, user, sizeof(user))) { |
| + return False; |
| + } |
| + if (db) fprintf(stderr, "wrote user.\n"); |
| + |
| + if (!WriteExact(rfbsock, passwd, sizeof(passwd))) { |
| + return False; |
| + } |
| + if (db) fprintf(stderr, "wrote passwd.\n"); |
| + |
| + if (!ReadFromRFBServer((char *) &authResult, 4)) { |
| + return False; |
| + } |
| + authResult = Swap32IfLE(authResult); |
| + |
| + if (db) fprintf(stderr, "authResult: %d\n", (int) authResult); |
| + |
| + switch (authResult) { |
| + case rfbVncAuthOK: |
| + fprintf(stderr, "UVNC MS-Logon authentication succeeded.\n\n"); |
| + break; |
| + case rfbVncAuthFailed: |
| + fprintf(stderr, "UVNC MS-Logon authentication failed.\n"); |
| + if (viewer_minor >= 8) { |
| + printFailureReason(); |
| + } else { |
| + sprintf(msgbuf, "UVNC MS-Logon authentication failed.\n"); |
| + wmsg(msgbuf, 1); |
| + } |
| + fprintf(stderr, "\n"); |
| + return False; |
| + case rfbVncAuthTooMany: |
| + sprintf(msgbuf, "UVNC MS-Logon authentication failed - too many tries.\n\n"); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + default: |
| + sprintf(msgbuf, "Unknown UVNC MS-Logon authentication result: %d\n\n", |
| + (int)authResult); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + |
| + return True; |
| +} |
| |
| /* |
| * Standard VNC authentication. |
| @@ -519,80 +1560,119 @@ |
| 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"); |
| + if (authScheme) {} |
| |
| - if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) |
| - return False; |
| + fprintf(stderr, "\nPerforming standard VNC authentication\n"); |
| |
| - 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 (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) { |
| + return False; |
| + } |
| + |
| + if (restart_session_pw != NULL) { |
| + passwd = restart_session_pw; |
| + restart_session_pw = NULL; |
| + restart = 1; |
| + } else if (appData.passwordFile) { |
| + passwd = vncDecryptPasswdFromFile(appData.passwordFile); |
| + if (!passwd) { |
| + sprintf(msgbuf, "Cannot read valid password from file \"%s\"\n", appData.passwordFile); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + } else if (appData.autoPass) { |
| + passwd = buffer; |
| + raiseme(1); |
| + cstatus = fgets(buffer, sizeof buffer, stdin); |
| + if (cstatus == NULL) { |
| + buffer[0] = '\0'; |
| + } else { |
| + len = strlen(buffer); |
| + if (len > 0 && buffer[len - 1] == '\n') { |
| + buffer[len - 1] = '\0'; |
| + } |
| + } |
| + } else if (getenv("VNCVIEWER_PASSWORD")) { |
| + passwd = strdup(getenv("VNCVIEWER_PASSWORD")); |
| + } else if (appData.passwordDialog || !use_tty()) { |
| + passwd = DoPasswordDialog(); |
| + } else { |
| + raiseme(1); |
| + passwd = getpass("VNC Password: "); |
| + } |
| |
| - if (!passwd || strlen(passwd) == 0) { |
| - fprintf(stderr, "Reading password failed\n"); |
| - return False; |
| - } |
| - if (strlen(passwd) > 8) { |
| - passwd[8] = '\0'; |
| - } |
| + if (getenv("VNCVIEWER_PASSWORD")) { |
| + putenv("VNCVIEWER_PASSWORD=none"); |
| + } |
| |
| - vncEncryptBytes(challenge, passwd); |
| + if (restart) { |
| +#define EN0 0 |
| +#define DE1 1 |
| + unsigned char s_fixedkey[8] = {23,82,107,6,35,78,88,7}; |
| + deskey(s_fixedkey, DE1); |
| + des(passwd, passwd); |
| + } else { |
| + if (!passwd || strlen(passwd) == 0) { |
| + sprintf(msgbuf, "Reading password failed\n\n"); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + if (strlen(passwd) > 8) { |
| + passwd[8] = '\0'; |
| + } |
| + } |
| |
| - /* Lose the password from memory */ |
| - memset(passwd, '\0', strlen(passwd)); |
| + vncEncryptBytes(challenge, passwd); |
| + |
| |
| - if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) |
| - return False; |
| |
| - if (!ReadFromRFBServer((char *)&authResult, 4)) |
| - return False; |
| +#if 0 |
| + /* Lose the password from memory */ |
| + memset(passwd, '\0', strlen(passwd)); |
| +#endif |
| |
| - authResult = Swap32IfLE(authResult); |
| + if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) { |
| + return False; |
| + } |
| |
| - switch (authResult) { |
| - case rfbVncAuthOK: |
| - fprintf(stderr, "VNC authentication succeeded\n"); |
| - break; |
| - case rfbVncAuthFailed: |
| - fprintf(stderr, "VNC authentication failed\n"); |
| - return False; |
| - case rfbVncAuthTooMany: |
| - fprintf(stderr, "VNC authentication failed - too many tries\n"); |
| - return False; |
| - default: |
| - fprintf(stderr, "Unknown VNC authentication result: %d\n", |
| - (int)authResult); |
| - return False; |
| - } |
| + if (!ReadFromRFBServer((char *)&authResult, 4)) { |
| + return False; |
| + } |
| |
| - return True; |
| + authResult = Swap32IfLE(authResult); |
| + |
| + switch (authResult) { |
| + case rfbVncAuthOK: |
| + fprintf(stderr, "VNC authentication succeeded\n\n"); |
| + break; |
| + case rfbVncAuthFailed: |
| + fprintf(stderr, "VNC authentication failed.\n"); |
| + if (viewer_minor >= 8) { |
| + printFailureReason(); |
| + } else { |
| + sprintf(msgbuf, "VNC authentication failed.\n"); |
| + wmsg(msgbuf, 1); |
| + } |
| + fprintf(stderr, "\n"); |
| + return False; |
| + case rfbVncAuthTooMany: |
| + sprintf(msgbuf, "VNC authentication failed - too many tries\n\n"); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + default: |
| + sprintf(msgbuf, "Unknown VNC authentication result: %d\n\n", (int)authResult); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| + |
| + return True; |
| } |
| |
| /* |
| @@ -602,68 +1682,77 @@ |
| static Bool |
| AuthenticateUnixLogin(void) |
| { |
| - CARD32 loginLen, passwdLen, authResult; |
| - char *login; |
| - char *passwd; |
| - struct passwd *ps; |
| - |
| - fprintf(stderr, "Performing Unix login-style authentication\n"); |
| - |
| - if (appData.userLogin) { |
| - login = appData.userLogin; |
| - } else { |
| - ps = getpwuid(getuid()); |
| - login = ps->pw_name; |
| - } |
| + CARD32 loginLen, passwdLen, authResult; |
| + char *login; |
| + char *passwd; |
| + struct passwd *ps; |
| + |
| + fprintf(stderr, "\nPerforming Unix login-style authentication\n"); |
| + |
| + if (appData.userLogin) { |
| + login = appData.userLogin; |
| + } else { |
| + ps = getpwuid(getuid()); |
| + login = ps->pw_name; |
| + } |
| |
| - fprintf(stderr, "Using user name \"%s\"\n", login); |
| + fprintf(stderr, "Using user name \"%s\"\n", login); |
| |
| - if (appData.passwordDialog) { |
| - passwd = DoPasswordDialog(); |
| - } else { |
| - passwd = getpass("Password: "); |
| - } |
| - if (!passwd || strlen(passwd) == 0) { |
| - fprintf(stderr, "Reading password failed\n"); |
| - return False; |
| - } |
| + if (appData.passwordDialog || !use_tty()) { |
| + passwd = DoPasswordDialog(); |
| + } else { |
| + raiseme(1); |
| + passwd = getpass("VNC Password: "); |
| + } |
| + if (!passwd || strlen(passwd) == 0) { |
| + fprintf(stderr, "Reading password failed\n"); |
| + return False; |
| + } |
| |
| - loginLen = Swap32IfLE((CARD32)strlen(login)); |
| - passwdLen = Swap32IfLE((CARD32)strlen(passwd)); |
| + loginLen = Swap32IfLE((CARD32)strlen(login)); |
| + passwdLen = Swap32IfLE((CARD32)strlen(passwd)); |
| |
| - if (!WriteExact(rfbsock, (char *)&loginLen, sizeof(loginLen)) || |
| - !WriteExact(rfbsock, (char *)&passwdLen, sizeof(passwdLen))) |
| - return False; |
| + if (!WriteExact(rfbsock, (char *)&loginLen, sizeof(loginLen)) || |
| + !WriteExact(rfbsock, (char *)&passwdLen, sizeof(passwdLen))) { |
| + return False; |
| + } |
| |
| - if (!WriteExact(rfbsock, login, strlen(login)) || |
| - !WriteExact(rfbsock, passwd, strlen(passwd))) |
| - return False; |
| + if (!WriteExact(rfbsock, login, strlen(login)) || |
| + !WriteExact(rfbsock, passwd, strlen(passwd))) { |
| + return False; |
| + } |
| |
| - /* Lose the password from memory */ |
| - memset(passwd, '\0', strlen(passwd)); |
| +#if 0 |
| + /* Lose the password from memory */ |
| + memset(passwd, '\0', strlen(passwd)); |
| +#endif |
| |
| - if (!ReadFromRFBServer((char *)&authResult, sizeof(authResult))) |
| - return False; |
| + if (!ReadFromRFBServer((char *)&authResult, sizeof(authResult))) { |
| + return False; |
| + } |
| |
| - authResult = Swap32IfLE(authResult); |
| + authResult = Swap32IfLE(authResult); |
| |
| - switch (authResult) { |
| - case rfbVncAuthOK: |
| - fprintf(stderr, "Authentication succeeded\n"); |
| - break; |
| - case rfbVncAuthFailed: |
| - fprintf(stderr, "Authentication failed\n"); |
| - return False; |
| - case rfbVncAuthTooMany: |
| - fprintf(stderr, "Authentication failed - too many tries\n"); |
| - return False; |
| - default: |
| - fprintf(stderr, "Unknown authentication result: %d\n", |
| - (int)authResult); |
| - return False; |
| - } |
| + switch (authResult) { |
| + case rfbVncAuthOK: |
| + fprintf(stderr, "Authentication succeeded\n\n"); |
| + break; |
| + case rfbVncAuthFailed: |
| + sprintf(msgbuf, "Authentication failed\n\n"); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + case rfbVncAuthTooMany: |
| + sprintf(msgbuf, "Authentication failed - too many tries\n\n"); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + default: |
| + sprintf(msgbuf, "Unknown authentication result: %d\n\n", |
| + (int)authResult); |
| + wmsg(msgbuf, 1); |
| + return False; |
| + } |
| |
| - return True; |
| + return True; |
| } |
| |
| |
| @@ -675,19 +1764,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)); |
| } |
| |
| |
| @@ -697,22 +1787,70 @@ |
| * many records to read from the socket. |
| */ |
| |
| -static Bool |
| -ReadCapabilityList(CapsContainer *caps, int count) |
| -{ |
| - rfbCapabilityInfo msginfo; |
| - int i; |
| +static Bool |
| +ReadCapabilityList(CapsContainer *caps, int count) |
| +{ |
| + 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); |
| + } |
| + |
| + return True; |
| +} |
| + |
| |
| - for (i = 0; i < count; i++) { |
| - if (!ReadFromRFBServer((char *)&msginfo, sz_rfbCapabilityInfo)) |
| - return False; |
| - msginfo.code = Swap32IfLE(msginfo.code); |
| - CapsEnable(caps, &msginfo); |
| - } |
| +/* used to have !tunnelSpecified */ |
| |
| - return True; |
| +static int guess_compresslevel(void) { |
| + int n; |
| + if (latency > 200.0) { |
| + n = 8; |
| + } else if (latency > 100.0) { |
| + n = 7; |
| + } else if (latency > 60.0) { |
| + n = 6; |
| + } else if (latency > 15.0) { |
| + n = 4; |
| + } else if (latency > 8.0) { |
| + n = 2; |
| + } else if (latency > 0.0) { |
| + n = 1; |
| + } else { |
| + /* no latency measurement */ |
| + n = 3; |
| + } |
| + return n; |
| } |
| |
| +static int guess_qualitylevel(void) { |
| + int n; |
| + if (latency > 200.0) { |
| + n = 4; |
| + } else if (latency > 100.0) { |
| + n = 5; |
| + } else if (latency > 60.0) { |
| + n = 6; |
| + } else if (latency > 15.0) { |
| + n = 7; |
| + } else if (latency > 8.0) { |
| + n = 8; |
| + } else if (latency > 0.0) { |
| + n = 9; |
| + } else { |
| + /* no latency measurement */ |
| + n = 6; |
| + } |
| +#ifdef TURBOVNC |
| + n *= 10; |
| +#endif |
| + return n; |
| +} |
| |
| /* |
| * SetFormatAndEncodings. |
| @@ -729,6 +1867,21 @@ |
| Bool requestCompressLevel = False; |
| Bool requestQualityLevel = False; |
| Bool requestLastRectEncoding = False; |
| + Bool requestNewFBSizeEncoding = True; |
| + Bool requestTextChatEncoding = True; |
| + Bool requestSubsampLevel = False; |
| + int dsm = 0; |
| + int tQL, tQLmax = 9; |
| + static int qlmsg = 0, clmsg = 0; |
| +#ifdef TURBOVNC |
| + tQLmax = 100; |
| +#endif |
| + |
| + if (requestTextChatEncoding || requestSubsampLevel || tQL) {} |
| + |
| +#if 0 |
| + fprintf(stderr, "SetFormatAndEncodings: sent_FBU state: %2d\n", sent_FBU); |
| +#endif |
| |
| spf.type = rfbSetPixelFormat; |
| spf.format = myFormat; |
| @@ -736,15 +1889,32 @@ |
| spf.format.greenMax = Swap16IfLE(spf.format.greenMax); |
| spf.format.blueMax = Swap16IfLE(spf.format.blueMax); |
| |
| + |
| + currentMsg = rfbSetPixelFormat; |
| if (!WriteExact(rfbsock, (char *)&spf, sz_rfbSetPixelFormatMsg)) |
| return False; |
| |
| se->type = rfbSetEncodings; |
| se->nEncodings = 0; |
| |
| + if (appData.ultraDSM) { |
| + dsm = 1; |
| + } |
| + |
| if (appData.encodingsString) { |
| char *encStr = appData.encodingsString; |
| int encStrLen; |
| + if (strchr(encStr, ',')) { |
| + char *p; |
| + encStr = strdup(encStr); |
| + p = encStr; |
| + while (*p != '\0') { |
| + if (*p == ',') { |
| + *p = ' '; |
| + } |
| + p++; |
| + } |
| + } |
| do { |
| char *nextEncStr = strchr(encStr, ' '); |
| if (nextEncStr) { |
| @@ -754,50 +1924,102 @@ |
| encStrLen = strlen(encStr); |
| } |
| |
| +if (getenv("DEBUG_SETFORMAT")) { |
| + fprintf(stderr, "encs: "); |
| + write(2, encStr, encStrLen); |
| + fprintf(stderr, "\n"); |
| +} |
| + |
| if (strncasecmp(encStr,"raw",encStrLen) == 0) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw); |
| } else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect); |
| - } else if (strncasecmp(encStr,"tight",encStrLen) == 0) { |
| + } else if (strncasecmp(encStr,"tight",encStrLen) == 0 && !dsm) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); |
| requestLastRectEncoding = True; |
| - if (appData.compressLevel >= 0 && appData.compressLevel <= 9) |
| - requestCompressLevel = True; |
| - if (appData.enableJPEG) |
| - requestQualityLevel = True; |
| + if (appData.compressLevel >= 0 && appData.compressLevel <= 9) { |
| + requestCompressLevel = True; |
| + } |
| + if (appData.enableJPEG) { |
| + requestQualityLevel = True; |
| + } |
| +#ifdef TURBOVNC |
| + requestSubsampLevel = True; |
| +#endif |
| } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile); |
| - } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) { |
| + } else if (strncasecmp(encStr,"zlib",encStrLen) == 0 && !dsm) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib); |
| - if (appData.compressLevel >= 0 && appData.compressLevel <= 9) |
| - requestCompressLevel = True; |
| - } else if (strncasecmp(encStr,"corre",encStrLen) == 0) { |
| + if (appData.compressLevel >= 0 && appData.compressLevel <= 9) { |
| + requestCompressLevel = True; |
| + } |
| + } else if (strncasecmp(encStr,"corre",encStrLen) == 0 && !dsm) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE); |
| } else if (strncasecmp(encStr,"rre",encStrLen) == 0) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE); |
| + } else if (strncasecmp(encStr,"zrle",encStrLen) == 0) { |
| + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZRLE); |
| +#if DO_ZYWRLE |
| + } else if (strncasecmp(encStr,"zywrle",encStrLen) == 0) { |
| + int qlevel = appData.qualityLevel; |
| + if (qlevel < 0 || qlevel > tQLmax) qlevel = guess_qualitylevel(); |
| + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZYWRLE); |
| + requestQualityLevel = True; |
| + if (qlevel < 3) { |
| + zywrle_level = 3; |
| + } else if (qlevel < 6) { |
| + zywrle_level = 2; |
| + } else { |
| + zywrle_level = 1; |
| + } |
| +#endif |
| } else { |
| fprintf(stderr,"Unknown encoding '%.*s'\n",encStrLen,encStr); |
| + if (dsm && strstr(encStr, "tight") == encStr) fprintf(stderr, "tight encoding does not yet work with ultraDSM, skipping it.\n"); |
| + if (dsm && strstr(encStr, "corre") == encStr) fprintf(stderr, "corre encoding does not yet work with ultraDSM, skipping it.\n"); |
| + if (dsm && strstr(encStr, "zlib" ) == encStr) fprintf(stderr, "zlib encoding does not yet work with ultraDSM, skipping it.\n"); |
| } |
| |
| encStr = nextEncStr; |
| } while (encStr && se->nEncodings < MAX_ENCODINGS); |
| |
| if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) { |
| - encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + |
| - rfbEncodingCompressLevel0); |
| + ; |
| + } else if (se->nEncodings < MAX_ENCODINGS) { |
| + appData.compressLevel = guess_compresslevel(); |
| + if (clmsg++ == 0) fprintf(stderr, "guessed: -compresslevel %d\n", appData.compressLevel); |
| } |
| + encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0); |
| |
| if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) { |
| - if (appData.qualityLevel < 0 || appData.qualityLevel > 9) |
| - appData.qualityLevel = 5; |
| - encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + |
| - rfbEncodingQualityLevel0); |
| + if (appData.qualityLevel < 0 || appData.qualityLevel > tQLmax) { |
| + appData.qualityLevel = guess_qualitylevel(); |
| + if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel %d\n", appData.qualityLevel); |
| + } |
| + } else if (se->nEncodings < MAX_ENCODINGS) { |
| + appData.qualityLevel = guess_qualitylevel(); |
| + if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel %d\n", appData.qualityLevel); |
| + } |
| +#ifdef TURBOVNC |
| + tQL = appData.qualityLevel / 10; |
| + if (tQL < 0) tQL = 1; |
| + if (tQL > 9) tQL = 9; |
| + encs[se->nEncodings++] = Swap32IfLE(tQL + rfbEncodingQualityLevel0); |
| + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbJpegQualityLevel1 - 1); |
| + if (se->nEncodings < MAX_ENCODINGS && requestSubsampLevel) { |
| + if (appData.subsampLevel < 0 || appData.subsampLevel > TVNC_SAMPOPT - 1) { |
| + appData.subsampLevel = TVNC_1X; |
| + } |
| + encs[se->nEncodings++] = Swap32IfLE(appData.subsampLevel + rfbJpegSubsamp1X); |
| } |
| +#else |
| + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbEncodingQualityLevel0); |
| +#endif |
| |
| if (appData.useRemoteCursor) { |
| if (se->nEncodings < MAX_ENCODINGS) |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor); |
| - if (se->nEncodings < MAX_ENCODINGS) |
| + if (se->nEncodings < MAX_ENCODINGS && !appData.useX11Cursor) |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor); |
| if (se->nEncodings < MAX_ENCODINGS) |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos); |
| @@ -806,10 +2028,16 @@ |
| if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect); |
| } |
| - } |
| - else { |
| + |
| + if (se->nEncodings < MAX_ENCODINGS && requestNewFBSizeEncoding) { |
| + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingNewFBSize); |
| + } |
| + |
| + } else { |
| + /* DIFFERENT CASE */ |
| + |
| if (SameMachine(rfbsock)) { |
| - if (!tunnelSpecified) { |
| + if (!tunnelSpecified && appData.useRawLocal) { |
| fprintf(stderr,"Same machine: preferring raw encoding\n"); |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw); |
| } else { |
| @@ -818,44 +2046,84 @@ |
| } |
| |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect); |
| - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); |
| + if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight); |
| + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZRLE); |
| + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZYWRLE); |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile); |
| - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib); |
| - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE); |
| + if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib); |
| + if (!dsm) encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE); |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE); |
| |
| - if (appData.compressLevel >= 0 && appData.compressLevel <= 9) { |
| - encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + |
| - rfbEncodingCompressLevel0); |
| - } else if (!tunnelSpecified) { |
| - /* If -tunnel option was provided, we assume that server machine is |
| - not in the local network so we use default compression level for |
| - tight encoding instead of fast compression. Thus we are |
| - requesting level 1 compression only if tunneling is not used. */ |
| - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCompressLevel1); |
| - } |
| - |
| - if (appData.enableJPEG) { |
| - if (appData.qualityLevel < 0 || appData.qualityLevel > 9) |
| - appData.qualityLevel = 5; |
| - encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + |
| - rfbEncodingQualityLevel0); |
| + if (!dsm && appData.compressLevel >= 0 && appData.compressLevel <= 9) { |
| + encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0); |
| + } else { |
| + /* |
| + * OUT OF DATE: If -tunnel option was provided, we assume that server machine is |
| + * not in the local network so we use default compression level for |
| + * tight encoding instead of fast compression. Thus we are |
| + * requesting level 1 compression only if tunneling is not used. |
| + */ |
| + appData.compressLevel = guess_compresslevel(); |
| + if (clmsg++ == 0) fprintf(stderr, "guessed: -compresslevel %d\n", appData.compressLevel); |
| + encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel + rfbEncodingCompressLevel0); |
| + } |
| + |
| + if (!dsm && appData.enableJPEG) { |
| + if (appData.qualityLevel < 0 || appData.qualityLevel > tQLmax) { |
| + appData.qualityLevel = guess_qualitylevel(); |
| + if (qlmsg++ == 0) fprintf(stderr, "guessed: -qualitylevel %d\n", appData.qualityLevel); |
| + } |
| + |
| +#ifdef TURBOVNC |
| + requestSubsampLevel = True; |
| + tQL = appData.qualityLevel / 10; |
| + if (tQL < 0) tQL = 1; |
| + if (tQL > 9) tQL = 9; |
| + encs[se->nEncodings++] = Swap32IfLE(tQL + rfbEncodingQualityLevel0); |
| + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbJpegQualityLevel1 - 1); |
| + if (se->nEncodings < MAX_ENCODINGS && requestSubsampLevel) { |
| + if (appData.subsampLevel < 0 || appData.subsampLevel > TVNC_SAMPOPT - 1) { |
| + appData.subsampLevel = TVNC_1X; |
| + } |
| + encs[se->nEncodings++] = Swap32IfLE(appData.subsampLevel + rfbJpegSubsamp1X); |
| + } |
| +#else |
| + encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel + rfbEncodingQualityLevel0); |
| +#endif |
| + |
| } |
| |
| if (appData.useRemoteCursor) { |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor); |
| - encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor); |
| + if (!appData.useX11Cursor) { |
| + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor); |
| + } |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingPointerPos); |
| } |
| |
| encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect); |
| + encs[se->nEncodings++] = Swap32IfLE(rfbEncodingNewFBSize); |
| } |
| |
| len = sz_rfbSetEncodingsMsg + se->nEncodings * 4; |
| |
| - se->nEncodings = Swap16IfLE(se->nEncodings); |
| + if (!appData.ultraDSM) { |
| + se->nEncodings = Swap16IfLE(se->nEncodings); |
| |
| - if (!WriteExact(rfbsock, buf, len)) return False; |
| + if (!WriteExact(rfbsock, buf, len)) return False; |
| + } else { |
| + /* for UltraVNC encryption DSM we have to send each encoding separately (why?) */ |
| + int i, errs = 0, nenc = se->nEncodings; |
| + |
| + se->nEncodings = Swap16IfLE(se->nEncodings); |
| + |
| + currentMsg = rfbSetEncodings; |
| + if (!WriteExact(rfbsock, buf, sz_rfbSetEncodingsMsg)) errs++; |
| + for (i=0; i < nenc; i++) { |
| + if (!WriteExact(rfbsock, (char *)&encs[i], sizeof(CARD32))) errs++; |
| + } |
| + if (errs) return False; |
| + } |
| |
| return True; |
| } |
| @@ -868,31 +2136,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 +2226,38 @@ |
| Bool |
| SendPointerEvent(int x, int y, int buttonMask) |
| { |
| - rfbPointerEventMsg pe; |
| + rfbPointerEventMsg pe; |
| + |
| + if (appData.fileActive) { |
| + if (!dyn || time(NULL) < last_filexfer + delay_filexfer) { |
| +#if 0 |
| + fprintf(stderr, "skip SendPointerEvent: %d - %d\n", last_filexfer, time(NULL)); |
| +#endif |
| + return True; |
| + } |
| + } |
| |
| - pe.type = rfbPointerEvent; |
| - pe.buttonMask = buttonMask; |
| - if (x < 0) x = 0; |
| - if (y < 0) y = 0; |
| - |
| - if (!appData.useX11Cursor) |
| - SoftCursorMove(x, y); |
| - |
| - pe.x = Swap16IfLE(x); |
| - pe.y = Swap16IfLE(y); |
| - return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg); |
| + pe.type = rfbPointerEvent; |
| + pe.buttonMask = buttonMask; |
| + |
| + if (scale_factor_x > 0.0 && scale_factor_x != 1.0) { |
| + x /= scale_factor_x; |
| + } |
| + if (scale_factor_y > 0.0 && scale_factor_y != 1.0) { |
| + y /= scale_factor_y; |
| + } |
| + |
| + if (x < 0) x = 0; |
| + if (y < 0) y = 0; |
| + |
| + if (!appData.useX11Cursor) { |
| + SoftCursorMove(x, y); |
| + } |
| + |
| + pe.x = Swap16IfLE(x); |
| + pe.y = Swap16IfLE(y); |
| + currentMsg = rfbPointerEvent; |
| + return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg); |
| } |
| |
| |
| @@ -926,12 +2268,22 @@ |
| Bool |
| SendKeyEvent(CARD32 key, Bool down) |
| { |
| - rfbKeyEventMsg ke; |
| + rfbKeyEventMsg ke; |
| + |
| + if (appData.fileActive) { |
| + if (!dyn || time(NULL) < last_filexfer + delay_filexfer) { |
| +#if 0 |
| + fprintf(stderr, "skip SendPointerEvent: %d - %d\n", last_filexfer, time(NULL)); |
| +#endif |
| + 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 +2294,1025 @@ |
| Bool |
| SendClientCutText(char *str, int len) |
| { |
| - rfbClientCutTextMsg cct; |
| + rfbClientCutTextMsg cct; |
| + |
| + if (serverCutText) { |
| + free(serverCutText); |
| + } |
| + serverCutText = NULL; |
| + |
| + if (appData.fileActive) { |
| + if (!dyn || time(NULL) < last_filexfer + delay_filexfer) { |
| + /* ultravnc java viewer lets this one through. */ |
| + return True; |
| + } |
| + } |
| + |
| + if (appData.viewOnly) { |
| + return True; |
| + } |
| |
| - if (serverCutText) |
| - free(serverCutText); |
| - serverCutText = NULL; |
| - |
| - cct.type = rfbClientCutText; |
| - cct.length = Swap32IfLE(len); |
| - return (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) && |
| - WriteExact(rfbsock, str, len)); |
| + cct.type = rfbClientCutText; |
| + cct.length = Swap32IfLE((unsigned int) 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", (int) 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) |
| +{ |
| + rfbTextChatMsg chat; |
| |
| - msg.fu.nRects = Swap16IfLE(msg.fu.nRects); |
| + raiseme(0); |
| + chat.type = rfbTextChat; |
| + chat.pad1 = 0; |
| + chat.pad2 = 0; |
| + chat.length = Swap32IfLE(rfbTextChatOpen); |
| + return WriteExact(rfbsock, (char *)&chat, sz_rfbTextChatMsg); |
| +} |
| |
| - for (i = 0; i < msg.fu.nRects; i++) { |
| - if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) |
| - return False; |
| +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); |
| +} |
| |
| - rect.encoding = Swap32IfLE(rect.encoding); |
| - if (rect.encoding == rfbEncodingLastRect) |
| - break; |
| +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 |
| + |
| +/*fprintf(stderr, "In HandleFileXfer\n"); */ |
| |
| - rect.r.x = Swap16IfLE(rect.r.x); |
| - rect.r.y = Swap16IfLE(rect.r.y); |
| - rect.r.w = Swap16IfLE(rect.r.w); |
| - rect.r.h = Swap16IfLE(rect.r.h); |
| - |
| - if (rect.encoding == rfbEncodingXCursor || |
| - rect.encoding == rfbEncodingRichCursor) { |
| - if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, |
| - rect.encoding)) { |
| - return False; |
| + if (db < 0) { |
| + if (getenv("DEBUG_HandleFileXfer")) { |
| + db = 1; |
| + } else { |
| + db = 0; |
| + } |
| } |
| - continue; |
| - } |
| |
| - if (rect.encoding == rfbEncodingPointerPos) { |
| - if (!HandleCursorPos(rect.r.x, rect.r.y)) { |
| - return False; |
| + last_filexfer = time(NULL); |
| + /*fprintf(stderr, "last_filexfer-1: %d\n", last_filexfer); */ |
| + |
| + /* load first byte to send to Java be the FT msg number: */ |
| + hdr[0] = rfbFileTransfer; |
| + |
| + /* this is to avoid XtAppProcessEvent() calls induce by our ReadFromRFBServer calls below: */ |
| + skip_XtUpdateAll = 1; |
| + if (!ReadFromRFBServer(&hdr[1], 11)) { |
| + skip_XtUpdateAll = 0; |
| + return False; |
| + } |
| + if (filexfer_sock >= 0) { |
| + write(filexfer_sock, hdr, 12); |
| + } else { |
| + fprintf(stderr, "filexfer_sock closed, discarding 12 bytes\n"); |
| + } |
| + if (db) fprintf(stderr, "\n"); |
| + if (db) fprintf(stderr, "Got rfbFileTransfer hdr\n"); |
| + if (db > 1) write(2, hdr, 12); |
| + |
| + if (db) { |
| + int i; |
| + fprintf(stderr, "HFX HDR:"); |
| + for (i=0; i < 12; i++) { |
| + fprintf(stderr, " %d", (int) hdr[i]); |
| + } |
| + fprintf(stderr, "\n"); |
| } |
| - continue; |
| - } |
| |
| - if ((rect.r.x + rect.r.w > si.framebufferWidth) || |
| - (rect.r.y + rect.r.h > si.framebufferHeight)) |
| - { |
| - fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n", |
| - rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| - return False; |
| + if (hdr[1] == rfbEndOfFile) { |
| + goto read_no_more; |
| + } else if (hdr[1] == rfbAbortFileTransfer) { |
| + goto read_no_more; |
| } |
| |
| - if (rect.r.h * rect.r.w == 0) { |
| - fprintf(stderr,"Zero size rect - ignoring\n"); |
| - continue; |
| - } |
| + if (hdr[1] == rfbDirPacket && hdr[3] == rfbADirectory) { |
| + |
| + } |
| + |
| + len = (hdr[8] << 24) | (hdr[9] << 16) | (hdr[10] << 8) | hdr[11]; |
| + if (db) fprintf(stderr, "Got rfbFileTransfer: len1 %u\n", len); |
| + if (len > 0) { |
| + if (!ReadFromRFBServer(fxfer, len)) { |
| + skip_XtUpdateAll = 0; |
| + return False; |
| + } |
| + if (db > 1) write(2, fxfer, len); |
| + if (len >= 12 && hdr[1] == rfbDirPacket) { |
| + /* try to guess if x11vnc or not... */ |
| + if (db) { |
| + int i; |
| + fprintf(stderr, "HFX DIR PKT (attr, timeL, timeH):"); |
| + for (i=0; i < 12; i++) { |
| + fprintf(stderr, " %d", (unsigned char) fxfer[i]); |
| + } |
| + fprintf(stderr, "\n"); |
| + } |
| + if (hdr[2] == 1) { |
| + int dattr = (unsigned char) fxfer[0]; |
| + int timeL1 = (unsigned char) fxfer[4]; |
| + int timeL2 = (unsigned char) fxfer[5]; |
| + int timeL3 = (unsigned char) fxfer[6]; |
| + int timeL4 = (unsigned char) fxfer[7]; |
| + int timeH1 = (unsigned char) fxfer[8]; |
| + int timeH2 = (unsigned char) fxfer[9]; |
| + int timeH3 = (unsigned char) fxfer[10]; |
| + int timeH4 = (unsigned char) fxfer[11]; |
| + if (dattr != 0) { |
| + if (timeH1 == 0 && timeH2 == 0 && timeH3 == 0 && timeH4 == 0) { |
| + if ((timeL1 != 0 || timeL2 != 0) && timeL3 != 0 && timeL4 != 0) { |
| + if (!guess_x11vnc) fprintf(stderr, "guessed x11vnc server\n"); |
| + guess_x11vnc = 1; |
| + } |
| + } |
| + } |
| + } |
| + } |
| + if (db && 0) fprintf(stderr, "\n"); |
| + if (filexfer_sock >= 0) { |
| + write(filexfer_sock, fxfer, len); |
| + } else { |
| + fprintf(stderr, "filexfer_sock closed, discarding %d bytes\n", len); |
| + } |
| + } |
| + |
| + len = (hdr[4] << 24) | (hdr[5] << 16) | (hdr[6] << 8) | hdr[7]; |
| + if (db) fprintf(stderr, "Got rfbFileTransfer: len2 %u\n", len); |
| + |
| +#if 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); |
| + } |
| + } |
| |
| - /* 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); |
| + read_no_more: |
| |
| - switch (rect.encoding) { |
| + if (filexfer_sock < 0) { |
| + int stop = 0; |
| + static time_t last_stop = 0; |
| +#if 0 |
| + /* this isn't working */ |
| + if (hdr[1] == rfbFilePacket || hdr[1] == rfbFileHeader) { |
| + fprintf(stderr, "filexfer_sock closed, trying to abort receive\n"); |
| + stop = 1; |
| + } |
| +#endif |
| + if (stop && time(NULL) > last_stop+1) { |
| + unsigned char rpl[12]; |
| + int k; |
| + rpl[0] = rfbFileTransfer; |
| + rpl[1] = rfbAbortFileTransfer; |
| + for (k=2; k < 12; k++) { |
| + rpl[k] = 0; |
| + } |
| + WriteExact(rfbsock, rpl, 12); |
| + last_stop = time(NULL); |
| + } |
| + } |
| |
| - case rfbEncodingRaw: |
| + if (db) fprintf(stderr, "Got rfbFileTransfer done.\n"); |
| + skip_XtUpdateAll = 0; |
| |
| - bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; |
| - linesToRead = BUFFER_SIZE / bytesPerLine; |
| + if (db) fprintf(stderr, "CFX: B\n"); |
| + CheckFileXfer(); |
| +/*fprintf(stderr, "Out HandleFileXfer\n"); */ |
| + return True; |
| +} |
| |
| - while (rect.r.h > 0) { |
| - if (linesToRead > rect.r.h) |
| - linesToRead = rect.r.h; |
| +/* |
| + * HandleRFBServerMessage. |
| + */ |
| |
| - if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) |
| - return False; |
| |
| - CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, |
| - linesToRead); |
| +Bool |
| +HandleRFBServerMessage() |
| +{ |
| + static int db = -1; |
| + rfbServerToClientMsg msg; |
| |
| - rect.r.h -= linesToRead; |
| - rect.r.y += linesToRead; |
| + if (db < 0) { |
| + if (getenv("DEBUG_RFB_SMSG")) { |
| + db = 1; |
| + } else { |
| + db = 0; |
| + } |
| + } |
| |
| + if (!ReadFromRFBServer((char *)&msg, 1)) { |
| + return False; |
| } |
| - break; |
| + if (appData.ultraDSM) { |
| + if (!ReadFromRFBServer((char *)&msg, 1)) { |
| + return False; |
| + } |
| + } |
| + |
| +/*fprintf(stderr, "msg.type: %d\n", msg.type); */ |
| |
| - case rfbEncodingCopyRect: |
| - { |
| - rfbCopyRect cr; |
| - |
| - if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) |
| - return False; |
| - |
| - cr.srcX = Swap16IfLE(cr.srcX); |
| - cr.srcY = Swap16IfLE(cr.srcY); |
| - |
| - /* If RichCursor encoding is used, we should extend our |
| - "cursor lock area" (previously set to destination |
| - rectangle) to the source rectangle as well. */ |
| - SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h); |
| - |
| - if (appData.copyRectDelay != 0) { |
| - XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, |
| - rect.r.w, rect.r.h); |
| - XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, |
| - rect.r.w, rect.r.h); |
| - XSync(dpy,False); |
| - usleep(appData.copyRectDelay * 1000); |
| - XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, |
| - rect.r.w, rect.r.h); |
| - XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, |
| - rect.r.w, rect.r.h); |
| + if (msg.type == rfbFileTransfer) { |
| + return HandleFileXfer(); |
| } |
| |
| - XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY, |
| - rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + switch (msg.type) { |
| |
| - break; |
| - } |
| + case rfbSetColourMapEntries: |
| + { |
| + int i; |
| + CARD16 rgb[3]; |
| + XColor xc; |
| |
| - case rfbEncodingRRE: |
| - { |
| - switch (myFormat.bitsPerPixel) { |
| - case 8: |
| - if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| - case 16: |
| - if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| - case 32: |
| - if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| + if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbSetColourMapEntriesMsg - 1)) { |
| + return False; |
| } |
| - break; |
| - } |
| |
| - case rfbEncodingCoRRE: |
| - { |
| - switch (myFormat.bitsPerPixel) { |
| - case 8: |
| - if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| - case 16: |
| - if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| - case 32: |
| - if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| + msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour); |
| + msg.scme.nColours = Swap16IfLE(msg.scme.nColours); |
| + |
| + for (i = 0; i < msg.scme.nColours; i++) { |
| + if (!ReadFromRFBServer((char *)rgb, 6)) { |
| + return False; |
| + } |
| + xc.pixel = msg.scme.firstColour + i; |
| + xc.red = Swap16IfLE(rgb[0]); |
| + xc.green = Swap16IfLE(rgb[1]); |
| + xc.blue = Swap16IfLE(rgb[2]); |
| + if (appData.useGreyScale) { |
| + int ave = (xc.red + xc.green + xc.blue)/3; |
| + xc.red = ave; |
| + xc.green = ave; |
| + xc.blue = ave; |
| + } |
| + xc.flags = DoRed|DoGreen|DoBlue; |
| + XStoreColor(dpy, cmap, &xc); |
| } |
| + |
| break; |
| - } |
| + } |
| + |
| + case rfbFramebufferUpdate: |
| + { |
| + rfbFramebufferUpdateRectHeader rect; |
| + int linesToRead; |
| + int bytesPerLine; |
| + int i; |
| + |
| + int area_copyrect = 0; |
| + int area_tight = 0; |
| + int area_zrle = 0; |
| + int area_raw = 0; |
| + static int rdb = -1; |
| + static int delay_sync = -1; |
| + static int delay_sync_env = -1; |
| + int try_delay_sync = 0; |
| + int cnt_pseudo = 0; |
| + int cnt_image = 0; |
| + |
| + int skip_incFBU = 0; |
| + |
| + if (db) fprintf(stderr, "FBU-0: %.6f\n", dnow()); |
| + if (rdb < 0) { |
| + if (getenv("SSVNC_DEBUG_RECTS")) { |
| + rdb = atoi(getenv("SSVNC_DEBUG_RECTS")); |
| + } else { |
| + rdb = 0; |
| + } |
| + } |
| + if (delay_sync < 0) { |
| + if (getenv("SSVNC_DELAY_SYNC")) { |
| + delay_sync = atoi(getenv("SSVNC_DELAY_SYNC")); |
| + delay_sync_env = delay_sync; |
| + } else { |
| + delay_sync = 0; |
| + } |
| + } |
| + |
| + sent_FBU = -1; |
| |
| - 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; |
| + if (appData.pipelineUpdates) { |
| + /* turbovnc speed idea */ |
| + XEvent ev; |
| + memset(&ev, 0, sizeof(ev)); |
| + ev.xclient.type = ClientMessage; |
| + ev.xclient.window = XtWindow(desktop); |
| + ev.xclient.message_type = XA_INTEGER; |
| + ev.xclient.format = 8; |
| + strcpy(ev.xclient.data.b, "SendRFBUpdate"); |
| + XSendEvent(dpy, XtWindow(desktop), False, 0, &ev); |
| } |
| - break; |
| - } |
| |
| - case rfbEncodingZlib: |
| - { |
| - switch (myFormat.bitsPerPixel) { |
| - case 8: |
| - if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| - case 16: |
| - if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| - case 32: |
| - if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) |
| - return False; |
| - break; |
| + if (!ReadFromRFBServer(((char *)&msg.fu) + 1, sz_rfbFramebufferUpdateMsg - 1)) { |
| + return False; |
| } |
| - 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; |
| + msg.fu.nRects = Swap16IfLE(msg.fu.nRects); |
| + |
| + if (rdb) fprintf(stderr, "Begin rect loop %d\n", msg.fu.nRects); |
| + |
| + if (delay_sync) { |
| + try_delay_sync = 1; |
| + } else { |
| + if (delay_sync_env != -1 && delay_sync_env == 0) { |
| + ; |
| + } else if (appData.yCrop > 0) { |
| + ; |
| + } else if (scale_factor_x > 0.0 && scale_factor_x != 1.0) { |
| + ; |
| + } else if (scale_factor_y > 0.0 && scale_factor_y != 1.0) { |
| + ; |
| + } else { |
| + static int msg = 0; |
| + /* fullScreen? */ |
| + /* useXserverBackingStore? */ |
| + /* useX11Cursor & etc? */ |
| + /* scrollbars? */ |
| + if (!msg) { |
| + fprintf(stderr, "enabling 'delay_sync' mode for faster local drawing,\ndisable via env SSVNC_DELAY_SYNC=0 if there are painting errors.\n"); |
| + msg = 1; |
| + } |
| + try_delay_sync = 1; |
| + } |
| + } |
| + if (try_delay_sync) { |
| + skip_maybe_sync = 1; |
| + } |
| +#define STOP_DELAY_SYNC \ |
| + if (try_delay_sync) { \ |
| + if (cnt_image && skip_maybe_sync) { \ |
| + XSync(dpy, False); \ |
| + } \ |
| + try_delay_sync = 0; \ |
| + skip_maybe_sync = 0; \ |
| } |
| - break; |
| - } |
| |
| - default: |
| - fprintf(stderr,"Unknown rect encoding %d\n", |
| - (int)rect.encoding); |
| - return False; |
| - } |
| + for (i = 0; i < msg.fu.nRects; i++) { |
| + if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) { |
| + return False; |
| + } |
| + |
| + rect.encoding = Swap32IfLE(rect.encoding); |
| + if (rect.encoding == rfbEncodingLastRect) { |
| + break; |
| + } |
| + |
| + rect.r.x = Swap16IfLE(rect.r.x); |
| + rect.r.y = Swap16IfLE(rect.r.y); |
| + rect.r.w = Swap16IfLE(rect.r.w); |
| + rect.r.h = Swap16IfLE(rect.r.h); |
| + |
| + if (rdb > 1) fprintf(stderr, "nRects: %d i=%d enc: %d %dx%d+%d+%d\n", msg.fu.nRects, i, (int) rect.encoding, rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + |
| + if (rect.encoding == rfbEncodingXCursor || rect.encoding == rfbEncodingRichCursor) { |
| + cnt_pseudo++; |
| + STOP_DELAY_SYNC |
| + |
| + if (db) fprintf(stderr, "FBU-Cur1 %.6f\n", dnow()); |
| + if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, rect.encoding)) { |
| + return False; |
| + } |
| + if (db) fprintf(stderr, "FBU-Cur2 %.6f\n", dnow()); |
| + continue; |
| + } |
| + |
| + if (rect.encoding == rfbEncodingPointerPos) { |
| + cnt_pseudo++; |
| + STOP_DELAY_SYNC |
| + if (db) fprintf(stderr, "FBU-Pos1 %.6f\n", dnow()); |
| + if (0) fprintf(stderr, "CursorPos: %d %d / %d %d\n", rect.r.x, rect.r.y, rect.r.w, rect.r.h); |
| + if (ultra_scale > 0) { |
| + int f = ultra_scale; |
| + if (!HandleCursorPos(rect.r.x/f, rect.r.y/f)) { |
| + return False; |
| + } |
| + } else { |
| + if (!HandleCursorPos(rect.r.x, rect.r.y)) { |
| + return False; |
| + } |
| + } |
| + if (db) fprintf(stderr, "FBU-Pos2 %.6f\n", dnow()); |
| + continue; |
| + } |
| + if (rect.encoding == rfbEncodingNewFBSize) { |
| + cnt_pseudo++; |
| + STOP_DELAY_SYNC |
| + if (appData.chatOnly) { |
| + continue; |
| + } |
| + fprintf(stderr,"New Size: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + si.framebufferWidth = rect.r.w; |
| + si.framebufferHeight = rect.r.h; |
| + /*fprintf(stderr, "si: %d %d\n", si.framebufferWidth, si.framebufferHeight); */ |
| + ReDoDesktop(); |
| + continue; |
| + } |
| + if (rdb) fprintf(stderr,"Rect: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + cnt_image++; |
| + |
| + if (appData.ultraDSM) { |
| + /* |
| + * What a huge mess the UltraVNC DSM plugin is!!! |
| + * We read and ignore their little "this much data" hint... |
| + */ |
| + switch (rect.encoding) |
| + { |
| + case rfbEncodingRaw: |
| + case rfbEncodingRRE: |
| + case rfbEncodingCoRRE: |
| + case rfbEncodingHextile: |
| + /*case rfbEncodingUltra: */ |
| +/* case rfbEncodingZlib: */ |
| + /*case rfbEncodingXOR_Zlib: */ |
| + /*case rfbEncodingXORMultiColor_Zlib: */ |
| + /*case rfbEncodingXORMonoColor_Zlib: */ |
| + /*case rfbEncodingSolidColor: */ |
| + case rfbEncodingTight: |
| + case rfbEncodingZlibHex: |
| + case rfbEncodingZRLE: |
| + case rfbEncodingZYWRLE: |
| + { |
| + CARD32 discard; |
| + ReadFromRFBServer((char *)&discard, sizeof(CARD32)); |
| + } |
| + break; |
| + } |
| + } |
| + |
| + if ((rect.r.x + rect.r.w > si.framebufferWidth) || |
| + (rect.r.y + rect.r.h > si.framebufferHeight)) { |
| + if (!appData.chatOnly) { |
| + fprintf(stderr,"Rect too large: %dx%d at (%d, %d) encoding=%d\n", |
| + rect.r.w, rect.r.h, rect.r.x, rect.r.y, (int) 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, (int) rect.encoding); |
| + if (0) continue; |
| + } |
| + |
| + /* If RichCursor encoding is used, we should prevent collisions |
| + between framebuffer updates and cursor drawing operations. */ |
| + if (db) fprintf(stderr, "FBU-SCL1 %.6f\n", dnow()); |
| + |
| + SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h); |
| + |
| + if (db) fprintf(stderr, "FBU-SCL2 %.6f\n", dnow()); |
| + |
| + |
| + switch (rect.encoding) { |
| + |
| + case rfbEncodingRaw: |
| + |
| + bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; |
| + linesToRead = BUFFER_SIZE / bytesPerLine; |
| + |
| + if (db) fprintf(stderr, "Raw: %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + area_raw += rect.r.w * rect.r.h; |
| + |
| + while (rect.r.h > 0) { |
| + if (linesToRead > rect.r.h) { |
| + linesToRead = rect.r.h; |
| + } |
| + |
| + if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) { |
| + return False; |
| + } |
| + |
| + CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, linesToRead); |
| + |
| + rect.r.h -= linesToRead; |
| + rect.r.y += linesToRead; |
| + } |
| + break; |
| + |
| + case rfbEncodingCopyRect: |
| + { |
| + rfbCopyRect cr; |
| + |
| + STOP_DELAY_SYNC |
| + XSync(dpy, False); |
| + |
| + if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) { |
| + return False; |
| + } |
| + if (appData.chatOnly) { |
| + break; |
| + } |
| + |
| + cr.srcX = Swap16IfLE(cr.srcX); |
| + cr.srcY = Swap16IfLE(cr.srcY); |
| + |
| + if (db) fprintf(stderr, "Copy: %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + area_copyrect += rect.r.w * rect.r.h; |
| + |
| + /* If RichCursor encoding is used, we should extend our |
| + "cursor lock area" (previously set to destination |
| + rectangle) to the source rectangle as well. */ |
| + |
| + if (db) fprintf(stderr, "FBU-SCL3 %.6f\n", dnow()); |
| + |
| + SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h); |
| + |
| + if (db) fprintf(stderr, "FBU-SCL4 %.6f\n", dnow()); |
| + |
| + if (appData.copyRectDelay != 0) { |
| + XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); |
| + XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h); |
| + XSync(dpy,False); |
| + usleep(appData.copyRectDelay * 1000); |
| + XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h); |
| + XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); |
| + } |
| + |
| + if (db) fprintf(stderr, "FBU-CPA1 %.6f\n", dnow()); |
| + if (!appData.useXserverBackingStore) { |
| + copy_rect(rect.r.x, rect.r.y, rect.r.w, rect.r.h, cr.srcX, cr.srcY); |
| + put_image(rect.r.x, rect.r.y, rect.r.x, rect.r.y, rect.r.w, rect.r.h, 0); |
| + XSync(dpy, False); |
| + } else { |
| + XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY, |
| + rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + } |
| + if (db) fprintf(stderr, "FBU-CPA2 %.6f\n", dnow()); |
| + |
| + break; |
| + } |
| + |
| + case rfbEncodingRRE: |
| + { |
| + switch (myFormat.bitsPerPixel) { |
| + case 8: |
| + if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 16: |
| + if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 32: |
| + if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + } |
| + break; |
| + } |
| + |
| + case rfbEncodingCoRRE: |
| + { |
| + switch (myFormat.bitsPerPixel) { |
| + case 8: |
| + if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 16: |
| + if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 32: |
| + if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + } |
| + break; |
| + } |
| + |
| + case rfbEncodingHextile: |
| + { |
| + switch (myFormat.bitsPerPixel) { |
| + case 8: |
| + if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 16: |
| + if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 32: |
| + if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + } |
| + break; |
| + } |
| + |
| + case rfbEncodingZlib: |
| + { |
| + switch (myFormat.bitsPerPixel) { |
| + case 8: |
| + if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 16: |
| + if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 32: |
| + if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + } |
| + break; |
| + } |
| + |
| + case rfbEncodingTight: |
| + { |
| + if (db) fprintf(stderr, "Tight: %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + area_tight += rect.r.w * rect.r.h; |
| + if (db) fprintf(stderr, "FBU-TGH1 %.6f\n", dnow()); |
| + |
| + switch (myFormat.bitsPerPixel) { |
| + case 8: |
| + if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 16: |
| + if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 32: |
| + if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + } |
| + if (db) fprintf(stderr, "FBU-TGH2 %.6f\n", dnow()); |
| + break; |
| + } |
| + |
| + /* runge adds zrle and zywrle: */ |
| + case rfbEncodingZRLE: |
| +#if DO_ZYWRLE |
| + zywrle_level = 0; |
| + case rfbEncodingZYWRLE: |
| +#endif |
| + { |
| + if (db) fprintf(stderr, "ZRLE: %dx%d+%d+%d\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); |
| + area_zrle += rect.r.w * rect.r.h; |
| + switch (myFormat.bitsPerPixel) { |
| + case 8: |
| + if (!HandleZRLE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + case 16: |
| + if (myFormat.greenMax > 0x1f) { |
| + if (!HandleZRLE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + } else { |
| + if (!HandleZRLE15(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + } |
| + break; |
| + case 32: |
| + { |
| + unsigned int maxColor=(myFormat.redMax<<myFormat.redShift)| |
| + (myFormat.greenMax<<myFormat.greenShift)| |
| + (myFormat.blueMax<<myFormat.blueShift); |
| + static int ZRLE32 = -1; |
| + |
| + if (ZRLE32 < 0) { |
| + /* for debugging or workaround e.g. BE display to LE */ |
| + if (getenv("ZRLE32")) { |
| + if (strstr(getenv("ZRLE32"), "24Up")) { |
| + ZRLE32 = 3; |
| + } else if (strstr(getenv("ZRLE32"), "24Down")) { |
| + ZRLE32 = 2; |
| + } else { |
| + ZRLE32 = 1; |
| + } |
| + } else { |
| + ZRLE32 = 0; |
| + } |
| + } |
| + |
| +if (db) fprintf(stderr, "maxColor: 0x%x mfbigEnding: %d\n", maxColor, myFormat.bigEndian); |
| + |
| + if (ZRLE32 == 1) { |
| +if (db) fprintf(stderr, "HandleZRLE32\n"); |
| + if (!HandleZRLE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + } else if (ZRLE32 == 2) { |
| +if (db) fprintf(stderr, "HandleZRLE24Down\n"); |
| + if (!HandleZRLE24Down(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + } else if (ZRLE32 == 3) { |
| +if (db) fprintf(stderr, "HandleZRLE24Up\n"); |
| + if (!HandleZRLE24Up(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + } else if ((myFormat.bigEndian && (maxColor&0xff)==0) || (!myFormat.bigEndian && (maxColor&0xff000000)==0)) { |
| +if (db) fprintf(stderr, "HandleZRLE24\n"); |
| + if (!HandleZRLE24(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + } else if (!myFormat.bigEndian && (maxColor&0xff)==0) { |
| +if (db) fprintf(stderr, "HandleZRLE24Up\n"); |
| + if (!HandleZRLE24Up(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + } else if (myFormat.bigEndian && (maxColor&0xff000000)==0) { |
| +if (db) fprintf(stderr, "HandleZRLE24Down\n"); |
| + if (!HandleZRLE24Down(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + } else if (!HandleZRLE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) { |
| + return False; |
| + } |
| + break; |
| + } |
| + } |
| + break; |
| + } |
| + |
| + default: |
| + fprintf(stderr,"Unknown rect encoding %d\n", (int)rect.encoding); |
| + return False; |
| + } |
| |
| - /* Now we may discard "soft cursor locks". */ |
| - SoftCursorUnlockScreen(); |
| - } |
| + /* Now we may discard "soft cursor locks". */ |
| + if (db) fprintf(stderr, "FBU-SUL1 %.6f\n", dnow()); |
| + |
| + SoftCursorUnlockScreen(); |
| + |
| + if (db) fprintf(stderr, "FBU-SUL2 %.6f\n", dnow()); |
| + } |
| + |
| + if (try_delay_sync) { |
| + skip_maybe_sync = 0; |
| + } |
| + |
| + if (1 || area_copyrect) { |
| + /* we always do this now for some reason... */ |
| + if (db) fprintf(stderr, "FBU-XSN1 %.6f\n", dnow()); |
| + XSync(dpy, False); |
| + if (db) fprintf(stderr, "FBU-XSN2 %.6f\n", dnow()); |
| + } |
| + sent_FBU = 0; |
| + /* |
| + * we need to be careful since Xt events are processed |
| + * usually in the middle of FBU. So we do any scheduled ones now |
| + * which is pretty safe but not absolutely safe. |
| + */ |
| + if (do_format_change) { |
| + cutover_format_change(); |
| + do_format_change = 0; |
| + SetVisualAndCmap(); |
| + SetFormatAndEncodings(); |
| + if (do_cursor_change) { |
| + if (do_cursor_change == 1) { |
| + DesktopCursorOff(); |
| + } |
| + do_cursor_change = 0; |
| + } else { |
| + SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, |
| + si.framebufferHeight, False); |
| + skip_incFBU = 1; |
| + } |
| + } |
| + if (do_fb_update != 0.0) { |
| + if (dnow() > 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 +3320,168 @@ |
| mainly to avoid copyrect using invalid screen contents - not sure |
| if we'd need it otherwise. */ |
| |
| - if (appData.useShm) |
| - XSync(dpy, False); |
| + if (appData.useShm) { |
| + XSync(dpy, False); |
| + } else |
| #endif |
| + { |
| + /* we do it always now. */ |
| + XSync(dpy, False); |
| + } |
| + |
| + if (skip_XtUpdate || skip_incFBU) { |
| + ; |
| + } else if (appData.pipelineUpdates) { |
| + ; |
| + } else if (!SendIncrementalFramebufferUpdateRequest()) { |
| + return False; |
| + } |
| |
| - if (!SendIncrementalFramebufferUpdateRequest()) |
| - return False; |
| - |
| - break; |
| + break; |
| } |
| |
| case rfbBell: |
| { |
| - Window toplevelWin; |
| + Window toplevelWin; |
| |
| - 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 +3501,93 @@ |
| #define CONCAT2(a,b) a##b |
| #define CONCAT2E(a,b) CONCAT2(a,b) |
| |
| +#define CONCAT3(a,b,c) a##b##c |
| +#define CONCAT3E(a,b,c) CONCAT3(a,b,c) |
| + |
| +static unsigned char* frameBuffer = NULL; |
| +static int frameBufferLen = 0; |
| + |
| +#ifdef TURBOVNC |
| +#include "turbovnc/turbojpeg.h" |
| +tjhandle tjhnd=NULL; |
| +static char *compressedData = NULL; |
| +static char *uncompressedData = NULL; |
| +#define CopyDataToImage CopyDataToScreen |
| +static void turbovnc_FillRectangle(XGCValues *gcv, int rx, int ry, int rw, int rh) { |
| + if (!appData.useXserverBackingStore) { |
| + FillScreen(rx, ry, rw, rh, gcv->foreground); |
| + } else { |
| + XChangeGC(dpy, gc, GCForeground, gcv); |
| + XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); |
| + } |
| +} |
| +static void CopyImageToScreen(int x, int y, int w, int h) { |
| + put_image(x, y, x, y, w, h, 0); |
| +} |
| +#endif |
| + |
| #define BPP 8 |
| #include "rre.c" |
| #include "corre.c" |
| #include "hextile.c" |
| #include "zlib.c" |
| + |
| +#ifdef TURBOVNC |
| +#undef FillRectangle |
| +#define FillRectangle turbovnc_FillRectangle |
| +#include "turbovnc/tight.c" |
| +#undef FillRectangle |
| +#else |
| #include "tight.c" |
| +#endif |
| + |
| +#include "zrle.c" |
| #undef BPP |
| + |
| #define BPP 16 |
| #include "rre.c" |
| #include "corre.c" |
| #include "hextile.c" |
| #include "zlib.c" |
| + |
| +#ifdef TURBOVNC |
| +#undef FillRectangle |
| +#define FillRectangle turbovnc_FillRectangle |
| +#include "turbovnc/tight.c" |
| +#undef FillRectangle |
| +#else |
| #include "tight.c" |
| +#endif |
| + |
| +#include "zrle.c" |
| +#define REALBPP 15 |
| +#include "zrle.c" |
| #undef BPP |
| + |
| #define BPP 32 |
| #include "rre.c" |
| #include "corre.c" |
| #include "hextile.c" |
| #include "zlib.c" |
| + |
| +#ifdef TURBOVNC |
| +#undef FillRectangle |
| +#define FillRectangle turbovnc_FillRectangle |
| +#include "turbovnc/tight.c" |
| +#undef FillRectangle |
| +#else |
| #include "tight.c" |
| +#endif |
| + |
| +#include "zrle.c" |
| +#define REALBPP 24 |
| +#include "zrle.c" |
| +#define REALBPP 24 |
| +#define UNCOMP 8 |
| +#include "zrle.c" |
| +#define REALBPP 24 |
| +#define UNCOMP -8 |
| +#include "zrle.c" |
| #undef BPP |
| |
| /* |
| @@ -1325,23 +3597,27 @@ |
| static void |
| ReadConnFailedReason(void) |
| { |
| - CARD32 reasonLen; |
| - char *reason = NULL; |
| + CARD32 reasonLen; |
| + char *reason = NULL; |
| |
| - if (ReadFromRFBServer((char *)&reasonLen, sizeof(reasonLen))) { |
| - reasonLen = Swap32IfLE(reasonLen); |
| - if ((reason = malloc(reasonLen)) != NULL && |
| - ReadFromRFBServer(reason, reasonLen)) { |
| - fprintf(stderr,"VNC connection failed: %.*s\n", (int)reasonLen, reason); |
| - free(reason); |
| - return; |
| - } |
| - } |
| + if (ReadFromRFBServer((char *)&reasonLen, sizeof(reasonLen))) { |
| + reasonLen = Swap32IfLE(reasonLen); |
| + if ((reason = malloc(reasonLen)) != NULL && |
| + ReadFromRFBServer(reason, reasonLen)) { |
| + int len = (int) reasonLen < sizeof(msgbuf) - 10 ? (int) reasonLen : sizeof(msgbuf) - 10; |
| + sprintf(msgbuf,"VNC connection failed: %.*s\n", len, reason); |
| + wmsg(msgbuf, 1); |
| + free(reason); |
| + return; |
| + } |
| + } |
| |
| - fprintf(stderr, "VNC connection failed\n"); |
| + sprintf(msgbuf, "VNC connection failed\n"); |
| + wmsg(msgbuf, 1); |
| |
| - if (reason != NULL) |
| - free(reason); |
| + if (reason != NULL) { |
| + free(reason); |
| + } |
| } |
| |
| /* |
| @@ -1358,9 +3634,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 +3738,3 @@ |
| |
| cinfo->src = &jpegSrcManager; |
| } |
| - |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/rre.c vnc_unixsrc/vncviewer/rre.c |
| --- vnc_unixsrc.orig/vncviewer/rre.c 2000-06-11 08:00:53.000000000 -0400 |
| +++ vnc_unixsrc/vncviewer/rre.c 2008-10-05 15:16:30.000000000 -0400 |
| @@ -29,6 +29,18 @@ |
| #define HandleRREBPP CONCAT2E(HandleRRE,BPP) |
| #define CARDBPP CONCAT2E(CARD,BPP) |
| |
| +#define FillRectangle(x, y, w, h, color) \ |
| + { \ |
| + XGCValues _gcv; \ |
| + _gcv.foreground = color; \ |
| + if (!appData.useXserverBackingStore) { \ |
| + FillScreen(x, y, w, h, _gcv.foreground); \ |
| + } else { \ |
| + XChangeGC(dpy, gc, GCForeground, &_gcv); \ |
| + XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \ |
| + } \ |
| + } |
| + |
| static Bool |
| HandleRREBPP (int rx, int ry, int rw, int rh) |
| { |
| @@ -49,11 +61,19 @@ |
| #if (BPP == 8) |
| gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix); |
| #else |
| +#if (BPP == 16) |
| + gcv.foreground = (appData.useBGR565 ? BGR565ToPixel[pix] : pix); |
| +#else |
| gcv.foreground = pix; |
| #endif |
| +#endif |
| |
| +#if 0 |
| XChangeGC(dpy, gc, GCForeground, &gcv); |
| XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); |
| +#else |
| + FillRectangle(rx, ry, rw, rh, gcv.foreground); |
| +#endif |
| |
| for (i = 0; i < hdr.nSubrects; i++) { |
| if (!ReadFromRFBServer((char *)&pix, sizeof(pix))) |
| @@ -70,13 +90,23 @@ |
| #if (BPP == 8) |
| gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix); |
| #else |
| +#if (BPP == 16) |
| + gcv.foreground = (appData.useBGR565 ? BGR565ToPixel[pix] : pix); |
| +#else |
| gcv.foreground = pix; |
| #endif |
| +#endif |
| |
| +#if 0 |
| XChangeGC(dpy, gc, GCForeground, &gcv); |
| XFillRectangle(dpy, desktopWin, gc, rx + subrect.x, ry + subrect.y, |
| subrect.w, subrect.h); |
| +#else |
| + FillRectangle(rx + subrect.x, ry + subrect.y, subrect.w, subrect.h, gcv.foreground); |
| +#endif |
| } |
| |
| return True; |
| } |
| + |
| +#undef FillRectangle |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/selection.c vnc_unixsrc/vncviewer/selection.c |
| --- vnc_unixsrc.orig/vncviewer/selection.c 2004-03-03 04:11:52.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/selection.c 2010-02-25 23:28:48.000000000 -0500 |
| @@ -43,13 +43,16 @@ |
| unsigned long* length, int* format); |
| static void LoseSelection(Widget w, Atom *selection); |
| |
| -static Bool iAmSelectionOwner = False; |
| +static Bool PrimarySelectionOwner = False; |
| +static Bool ClipboardSelectionOwner = False; |
| static Time prevSelectionTime = 0L; |
| static Time cutBufferTime = 0L; |
| |
| #define TIME_LATER(a, b) ((a) != 0 && ((b) == 0 || (INT32)((a) - (b)) > 0)) |
| |
| |
| +static Atom clipboard_atom = None; |
| + |
| /* |
| * InitialiseSelection() must be called after realizing widgets (because |
| * otherwise XtGetSelectionValue() fails). We register events on the root |
| @@ -62,22 +65,28 @@ |
| * available. |
| */ |
| |
| -void |
| -InitialiseSelection() |
| -{ |
| +static int dbg_sel = -1; |
| + |
| +void InitialiseSelection() { |
| #if XtSpecificationRelease >= 6 |
| - XtRegisterDrawable(dpy, DefaultRootWindow(dpy), toplevel); |
| + XtRegisterDrawable(dpy, DefaultRootWindow(dpy), toplevel); |
| #else |
| - _XtRegisterWindow(DefaultRootWindow(dpy), toplevel); |
| + _XtRegisterWindow(DefaultRootWindow(dpy), toplevel); |
| #endif |
| - XSelectInput(dpy, DefaultRootWindow(dpy), PropertyChangeMask); |
| + XSelectInput(dpy, DefaultRootWindow(dpy), PropertyChangeMask); |
| |
| - XtAddRawEventHandler(toplevel, PropertyChangeMask, False, CutBufferChange, |
| - NULL); |
| + XtAddRawEventHandler(toplevel, PropertyChangeMask, False, CutBufferChange, NULL); |
| |
| - XtGetSelectionValue(toplevel, XA_PRIMARY, |
| + clipboard_atom = XInternAtom(dpy, "CLIPBOARD", False); |
| + |
| + XtGetSelectionValue(toplevel, XA_PRIMARY, |
| XInternAtom(dpy, "TIMESTAMP", False), |
| GetInitialSelectionTimeCallback, NULL, CurrentTime); |
| + |
| + if (dbg_sel < 0) { |
| + dbg_sel = 0; |
| + if (getenv("SSVNC_DEBUG_SELECTION")) dbg_sel = 1; |
| + } |
| } |
| |
| |
| @@ -93,13 +102,16 @@ |
| Atom* selection, Atom* type, XtPointer value, |
| unsigned long* length, int* format) |
| { |
| - if (value && *format == 32 && *length == 1) |
| - prevSelectionTime = *(CARD32 *)value; |
| - else |
| - prevSelectionTime = 0L; |
| - |
| - if (value) |
| - XtFree(value); |
| + if (value && *format == 32 && *length == 1) { |
| + prevSelectionTime = *(CARD32 *)value; |
| + } else { |
| + prevSelectionTime = 0L; |
| + } |
| + |
| + if (value) { |
| + XtFree(value); |
| + } |
| + if (w || clientData || selection || type || value || length || format) {} |
| } |
| |
| |
| @@ -121,26 +133,30 @@ |
| void |
| SelectionToVNC(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| { |
| - Bool always = False; |
| + Bool always = appData.sendAlways; |
| + Atom sendsel = XA_PRIMARY; |
| |
| - if (*num_params != 0) { |
| - if (strcmp(params[0],"always") == 0) { |
| - always = True; |
| - } else if (strcmp(params[0],"new") == 0) { |
| - always = False; |
| - } else { |
| - fprintf(stderr,"Invalid params: SelectionToVNC(always|new)\n"); |
| - return; |
| - } |
| - } |
| - |
| - if (always) { |
| - XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL, |
| - TimeFromEvent(event)); |
| - } else { |
| - XtGetSelectionValue(w, XA_PRIMARY, XInternAtom(dpy, "TIMESTAMP", False), |
| - GetSelectionTimeCallback, NULL, TimeFromEvent(event)); |
| - } |
| + if (*num_params != 0) { |
| + if (strcmp(params[0],"always") == 0) { |
| + always = True; |
| + } else if (strcmp(params[0],"new") == 0) { |
| + always = False; |
| + } else { |
| + fprintf(stderr,"Invalid params: SelectionToVNC(always|new)\n"); |
| + return; |
| + } |
| + } |
| + if (appData.sendClipboard && clipboard_atom != None) { |
| + sendsel = clipboard_atom; |
| + } |
| + if (dbg_sel) fprintf(stderr, "SelectionToVNC %s\n", sendsel == XA_PRIMARY ? "PRIMARY" : "CLIPBOARD"); |
| + |
| + if (always) { |
| + XtGetSelectionValue(w, sendsel, XA_STRING, GetSelectionCallback, NULL, TimeFromEvent(event)); |
| + } else { |
| + XtGetSelectionValue(w, sendsel, XInternAtom(dpy, "TIMESTAMP", False), GetSelectionTimeCallback, NULL, TimeFromEvent(event)); |
| + } |
| + if (w || event || params || num_params) {} |
| } |
| |
| |
| @@ -158,10 +174,13 @@ |
| int len = *length; |
| char *str = (char *)value; |
| |
| - if (str) |
| - SendClientCutText(str, len); |
| - else |
| - SendCutBuffer(); |
| + if (str) { |
| + if (dbg_sel) fprintf(stderr, "SendClientCutText len: %d\n", len); |
| + SendClientCutText(str, len); |
| + } else if (!getenv("VNCVIEWER_NO_CUTBUFFER")) { |
| + SendCutBuffer(); |
| + } |
| + if (w || clientData || selection || type || value || length || format) {} |
| } |
| |
| |
| @@ -180,26 +199,24 @@ |
| Atom* type, XtPointer value, unsigned long* length, |
| int* format) |
| { |
| - if (value && *format == 32 && *length == 1) { |
| + if (value && *format == 32 && *length == 1) { |
| + Time t = *(CARD32 *)value; |
| |
| - Time t = *(CARD32 *)value; |
| - |
| - if (TIME_LATER(t, prevSelectionTime)) { |
| - prevSelectionTime = t; |
| - XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL, |
| - CurrentTime); |
| - } |
| - |
| - } else { |
| - |
| - if (TIME_LATER(cutBufferTime, prevSelectionTime)) { |
| - prevSelectionTime = cutBufferTime; |
| - SendCutBuffer(); |
| - } |
| - } |
| - |
| - if (value) |
| - XtFree(value); |
| + if (TIME_LATER(t, prevSelectionTime)) { |
| + prevSelectionTime = t; |
| + XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL, CurrentTime); |
| + } |
| + } else if (!getenv("VNCVIEWER_NO_CUTBUFFER")) { |
| + if (TIME_LATER(cutBufferTime, prevSelectionTime)) { |
| + prevSelectionTime = cutBufferTime; |
| + SendCutBuffer(); |
| + } |
| + } |
| + |
| + if (value) { |
| + XtFree(value); |
| + } |
| + if (w || clientData || selection || type || value || length || format) {} |
| } |
| |
| |
| @@ -209,16 +226,17 @@ |
| */ |
| |
| static void |
| -SendCutBuffer() |
| -{ |
| - char *str; |
| - int len; |
| +SendCutBuffer() { |
| + char *str; |
| + int len; |
| |
| - str = XFetchBytes(dpy, &len); |
| - if (!str) return; |
| + if (dbg_sel) fprintf(stderr, "SendCutBuffer len: %d\n", len); |
| |
| - SendClientCutText(str, len); |
| - XFree(str); |
| + str = XFetchBytes(dpy, &len); |
| + if (!str) return; |
| + |
| + SendClientCutText(str, len); |
| + XFree(str); |
| } |
| |
| |
| @@ -230,10 +248,12 @@ |
| static void |
| CutBufferChange(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont) |
| { |
| - if (ev->type != PropertyNotify || ev->xproperty.atom != XA_CUT_BUFFER0) |
| - return; |
| + if (ev->type != PropertyNotify || ev->xproperty.atom != XA_CUT_BUFFER0) { |
| + return; |
| + } |
| |
| - cutBufferTime = ev->xproperty.time; |
| + cutBufferTime = ev->xproperty.time; |
| + if (w || ptr || cont) {} |
| } |
| |
| |
| @@ -249,36 +269,69 @@ |
| void |
| SelectionFromVNC(Widget w, XEvent *event, String *params, Cardinal *num_params) |
| { |
| - Bool always = False; |
| - Time t = TimeFromEvent(event); |
| - |
| - if (*num_params != 0) { |
| - if (strcmp(params[0],"always") == 0) { |
| - always = True; |
| - } else if (strcmp(params[0],"new") == 0) { |
| - always = False; |
| - } else { |
| - fprintf(stderr,"Invalid params: SelectionFromVNC(always|new)\n"); |
| - return; |
| - } |
| - } |
| - |
| - if (t == CurrentTime) { |
| - fprintf(stderr,"Error in translations: SelectionFromVNC() must act on " |
| - "event with time field\n"); |
| - return; |
| - } |
| - |
| - if (!serverCutText || (!always && !newServerCutText)) |
| - return; |
| - |
| - newServerCutText = False; |
| - |
| - XStoreBytes(dpy, serverCutText, strlen(serverCutText)); |
| - if (XtOwnSelection(desktop, XA_PRIMARY, t, ConvertSelection, LoseSelection, |
| - NULL)) { |
| - iAmSelectionOwner = True; |
| - } |
| + Bool always = False; |
| + Time t = TimeFromEvent(event); |
| + int hold_primary = 0; |
| + int hold_clipboard = 0; |
| + |
| + if (dbg_sel) fprintf(stderr, "SelectionFromVNC\n"); |
| + |
| + if (*num_params != 0) { |
| + if (strcmp(params[0],"always") == 0) { |
| + always = True; |
| + } else if (strcmp(params[0],"new") == 0) { |
| + always = False; |
| + } else { |
| + fprintf(stderr,"Invalid params: SelectionFromVNC(always|new)\n"); |
| + return; |
| + } |
| + } |
| + |
| + if (t == CurrentTime) { |
| + fprintf(stderr,"Error in translations: SelectionFromVNC() must act on " |
| + "event with time field\n"); |
| + return; |
| + } |
| + |
| + if (!serverCutText || (!always && !newServerCutText)) { |
| + return; |
| + } |
| + |
| + newServerCutText = False; |
| + |
| + if (appData.appShare) { |
| + if (strstr(serverCutText, "X11VNC_APPSHARE_CMD:") == serverCutText) { |
| + /* do something with it? */ |
| + return; |
| + } |
| + } |
| + |
| + XStoreBytes(dpy, serverCutText, strlen(serverCutText)); |
| + |
| + if (appData.recvText == NULL) { |
| + appData.recvText = strdup("both"); |
| + } |
| + if (!strcasecmp(appData.recvText, "primary")) { |
| + hold_primary = 1; |
| + } else if (!strcasecmp(appData.recvText, "clipboard")) { |
| + hold_clipboard = 1; |
| + } else { |
| + hold_primary = hold_clipboard = 1; |
| + } |
| + |
| + if (!hold_primary) { |
| + ; |
| + } else if (XtOwnSelection(desktop, XA_PRIMARY, t, ConvertSelection, LoseSelection, NULL)) { |
| + PrimarySelectionOwner = True; |
| + if (dbg_sel) fprintf(stderr, "Own PRIMARY\n"); |
| + } |
| + if (!hold_clipboard || clipboard_atom == None) { |
| + ; |
| + } else if (XtOwnSelection(desktop, clipboard_atom, t, ConvertSelection, LoseSelection, NULL)) { |
| + ClipboardSelectionOwner = True; |
| + if (dbg_sel) fprintf(stderr, "Own CLIPBOARD\n"); |
| + } |
| + if (w || event || params || num_params) {} |
| } |
| |
| |
| @@ -293,37 +346,36 @@ |
| XtPointer* value, unsigned long* length, int* format) |
| { |
| |
| - if (*target == XA_STRING && serverCutText != NULL) { |
| - *type = XA_STRING; |
| - *length = strlen(serverCutText); |
| - *value = (XtPointer)XtMalloc(*length); |
| - memcpy((char*)*value, serverCutText, *length); |
| - *format = 8; |
| - return True; |
| - } |
| + if (*target == XA_STRING && serverCutText != NULL) { |
| + *type = XA_STRING; |
| + *length = strlen(serverCutText); |
| + *value = (XtPointer)XtMalloc(*length); |
| + memcpy((char*)*value, serverCutText, *length); |
| + *format = 8; |
| + return True; |
| + } |
| |
| - if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type, |
| + if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type, |
| (XPointer*)value, length, format)) { |
| - if (*target == XInternAtom(dpy, "TARGETS", False)) { |
| - /* add STRING to list of standard targets */ |
| - Atom* targetP; |
| - Atom* std_targets = (Atom*)*value; |
| - unsigned long std_length = *length; |
| - |
| - *length = std_length + 1; |
| - *value = (XtPointer)XtMalloc(sizeof(Atom)*(*length)); |
| - targetP = *(Atom**)value; |
| - *targetP++ = XA_STRING; |
| - memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); |
| - XtFree((char*)std_targets); |
| - *type = XA_ATOM; |
| - *format = 32; |
| - return True; |
| - } |
| - |
| - return True; |
| - } |
| - return False; |
| + if (*target == XInternAtom(dpy, "TARGETS", False)) { |
| + /* add STRING to list of standard targets */ |
| + Atom* targetP; |
| + Atom* std_targets = (Atom*)*value; |
| + unsigned long std_length = *length; |
| + |
| + *length = std_length + 1; |
| + *value = (XtPointer)XtMalloc(sizeof(Atom)*(*length)); |
| + targetP = *(Atom**)value; |
| + *targetP++ = XA_STRING; |
| + memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); |
| + XtFree((char*)std_targets); |
| + *type = XA_ATOM; |
| + *format = 32; |
| + return True; |
| + } |
| + return True; |
| + } |
| + return False; |
| } |
| |
| |
| @@ -332,7 +384,13 @@ |
| */ |
| |
| static void |
| -LoseSelection(Widget w, Atom *selection) |
| -{ |
| - iAmSelectionOwner = False; |
| +LoseSelection(Widget w, Atom *selection) { |
| + if (*selection == XA_PRIMARY) { |
| + if (dbg_sel) fprintf(stderr, "lost PRIMARY\n"); |
| + PrimarySelectionOwner = False; |
| + } else if (clipboard_atom != None && *selection == clipboard_atom) { |
| + if (dbg_sel) fprintf(stderr, "lost CLIPBOARD\n"); |
| + ClipboardSelectionOwner = False; |
| + } |
| + if (w) {} |
| } |
| 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 2010-02-25 23:40:58.000000000 -0500 |
| @@ -30,71 +30,113 @@ |
| static Bool caughtShmError = False; |
| static Bool needShmCleanup = False; |
| |
| -void |
| -ShmCleanup() |
| -{ |
| - fprintf(stderr,"ShmCleanup called\n"); |
| - if (needShmCleanup) { |
| - shmdt(shminfo.shmaddr); |
| - shmctl(shminfo.shmid, IPC_RMID, 0); |
| - needShmCleanup = False; |
| - } |
| +static int ShmCreationXErrorHandler(Display *dpy, XErrorEvent *error) { |
| + caughtShmError = True; |
| + if (dpy || error) {} |
| + return 0; |
| } |
| |
| -static int |
| -ShmCreationXErrorHandler(Display *dpy, XErrorEvent *error) |
| -{ |
| - caughtShmError = True; |
| - return 0; |
| +void ShmDetach() { |
| + if (needShmCleanup) { |
| + XErrorHandler oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler); |
| + fprintf(stderr,"ShmDetach called.\n"); |
| + XShmDetach(dpy, &shminfo); |
| + XSync(dpy, False); |
| + XSetErrorHandler(oldXErrorHandler); |
| + } |
| } |
| |
| -XImage * |
| -CreateShmImage() |
| -{ |
| - XImage *image; |
| - XErrorHandler oldXErrorHandler; |
| - |
| - if (!XShmQueryExtension(dpy)) |
| - return NULL; |
| - |
| - image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo, |
| - si.framebufferWidth, si.framebufferHeight); |
| - if (!image) return NULL; |
| - |
| - shminfo.shmid = shmget(IPC_PRIVATE, |
| - image->bytes_per_line * image->height, |
| - IPC_CREAT|0777); |
| +void ShmCleanup() { |
| + if (needShmCleanup) { |
| + fprintf(stderr,"ShmCleanup called.\n"); |
| + XSync(dpy, False); |
| + shmdt(shminfo.shmaddr); |
| + shmctl(shminfo.shmid, IPC_RMID, 0); |
| |
| - if (shminfo.shmid == -1) { |
| - XDestroyImage(image); |
| - return NULL; |
| - } |
| - |
| - shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0); |
| - |
| - if (shminfo.shmaddr == (char *)-1) { |
| - XDestroyImage(image); |
| - shmctl(shminfo.shmid, IPC_RMID, 0); |
| - return NULL; |
| - } |
| + needShmCleanup = False; |
| + } |
| +} |
| |
| - shminfo.readOnly = True; |
| +Bool UsingShm() { |
| + return needShmCleanup; |
| +} |
| |
| - oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler); |
| - XShmAttach(dpy, &shminfo); |
| - XSync(dpy, False); |
| - XSetErrorHandler(oldXErrorHandler); |
| +int scale_round(int len, double fac); |
| +extern int scale_x, scale_y; |
| +extern double scale_factor_x, scale_factor_y; |
| |
| - if (caughtShmError) { |
| - XDestroyImage(image); |
| - shmdt(shminfo.shmaddr); |
| - shmctl(shminfo.shmid, IPC_RMID, 0); |
| - return NULL; |
| - } |
| +XImage * |
| +CreateShmImage(int do_ycrop) |
| +{ |
| + XImage *image; |
| + XErrorHandler oldXErrorHandler; |
| + int ymax = si.framebufferHeight; |
| + int xmax = si.framebufferWidth; |
| + |
| + if (!XShmQueryExtension(dpy)) { |
| + return NULL; |
| + } |
| + if (!appData.useShm) { |
| + return NULL; |
| + } |
| + if (do_ycrop == -1) { |
| + /* kludge to test for shm prescence */ |
| + return (XImage *) 0x1; |
| + } |
| + |
| + if (do_ycrop) { |
| + ymax = appData.yCrop; |
| + } |
| + |
| + if (scale_x > 0) { |
| + xmax = scale_round(xmax, scale_factor_x); |
| + ymax = scale_round(ymax, scale_factor_y); |
| + } |
| + |
| + image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo, xmax, ymax); |
| + if (!image) { |
| + return NULL; |
| + } |
| + |
| + shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height, IPC_CREAT|0777); |
| + |
| + if (shminfo.shmid == -1) { |
| + XDestroyImage(image); |
| + if (0) 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); |
| +#if 0 |
| + fprintf(stderr, "CreateShmImage: destroyed 'image' (2)\n"); |
| +#endif |
| + 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); |
| +#if 0 |
| + fprintf(stderr, "CreateShmImage: destroyed 'image' (3)\n"); |
| +#endif |
| + 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 2010-04-18 11:41:07.000000000 -0400 |
| @@ -22,17 +22,31 @@ |
| */ |
| |
| #include <unistd.h> |
| +#include <time.h> |
| #include <sys/socket.h> |
| #include <errno.h> |
| #include <netinet/in.h> |
| #include <netinet/tcp.h> |
| #include <arpa/inet.h> |
| +#include <sys/un.h> |
| #include <netdb.h> |
| #include <fcntl.h> |
| #include <assert.h> |
| #include <vncviewer.h> |
| |
| +#ifndef SOL_IPV6 |
| +#ifdef IPPROTO_IPV6 |
| +#define SOL_IPV6 IPPROTO_IPV6 |
| +#endif |
| +#endif |
| + |
| +/* Solaris (sysv?) needs INADDR_NONE */ |
| +#ifndef INADDR_NONE |
| +#define INADDR_NONE ((in_addr_t) 0xffffffff) |
| +#endif |
| + |
| void PrintInHex(char *buf, int len); |
| +extern void printChat(char *, Bool); |
| |
| Bool errorMessageOnReadFailure = True; |
| |
| @@ -56,31 +70,396 @@ |
| */ |
| |
| 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; |
| +#if 0 |
| + XtRemoveInput(*id); |
| +#endif |
| + XtRemoveInput(rfbsockId); |
| + if (do_xfrsockId) { |
| + XtRemoveInput(xfrsockId); |
| + } |
| + if (clientData || fd || id) {} |
| } |
| |
| static void |
| -ProcessXtEvents() |
| +xfrsockReadyCallback(XtPointer clientData, int *fd, XtInputId *id) |
| { |
| - rfbsockReady = False; |
| - XtAppAddInput(appContext, rfbsock, (XtPointer)XtInputReadMask, |
| - rfbsockReadyCallback, NULL); |
| - while (!rfbsockReady) { |
| - XtAppProcessEvent(appContext, XtIMAll); |
| - } |
| + xfrsockReady = True; |
| + XtRemoveInput(xfrsockId); |
| + if (do_rfbsockId) { |
| + XtRemoveInput(rfbsockId); |
| + } |
| + if (clientData || fd || id) {} |
| +} |
| + |
| + |
| +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; |
| + } |
| +if (0) 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 (hdr || len || i) {} |
| +#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); |
| +#if 0 |
| + fprintf(stderr, "last_filexfer-2a: %d\n", last_filexfer); |
| +#endif |
| + 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); |
| +#if 0 |
| + fprintf(stderr, "last_filexfer-2b: %d\n", last_filexfer); |
| +#endif |
| + |
| + 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; |
| +#if 0 |
| + fprintf(stderr, "grace: %d\n", grace); |
| + /* forgot that this is about... */ |
| +#endif |
| + usleep(10 * 1000); |
| + continue; |
| + } |
| + } |
| + break; |
| + } |
| + } |
| + if (igot) { |
| + last_filexfer = time(NULL); |
| +#if 0 |
| + fprintf(stderr, "last_filexfer-2c: %d\n", last_filexfer); |
| +#endif |
| + } |
| +#if 0 |
| +fprintf(stderr, "Out CheckFileXfer\n"); |
| +#endif |
| + 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: ", False); |
| +} |
| + |
| +static time_t time_mark; |
| +extern int delay_filexfer; |
| +#include <sys/stat.h> |
| + |
| +extern double start_time; |
| + |
| +void ProcessXtEvents() |
| +{ |
| + int 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 |
| + if (0) fprintf(stderr, "ProcessXtEvents: %d %.4f\n", skip_XtUpdateAll, dnow() - start_time); |
| +#endif |
| + |
| + 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) { |
| + check_chat = 1; |
| + last_check = now; |
| + } |
| + } |
| + if (check_chat) { |
| + if (appData.chatActive) { |
| + chat_was_active = 1; |
| + } |
| + if (!appData.termChat) { |
| + CheckTextInput(); |
| + } else { |
| + check_term_chat(); |
| + } |
| + } |
| + |
| + if (skip_XtUpdate) { |
| + return; |
| + } |
| + |
| + rfbsockReady = False; |
| + xfrsockReady = False; |
| + do_rfbsockId = 1; |
| + rfbsockId = XtAppAddInput(appContext, rfbsock, (XtPointer)XtInputReadMask, |
| + rfbsockReadyCallback, NULL); |
| + |
| + do_xfrsockId = 0; |
| + if (filexfer_sock >= 0) { |
| + do_xfrsockId = 1; |
| + xfrsockId = XtAppAddInput(appContext, filexfer_sock, (XtPointer)XtInputReadMask, |
| + xfrsockReadyCallback, NULL); |
| + } |
| + |
| + time_mark = time(NULL); |
| + |
| + if (appData.fileActive) { |
| + static int first = 1; |
| + if (first) { |
| + fprintf(stderr, "PXT: dynamic fb updates during filexfer: %d\n", dyn); |
| + first = 0; |
| + } |
| + } |
| + |
| + if (db) fprintf(stderr, "XtAppAddInput: "); |
| + while (!rfbsockReady && !xfrsockReady) { |
| + int w = si.framebufferWidth; |
| + int h = si.framebufferHeight; |
| + if (db) fprintf(stderr, "."); |
| + if (dyn && filexfer_sock >= 0 && time(NULL) > time_mark + delay_filexfer) { |
| + SendFramebufferUpdateRequest(0, 0, w, h, False); |
| + } |
| + XtAppProcessEvent(appContext, XtIMAll); |
| + } |
| + if (db) fprintf(stderr, " done. r: %d x: %d\n", rfbsockReady, xfrsockReady); |
| + |
| + if (xfrsockReady) { |
| + CheckFileXfer(); |
| + } |
| } |
| |
| Bool |
| ReadFromRFBServer(char *out, unsigned int n) |
| { |
| +#if 0 |
| + double start = dnow(), dn = n; |
| +#endif |
| if (n <= buffered) { |
| memcpy(out, bufoutptr, n); |
| bufoutptr += n; |
| buffered -= n; |
| +#if 0 |
| +fprintf(stderr, "R0: %06d\n", (int) dn); |
| +#endif |
| return True; |
| } |
| |
| @@ -119,6 +498,9 @@ |
| memcpy(out, bufoutptr, n); |
| bufoutptr += n; |
| buffered -= n; |
| +#if 0 |
| +fprintf(stderr, "R1: %06d %06d %10.2f KB/sec\n", (int) dn, buffered+n, 1e-3 * (buffered+n)/(dnow() - start)); |
| +#endif |
| return True; |
| |
| } else { |
| @@ -146,11 +528,16 @@ |
| n -= i; |
| } |
| |
| +#if 0 |
| +fprintf(stderr, "R2: %06d %06d %10.2f KB/sec\n", (int) dn, (int) dn, 1e-3 * (dn)/(dnow() - start)); |
| +#endif |
| return True; |
| } |
| } |
| |
| |
| +int currentMsg = -1; |
| + |
| /* |
| * Write an exact number of bytes, and don't return until you've sent them. |
| */ |
| @@ -158,81 +545,321 @@ |
| 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; |
| +} |
| + |
| +char *ipv6_getipaddr(struct sockaddr *paddr, int addrlen) { |
| +#if defined(AF_INET6) && defined(NI_NUMERICHOST) |
| + char name[200]; |
| + if (appData.noipv6) { |
| + return strdup("unknown"); |
| + } |
| + if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST) == 0) { |
| + return strdup(name); |
| + } |
| +#endif |
| + if (paddr || addrlen) {} |
| + return strdup("unknown"); |
| +} |
| + |
| +char *ipv6_getnameinfo(struct sockaddr *paddr, int addrlen) { |
| +#if defined(AF_INET6) |
| + char name[200]; |
| + if (appData.noipv6) { |
| + return strdup("unknown"); |
| + } |
| + if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, 0) == 0) { |
| + return strdup(name); |
| + } |
| +#endif |
| + if (paddr || addrlen) {} |
| + return strdup("unknown"); |
| +} |
| + |
| +int dotted_ip(char *host, int partial) { |
| + int len, dots = 0; |
| + char *p = host; |
| + |
| + if (!host) { |
| + return 0; |
| + } |
| + |
| + if (!isdigit((unsigned char) host[0])) { |
| + return 0; |
| + } |
| + |
| + len = strlen(host); |
| + if (!partial && !isdigit((unsigned char) host[len-1])) { |
| + return 0; |
| + } |
| + |
| + while (*p != '\0') { |
| + if (*p == '.') dots++; |
| + if (*p == '.' || isdigit((unsigned char) (*p))) { |
| + p++; |
| + continue; |
| + } |
| + return 0; |
| + } |
| + if (!partial && dots != 3) { |
| + return 0; |
| + } |
| + return 1; |
| +} |
| |
| /* |
| * ConnectToTcpAddr connects to the given TCP port. |
| */ |
| |
| -int |
| -ConnectToTcpAddr(unsigned int host, int port) |
| -{ |
| - int sock; |
| - struct sockaddr_in addr; |
| - int one = 1; |
| - |
| - addr.sin_family = AF_INET; |
| - addr.sin_port = htons(port); |
| - addr.sin_addr.s_addr = host; |
| +int ConnectToTcpAddr(const char *hostname, int port) { |
| + int sock = -1, one = 1; |
| + unsigned int host; |
| + struct sockaddr_in addr; |
| + |
| + if (appData.noipv4) { |
| + fprintf(stderr, "ipv4 is disabled via VNCVIEWER_NO_IPV4/-noipv4.\n"); |
| + goto try6; |
| + } |
| |
| - sock = socket(AF_INET, SOCK_STREAM, 0); |
| - if (sock < 0) { |
| - fprintf(stderr,programName); |
| - perror(": ConnectToTcpAddr: socket"); |
| - return -1; |
| - } |
| + if (!StringToIPAddr(hostname, &host)) { |
| + fprintf(stderr, "Could not convert '%s' to ipv4 host address.\n", hostname); |
| + goto try6; |
| + } |
| |
| - if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { |
| - fprintf(stderr,programName); |
| - perror(": ConnectToTcpAddr: connect"); |
| - close(sock); |
| - return -1; |
| - } |
| + memset(&addr, 0, sizeof(struct sockaddr_in)); |
| |
| - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, |
| - (char *)&one, sizeof(one)) < 0) { |
| - fprintf(stderr,programName); |
| - perror(": ConnectToTcpAddr: setsockopt"); |
| - close(sock); |
| - return -1; |
| - } |
| + addr.sin_family = AF_INET; |
| + addr.sin_port = htons(port); |
| + addr.sin_addr.s_addr = host; |
| + |
| + sock = socket(AF_INET, SOCK_STREAM, 0); |
| + if (sock < 0) { |
| + perror("ConnectToTcpAddr[ipv4]: socket"); |
| + sock = -1; |
| + goto try6; |
| + } |
| + |
| + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { |
| + perror("ConnectToTcpAddr[ipv4]: connect"); |
| + close(sock); |
| + sock = -1; |
| + goto try6; |
| + } |
| + |
| + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { |
| + perror("ConnectToTcpAddr[ipv4]: setsockopt"); |
| + close(sock); |
| + sock = -1; |
| + goto try6; |
| + } |
| |
| - return sock; |
| + if (sock >= 0) { |
| + return sock; |
| + } |
| + |
| + try6: |
| + |
| +#ifdef AF_INET6 |
| + if (!appData.noipv6) { |
| + int err; |
| + struct addrinfo *ai; |
| + struct addrinfo hints; |
| + char service[32], *host2, *q; |
| + |
| + fprintf(stderr, "Trying ipv6 connection to '%s'\n", hostname); |
| + |
| + memset(&hints, 0, sizeof(hints)); |
| + sprintf(service, "%d", port); |
| + |
| + hints.ai_family = AF_UNSPEC; |
| + hints.ai_socktype = SOCK_STREAM; |
| +#ifdef AI_ADDRCONFIG |
| + hints.ai_flags |= AI_ADDRCONFIG; |
| +#endif |
| +#ifdef AI_NUMERICSERV |
| + hints.ai_flags |= AI_NUMERICSERV; |
| +#endif |
| + if (!strcmp(hostname, "localhost")) { |
| + host2 = strdup("::1"); |
| + } else if (!strcmp(hostname, "127.0.0.1")) { |
| + host2 = strdup("::1"); |
| + } else if (hostname[0] == '[') { |
| + host2 = strdup(hostname+1); |
| + } else { |
| + host2 = strdup(hostname); |
| + } |
| + q = strrchr(host2, ']'); |
| + if (q) { |
| + *q = '\0'; |
| + } |
| + |
| + err = getaddrinfo(host2, service, &hints, &ai); |
| + if (err != 0) { |
| + fprintf(stderr, "ConnectToTcpAddr[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err)); |
| + usleep(100 * 1000); |
| + err = getaddrinfo(host2, service, &hints, &ai); |
| + } |
| + free(host2); |
| + |
| + if (err != 0) { |
| + fprintf(stderr, "ConnectToTcpAddr[ipv6]: getaddrinfo[%d]: %s (2nd try)\n", err, gai_strerror(err)); |
| + } else { |
| + struct addrinfo *ap = ai; |
| + while (ap != NULL) { |
| + int fd = -1; |
| + char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen); |
| + if (s) { |
| + fprintf(stderr, "ConnectToTcpAddr[ipv6]: trying ip-addr: '%s'\n", s); |
| + free(s); |
| + } |
| + if (appData.noipv4) { |
| + struct sockaddr_in6 *s6ptr; |
| + if (ap->ai_family != AF_INET6) { |
| + fprintf(stderr, "ConnectToTcpAddr[ipv6]: skipping AF_INET address under VNCVIEWER_NO_IPV4/-noipv4\n"); |
| + ap = ap->ai_next; |
| + continue; |
| + } |
| +#ifdef IN6_IS_ADDR_V4MAPPED |
| + s6ptr = (struct sockaddr_in6 *) ap->ai_addr; |
| + if (IN6_IS_ADDR_V4MAPPED(&(s6ptr->sin6_addr))) { |
| + fprintf(stderr, "ConnectToTcpAddr[ipv6]: skipping V4MAPPED address under VNCVIEWER_NO_IPV4/-noipv4\n"); |
| + ap = ap->ai_next; |
| + continue; |
| + } |
| +#endif |
| + } |
| + |
| + fd = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); |
| + if (fd == -1) { |
| + perror("ConnectToTcpAddr[ipv6]: socket"); |
| + } else { |
| + int dmsg = 0; |
| + int res = connect(fd, ap->ai_addr, ap->ai_addrlen); |
| +#if defined(SOL_IPV6) && defined(IPV6_V6ONLY) |
| + if (res != 0) { |
| + int zero = 0; |
| + perror("ConnectToTcpAddr[ipv6]: connect"); |
| + dmsg = 1; |
| + if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (char *)&zero, sizeof(zero)) == 0) { |
| + fprintf(stderr, "ConnectToTcpAddr[ipv6]: trying again with IPV6_V6ONLY=0\n"); |
| + res = connect(fd, ap->ai_addr, ap->ai_addrlen); |
| + dmsg = 0; |
| + } |
| + } |
| +#endif |
| + if (res == 0) { |
| + fprintf(stderr, "ConnectToTcpAddr[ipv6]: connect OK\n"); |
| + sock = fd; |
| + break; |
| + } else { |
| + if (!dmsg) perror("ConnectToTcpAddr[ipv6]: connect"); |
| + close(fd); |
| + } |
| + } |
| + ap = ap->ai_next; |
| + } |
| + freeaddrinfo(ai); |
| + } |
| + if (sock >= 0 && setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { |
| + perror("ConnectToTcpAddr: setsockopt"); |
| + close(sock); |
| + sock = -1; |
| + } |
| + } |
| +#endif |
| + 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 |
| @@ -242,29 +869,31 @@ |
| int |
| FindFreeTcpPort(void) |
| { |
| - int sock, port; |
| - struct sockaddr_in addr; |
| + int sock, port; |
| + struct sockaddr_in addr; |
| |
| - addr.sin_family = AF_INET; |
| - addr.sin_addr.s_addr = INADDR_ANY; |
| + memset(&addr, 0, sizeof(struct sockaddr_in)); |
| |
| - sock = socket(AF_INET, SOCK_STREAM, 0); |
| - if (sock < 0) { |
| - fprintf(stderr,programName); |
| - perror(": FindFreeTcpPort: socket"); |
| - return 0; |
| - } |
| + addr.sin_family = AF_INET; |
| + addr.sin_addr.s_addr = INADDR_ANY; |
| |
| - for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) { |
| - addr.sin_port = htons((unsigned short)port); |
| - if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { |
| - close(sock); |
| - return port; |
| - } |
| - } |
| + sock = socket(AF_INET, SOCK_STREAM, 0); |
| + if (sock < 0) { |
| + fprintf(stderr,programName); |
| + perror(": FindFreeTcpPort: socket"); |
| + return 0; |
| + } |
| + |
| + for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) { |
| + addr.sin_port = htons((unsigned short)port); |
| + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { |
| + close(sock); |
| + return port; |
| + } |
| + } |
| |
| - close(sock); |
| - return 0; |
| + close(sock); |
| + return 0; |
| } |
| |
| |
| @@ -272,47 +901,110 @@ |
| * ListenAtTcpPort starts listening at the given TCP port. |
| */ |
| |
| -int |
| -ListenAtTcpPort(int port) |
| -{ |
| - int sock; |
| - struct sockaddr_in addr; |
| - int one = 1; |
| - |
| - addr.sin_family = AF_INET; |
| - addr.sin_port = htons(port); |
| - addr.sin_addr.s_addr = INADDR_ANY; |
| +int use_loopback = 0; |
| |
| - sock = socket(AF_INET, SOCK_STREAM, 0); |
| - if (sock < 0) { |
| - fprintf(stderr,programName); |
| - perror(": ListenAtTcpPort: socket"); |
| - return -1; |
| - } |
| +int ListenAtTcpPort(int port) { |
| + int sock; |
| + struct sockaddr_in addr; |
| + int one = 1; |
| + |
| + if (appData.noipv4) { |
| + fprintf(stderr, "ipv4 is disabled via VNCVIEWER_NO_IPV4/-noipv4.\n"); |
| + return -1; |
| + } |
| |
| - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, |
| - (const char *)&one, sizeof(one)) < 0) { |
| - fprintf(stderr,programName); |
| - perror(": ListenAtTcpPort: setsockopt"); |
| - close(sock); |
| - return -1; |
| - } |
| + memset(&addr, 0, sizeof(struct sockaddr_in)); |
| |
| - if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { |
| - fprintf(stderr,programName); |
| - perror(": ListenAtTcpPort: bind"); |
| - close(sock); |
| - return -1; |
| - } |
| + addr.sin_family = AF_INET; |
| + addr.sin_port = htons(port); |
| + addr.sin_addr.s_addr = INADDR_ANY; |
| |
| - if (listen(sock, 5) < 0) { |
| - fprintf(stderr,programName); |
| - perror(": ListenAtTcpPort: listen"); |
| - close(sock); |
| - return -1; |
| - } |
| + 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) { |
| + perror("ListenAtTcpPort: socket"); |
| + return -1; |
| + } |
| |
| - return sock; |
| + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one)) < 0) { |
| + perror("ListenAtTcpPort: setsockopt"); |
| + close(sock); |
| + return -1; |
| + } |
| + |
| + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { |
| + perror("ListenAtTcpPort: bind"); |
| + close(sock); |
| + return -1; |
| + } |
| + |
| + if (listen(sock, 32) < 0) { |
| + perror("ListenAtTcpPort: listen"); |
| + close(sock); |
| + return -1; |
| + } |
| + |
| + return sock; |
| +} |
| + |
| +int ListenAtTcpPort6(int port) { |
| + int sock = -1; |
| +#ifdef AF_INET6 |
| + struct sockaddr_in6 sin; |
| + int one = 1; |
| + |
| + if (appData.noipv6) { |
| + fprintf(stderr, "ipv6 is disabled via VNCVIEWER_NO_IPV6/-noipv6.\n"); |
| + return -1; |
| + } |
| + |
| + sock = socket(AF_INET6, SOCK_STREAM, 0); |
| + if (sock < 0) { |
| + perror("ListenAtTcpPort[ipv6]: socket"); |
| + return -1; |
| + } |
| + |
| + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) { |
| + perror("ListenAtTcpPort[ipv6]: setsockopt1"); |
| + close(sock); |
| + return -1; |
| + } |
| + |
| +#if defined(SOL_IPV6) && defined(IPV6_V6ONLY) |
| + if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) { |
| + perror("ListenAtTcpPort[ipv6]: setsockopt2"); |
| + close(sock); |
| + return -1; |
| + } |
| +#endif |
| + |
| + memset((char *)&sin, 0, sizeof(sin)); |
| + sin.sin6_family = AF_INET6; |
| + sin.sin6_port = htons(port); |
| + sin.sin6_addr = in6addr_any; |
| + |
| + if (getenv("VNCVIEWER_LISTEN_LOCALHOST") || use_loopback) { |
| + sin.sin6_addr = in6addr_loopback; |
| + } |
| + |
| + if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { |
| + perror("ListenAtTcpPort[ipv6]: bind"); |
| + close(sock); |
| + return -1; |
| + } |
| + |
| + if (listen(sock, 32) < 0) { |
| + perror("ListenAtTcpPort[ipv6]: listen"); |
| + close(sock); |
| + return -1; |
| + } |
| + |
| +#endif |
| + if (port) {} |
| + return sock; |
| } |
| |
| |
| @@ -320,33 +1012,69 @@ |
| * AcceptTcpConnection accepts a TCP connection. |
| */ |
| |
| -int |
| -AcceptTcpConnection(int listenSock) |
| -{ |
| - int sock; |
| - struct sockaddr_in addr; |
| - int addrlen = sizeof(addr); |
| - int one = 1; |
| +int AcceptTcpConnection(int listenSock) { |
| + int sock; |
| + struct sockaddr_in addr; |
| + int addrlen = sizeof(addr); |
| + int one = 1; |
| + |
| + sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen); |
| + if (sock < 0) { |
| + perror("AcceptTcpConnection: accept"); |
| + return -1; |
| + } |
| |
| - sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen); |
| - if (sock < 0) { |
| - fprintf(stderr,programName); |
| - perror(": AcceptTcpConnection: accept"); |
| - return -1; |
| - } |
| + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { |
| + perror("AcceptTcpConnection: setsockopt"); |
| + close(sock); |
| + return -1; |
| + } |
| |
| - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, |
| - (char *)&one, sizeof(one)) < 0) { |
| - fprintf(stderr,programName); |
| - perror(": AcceptTcpConnection: setsockopt"); |
| - close(sock); |
| - return -1; |
| - } |
| + return sock; |
| +} |
| + |
| +char *accept6_ipaddr = NULL; |
| +char *accept6_hostname = NULL; |
| + |
| +int AcceptTcpConnection6(int listenSock) { |
| + int sock = -1; |
| +#ifdef AF_INET6 |
| + struct sockaddr_in6 addr; |
| + socklen_t addrlen = sizeof(addr); |
| + int one = 1; |
| + char *name; |
| + |
| + if (appData.noipv6) { |
| + return -1; |
| + } |
| + |
| + sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen); |
| + if (sock < 0) { |
| + perror("AcceptTcpConnection[ipv6]: accept"); |
| + return -1; |
| + } |
| + |
| + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { |
| + perror("AcceptTcpConnection[ipv6]: setsockopt"); |
| + close(sock); |
| + return -1; |
| + } |
| |
| - return sock; |
| + name = ipv6_getipaddr((struct sockaddr *) &addr, addrlen); |
| + if (!name) name = strdup("unknown"); |
| + accept6_ipaddr = name; |
| + fprintf(stderr, "AcceptTcpConnection6: ipv6 connection from: '%s'\n", name); |
| + |
| + name = ipv6_getnameinfo((struct sockaddr *) &addr, addrlen); |
| + if (!name) name = strdup("unknown"); |
| + accept6_hostname = name; |
| +#endif |
| + if (listenSock) {} |
| + return sock; |
| } |
| |
| |
| + |
| /* |
| * SetNonBlocking sets a socket into non-blocking mode. |
| */ |
| @@ -379,7 +1107,7 @@ |
| |
| *addr = inet_addr(str); |
| |
| - if (*addr != -1) |
| + if (*addr != (unsigned int) -1) |
| return True; |
| |
| hp = gethostbyname(str); |
| @@ -392,6 +1120,42 @@ |
| return False; |
| } |
| |
| +char *get_peer_ip(int sock) { |
| + struct sockaddr_in saddr; |
| + unsigned int saddr_len; |
| + int saddr_port; |
| + char *saddr_ip_str = NULL; |
| + |
| + saddr_len = sizeof(saddr); |
| + memset(&saddr, 0, sizeof(saddr)); |
| + saddr_port = -1; |
| + if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) { |
| + saddr_ip_str = inet_ntoa(saddr.sin_addr); |
| + } |
| + if (! saddr_ip_str) { |
| + saddr_ip_str = "unknown"; |
| + } |
| + return strdup(saddr_ip_str); |
| +} |
| + |
| +char *ip2host(char *ip) { |
| + char *str; |
| + struct hostent *hp; |
| + in_addr_t iaddr; |
| + |
| + iaddr = inet_addr(ip); |
| + if (iaddr == htonl(INADDR_NONE)) { |
| + return strdup("unknown"); |
| + } |
| + |
| + hp = gethostbyaddr((char *)&iaddr, sizeof(in_addr_t), AF_INET); |
| + if (!hp) { |
| + return strdup("unknown"); |
| + } |
| + str = strdup(hp->h_name); |
| + return str; |
| +} |
| + |
| |
| /* |
| * Test if the other end of a socket is on the same machine. |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tight.c vnc_unixsrc/vncviewer/tight.c |
| --- vnc_unixsrc.orig/vncviewer/tight.c 2002-04-30 09:07:31.000000000 -0400 |
| +++ vnc_unixsrc/vncviewer/tight.c 2008-10-05 15:16:35.000000000 -0400 |
| @@ -129,14 +129,21 @@ |
| #endif |
| |
| #if (BPP == 8) |
| - gcv.foreground = (appData.useBGR233) ? |
| - BGR233ToPixel[fill_colour] : fill_colour; |
| + gcv.foreground = (appData.useBGR233) ? BGR233ToPixel[fill_colour] : fill_colour; |
| +#else |
| +#if (BPP == 16) |
| + gcv.foreground = (appData.useBGR565) ? BGR565ToPixel[fill_colour] : fill_colour; |
| #else |
| gcv.foreground = fill_colour; |
| #endif |
| +#endif |
| |
| - XChangeGC(dpy, gc, GCForeground, &gcv); |
| - XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); |
| + if (!appData.useXserverBackingStore) { |
| + FillScreen(rx, ry, rw, rh, gcv.foreground); |
| + } else { |
| + XChangeGC(dpy, gc, GCForeground, &gcv); |
| + XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh); |
| + } |
| return True; |
| } |
| |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tmake vnc_unixsrc/vncviewer/tmake |
| --- vnc_unixsrc.orig/vncviewer/tmake 1969-12-31 19:00:00.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/tmake 2009-10-25 10:31:22.000000000 -0400 |
| @@ -0,0 +1,17 @@ |
| +#!/bin/sh |
| +TURBOVNC_DIR=/home/runge/turbojpeg |
| +make clean |
| +(cd ../libvncauth || exit 1; make) |
| +if [ "X$1" = "X-a" ]; then |
| + exit |
| +fi |
| +make CCOPTIONS=-DTURBOVNC EXTRA_LIBRARIES="-L$TURBOVNC_DIR -Xlinker --rpath=$TURBOVNC_DIR -Xlinker --rpath=/usr/local/lib -lturbojpeg" |
| +cp -p vncviewer vncviewer.turbovnc |
| +strip vncviewer.turbovnc |
| +ls -l vncviewer.turbovnc |
| +ldd vncviewer.turbovnc |
| + |
| +echo |
| +make clean all |
| +ls -l vncviewer |
| +ldd vncviewer |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/tunnel.c vnc_unixsrc/vncviewer/tunnel.c |
| --- vnc_unixsrc.orig/vncviewer/tunnel.c 2003-07-31 04:03:49.000000000 -0400 |
| +++ vnc_unixsrc/vncviewer/tunnel.c 2010-02-25 23:39:24.000000000 -0500 |
| @@ -100,7 +100,6 @@ |
| int *pargc, char **argv, int tunnelArgIndex) |
| { |
| char *pdisplay; |
| - int port; |
| |
| if (tunnelArgIndex >= *pargc - 1) |
| usage(); |
| @@ -132,6 +131,7 @@ |
| { |
| char *colonPos; |
| int len, portOffset; |
| + int disp; |
| |
| if (tunnelArgIndex >= *pargc - 2) |
| usage(); |
| @@ -150,10 +150,17 @@ |
| len--; |
| portOffset = 0; |
| } |
| - if (!len || strspn(colonPos, "-0123456789") != len) { |
| + if (!len || (int) strspn(colonPos, "-0123456789") != len) { |
| usage(); |
| } |
| +#if 0 |
| *remotePort = atoi(colonPos) + portOffset; |
| +#else |
| + disp = atoi(colonPos); |
| + if (portOffset != 0 && disp >= 100) |
| + portOffset = 0; |
| + *remotePort = disp + portOffset; |
| +#endif |
| } |
| |
| sprintf(lastArgv, "localhost::%d", localPort); |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/turbovnc/tight.c vnc_unixsrc/vncviewer/turbovnc/tight.c |
| --- vnc_unixsrc.orig/vncviewer/turbovnc/tight.c 1969-12-31 19:00:00.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/turbovnc/tight.c 2008-08-20 13:35:58.000000000 -0400 |
| @@ -0,0 +1,613 @@ |
| +/* |
| + * Copyright (C) 2005-2006 Sun Microsystems, Inc. All Rights Reserved. |
| + * Copyright (C) 2004 Landmark Graphics Corporation. All Rights Reserved. |
| + * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. |
| + * |
| + * This is free software; you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License as published by |
| + * the Free Software Foundation; either version 2 of the License, or |
| + * (at your option) any later version. |
| + * |
| + * This software is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with this software; if not, write to the Free Software |
| + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| + * USA. |
| + */ |
| + |
| +/* |
| + * tight.c - handle ``tight'' encoding. |
| + * |
| + * This file shouldn't be compiled directly. It is included multiple |
| + * times by rfbproto.c, each time with a different definition of the |
| + * macro BPP. For each value of BPP, this file defines a function |
| + * which handles a tight-encoded rectangle with BPP bits per pixel. |
| + * |
| + */ |
| + |
| +#define TIGHT_MIN_TO_COMPRESS 12 |
| + |
| +#define CARDBPP CONCAT2E(CARD,BPP) |
| +#define filterPtrBPP CONCAT2E(filterPtr,BPP) |
| + |
| +#define HandleTightBPP CONCAT2E(HandleTight,BPP) |
| +#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP) |
| +#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP) |
| +#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP) |
| +#define FilterCopyBPP CONCAT2E(FilterCopy,BPP) |
| +#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP) |
| +#define FilterGradientBPP CONCAT2E(FilterGradient,BPP) |
| + |
| +#if BPP != 8 |
| +#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP) |
| +#endif |
| + |
| +#ifndef RGB_TO_PIXEL |
| + |
| +#define RGB_TO_PIXEL(bpp,r,g,b) \ |
| + (((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift | \ |
| + ((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift | \ |
| + ((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift) |
| + |
| +#define RGB24_TO_PIXEL(bpp,r,g,b) \ |
| + ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255 \ |
| + << myFormat.redShift | \ |
| + (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \ |
| + << myFormat.greenShift | \ |
| + (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \ |
| + << myFormat.blueShift) |
| + |
| +#define RGB24_TO_PIXEL32(r,g,b) \ |
| + (((CARD32)(r) & 0xFF) << myFormat.redShift | \ |
| + ((CARD32)(g) & 0xFF) << myFormat.greenShift | \ |
| + ((CARD32)(b) & 0xFF) << myFormat.blueShift) |
| + |
| +#endif |
| + |
| +extern XImage *image; |
| + |
| +/* Type declarations */ |
| + |
| +typedef void (*filterPtrBPP)(int, int, int); |
| + |
| +/* Prototypes */ |
| + |
| +static int InitFilterCopyBPP (int rw, int rh); |
| +static int InitFilterPaletteBPP (int rw, int rh); |
| +static int InitFilterGradientBPP (int rw, int rh); |
| +static void FilterCopyBPP (int srcx, int srcy, int numRows); |
| +static void FilterPaletteBPP (int srcx, int srcy, int numRows); |
| +static void FilterGradientBPP (int srcx, int srcy, int numRows); |
| + |
| +static Bool DecompressJpegRectBPP(int x, int y, int w, int h); |
| + |
| +/* Definitions */ |
| + |
| +static Bool |
| +HandleTightBPP (int rx, int ry, int rw, int rh) |
| +{ |
| + CARDBPP fill_colour; |
| + XGCValues gcv; |
| + CARD8 comp_ctl; |
| + CARD8 filter_id; |
| + filterPtrBPP filterFn; |
| + z_streamp zs; |
| + int err, stream_id, compressedLen, bitsPixel; |
| + int bufferSize, rowSize, numRows; |
| + Bool readUncompressed = False; |
| + CARDBPP *rawData; |
| + |
| + if (!ReadFromRFBServer((char *)&comp_ctl, 1)) |
| + return False; |
| + |
| + /* Flush zlib streams if we are told by the server to do so. */ |
| + for (stream_id = 0; stream_id < 4; stream_id++) { |
| + if ((comp_ctl & 1) && zlibStreamActive[stream_id]) { |
| + if (inflateEnd (&zlibStream[stream_id]) != Z_OK && |
| + zlibStream[stream_id].msg != NULL) |
| + fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg); |
| + zlibStreamActive[stream_id] = False; |
| + } |
| + comp_ctl >>= 1; |
| + } |
| + |
| + if ((comp_ctl & rfbTightNoZlib) == rfbTightNoZlib) { |
| + comp_ctl &= ~(rfbTightNoZlib); |
| + readUncompressed = True; |
| + } |
| + |
| + /* Handle solid rectangles. */ |
| + if (comp_ctl == rfbTightFill) { |
| +#if BPP == 32 |
| + if (myFormat.depth == 24 && myFormat.redMax == 0xFF && |
| + myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { |
| + if (!ReadFromRFBServer(buffer, 3)) |
| + return False; |
| + fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]); |
| + } else { |
| + if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour))) |
| + return False; |
| + } |
| +#else |
| + if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour))) |
| + return False; |
| +#endif |
| + |
| +#if (BPP == 8) |
| + gcv.foreground = (appData.useBGR233) ? |
| + BGR233ToPixel[fill_colour] : fill_colour; |
| +#else |
| + gcv.foreground = fill_colour; |
| +#endif |
| + |
| + FillRectangle(&gcv, rx, ry, rw, rh); |
| + return True; |
| + } |
| + |
| +#if BPP == 8 |
| + if (comp_ctl == rfbTightJpeg) { |
| + fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n"); |
| + return False; |
| + } |
| +#else |
| + if (comp_ctl == rfbTightJpeg) { |
| + return DecompressJpegRectBPP(rx, ry, rw, rh); |
| + } |
| +#endif |
| + |
| + /* Quit on unsupported subencoding value. */ |
| + if (comp_ctl > rfbTightMaxSubencoding) { |
| + fprintf(stderr, "Tight encoding: bad subencoding value received.\n"); |
| + return False; |
| + } |
| + |
| + /* |
| + * Here primary compression mode handling begins. |
| + * Data was processed with optional filter + zlib compression. |
| + */ |
| + |
| + /* First, we should identify a filter to use. */ |
| + if ((comp_ctl & rfbTightExplicitFilter) != 0) { |
| + if (!ReadFromRFBServer((char*)&filter_id, 1)) |
| + return False; |
| + |
| + switch (filter_id) { |
| + case rfbTightFilterCopy: |
| + filterFn = FilterCopyBPP; |
| + bitsPixel = InitFilterCopyBPP(rw, rh); |
| + break; |
| + case rfbTightFilterPalette: |
| + filterFn = FilterPaletteBPP; |
| + bitsPixel = InitFilterPaletteBPP(rw, rh); |
| + break; |
| + case rfbTightFilterGradient: |
| + filterFn = FilterGradientBPP; |
| + bitsPixel = InitFilterGradientBPP(rw, rh); |
| + break; |
| + default: |
| + fprintf(stderr, "Tight encoding: unknown filter code received.\n"); |
| + return False; |
| + } |
| + } else { |
| + filterFn = FilterCopyBPP; |
| + bitsPixel = InitFilterCopyBPP(rw, rh); |
| + } |
| + if (bitsPixel == 0) { |
| + fprintf(stderr, "Tight encoding: error receiving palette.\n"); |
| + return False; |
| + } |
| + |
| + /* Determine if the data should be decompressed or just copied. */ |
| + rowSize = (rw * bitsPixel + 7) / 8; |
| + bufferSize = -1; |
| + if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) |
| + bufferSize = rh * rowSize; |
| + else if (readUncompressed) { |
| + bufferSize = (int)ReadCompactLen(); |
| + } |
| + if (bufferSize != -1) { |
| + uncompressedData = (char *)realloc(uncompressedData, bufferSize); |
| + if (!uncompressedData) { |
| + fprintf(stderr, "Memory allocation error\n"); |
| + return False; |
| + } |
| + if (!ReadFromRFBServer(uncompressedData, bufferSize)) |
| + return False; |
| + filterFn(rx, ry, rh); |
| + if (appData.useBGR233) CopyDataToImage(buffer, rx, ry, rw, rh); |
| + if (!appData.doubleBuffer) CopyImageToScreen(rx, ry, rw, rh); |
| + |
| + return True; |
| + } |
| + |
| + /* Read the length (1..3 bytes) of compressed data following. */ |
| + compressedLen = (int)ReadCompactLen(); |
| + if (compressedLen <= 0) { |
| + fprintf(stderr, "Incorrect data received from the server.\n"); |
| + return False; |
| + } |
| + |
| + /* Now let's initialize compression stream if needed. */ |
| + stream_id = comp_ctl & 0x03; |
| + zs = &zlibStream[stream_id]; |
| + if (!zlibStreamActive[stream_id]) { |
| + zs->zalloc = Z_NULL; |
| + zs->zfree = Z_NULL; |
| + zs->opaque = Z_NULL; |
| + err = inflateInit(zs); |
| + if (err != Z_OK) { |
| + if (zs->msg != NULL) |
| + fprintf(stderr, "InflateInit error: %s.\n", zs->msg); |
| + return False; |
| + } |
| + zlibStreamActive[stream_id] = True; |
| + } |
| + |
| + /* Read, decode and draw actual pixel data in a loop. */ |
| + |
| + compressedData = (char *)realloc(compressedData, compressedLen); |
| + if (!compressedData) { |
| + fprintf(stderr, "Memory allocation error\n"); |
| + return False; |
| + } |
| + uncompressedData = (char *)realloc(uncompressedData, rh * rowSize); |
| + if (!uncompressedData) { |
| + fprintf(stderr, "Memory allocation error\n"); |
| + return False; |
| + } |
| + |
| + if (!ReadFromRFBServer(compressedData, compressedLen)) |
| + return False; |
| + zs->next_in = (Bytef *)compressedData; |
| + zs->avail_in = compressedLen; |
| + zs->next_out = (Bytef *)uncompressedData; |
| + zs->avail_out = rh * rowSize; |
| + |
| + err = inflate(zs, Z_SYNC_FLUSH); |
| + if (err != Z_OK && err != Z_STREAM_END) { |
| + if (zs->msg != NULL) { |
| + fprintf(stderr, "Inflate error: %s.\n", zs->msg); |
| + } else { |
| + fprintf(stderr, "Inflate error: %d.\n", err); |
| + } |
| + return False; |
| + } |
| + |
| + filterFn(rx, ry, rh); |
| + if (appData.useBGR233) CopyDataToImage(buffer, rx, ry, rw, rh); |
| + if (!appData.doubleBuffer) CopyImageToScreen(rx, ry, rw, rh); |
| + |
| + return True; |
| +} |
| + |
| +/*---------------------------------------------------------------------------- |
| + * |
| + * Filter stuff. |
| + * |
| + */ |
| + |
| +/* |
| + The following variables are defined in rfbproto.c: |
| + static Bool cutZeros; |
| + static int rectWidth, rectColors; |
| + static CARD8 tightPalette[256*4]; |
| + static CARD8 tightPrevRow[2048*3*sizeof(CARD16)]; |
| +*/ |
| + |
| +static int |
| +InitFilterCopyBPP (int rw, int rh) |
| +{ |
| + rectWidth = rw; |
| + |
| +#if BPP == 32 |
| + if (myFormat.depth == 24 && myFormat.redMax == 0xFF && |
| + myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { |
| + cutZeros = True; |
| + return 24; |
| + } else { |
| + cutZeros = False; |
| + } |
| +#endif |
| + |
| + return BPP; |
| +} |
| + |
| +static void |
| +FilterCopyBPP (int srcx, int srcy, int numRows) |
| +{ |
| + CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line |
| + + srcx * image->bits_per_pixel/8]; |
| + int dstw = image->bytes_per_line / (image->bits_per_pixel / 8); |
| + int y; |
| +#if BPP == 32 |
| + int x; |
| +#endif |
| + |
| + if (appData.useBGR233) { |
| + dst = (CARDBPP *)buffer; |
| + dstw = rectWidth; |
| + } |
| + |
| +#if BPP == 32 |
| + if (cutZeros) { |
| + for (y = 0; y < numRows; y++) { |
| + for (x = 0; x < rectWidth; x++) { |
| + dst[y*dstw+x] = |
| + RGB24_TO_PIXEL32(uncompressedData[(y*rectWidth+x)*3], |
| + uncompressedData[(y*rectWidth+x)*3+1], |
| + uncompressedData[(y*rectWidth+x)*3+2]); |
| + } |
| + } |
| + return; |
| + } |
| +#endif |
| + |
| + for (y = 0; y < numRows; y++) |
| + memcpy (&dst[y*dstw], &uncompressedData[y*rectWidth], rectWidth * (BPP / 8)); |
| +} |
| + |
| +static int |
| +InitFilterGradientBPP (int rw, int rh) |
| +{ |
| + int bits; |
| + |
| + bits = InitFilterCopyBPP(rw, rh); |
| + if (cutZeros) |
| + memset(tightPrevRow, 0, rw * 3); |
| + else |
| + memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16)); |
| + |
| + return bits; |
| +} |
| + |
| +#if BPP == 32 |
| + |
| +static void |
| +FilterGradient24 (int srcx, int srcy, int numRows) |
| +{ |
| + CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line |
| + + srcx * image->bits_per_pixel/8]; |
| + int dstw = image->bytes_per_line / (image->bits_per_pixel / 8); |
| + int x, y, c; |
| + CARD8 thisRow[2048*3]; |
| + CARD8 pix[3]; |
| + int est[3]; |
| + |
| + if (appData.useBGR233) { |
| + dst = (CARDBPP *)buffer; |
| + dstw = rectWidth; |
| + } |
| + |
| + for (y = 0; y < numRows; y++) { |
| + |
| + /* First pixel in a row */ |
| + for (c = 0; c < 3; c++) { |
| + pix[c] = tightPrevRow[c] + uncompressedData[y*rectWidth*3+c]; |
| + thisRow[c] = pix[c]; |
| + } |
| + dst[y*dstw] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]); |
| + |
| + /* Remaining pixels of a row */ |
| + for (x = 1; x < rectWidth; x++) { |
| + for (c = 0; c < 3; c++) { |
| + est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] - |
| + (int)tightPrevRow[(x-1)*3+c]; |
| + if (est[c] > 0xFF) { |
| + est[c] = 0xFF; |
| + } else if (est[c] < 0x00) { |
| + est[c] = 0x00; |
| + } |
| + pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c]; |
| + thisRow[x*3+c] = pix[c]; |
| + } |
| + dst[y*dstw+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]); |
| + } |
| + |
| + memcpy(tightPrevRow, thisRow, rectWidth * 3); |
| + } |
| +} |
| + |
| +#endif |
| + |
| +static void |
| +FilterGradientBPP (int srcx, int srcy, int numRows) |
| +{ |
| + int x, y, c; |
| + CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line |
| + + srcx * image->bits_per_pixel/8]; |
| + int dstw = image->bytes_per_line / (image->bits_per_pixel / 8); |
| + CARDBPP *src = (CARDBPP *)uncompressedData; |
| + CARD16 *thatRow = (CARD16 *)tightPrevRow; |
| + CARD16 thisRow[2048*3]; |
| + CARD16 pix[3]; |
| + CARD16 max[3]; |
| + int shift[3]; |
| + int est[3]; |
| + |
| + if (appData.useBGR233) { |
| + dst = (CARDBPP *)buffer; |
| + dstw = rectWidth; |
| + } |
| + |
| +#if BPP == 32 |
| + if (cutZeros) { |
| + FilterGradient24(srcx, srcy, numRows); |
| + return; |
| + } |
| +#endif |
| + |
| + max[0] = myFormat.redMax; |
| + max[1] = myFormat.greenMax; |
| + max[2] = myFormat.blueMax; |
| + |
| + shift[0] = myFormat.redShift; |
| + shift[1] = myFormat.greenShift; |
| + shift[2] = myFormat.blueShift; |
| + |
| + for (y = 0; y < numRows; y++) { |
| + |
| + /* First pixel in a row */ |
| + for (c = 0; c < 3; c++) { |
| + pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]); |
| + thisRow[c] = pix[c]; |
| + } |
| + dst[y*dstw] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]); |
| + |
| + /* Remaining pixels of a row */ |
| + for (x = 1; x < rectWidth; x++) { |
| + for (c = 0; c < 3; c++) { |
| + est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c]; |
| + if (est[c] > (int)max[c]) { |
| + est[c] = (int)max[c]; |
| + } else if (est[c] < 0) { |
| + est[c] = 0; |
| + } |
| + pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]); |
| + thisRow[x*3+c] = pix[c]; |
| + } |
| + dst[y*dstw+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]); |
| + } |
| + memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16)); |
| + } |
| +} |
| + |
| +static int |
| +InitFilterPaletteBPP (int rw, int rh) |
| +{ |
| + int i; |
| + CARD8 numColors; |
| + CARDBPP *palette = (CARDBPP *)tightPalette; |
| + |
| + rectWidth = rw; |
| + |
| + if (!ReadFromRFBServer((char*)&numColors, 1)) |
| + return 0; |
| + |
| + rectColors = (int)numColors; |
| + if (++rectColors < 2) |
| + return 0; |
| + |
| +#if BPP == 32 |
| + if (myFormat.depth == 24 && myFormat.redMax == 0xFF && |
| + myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) { |
| + if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3)) |
| + return 0; |
| + for (i = rectColors - 1; i >= 0; i--) { |
| + palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3], |
| + tightPalette[i*3+1], |
| + tightPalette[i*3+2]); |
| + } |
| + return (rectColors == 2) ? 1 : 8; |
| + } |
| +#endif |
| + |
| + if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8))) |
| + return 0; |
| + |
| + return (rectColors == 2) ? 1 : 8; |
| +} |
| + |
| +static void |
| +FilterPaletteBPP (int srcx, int srcy, int numRows) |
| +{ |
| + int x, y, b, w; |
| + CARDBPP *dst = (CARDBPP *)&image->data[srcy * image->bytes_per_line |
| + + srcx * image->bits_per_pixel/8]; |
| + int dstw = image->bytes_per_line / (image->bits_per_pixel / 8); |
| + CARD8 *src = (CARD8 *)uncompressedData; |
| + CARDBPP *palette = (CARDBPP *)tightPalette; |
| + |
| + if (appData.useBGR233) { |
| + dst = (CARDBPP *)buffer; |
| + dstw = rectWidth; |
| + } |
| + |
| + if (rectColors == 2) { |
| + w = (rectWidth + 7) / 8; |
| + for (y = 0; y < numRows; y++) { |
| + for (x = 0; x < rectWidth / 8; x++) { |
| + for (b = 7; b >= 0; b--) |
| + dst[y*dstw+x*8+7-b] = palette[src[y*w+x] >> b & 1]; |
| + } |
| + for (b = 7; b >= 8 - rectWidth % 8; b--) { |
| + dst[y*dstw+x*8+7-b] = palette[src[y*w+x] >> b & 1]; |
| + } |
| + } |
| + } else { |
| + for (y = 0; y < numRows; y++) |
| + for (x = 0; x < rectWidth; x++) |
| + dst[y*dstw+x] = palette[(int)src[y*rectWidth+x]]; |
| + } |
| +} |
| + |
| +#if BPP != 8 |
| + |
| +/*---------------------------------------------------------------------------- |
| + * |
| + * JPEG decompression. |
| + * |
| + */ |
| + |
| +/* |
| + The following variables are defined in rfbproto.c: |
| + static Bool jpegError; |
| + static struct jpeg_source_mgr jpegSrcManager; |
| + static JOCTET *jpegBufferPtr; |
| + static size_t *jpegBufferLen; |
| +*/ |
| + |
| +static Bool |
| +DecompressJpegRectBPP(int x, int y, int w, int h) |
| +{ |
| + int compressedLen; |
| + char *dstptr; |
| + int ps, flags=0; |
| + |
| + compressedLen = (int)ReadCompactLen(); |
| + if (compressedLen <= 0) { |
| + fprintf(stderr, "Incorrect data received from the server.\n"); |
| + return False; |
| + } |
| + |
| + compressedData = (char *)realloc(compressedData, compressedLen); |
| + if (compressedData == NULL) { |
| + fprintf(stderr, "Memory allocation error.\n"); |
| + return False; |
| + } |
| + |
| + if (!ReadFromRFBServer(compressedData, compressedLen)) { |
| + return False; |
| + } |
| + |
| + if(!tjhnd) { |
| + if((tjhnd=tjInitDecompress())==NULL) { |
| + fprintf(stderr, "TurboJPEG error: %s\n", tjGetErrorStr()); |
| + return False; |
| + } |
| + } |
| + |
| + ps=image->bits_per_pixel/8; |
| + if(myFormat.bigEndian && ps==4) flags|=TJ_ALPHAFIRST; |
| + if(myFormat.redShift==16 && myFormat.blueShift==0) |
| + flags|=TJ_BGR; |
| + if(myFormat.bigEndian) flags^=TJ_BGR; |
| + |
| + dstptr=&image->data[image->bytes_per_line*y+x*ps]; |
| + if(tjDecompress(tjhnd, (unsigned char *)compressedData, (unsigned long)compressedLen, |
| + (unsigned char *)dstptr, w, image->bytes_per_line, h, ps, flags)==-1) { |
| + fprintf(stderr, "TurboJPEG error: %s\n", tjGetErrorStr()); |
| + return False; |
| + } |
| + |
| + if (!appData.doubleBuffer) |
| + CopyImageToScreen(x, y, w, h); |
| + |
| + return True; |
| +} |
| + |
| +#endif |
| + |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/turbovnc/turbojpeg.h vnc_unixsrc/vncviewer/turbovnc/turbojpeg.h |
| --- vnc_unixsrc.orig/vncviewer/turbovnc/turbojpeg.h 1969-12-31 19:00:00.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/turbovnc/turbojpeg.h 2008-04-03 04:28:56.000000000 -0400 |
| @@ -0,0 +1,229 @@ |
| +/* Copyright (C)2004 Landmark Graphics |
| + * Copyright (C)2005, 2006 Sun Microsystems, Inc. |
| + * |
| + * This library is free software and may be redistributed and/or modified under |
| + * the terms of the wxWindows Library License, Version 3.1 or (at your option) |
| + * any later version. The full license is in the LICENSE.txt file included |
| + * with this distribution. |
| + * |
| + * This library is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * wxWindows Library License for more details. |
| + */ |
| + |
| +#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) && defined(_WIN32) && defined(DLLDEFINE) |
| +#define DLLEXPORT __declspec(dllexport) |
| +#else |
| +#define DLLEXPORT |
| +#endif |
| + |
| +#define DLLCALL |
| + |
| +/* Subsampling */ |
| +#define NUMSUBOPT 4 |
| + |
| +enum {TJ_444=0, TJ_422, TJ_411, TJ_GRAYSCALE}; |
| + |
| +/* Flags */ |
| +#define TJ_BGR 1 |
| +#define TJ_BOTTOMUP 2 |
| +#define TJ_FORCEMMX 8 /* Force IPP to use MMX code even if SSE available */ |
| +#define TJ_FORCESSE 16 /* Force IPP to use SSE1 code even if SSE2 available */ |
| +#define TJ_FORCESSE2 32 /* Force IPP to use SSE2 code (useful if auto-detect is not working properly) */ |
| +#define TJ_ALPHAFIRST 64 /* BGR buffer is ABGR and RGB buffer is ARGB */ |
| +#define TJ_FORCESSE3 128 /* Force IPP to use SSE3 code (useful if auto-detect is not working properly) */ |
| + |
| +typedef void* tjhandle; |
| + |
| +#define TJPAD(p) (((p)+3)&(~3)) |
| +#ifndef max |
| + #define max(a,b) ((a)>(b)?(a):(b)) |
| +#endif |
| + |
| +#ifdef __cplusplus |
| +extern "C" { |
| +#endif |
| + |
| +/* API follows */ |
| + |
| + |
| +/* |
| + tjhandle tjInitCompress(void) |
| + |
| + Creates a new JPEG compressor instance, allocates memory for the structures, |
| + and returns a handle to the instance. Most applications will only |
| + need to call this once at the beginning of the program or once for each |
| + concurrent thread. Don't try to create a new instance every time you |
| + compress an image, because this will cause performance to suffer. |
| + |
| + RETURNS: NULL on error |
| +*/ |
| +DLLEXPORT tjhandle DLLCALL tjInitCompress(void); |
| + |
| + |
| +/* |
| + int tjCompress(tjhandle j, |
| + unsigned char *srcbuf, int width, int pitch, int height, int pixelsize, |
| + unsigned char *dstbuf, unsigned long *size, |
| + int jpegsubsamp, int jpegqual, int flags) |
| + |
| + [INPUT] j = instance handle previously returned from a call to |
| + tjInitCompress() |
| + [INPUT] srcbuf = pointer to user-allocated image buffer containing pixels in |
| + RGB(A) or BGR(A) form |
| + [INPUT] width = width (in pixels) of the source image |
| + [INPUT] pitch = bytes per line of the source image (width*pixelsize if the |
| + bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap |
| + is padded to the nearest 32-bit boundary, such as is the case for Windows |
| + bitmaps. You can also be clever and use this parameter to skip lines, etc., |
| + as long as the pitch is greater than 0.) |
| + [INPUT] height = height (in pixels) of the source image |
| + [INPUT] pixelsize = size (in bytes) of each pixel in the source image |
| + RGBA and BGRA: 4, RGB and BGR: 3 |
| + [INPUT] dstbuf = pointer to user-allocated image buffer which will receive |
| + the JPEG image. Use the macro TJBUFSIZE(width, height) to determine |
| + the appropriate size for this buffer based on the image width and height. |
| + [OUTPUT] size = pointer to unsigned long which receives the size (in bytes) |
| + of the compressed image |
| + [INPUT] jpegsubsamp = Specifies either 4:1:1, 4:2:2, or 4:4:4 subsampling. |
| + When the image is converted from the RGB to YCbCr colorspace as part of the |
| + JPEG compression process, every other Cb and Cr (chrominance) pixel can be |
| + discarded to produce a smaller image with little perceptible loss of |
| + image clarity (the human eye is more sensitive to small changes in |
| + brightness than small changes in color.) |
| + |
| + TJ_411: 4:1:1 subsampling. Discards every other Cb, Cr pixel in both |
| + horizontal and vertical directions. |
| + TJ_422: 4:2:2 subsampling. Discards every other Cb, Cr pixel only in |
| + the horizontal direction. |
| + TJ_444: no subsampling. |
| + TJ_GRAYSCALE: Generate grayscale JPEG image |
| + |
| + [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive.) |
| + [INPUT] flags = the bitwise OR of one or more of the following |
| + |
| + TJ_BGR: The components of each pixel in the source image are stored in |
| + B,G,R order, not R,G,B |
| + TJ_BOTTOMUP: The source image is stored in bottom-up (Windows) order, |
| + not top-down |
| + TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation |
| + of this codec-- force IPP to use MMX code (bypass CPU auto-detection) |
| + TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation |
| + of this codec-- force IPP to use SSE code (bypass CPU auto-detection) |
| + TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation |
| + of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection) |
| + TJ_FORCESSE3: Valid only for the Intel Performance Primitives implementation |
| + of this codec-- force IPP to use SSE3 code (bypass CPU auto-detection) |
| + |
| + RETURNS: 0 on success, -1 on error |
| +*/ |
| +DLLEXPORT int DLLCALL tjCompress(tjhandle j, |
| + unsigned char *srcbuf, int width, int pitch, int height, int pixelsize, |
| + unsigned char *dstbuf, unsigned long *size, |
| + int jpegsubsamp, int jpegqual, int flags); |
| + |
| +DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height); |
| + |
| +/* |
| + tjhandle tjInitDecompress(void) |
| + |
| + Creates a new JPEG decompressor instance, allocates memory for the |
| + structures, and returns a handle to the instance. Most applications will |
| + only need to call this once at the beginning of the program or once for each |
| + concurrent thread. Don't try to create a new instance every time you |
| + decompress an image, because this will cause performance to suffer. |
| + |
| + RETURNS: NULL on error |
| +*/ |
| +DLLEXPORT tjhandle DLLCALL tjInitDecompress(void); |
| + |
| + |
| +/* |
| + int tjDecompressHeader(tjhandle j, |
| + unsigned char *srcbuf, unsigned long size, |
| + int *width, int *height) |
| + |
| + [INPUT] j = instance handle previously returned from a call to |
| + tjInitDecompress() |
| + [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image |
| + to decompress |
| + [INPUT] size = size of the JPEG image buffer (in bytes) |
| + [OUTPUT] width = width (in pixels) of the JPEG image |
| + [OUTPUT] height = height (in pixels) of the JPEG image |
| + |
| + RETURNS: 0 on success, -1 on error |
| +*/ |
| +DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j, |
| + unsigned char *srcbuf, unsigned long size, |
| + int *width, int *height); |
| + |
| + |
| +/* |
| + int tjDecompress(tjhandle j, |
| + unsigned char *srcbuf, unsigned long size, |
| + unsigned char *dstbuf, int width, int pitch, int height, int pixelsize, |
| + int flags) |
| + |
| + [INPUT] j = instance handle previously returned from a call to |
| + tjInitDecompress() |
| + [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image |
| + to decompress |
| + [INPUT] size = size of the JPEG image buffer (in bytes) |
| + [INPUT] dstbuf = pointer to user-allocated image buffer which will receive |
| + the bitmap image. This buffer should normally be pitch*height |
| + bytes in size, although this pointer may also be used to decompress into |
| + a specific region of a larger buffer. |
| + [INPUT] width = width (in pixels) of the destination image |
| + [INPUT] pitch = bytes per line of the destination image (width*pixelsize if the |
| + bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap |
| + is padded to the nearest 32-bit boundary, such as is the case for Windows |
| + bitmaps. You can also be clever and use this parameter to skip lines, etc., |
| + as long as the pitch is greater than 0.) |
| + [INPUT] height = height (in pixels) of the destination image |
| + [INPUT] pixelsize = size (in bytes) of each pixel in the destination image |
| + RGBA/RGBx and BGRA/BGRx: 4, RGB and BGR: 3 |
| + [INPUT] flags = the bitwise OR of one or more of the following |
| + |
| + TJ_BGR: The components of each pixel in the destination image should be |
| + written in B,G,R order, not R,G,B |
| + TJ_BOTTOMUP: The destination image should be stored in bottom-up |
| + (Windows) order, not top-down |
| + TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation |
| + of this codec-- force IPP to use MMX code (bypass CPU auto-detection) |
| + TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation |
| + of this codec-- force IPP to use SSE code (bypass CPU auto-detection) |
| + TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation |
| + of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection) |
| + |
| + RETURNS: 0 on success, -1 on error |
| +*/ |
| +DLLEXPORT int DLLCALL tjDecompress(tjhandle j, |
| + unsigned char *srcbuf, unsigned long size, |
| + unsigned char *dstbuf, int width, int pitch, int height, int pixelsize, |
| + int flags); |
| + |
| + |
| +/* |
| + int tjDestroy(tjhandle h) |
| + |
| + Frees structures associated with a compression or decompression instance |
| + |
| + [INPUT] h = instance handle (returned from a previous call to |
| + tjInitCompress() or tjInitDecompress() |
| + |
| + RETURNS: 0 on success, -1 on error |
| +*/ |
| +DLLEXPORT int DLLCALL tjDestroy(tjhandle h); |
| + |
| + |
| +/* |
| + char *tjGetErrorStr(void) |
| + |
| + Returns a descriptive error message explaining why the last command failed |
| +*/ |
| +DLLEXPORT char* DLLCALL tjGetErrorStr(void); |
| + |
| +#ifdef __cplusplus |
| +} |
| +#endif |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer._man vnc_unixsrc/vncviewer/vncviewer._man |
| --- vnc_unixsrc.orig/vncviewer/vncviewer._man 1969-12-31 19:00:00.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/vncviewer._man 2010-04-11 23:30:24.000000000 -0400 |
| @@ -0,0 +1,829 @@ |
| +'\" 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 <const@ce.cctpu.edu.ru> |
| +.\" Copyright (C) 2006-2010 Karl J. Runge <runge@karlrunge.com> |
| +.\" |
| +.\" 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 "April 2010" "" "SSVNC" |
| +.SH NAME |
| +ssvncviewer \- an X viewer client for VNC |
| +.SH SYNOPSIS |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.RI [\| host \|][\| :display \|] |
| +.br |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.RI [\| host \|][\| ::port \|] |
| +.br |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.RI exec=[\| cmd+args... \|] |
| +.br |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.RI fd=n |
| +.br |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.RI /path/to/unix/socket |
| +.br |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.IR \-listen |
| +.RI [\| display \|] |
| +.br |
| +.B ssvncviewer |
| +.IR \-help |
| +.br |
| +.SH DESCRIPTION |
| +.B ssvncviewer |
| +is an Xt\-based client application for the VNC (Virtual Network |
| +Computing) system. It can connect to any VNC\-compatible server such |
| +as \fBXvnc\fR, WinVNC, or \fBx11vnc\fR, allowing you to control desktop environment |
| +of a different machine. |
| + |
| +ssvncviewer is an enhanced version of the tightvnc unix viewer that can |
| +take advantage of features in the \fBx11vnc\fR and UltraVNC VNC servers. |
| +See below for the description of these features. |
| + |
| +You can use F8 to display a pop\-up utility menu. Press F8 twice to |
| +pass single F8 to the remote side. |
| +.SH OPTIONS |
| +.TP |
| +\fB\-help\fR |
| +Prints a short usage notice to stderr. |
| +.TP |
| +\fB\-listen\fR |
| +Make the viewer listen on port 5500+\fIdisplay\fR for reverse |
| +connections from a server. WinVNC supports reverse connections using |
| +the "Add New Client" menu option, or the \-connect command line |
| +option. \fBXvnc\fR requires the use of the helper program |
| +\fBvncconnect\fR. |
| +.TP |
| +\fB\-via\fR \fIgateway\fR |
| +Automatically create encrypted TCP tunnel to the \fIgateway\fR machine |
| +before connection, connect to the \fIhost\fR through that tunnel |
| +(TightVNC\-specific). By default, this option invokes SSH local port |
| +forwarding, assuming that SSH client binary can be accessed as |
| +/usr/bin/ssh. Note that when using the \fB\-via\fR option, the host |
| +machine name should be specified as known to the gateway machine, e.g. |
| +"localhost" denotes the \fIgateway\fR, not the machine where vncviewer |
| +was launched. See the ENVIRONMENT section below for the information on |
| +configuring the \fB\-via\fR option. |
| +.TP |
| +\fB\-shared\fR |
| +When connecting, specify that a shared connection is requested. In |
| +TightVNC, this is the default mode, allowing you to share the desktop |
| +with other clients already using it. |
| +.TP |
| +\fB\-noshared\fR |
| +When connecting, specify that the session may not be shared. This |
| +would either disconnect other connected clients or refuse your |
| +connection, depending on the server configuration. |
| +.TP |
| +\fB\-viewonly\fR |
| +Disable transfer of mouse and keyboard events from the client to the |
| +server. |
| +.TP |
| +\fB\-fullscreen\fR |
| +Start in full\-screen mode. Please be aware that operating in |
| +full\-screen mode may confuse X window managers. Typically, such |
| +conflicts cause incorrect handling of input focus or make the viewer |
| +window disappear mysteriously. See the grabKeyboard setting in the |
| +RESOURCES section below for a method to solve input focus problem. |
| +.TP |
| +\fB\-noraiseonbeep\fR |
| +By default, the viewer shows and raises its window on remote beep |
| +(bell) event. This option disables such behaviour |
| +(TightVNC\-specific). |
| +.TP |
| +\fB\-user\fR \fIusername\fR |
| +User name for Unix login authentication. Default is to use current |
| +Unix user name. If this option was given, the viewer will prefer Unix |
| +login authentication over the standard VNC authentication. |
| +.TP |
| +\fB\-passwd\fR \fIpasswd\-file\fR |
| +File from which to get the password (as generated by the |
| +\fBvncpasswd\fR(1) program). This option affects only the standard VNC |
| +authentication. |
| +.TP |
| +\fB\-encodings\fR \fIencoding\-list\fR |
| +TightVNC supports several different compression methods to encode |
| +screen updates; this option specifies a set of them to use in order of |
| +preference. Encodings are specified separated with spaces, and must |
| +thus be enclosed in quotes if more than one is specified. Commas may be used to avoid spaces. |
| +Available encodings, in default order for a remote connection, are |
| +"copyrect tight hextile zlib corre rre raw". For a local connection |
| +(to the same machine), the default order to try is "raw copyrect tight |
| +hextile zlib corre rre". Raw encoding is always assumed as a last option |
| +if no other encoding can be used for some reason. For more information |
| +on encodings, see the section ENCODINGS below. |
| +.TP |
| +\fB\-bgr233\fR |
| +Always use the BGR233 format to encode pixel data. This reduces |
| +network traffic, but colors may be represented inaccurately. The |
| +bgr233 format is an 8\-bit "true color" format, with 2 bits blue, 3 |
| +bits green, and 3 bits red. |
| +.TP |
| +\fB\-owncmap\fR |
| +Try to use a PseudoColor visual and a private colormap. This allows |
| +the VNC server to control the colormap. |
| +.TP |
| +\fB\-truecolour\fR, \fB\-truecolor\fR |
| +Try to use a TrueColor visual. |
| +.TP |
| +\fB\-depth\fR \fIdepth\fR |
| +On an X server which supports multiple TrueColor visuals of different |
| +depths, attempt to use the specified one (in bits per pixel); if |
| +successful, this depth will be requested from the VNC server. |
| +.TP |
| +\fB\-compresslevel \fIlevel\fR |
| +Use specified compression \fIlevel\fR (0..9) for "tight" and "zlib" |
| +encodings (TightVNC\-specific). Level 1 uses minimum of CPU time and |
| +achieves weak compression ratios, while level 9 offers best |
| +compression but is slow in terms of CPU time consumption on the server |
| +side. Use high levels with very slow network connections, and low |
| +levels when working over high\-speed LANs. It's not recommended to use |
| +compression level 0, reasonable choices start from the level 1. |
| +.TP |
| +\fB\-quality \fIlevel\fR |
| +Use the specified JPEG quality \fIlevel\fR (0..9) for the "tight" |
| +encoding (TightVNC\-specific). Quality level 0 denotes bad image |
| +quality but very impressive compression ratios, while level 9 offers |
| +very good image quality at lower compression ratios. Note that the |
| +"tight" encoder uses JPEG to encode only those screen areas that look |
| +suitable for lossy compression, so quality level 0 does not always |
| +mean unacceptable image quality. |
| +.TP |
| +\fB\-nojpeg\fR |
| +Disable lossy JPEG compression in Tight encoding (TightVNC\-specific). |
| +Disabling JPEG compression is not a good idea in typical cases, as |
| +that makes the Tight encoder less efficient. You might want to use |
| +this option if it's absolutely necessary to achieve perfect image |
| +quality (see also the \fB\-quality\fR option). |
| +.TP |
| +\fB\-nocursorshape\fR |
| +Disable cursor shape updates, protocol extensions used to handle |
| +remote cursor movements locally on the client side |
| +(TightVNC\-specific). Using cursor shape updates decreases delays with |
| +remote cursor movements, and can improve bandwidth usage dramatically. |
| +.TP |
| +\fB\-x11cursor\fR |
| +Use a real X11 cursor with X-style cursor shape updates, instead of |
| +drawing the remote cursor on the framebuffer. This option also |
| +disables the dot cursor, and disables cursor position updates in |
| +non-fullscreen mode. |
| +.TP |
| +\fB\-autopass\fR |
| +Read a plain-text password from stdin. This option affects only the |
| +standard VNC authentication. |
| + |
| +.SH Enhanced TightVNC Viewer (SSVNC) OPTIONS |
| +.TP |
| +Enhanced TightVNC Viewer (SSVNC) web page is located at: |
| +.TP |
| +http://www.karlrunge.com/x11vnc/ssvnc.html |
| +.TP |
| +Note: ZRLE and ZYWRLE encodings are now supported. |
| +.TP |
| +Note: F9 is shortcut to Toggle FullScreen mode. |
| +.TP |
| +Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1 |
| +to allow more than one incoming VNC server at a time. |
| +This is the same as -multilisten described below. Set |
| +SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than "n" |
| +simultaneous reverse connections. |
| + |
| +If the host:port is specified as "exec=command args..." |
| +then instead of making a TCP/IP socket connection to the |
| +remote VNC server, "command args..." is executed and the |
| +viewer is attached to its stdio. This enables tunnelling |
| +established via an external command, e.g. an stunnel(8) |
| +that does not involve a listening socket. |
| +This mode does not work for -listen reverse connections. |
| + |
| +If the host:port is specified as "fd=n" then it is assumed |
| +n is an already opened file descriptor to the socket. (i.e |
| +the parent did fork+exec) |
| + |
| +If the host:port contains a '/' it is interpreted as a |
| +unix-domain socket (AF_LOCAL insead of AF_INET) |
| +.TP |
| +\fB\-multilisten\fR |
| +As in -listen (reverse connection listening) except |
| +allow more than one incoming VNC server to be connected |
| +at a time. The default for -listen of only one at a |
| +time tries to play it safe by not allowing anyone on |
| +the network to put (many) desktops on your screen over |
| +a long window of time. Use -multilisten for no limit. |
| +.TP |
| +\fB\-acceptpopup\fR |
| +In \fB\-listen\fR (reverse connection listening) mode when |
| +a reverse VNC connection comes in show a popup asking |
| +whether to Accept or Reject the connection. The IP |
| +address of the connecting host is shown. Same as |
| +setting the env. var. SSVNC_ACCEPT_POPUP=1. |
| +.TP |
| +\fB\-acceptpopupsc\fR |
| +As in \fB\-acceptpopup\fR except assume UltraVNC Single |
| +Click (SC) server. Retrieve User and ComputerName |
| +info from UltraVNC Server and display in the Popup. |
| +.TP |
| +\fB\-use64\fR |
| +In \fB\-bgr233\fR mode, use 64 colors instead of 256. |
| +.TP |
| +\fB\-bgr222\fR |
| +Same as \fB\-use64\fR. |
| +.TP |
| +\fB\-use8\fR |
| +In \fB\-bgr233\fR mode, use 8 colors instead of 256. |
| +.TP |
| +\fB\-bgr111\fR |
| +Same as \fB\-use8\fR. |
| +.TP |
| +\fB\-16bpp\fR |
| +If the vnc viewer X display is depth 24 at 32bpp |
| +request a 16bpp format from the VNC server to cut |
| +network traffic by up to 2X, then tranlate the |
| +pixels to 32bpp locally. |
| +.TP |
| +\fB\-bgr565\fR |
| +Same as \fB\-16bpp\fR. |
| +.TP |
| +\fB\-grey\fR |
| +Use a grey scale for the 16- and 8\fB\-bpp\fR modes. |
| +.TP |
| +\fB\-alpha\fR |
| +Use alphablending transparency for local cursors |
| +requires: x11vnc server, both client and server |
| +must be 32bpp and same endianness. |
| +.TP |
| +\fB\-scale\fR \fIstr\fR |
| +Scale the desktop locally. The string "str" can |
| +a floating point ratio, e.g. "0.9", or a fraction, |
| +e.g. "3/4", or WxH, e.g. 1280x1024. Use "fit" |
| +to fit in the current screen size. Use "auto" to |
| +fit in the window size. "str" can also be set by |
| +the env. var. SSVNC_SCALE. |
| + |
| +If you observe mouse trail painting errors, enable |
| +X11 Cursor mode (either via Popup or \fB\-x11cursor\fR.) |
| + |
| +Note that scaling is done in software and so can be |
| +slow and requires more memory. Some speedup Tips: |
| + |
| +ZRLE is faster than Tight in this mode. When |
| +scaling is first detected, the encoding will |
| +be automatically switched to ZRLE. Use the |
| +Popup menu if you want to go back to Tight. |
| +Set SSVNC_PRESERVE_ENCODING=1 to disable this. |
| + |
| +Use a solid background on the remote side. |
| +(e.g. manually or via x11vnc \fB\-solid\fR ...) |
| + |
| +If the remote server is x11vnc, try client |
| +side caching: x11vnc \fB\-ncache\fR 10 ... |
| +.TP |
| +\fB\-ycrop\fR n |
| +Only show the top n rows of the framebuffer. For |
| +use with x11vnc \fB\-ncache\fR client caching option |
| +to help "hide" the pixel cache region. |
| +Use a negative value (e.g. \fB\-1\fR) for autodetection. |
| +Autodetection will always take place if the remote |
| +fb height is more than 2 times the width. |
| +.TP |
| +\fB\-sbwidth\fR n |
| +Scrollbar width for x11vnc \fB\-ncache\fR mode (\fB\-ycrop\fR), |
| +default is very narrow: 2 pixels, it is narrow to |
| +avoid distraction in \fB\-ycrop\fR mode. |
| +.TP |
| +\fB\-nobell\fR |
| +Disable bell. |
| +.TP |
| +\fB\-rawlocal\fR |
| +Prefer raw encoding for localhost, default is |
| +no, i.e. assumes you have a SSH tunnel instead. |
| +.TP |
| +\fB\-notty\fR |
| +Try to avoid using the terminal for interactive |
| +responses: use windows for messages and prompting |
| +instead. Messages will also be printed to terminal. |
| +.TP |
| +\fB\-sendclipboard\fR |
| +Send the X CLIPBOARD selection (i.e. Ctrl+C, |
| +Ctrl+V) instead of the X PRIMARY selection (mouse |
| +select and middle button paste.) |
| +.TP |
| +\fB\-sendalways\fR |
| +Whenever the mouse enters the VNC viewer main |
| +window, send the selection to the VNC server even if |
| +it has not changed. This is like the Xt resource |
| +translation SelectionToVNC(always) |
| +.TP |
| +\fB\-recvtext\fR |
| +str When cut text is received from the VNC server, |
| +ssvncviewer will set both the X PRIMARY and the |
| +X CLIPBOARD local selections. To control which |
| +is set, specify 'str' as 'primary', 'clipboard', |
| +or 'both' (the default.) |
| +.TP |
| +\fB\-graball\fR |
| +Grab the entire X server when in fullscreen mode, |
| +needed by some old window managers like fvwm2. |
| +.TP |
| +\fB\-popupfix\fR |
| +Warp the popup back to the pointer position, |
| +needed by some old window managers like fvwm2. |
| +.TP |
| +\fB\-grabkbd\fR |
| +Grab the X keyboard when in fullscreen mode, |
| +needed by some window managers. Same as \fB\-grabkeyboard\fR. |
| +\fB\-grabkbd\fR is the default, use \fB\-nograbkbd\fR to disable. |
| +.TP |
| +\fB\-bs\fR, \fB\-nobs\fR |
| +Whether or not to use X server Backingstore for the |
| +main viewer window. The default is to not, mainly |
| +because most Linux, etc, systems X servers disable |
| +*all* Backingstore by default. To re\fB\-enable\fR it put |
| + |
| +Option "Backingstore" |
| + |
| +in the Device section of /etc/X11/xorg.conf. |
| +In \fB\-bs\fR mode with no X server backingstore, whenever an |
| +area of the screen is re\fB\-exposed\fR it must go out to the |
| +VNC server to retrieve the pixels. This is too slow. |
| + |
| +In \fB\-nobs\fR mode, memory is allocated by the viewer to |
| +provide its own backing of the main viewer window. This |
| +actually makes some activities faster (changes in large |
| +regions) but can appear to "flash" too much. |
| +.TP |
| +\fB\-noshm\fR |
| +Disable use of MIT shared memory extension (not recommended) |
| +.TP |
| +\fB\-termchat\fR |
| +Do the UltraVNC chat in the terminal vncviewer is in |
| +instead of in an independent window. |
| +.TP |
| +\fB\-unixpw\fR \fIstr\fR |
| +Useful for logging into x11vnc in \fB\-unixpw\fR mode. "str" is a |
| +string that allows many ways to enter the Unix Username |
| +and Unix Password. These characters: username, newline, |
| +password, newline are sent to the VNC server after any VNC |
| +authentication has taken place. Under x11vnc they are |
| +used for the \fB\-unixpw\fR login. Other VNC servers could do |
| +something similar. |
| + |
| +You can also indicate "str" via the environment |
| +variable SSVNC_UNIXPW. |
| + |
| +Note that the Escape key is actually sent first to tell |
| +x11vnc to not echo the Unix Username back to the VNC |
| +viewer. Set SSVNC_UNIXPW_NOESC=1 to override this. |
| + |
| +If str is ".", then you are prompted at the command line |
| +for the username and password in the normal way. If str is |
| +"-" the stdin is read via getpass(3) for username@password. |
| +Otherwise if str is a file, it is opened and the first line |
| +read is taken as the Unix username and the 2nd as the |
| +password. If str prefixed by "rm:" the file is removed |
| +after reading. Otherwise, if str has a "@" character, |
| +it is taken as username@password. Otherwise, the program |
| +exits with an error. Got all that? |
| +.TP |
| +\fB-repeater\fR \fIstr\fR |
| +This is for use with UltraVNC repeater proxy described |
| +here: http://www.uvnc.com/addons/repeater.html. The "str" |
| +is the ID string to be sent to the repeater. E.g. ID:1234 |
| +It can also be the hostname and port or display of the VNC |
| +server, e.g. 12.34.56.78:0 or snoopy.com:1. Note that when |
| +using -repeater, the host:dpy on the cmdline is the repeater |
| +server, NOT the VNC server. The repeater will connect you. |
| + |
| +Example: vncviewer ... -repeater ID:3333 repeat.host:5900 |
| + |
| +Example: vncviewer ... -repeater vhost:0 repeat.host:5900 |
| + |
| +Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a |
| +Single Click III (SSL) repeater (repeater_SSL.exe) and you |
| +are passing the SSL part of the connection through stunnel, socat, etc. |
| +This way the magic UltraVNC string 'testB' needed to work with the |
| +repeater is sent to it. |
| +.TP |
| +\fB-rfbversion\fR \fIstr\fR |
| +Set the advertised RFB version. E.g.: -rfbversion 3.6 For some |
| +servers, e.g. UltraVNC this needs to be done. |
| +.TP |
| +\fB-ultradsm\fR |
| +UltraVNC has symmetric private encryption DSM plugins. See |
| +http://www.uvnc.com/features/encryption.html. It is assumed |
| +you are using a unix program (e.g. our ultravnc_dsm_helper) to |
| +encrypt and decrypt the UltraVNC DSM stream. IN ADDITION TO |
| +THAT supply -ultradsm to tell THIS viewer to modify the RFB |
| +data sent so as to work with the UltraVNC Server. For some |
| +reason, each RFB msg type must be sent twice under DSM. |
| +.TP |
| +\fB\-mslogon\fR \fIuser\fR |
| +Use Windows MS Logon to an UltraVNC server. Supply the |
| +username or "1" to be prompted. The default is to |
| +autodetect the UltraVNC MS Logon server and prompt for |
| +the username and password. |
| + |
| +IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman |
| +exchange is very weak and can be brute forced to recover |
| +your username and password in a few seconds of CPU |
| +time. To be safe, be sure to use an additional encrypted |
| +tunnel (e.g. SSL or SSH) for the entire VNC session. |
| +.TP |
| +\fB\-chatonly\fR |
| +Try to be a client that only does UltraVNC text chat. This |
| +mode is used by x11vnc to present a chat window on the physical |
| +X11 console (i.e. to chat with the person at the display). |
| +.TP |
| +\fB-env\fR \fIVAR=VALUE\fR |
| +To save writing a shell script to set environment |
| +variables, specify as many as you need on the command line. For example, |
| +-env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi |
| +.TP |
| +\fB\-noipv6\fR |
| +Disable all IPv6 sockets. Same as VNCVIEWER_NO_IPV6=1. |
| +.TP |
| +\fB\-noipv4\fR |
| +Disable all IPv4 sockets. Same as VNCVIEWER_NO_IPV4=1. |
| +.TP |
| +\fB\-printres\fR |
| +Print out the Ssvnc X resources (appdefaults) and |
| +then exit. You can save them to a file and customize them (e.g. the |
| +keybindings and Popup menu) Then point to the file via |
| +XENVIRONMENT or XAPPLRESDIR. |
| +.TP |
| +\fB\-pipeline\fR |
| +Like TurboVNC, request the next framebuffer update as soon |
| +as possible instead of waiting until the end of the current |
| +framebuffer update coming in. Helps 'pipeline' the updates. |
| +This is currently the default, use \fB-nopipeline\fR to disable. |
| +.TP |
| +\fB\-appshare\fR |
| +Enable features for use with x11vnc's \fB\-appshare\fR mode where |
| +instead of sharing the full desktop only the application's |
| +windows are shared. Viewer multilisten mode is used to |
| +create the multiple windows: \fB\-multilisten\fR is implied. |
| +See 'x11vnc \fB\-appshare\fR \fB\-help\fR' more information on the mode. |
| +Features enabled in the viewer under \fB\-appshare\fR are: |
| +Minimum extra text in the title, auto \fB\-ycrop\fR is disabled, |
| +x11vnc \fB\-remote_prefix\fR X11VNC_APPSHARE_CMD: message channel, |
| +x11vnc initial window position hints. See also Escape Keys |
| +below for additional key and mouse bindings. |
| +.TP |
| +\fB\-escape \fR\fIstr\fR |
| +This sets the 'Escape Keys' modifier sequence and enables |
| +escape keys mode. When the modifier keys escape sequence |
| +is held down, the next keystroke is interpreted locally |
| +to perform a special action instead of being sent to the |
| +remote VNC server. |
| + |
| +Use '\fB\-escape\fR default' for the default modifier sequence. |
| +(Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L) |
| + |
| +Here are the 'Escape Keys: Help+Set' instructions from the Popup: |
| + |
| +Escape Keys: Enter a comma separated list of modifier keys to be the 'escape |
| +sequence'. When these keys are held down, the next keystroke is |
| +interpreted locally to invoke a special action instead of being sent to |
| +the remote VNC server. In other words, a set of 'Hot Keys'. |
| + |
| +Here is the list of local key mappings to special actions: |
| + |
| +r: refresh desktop b: toggle bell c: toggle full-color |
| + |
| +f: file transfer x: x11cursor z: toggle Tight/ZRLE |
| + |
| +l: full screen g: graball e: escape keys dialog |
| + |
| +s: scale dialog +: scale up (=) -: scale down (_) |
| + |
| +t: text chat a: alphablend cursor |
| + |
| +V: toggle viewonly Q: quit viewer 123456: UltraVNC scale 1/n |
| + |
| +Arrow keys: pan the viewport about 10% for each keypress. |
| + |
| +PageUp/PageDown: pan the viewport by a screenful vertically. |
| + |
| +Home/End: pan the viewport by a screenful horizontally. |
| + |
| +KeyPad Arrows: pan the viewport by 1 pixel for each keypress. |
| + |
| +Dragging the Mouse with Button1 pressed also pans the viewport. |
| + |
| +Clicking Mouse Button3 brings up the Popup Menu. |
| + |
| +The above mappings are \fBalways\fR active in ViewOnly mode, unless you set |
| +the Escape Keys value to 'never'. |
| + |
| +x11vnc -appshare hot-keys: x11vnc has a simple application sharing mode |
| +that enables the viewer-side to move, resize, or raise the remote toplevel |
| +windows. To enable it, hold down Shift + the Escape Keys and press these: |
| + |
| +Arrow keys: move the remote window around in its desktop. |
| + |
| +PageUp/PageDn/Home/End: resize the remote window. |
| + |
| ++/-: raise or lower the remote window. |
| + |
| +M or Button1 move win to local position; D or Button3: delete remote win. |
| + |
| +If the Escape Keys value below is set to 'default' then a default list of |
| +of modifier keys is used. For Unix it is: Alt_L,Super_L and for MacOSX it |
| +is Control_L,Meta_L. Note: the Super_L key usually has a Windows(TM) Flag |
| +on it. Also note the _L and _R mean the key is on the LEFT or RIGHT side |
| +of the keyboard. |
| + |
| +On Unix the default is Alt and Windows keys on Left side of keyboard. |
| +On MacOSX the default is Control and Command keys on Left side of keyboard. |
| + |
| +Example: Press and hold the Alt and Windows keys on the LEFT side of the |
| +keyboard and then press 'c' to toggle the full-color state. Or press 't' |
| +to toggle the ultravnc Text Chat window, etc. |
| + |
| +To use something besides the default, supply a comma separated list (or a |
| +single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L |
| +Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch. |
| +.TP |
| +\fB New Popup actions:\fR |
| + |
| + ViewOnly: ~ -viewonly |
| + Disable Bell: ~ -nobell |
| + Cursor Shape: ~ -nocursorshape |
| + X11 Cursor: ~ -x11cursor |
| + Cursor Alphablend: ~ -alpha |
| + Toggle Tight/Hextile: ~ -encodings hextile... |
| + Toggle Tight/ZRLE: ~ -encodings zrle... |
| + Toggle ZRLE/ZYWRLE: ~ -encodings zywrle... |
| + Quality Level ~ -quality (both Tight and ZYWRLE) |
| + Compress Level ~ -compresslevel |
| + Disable JPEG: ~ -nojpeg (Tight) |
| + Pipeline Updates ~ -pipeline |
| + |
| + Full Color as many colors as local screen allows. |
| + Grey scale (16 & 8-bpp) ~ -grey, for low colors 16/8bpp modes only. |
| + 16 bit color (BGR565) ~ -16bpp / -bgr565 |
| + 8 bit color (BGR233) ~ -bgr233 |
| + 256 colors ~ -bgr233 default # of colors. |
| + 64 colors ~ -bgr222 / -use64 |
| + 8 colors ~ -bgr111 / -use8 |
| + Scale Viewer ~ -scale |
| + Escape Keys: Toggle ~ -escape |
| + Escape Keys: Help+Set ~ -escape |
| + Set Y Crop (y-max) ~ -ycrop |
| + Set Scrollbar Width ~ -sbwidth |
| + XGrabServer ~ -graball |
| + |
| + UltraVNC Extensions: |
| + |
| + Set 1/n Server Scale Ultravnc ext. Scale desktop by 1/n. |
| + Text Chat Ultravnc ext. Do Text Chat. |
| + File Transfer Ultravnc ext. File xfer via Java helper. |
| + Single Window Ultravnc ext. Grab and view a single window. |
| + (select then click on the window you want). |
| + Disable Remote Input Ultravnc ext. Try to prevent input and |
| + viewing of monitor at physical display. |
| + |
| + Note: the Ultravnc extensions only apply to servers that support |
| + them. x11vnc/libvncserver supports some of them. |
| + |
| + Send Clipboard not Primary ~ -sendclipboard |
| + Send Selection Every time ~ -sendalways |
| + |
| +.SH ENCODINGS |
| +The server supplies information in whatever format is desired by the |
| +client, in order to make the client as easy as possible to implement. |
| +If the client represents itself as able to use multiple formats, the |
| +server will choose one. |
| + |
| +.I Pixel format |
| +refers to the representation of an individual pixel. The most common |
| +formats are 24 and 16 bit "true\-color" values, and 8\-bit "color map" |
| +representations, where an arbitrary map converts the color number to |
| +RGB values. |
| + |
| +.I Encoding |
| +refers to how a rectangle of pixels are sent (all pixel information in |
| +VNC is sent as rectangles). All rectangles come with a header giving |
| +the location and size of the rectangle and an encoding type used by |
| +the data which follows. These types are listed below. |
| +.TP |
| +.B Raw |
| +The raw encoding simply sends width*height pixel values. All clients |
| +are required to support this encoding type. Raw is also the fastest |
| +when the server and viewer are on the same machine, as the connection |
| +speed is essentially infinite and raw encoding minimizes processing |
| +time. |
| +.TP |
| +.B CopyRect |
| +The Copy Rectangle encoding is efficient when something is being |
| +moved; the only data sent is the location of a rectangle from which |
| +data should be copied to the current location. Copyrect could also be |
| +used to efficiently transmit a repeated pattern. |
| +.TP |
| +.B RRE |
| +The Rise\-and\-Run\-length\-Encoding is basically a 2D version of |
| +run\-length encoding (RLE). In this encoding, a sequence of identical |
| +pixels are compressed to a single value and repeat count. In VNC, this |
| +is implemented with a background color, and then specifications of an |
| +arbitrary number of subrectangles and color for each. This is an |
| +efficient encoding for large blocks of constant color. |
| +.TP |
| +.B CoRRE |
| +This is a minor variation on RRE, using a maximum of 255x255 pixel |
| +rectangles. This allows for single\-byte values to be used, reducing |
| +packet size. This is in general more efficient, because the savings |
| +from sending 1\-byte values generally outweighs the losses from the |
| +(relatively rare) cases where very large regions are painted the same |
| +color. |
| +.TP |
| +.B Hextile |
| +Here, rectangles are split up in to 16x16 tiles, which are sent in a |
| +predetermined order. The data within the tiles is sent either raw or |
| +as a variant on RRE. Hextile encoding is usually the best choice for |
| +using in high\-speed network environments (e.g. Ethernet local\-area |
| +networks). |
| +.TP |
| +.B Zlib |
| +Zlib is a very simple encoding that uses zlib library to compress raw |
| +pixel data. This encoding achieves good compression, but consumes a |
| +lot of CPU time. Support for this encoding is provided for |
| +compatibility with VNC servers that might not understand Tight |
| +encoding which is more efficient than Zlib in nearly all real\-life |
| +situations. |
| +.TP |
| +.B Tight |
| +Like Zlib encoding, Tight encoding uses zlib library to compress the |
| +pixel data, but it pre\-processes data to maximize compression ratios, |
| +and to minimize CPU usage on compression. Also, JPEG compression may |
| +be used to encode color\-rich screen areas (see the description of |
| +\-quality and \-nojpeg options above). Tight encoding is usually the |
| +best choice for low\-bandwidth network environments (e.g. slow modem |
| +connections). |
| +.TP |
| +.B ZRLE |
| +The SSVNC viewer has ported the RealVNC (www.realvnc.com) ZRLE encoding |
| +to the unix tightvnc viewer. |
| +.TP |
| +.B ZYWRLE |
| +The SSVNC viewer has ported the Hitachi lossy wavelet based ZRLE |
| +encoding from http://mobile.hitachi-system.co.jp/publications/ZYWRLE/ |
| +to the unix tightvnc viewer. |
| +.SH RESOURCES |
| +X resources that \fBvncviewer\fR knows about, aside from the |
| +normal Xt resources, are as follows: |
| +.TP |
| +.B shareDesktop |
| +Equivalent of \fB\-shared\fR/\fB\-noshared\fR options. Default true. |
| +.TP |
| +.B viewOnly |
| +Equivalent of \fB\-viewonly\fR option. Default false. |
| +.TP |
| +.B fullScreen |
| +Equivalent of \fB\-fullscreen\fR option. Default false. |
| +.TP |
| +.B grabKeyboard |
| +Grab keyboard in full-screen mode. This can help to solve problems |
| +with losing keyboard focus. Default false. |
| +.TP |
| +.B raiseOnBeep |
| +Equivalent of \fB\-noraiseonbeep\fR option, when set to false. Default |
| +true. |
| +.TP |
| +.B passwordFile |
| +Equivalent of \fB\-passwd\fR option. |
| +.TP |
| +.B userLogin |
| +Equivalent of \fB\-user\fR option. |
| +.TP |
| +.B passwordDialog |
| +Whether to use a dialog box to get the password (true) or get it from |
| +the tty (false). Irrelevant if \fBpasswordFile\fR is set. Default |
| +false. |
| +.TP |
| +.B encodings |
| +Equivalent of \fB\-encodings\fR option. |
| +.TP |
| +.B compressLevel |
| +Equivalent of \fB\-compresslevel\fR option (TightVNC\-specific). |
| +.TP |
| +.B qualityLevel |
| +Equivalent of \fB\-quality\fR option (TightVNC\-specific). |
| +.TP |
| +.B enableJPEG |
| +Equivalent of \fB\-nojpeg\fR option, when set to false. Default true. |
| +.TP |
| +.B useRemoteCursor |
| +Equivalent of \fB\-nocursorshape\fR option, when set to false |
| +(TightVNC\-specific). Default true. |
| +.TP |
| +.B useBGR233 |
| +Equivalent of \fB\-bgr233\fR option. Default false. |
| +.TP |
| +.B nColours |
| +When using BGR233, try to allocate this many "exact" colors from the |
| +BGR233 color cube. When using a shared colormap, setting this resource |
| +lower leaves more colors for other X clients. Irrelevant when using |
| +truecolor. Default is 256 (i.e. all of them). |
| +.TP |
| +.B useSharedColours |
| +If the number of "exact" BGR233 colors successfully allocated is less |
| +than 256 then the rest are filled in using the "nearest" colors |
| +available. This resource says whether to only use the "exact" BGR233 |
| +colors for this purpose, or whether to use other clients' "shared" |
| +colors as well. Default true (i.e. use other clients' colors). |
| +.TP |
| +.B forceOwnCmap |
| +Equivalent of \fB\-owncmap\fR option. Default false. |
| +.TP |
| +.B forceTrueColour |
| +Equivalent of \fB\-truecolour\fR option. Default false. |
| +.TP |
| +.B requestedDepth |
| +Equivalent of \fB\-depth\fR option. |
| +.TP |
| +.B useSharedMemory |
| +Use MIT shared memory extension if on the same machine as the X |
| +server. Default true. |
| +.TP |
| +.B wmDecorationWidth, wmDecorationHeight |
| +The total width and height taken up by window manager decorations. |
| +This is used to calculate the maximum size of the VNC viewer window. |
| +Default is width 4, height 24. |
| +.TP |
| +.B bumpScrollTime, bumpScrollPixels |
| +When in full screen mode and the VNC desktop is bigger than the X |
| +display, scrolling happens whenever the mouse hits the edge of the |
| +screen. The maximum speed of scrolling is bumpScrollPixels pixels |
| +every bumpScrollTime milliseconds. The actual speed of scrolling will |
| +be slower than this, of course, depending on how fast your machine is. |
| +Default 20 pixels every 25 milliseconds. |
| +.TP |
| +.B popupButtonCount |
| +The number of buttons in the popup window. See the README file for |
| +more information on how to customize the buttons. |
| +.TP |
| +.B debug |
| +For debugging. Default false. |
| +.TP |
| +.B rawDelay, copyRectDelay |
| +For debugging, see the README file for details. Default 0 (off). |
| +.SH ENVIRONMENT |
| +When started with the \fB\-via\fR option, vncviewer reads the |
| +\fBVNC_VIA_CMD\fR environment variable, expands patterns beginning |
| +with the "%" character, and executes result as a command assuming that |
| +it would create TCP tunnel that should be used for VNC connection. If |
| +not set, this environment variable defaults to "/usr/bin/ssh -f -L |
| +%L:%H:%R %G sleep 20". |
| + |
| +The following patterns are recognized in the \fBVNC_VIA_CMD\fR (note |
| +that all the patterns %G, %H, %L and %R must be present in the command |
| +template): |
| +.TP |
| +.B %% |
| +A literal "%"; |
| +.TP |
| +.B %G |
| +gateway host name; |
| +.TP |
| +.B %H |
| +remote VNC host name, as known to the gateway; |
| +.TP |
| +.B %L |
| +local TCP port number; |
| +.TP |
| +.B %R |
| +remote TCP port number. |
| +.SH SEE ALSO |
| +\fBvncserver\fR(1), \fBx11vnc\fR(1), \fBssvnc\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1), |
| +\fBvncconnect\fR(1), \fBssh\fR(1), http://www.karlrunge.com/x11vnc, http://www.karlrunge.com/x11vnc/ssvnc.html |
| +.SH AUTHORS |
| +Original VNC was developed in AT&T Laboratories Cambridge. TightVNC |
| +additions was implemented by Constantin Kaplinsky. Many other people |
| +participated in development, testing and support. Karl J. Runge |
| +added all of the SSVNC related features and improvements. |
| + |
| +\fBMan page authors:\fR |
| +.br |
| +Marcus Brinkmann <Marcus.Brinkmann@ruhr-uni-bochum.de>, |
| +.br |
| +Terran Melconian <terran@consistent.org>, |
| +.br |
| +Tim Waugh <twaugh@redhat.com>, |
| +.br |
| +Constantin Kaplinsky <const@ce.cctpu.edu.ru> |
| +.br |
| +Karl J. Runge <runge@karlrunge.com> |
| 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 2010-04-18 12:43:47.000000000 -0400 |
| @@ -22,6 +22,8 @@ |
| */ |
| |
| #include "vncviewer.h" |
| +#include <ctype.h> |
| +#include <X11/Xaw/Toggle.h> |
| |
| char *programName; |
| XtAppContext appContext; |
| @@ -29,11 +31,274 @@ |
| |
| Widget toplevel; |
| |
| +extern void raiseme(int force); |
| +extern void CreateChat(void); |
| + |
| +void set_sbwidth(int sbw) { |
| + char *q, *p, t[5]; |
| + int i, k, N = 4; |
| + int db = 0; |
| + |
| + if (sbw < 1) { |
| + sbw = 2; |
| + } else if (sbw > 100) { |
| + sbw = 100; |
| + } |
| + if (db) fprintf(stderr, "sbw: %d\n", sbw); |
| + |
| + sprintf(t, "%4d", sbw); |
| + k = 0; |
| + while (fallback_resources[k] != NULL) { |
| + q = strstr(fallback_resources[k], "horizontal.height: "); |
| + if (!q) { |
| + q = strstr(fallback_resources[k], "vertical.width: "); |
| + } |
| + if (q) { |
| + p = strdup(fallback_resources[k]); |
| + q = strstr(p, ": "); |
| + if (q) { |
| + q++; |
| + q++; |
| + for (i=0; i < N; i++) { |
| + *(q+i) = t[i]; |
| + } |
| + fallback_resources[k] = p; |
| + if (db) fprintf(stderr, "res: %s\n\n", p); |
| + } |
| + } |
| + k++; |
| + } |
| +} |
| + |
| +void min_title(void) { |
| + char *q; |
| + int k; |
| + |
| + k = 0; |
| + while (fallback_resources[k] != NULL) { |
| + q = strstr(fallback_resources[k], "Ssvnc.title: "); |
| + if (q) { |
| + fallback_resources[k] = strdup("Ssvnc.title: %s"); |
| + } |
| + k++; |
| + } |
| +} |
| + |
| +#include <sys/types.h> |
| +#include <sys/stat.h> |
| +#include <unistd.h> |
| + |
| +void unixpw(char *instr, int vencrypt_plain) { |
| + char *str, *q, *infile = NULL; |
| + FILE *in; |
| + int i, rmfile = 0; |
| + struct stat sb; |
| + int N = 99; |
| + char username[100], passwd[100]; |
| + static int did = 0; |
| + |
| + if (did) { |
| + return; |
| + } |
| + did = 1; |
| + |
| + for (i=0; i<100; i++) { |
| + username[i] = '\0'; |
| + passwd[i] = '\0'; |
| + } |
| + |
| + if (instr == NULL) { |
| + return; |
| + } else if (!strcmp(instr, "")) { |
| + return; |
| + } |
| + |
| + str = strdup(instr); |
| + |
| + if (strstr(str, "rm:") == str) { |
| + rmfile = 1; |
| + infile = str + strlen("rm:"); |
| + } else if (stat(str, &sb) == 0) { |
| + infile = str; |
| + } |
| + if (!strcmp(str, ".")) { |
| + char *p; |
| + if (!use_tty()) { |
| + char *u; |
| + fprintf(stderr, "\nEnter Unix Username and Password in the popups.\n"); |
| + u = DoUserDialog(); |
| + if (strlen(u) >= 100) { |
| + exit(1); |
| + } |
| + sprintf(username, u); |
| + p = DoPasswordDialog(); |
| + } else { |
| + raiseme(1); |
| + fprintf(stderr, "\nUnix Username: "); |
| + if (fgets(username, N, stdin) == NULL) { |
| + exit(1); |
| + } |
| + p = getpass("Unix Password: "); |
| + } |
| + if (! p) { |
| + exit(1); |
| + } |
| + strncpy(passwd, p, N); |
| + fprintf(stderr, "\n"); |
| + |
| + } else if (!strcmp(str, "-")) { |
| + char *p, *q; |
| + if (!use_tty()) { |
| + fprintf(stderr, "\nEnter unixuser@unixpasswd in the popup.\n"); |
| + p = DoPasswordDialog(); |
| + } else { |
| + raiseme(1); |
| + p = getpass("unixuser@unixpasswd: "); |
| + } |
| + if (! p) { |
| + exit(1); |
| + } |
| + q = strchr(p, '@'); |
| + if (! q) { |
| + exit(1); |
| + } |
| + *q = '\0'; |
| + strncpy(username, p, N); |
| + strncpy(passwd, q+1, N); |
| + |
| + } else if (infile) { |
| + in = fopen(infile, "r"); |
| + if (in == NULL) { |
| + fprintf(stderr, "failed to open -unixpw file.\n"); |
| + exit(1); |
| + } |
| + if (fgets(username, N, in) == NULL) { |
| + exit(1); |
| + } |
| + if (fgets(passwd, N, in) == NULL) { |
| + exit(1); |
| + } |
| + fclose(in); |
| + fprintf(stderr, "read username@passwd from file: %s\n", infile); |
| + if (rmfile) { |
| + fprintf(stderr, "deleting username@passwd file: %s\n", infile); |
| + unlink(infile); |
| + } |
| + } else if (strchr(str, '@')) { |
| + char *q = strchr(str, '@'); |
| + *q = '\0'; |
| + strncpy(username, str, N); |
| + strncpy(passwd, q+1, N); |
| + } else { |
| + exit(1); |
| + } |
| + |
| + free(str); |
| + |
| + if (vencrypt_plain) { |
| + CARD32 ulen, plen; |
| + char *q; |
| + |
| + q = strrchr(username, '\n'); |
| + if (q) *q = '\0'; |
| + q = strrchr(passwd, '\n'); |
| + if (q) *q = '\0'; |
| + |
| + ulen = Swap32IfLE((CARD32)strlen(username)); |
| + plen = Swap32IfLE((CARD32)strlen(passwd)); |
| + |
| + if (!WriteExact(rfbsock, (char *)&ulen, 4) || |
| + !WriteExact(rfbsock, (char *)&plen, 4)) { |
| + return; |
| + } |
| + |
| + if (!WriteExact(rfbsock, username, strlen(username)) || |
| + !WriteExact(rfbsock, passwd, strlen(passwd))) { |
| + return; |
| + } |
| + return; |
| + } |
| + |
| + |
| + if (! getenv("SSVNC_UNIXPW_NOESC")) { |
| + SendKeyEvent(XK_Escape, 1); |
| + SendKeyEvent(XK_Escape, 0); |
| + } |
| + |
| + q = username; |
| + while (*q != '\0' && *q != '\n') { |
| + char c = *q; |
| + if (c >= 0x20 && c <= 0x07e) { |
| + KeySym ks = (KeySym) c; |
| + SendKeyEvent(ks, 1); |
| + SendKeyEvent(ks, 0); |
| + } |
| + q++; |
| + } |
| + |
| + SendKeyEvent(XK_Return, 1); |
| + SendKeyEvent(XK_Return, 0); |
| + |
| + q = passwd; |
| + while (*q != '\0' && *q != '\n') { |
| + char c = *q; |
| + if (c >= 0x20 && c <= 0x07e) { |
| + KeySym ks = (KeySym) c; |
| + SendKeyEvent(ks, 1); |
| + SendKeyEvent(ks, 0); |
| + } |
| + q++; |
| + } |
| + |
| + SendKeyEvent(XK_Return, 1); |
| + SendKeyEvent(XK_Return, 0); |
| +} |
| + |
| +static void chat_window_only(void) { |
| + if (appData.chatOnly) { |
| + static double last_time = 0.0; |
| + if (dnow() > last_time + 1.5) { |
| + XSync(dpy, False); |
| + XUnmapWindow(dpy, XtWindow(toplevel)); |
| + } |
| + } |
| +} |
| + |
| +int saw_appshare = 0; |
| + |
| int |
| main(int argc, char **argv) |
| { |
| - int i; |
| - programName = argv[0]; |
| + int i, save_sbw, saw_listen = 0; |
| + char *pw_loc = NULL; |
| + programName = argv[0]; |
| + |
| + if (strrchr(programName, '/') != NULL) { |
| + programName = strrchr(programName, '/') + 1; |
| + } |
| + |
| + for (i = 1; i < argc; i++) { |
| + if (!strcmp(argv[i], "-env")) { |
| + if (i+1 < argc) { |
| + char *estr = argv[i+1]; |
| + if (strchr(estr, '=')) { |
| + putenv(estr); |
| + } |
| + } |
| + } |
| + if (!strcmp(argv[i], "-noipv4")) { |
| + putenv("VNCVIEWER_NO_IPV4=1"); |
| + } |
| + if (!strcmp(argv[i], "-noipv6")) { |
| + putenv("VNCVIEWER_NO_IPV6=1"); |
| + } |
| + } |
| + if (getenv("VNCVIEWER_NO_IPV4")) { |
| + appData.noipv4 = True; |
| + } |
| + if (getenv("VNCVIEWER_NO_IPV6")) { |
| + appData.noipv6 = True; |
| + } |
| |
| /* 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 +310,1744 @@ |
| listenForIncomingConnections() returns, setting the listenSpecified |
| flag. */ |
| |
| - for (i = 1; i < argc; i++) { |
| - if (strcmp(argv[i], "-listen") == 0) { |
| - listenForIncomingConnections(&argc, argv, i); |
| - break; |
| - } |
| - if (strcmp(argv[i], "-tunnel") == 0 || strcmp(argv[i], "-via") == 0) { |
| - if (!createTunnel(&argc, argv, i)) |
| - exit(1); |
| - break; |
| - } |
| - } |
| + for (i = 1; i < argc; i++) { |
| + if (!strcmp(argv[i], "-appshare")) { |
| + putenv("SSVNC_MULTIPLE_LISTEN=1"); |
| + fprintf(stderr, "Enabling -multilisten mode for 'x11vnc -appshare' usage.\n\n"); |
| + saw_appshare = 1; |
| + } |
| + if (!strcmp(argv[i], "-multilisten")) { |
| + putenv("SSVNC_MULTIPLE_LISTEN=1"); |
| + saw_listen = 2; |
| + } |
| + if (!strcmp(argv[i], "-listen")) { |
| + saw_listen = 1; |
| + } |
| + if (!strcmp(argv[i], "-acceptpopup")) { |
| + putenv("SSVNC_ACCEPT_POPUP=1"); |
| + } |
| + if (!strcmp(argv[i], "-acceptpopupsc")) { |
| + putenv("SSVNC_ACCEPT_POPUP_SC=1"); |
| + } |
| + if (strstr(argv[i], " pw=") != NULL) { |
| + pw_loc = strstr(argv[i], " pw=") + 1; |
| + } |
| + } |
| + |
| + for (i = 1; i < argc; i++) { |
| + if (!strcmp(argv[i], "-appshare") && !saw_listen) { |
| + listenForIncomingConnections(&argc, argv, i); |
| + break; |
| + } |
| + if (!strcmp(argv[i], "-multilisten")) { |
| + listenForIncomingConnections(&argc, argv, i); |
| + break; |
| + } |
| + if (!strcmp(argv[i], "-listen")) { |
| + listenForIncomingConnections(&argc, argv, i); |
| + break; |
| + } |
| + if (!strcmp(argv[i], "-tunnel") || !strcmp(argv[i], "-via")) { |
| + if (!createTunnel(&argc, argv, i)) { |
| + exit(1); |
| + } |
| + break; |
| + } |
| + if (!strcmp(argv[i], "-printres") || !strcmp(argv[i], "-res")) { |
| + int j = 0; |
| + fprintf(stdout, "\n! Ssvnc fallback X resources:\n\n"); |
| + while (1) { |
| + char *p = fallback_resources[j++]; |
| + int k = 0; |
| + if (p == NULL) break; |
| + while (*p != '\0') { |
| + fprintf(stdout, "%c", *p); |
| + if (k > 0 && *p == 'n' && *(p-1) == '\\') { |
| + fprintf(stdout, "\\\n"); |
| + } |
| + p++; k++; |
| + } |
| + fprintf(stdout, "\n\n"); |
| + } |
| + exit(0); |
| + } |
| + } |
| + |
| + |
| + if (argc > 1 && strstr(argv[1], "-h") == argv[1]) { |
| + usage(); |
| + return 0; |
| + } |
| |
| /* Call the main Xt initialisation function. It parses command-line options, |
| generating appropriate resource specs, and makes a connection to the X |
| display. */ |
| |
| - toplevel = XtVaAppInitialize(&appContext, "Vncviewer", |
| - cmdLineOptions, numCmdLineOptions, |
| - &argc, argv, fallback_resources, |
| - XtNborderWidth, 0, NULL); |
| + if (saw_appshare || getenv("VNCVIEWER_MIN_TITLE")) { |
| + min_title(); |
| + } |
| + appData.sbWidth = 0; |
| + if (getenv("VNCVIEWER_SBWIDTH")) { |
| + int sbw = atoi(getenv("VNCVIEWER_SBWIDTH")); |
| + if (sbw > 0) { |
| + appData.sbWidth = sbw; |
| + } |
| + } |
| + if (appData.sbWidth == 0) { |
| + int i, sbw = 0; |
| + for (i = 1; i < argc - 1; i++) { |
| + if (!strcmp(argv[i], "-sbwidth")) { |
| + sbw = atoi(argv[i+1]); |
| + } |
| + } |
| + if (sbw > 0) { |
| + appData.sbWidth = sbw; |
| + } |
| + } |
| + save_sbw = appData.sbWidth; |
| + if (save_sbw > 0) { |
| + set_sbwidth(save_sbw); |
| + } else { |
| + set_sbwidth(6); |
| + } |
| + |
| + toplevel = XtVaAppInitialize(&appContext, "Ssvnc", cmdLineOptions, |
| + numCmdLineOptions, &argc, argv, fallback_resources, |
| + XtNborderWidth, 0, NULL); |
| |
| - dpy = XtDisplay(toplevel); |
| + dpy = XtDisplay(toplevel); |
| |
| /* Interpret resource specs and process any remaining command-line arguments |
| (i.e. the VNC server name). If the server name isn't specified on the |
| command line, getArgsAndResources() will pop up a dialog box and wait |
| for one to be entered. */ |
| |
| - GetArgsAndResources(argc, argv); |
| + GetArgsAndResources(argc, argv); |
| + |
| + if (saw_appshare) { |
| + appData.appShare = True; |
| + } |
| + |
| + if (save_sbw) { |
| + appData.sbWidth = save_sbw; |
| + } |
| + |
| + if (appData.chatOnly) { |
| + appData.encodingsString = "raw hextile"; |
| + } |
| + |
| + if (pw_loc != NULL) { |
| + char *q = pw_loc; |
| + while (*q != '\0' && !isspace(*q)) { |
| + *q = ' '; |
| + q++; |
| + } |
| + } |
| |
| /* Unless we accepted an incoming connection, make a TCP connection to the |
| given VNC server */ |
| |
| - if (!listenSpecified) { |
| - if (!ConnectToRFBServer(vncServerHost, vncServerPort)) exit(1); |
| - } |
| + if (appData.repeaterUltra == NULL) { |
| + if (getenv("SSVNC_REPEATER") != NULL) { |
| + appData.repeaterUltra = strdup(getenv("SSVNC_REPEATER")); |
| + } |
| + } |
| + |
| + if (!listenSpecified) { |
| + if (!ConnectToRFBServer(vncServerHost, vncServerPort)) { |
| + exit(1); |
| + } |
| + if (appData.repeaterUltra != NULL) { |
| + char tmp[256]; |
| + if (strstr(appData.repeaterUltra, "SCIII=") == appData.repeaterUltra) { |
| + appData.repeaterUltra = strdup(appData.repeaterUltra + strlen("SCIII=")); |
| + fprintf(stderr, "sending 'testB' to ultravnc SC III SSL repeater...\n"); |
| + WriteExact(rfbsock, "testB" , 5); |
| + } |
| + if (ReadFromRFBServer(tmp, 12)) { |
| + tmp[12] = '\0'; |
| + fprintf(stderr, "repeater 1st proto line: '%s'\n", tmp); |
| + if (strstr(tmp, "RFB 000.000") == tmp) { |
| + int i; |
| + for (i=0; i<256; i++) { |
| + tmp[i] = '\0'; |
| + } |
| + for (i=0; i<250; i++) { |
| + if (i >= (int) strlen(appData.repeaterUltra)) { |
| + break; |
| + } |
| + tmp[i] = appData.repeaterUltra[i]; |
| + } |
| + fprintf(stderr, "sending '%s' to repeater...\n", tmp); |
| + WriteExact(rfbsock, tmp, 250); |
| + } |
| + } else { |
| + fprintf(stderr, "repeater NO proto line!\n"); |
| + } |
| + } |
| + } |
| |
| /* Initialise the VNC connection, including reading the password */ |
| |
| - if (!InitialiseRFBConnection()) exit(1); |
| + if (!InitialiseRFBConnection()) { |
| + Cleanup(); |
| + exit(1); |
| + } |
| + if (appData.unixPW != NULL) { |
| + unixpw(appData.unixPW, 0); |
| + } else if (getenv("SSVNC_UNIXPW")) { |
| + unixpw(getenv("SSVNC_UNIXPW"), 0); |
| + } |
| |
| /* Create the "popup" widget - this won't actually appear on the screen until |
| some user-defined event causes the "ShowPopup" action to be invoked */ |
| |
| - CreatePopup(); |
| + CreatePopup(); |
| + CreateScaleN(); |
| + CreateTurboVNC(); |
| + CreateQuality(); |
| + CreateCompress(); |
| + CreateChat(); |
| |
| /* Find the best pixel format and X visual/colormap to use */ |
| |
| - SetVisualAndCmap(); |
| + SetVisualAndCmap(); |
| |
| /* Create the "desktop" widget, and perform initialisation which needs doing |
| before the widgets are realized */ |
| |
| - ToplevelInitBeforeRealization(); |
| + ToplevelInitBeforeRealization(); |
| |
| - DesktopInitBeforeRealization(); |
| + DesktopInitBeforeRealization(); |
| |
| /* "Realize" all the widgets, i.e. actually create and map their X windows */ |
| |
| - XtRealizeWidget(toplevel); |
| + XtRealizeWidget(toplevel); |
| |
| /* Perform initialisation that needs doing after realization, now that the X |
| windows exist */ |
| |
| - InitialiseSelection(); |
| + InitialiseSelection(); |
| |
| - ToplevelInitAfterRealization(); |
| + ToplevelInitAfterRealization(); |
| |
| - DesktopInitAfterRealization(); |
| + DesktopInitAfterRealization(); |
| |
| /* Tell the VNC server which pixel format and encodings we want to use */ |
| |
| - SetFormatAndEncodings(); |
| + SetFormatAndEncodings(); |
| + |
| + if (appData.chatOnly) { |
| + chat_window_only(); |
| + ToggleTextChat(0, NULL, NULL, NULL); |
| + } |
| |
| /* Now enter the main loop, processing VNC messages. X events will |
| automatically be processed whenever the VNC connection is idle. */ |
| |
| - while (1) { |
| - if (!HandleRFBServerMessage()) |
| - break; |
| - } |
| + while (1) { |
| + if (!HandleRFBServerMessage()) { |
| + break; |
| + } |
| + if (appData.chatOnly) { |
| + chat_window_only(); |
| + } |
| + } |
| + |
| + Cleanup(); |
| + |
| + return 0; |
| +} |
| + |
| +/* |
| + * Toggle8bpp |
| + */ |
| + |
| +static int last_ncolors = 0; |
| +static int save_useBGR233 = 0; |
| +static Bool save_useBGR565 = False; |
| + |
| +static Widget b8 = NULL; |
| +static Widget b16 = NULL; |
| +static Widget bfull = NULL; |
| + |
| +int do_format_change = 0; |
| +int do_cursor_change = 0; |
| +double 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(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| + |
| +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(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +ToggleEscapeActive(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.escapeActive) { |
| + appData.escapeActive = False; |
| + } else { |
| + appData.escapeActive = True; |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +/* |
| + * 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(); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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(); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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(); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +/* |
| + * 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(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +/* |
| + * ToggleTightZRLE |
| + */ |
| + |
| +static Bool usingZRLE = False; |
| +static Bool usingZYWRLE = False; |
| +static Bool usingHextile = False; |
| +extern int skip_maybe_sync; |
| + |
| +void |
| +ToggleTightZRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + char prefTight[] = "copyrect tight zrle zywrle zlib hextile corre rre raw"; |
| + char prefZRLE[] = "copyrect zrle zywrle tight zlib hextile corre rre raw"; |
| + init_format_change(); |
| + usingHextile = False; |
| + if (! appData.encodingsString) { |
| + appDataNew.encodingsString = strdup(prefZRLE); |
| + usingZRLE = True; |
| + fprintf(stderr, "prefer: ZRLE\n"); |
| + } else { |
| + char *t, *z; |
| + static int first = 1; |
| + t = strstr(appData.encodingsString, "tight"); |
| + z = strstr(appData.encodingsString, "zrle"); |
| + if (first && usingZRLE) { |
| + appDataNew.encodingsString = strdup(prefTight); |
| + usingZRLE = False; |
| + usingZYWRLE = False; |
| + } else if (! t) { |
| + appDataNew.encodingsString = strdup(prefZRLE); |
| + usingZRLE = True; |
| + fprintf(stderr, "prefer: ZRLE\n"); |
| + } else if (! z) { |
| + appDataNew.encodingsString = strdup(prefTight); |
| + usingZRLE = False; |
| + usingZYWRLE = False; |
| + skip_maybe_sync = 0; |
| + fprintf(stderr, "prefer: Tight\n"); |
| + } else { |
| + if (t < z) { |
| + appDataNew.encodingsString = strdup(prefZRLE); |
| + usingZRLE = True; |
| + fprintf(stderr, "prefer: ZRLE\n"); |
| + } else { |
| + appDataNew.encodingsString = strdup(prefTight); |
| + usingZRLE = False; |
| + usingZYWRLE = False; |
| + skip_maybe_sync = 0; |
| + fprintf(stderr, "prefer: Tight\n"); |
| + } |
| + } |
| + first = 0; |
| + } |
| + schedule_format_change(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +ToggleZRLEZYWRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + char prefZYWRLE[] = "copyrect zywrle zrle tight zlib hextile corre rre raw"; |
| + char prefZRLE[] = "copyrect zrle zywrle tight zlib hextile corre rre raw"; |
| + init_format_change(); |
| + usingZRLE = True; |
| + usingHextile = False; |
| + if (! appData.encodingsString) { |
| + appDataNew.encodingsString = strdup(prefZYWRLE); |
| + usingZYWRLE = True; |
| + fprintf(stderr, "prefer: ZYWRLE\n"); |
| + } else { |
| + char *z, *w; |
| + w = strstr(appData.encodingsString, "zywrle"); |
| + z = strstr(appData.encodingsString, "zrle"); |
| + if (usingZYWRLE) { |
| + appDataNew.encodingsString = strdup(prefZRLE); |
| + fprintf(stderr, "prefer: ZRLE\n"); |
| + usingZYWRLE = False; |
| + skip_maybe_sync = 0; |
| + } else { |
| + appDataNew.encodingsString = strdup(prefZYWRLE); |
| + fprintf(stderr, "prefer: ZYWRLE\n"); |
| + usingZYWRLE = True; |
| + } |
| + } |
| + schedule_format_change(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +ToggleTightHextile(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + char prefTight[] = "copyrect tight zrle zywrle zlib hextile corre rre raw"; |
| + char prefHextile[] = "copyrect hextile tight zrle zywrle zlib corre rre raw"; |
| + init_format_change(); |
| + usingZRLE = False; |
| + usingZYWRLE = False; |
| + if (! appData.encodingsString) { |
| + appDataNew.encodingsString = strdup(prefHextile); |
| + usingHextile = True; |
| + fprintf(stderr, "prefer: Hextile\n"); |
| + } else { |
| + char *t, *z; |
| + static int first = 1; |
| + t = strstr(appData.encodingsString, "tight"); |
| + z = strstr(appData.encodingsString, "hextile"); |
| + if (first && usingHextile) { |
| + appDataNew.encodingsString = strdup(prefTight); |
| + usingHextile = False; |
| + } else if (! t) { |
| + appDataNew.encodingsString = strdup(prefHextile); |
| + usingHextile = True; |
| + fprintf(stderr, "prefer: Hextile\n"); |
| + } else if (! z) { |
| + appDataNew.encodingsString = strdup(prefTight); |
| + usingHextile = False; |
| + skip_maybe_sync = 0; |
| + fprintf(stderr, "prefer: Tight\n"); |
| + } else { |
| + if (t < z) { |
| + appDataNew.encodingsString = strdup(prefHextile); |
| + usingHextile = True; |
| + fprintf(stderr, "prefer: Hextile\n"); |
| + } else { |
| + appDataNew.encodingsString = strdup(prefTight); |
| + usingHextile = False; |
| + skip_maybe_sync = 0; |
| + fprintf(stderr, "prefer: Tight\n"); |
| + } |
| + } |
| + first = 0; |
| + } |
| + schedule_format_change(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void scale_check_zrle(void) { |
| + static int didit = 0; |
| + if (didit) { |
| + return; |
| + } |
| + didit = 1; |
| + if (getenv("SSVNC_PRESERVE_ENCODING")) { |
| + return; |
| + } |
| + if (!usingZRLE && !usingHextile) { |
| + Widget w = 0; |
| + fprintf(stderr, "\nSwitching to faster ZRLE encoding in client-side scaling mode.\n"); |
| + fprintf(stderr, "Switch back to Tight via the Popup menu if you prefer it.\n\n"); |
| + ToggleTightZRLE(w, NULL, NULL, NULL); |
| + } |
| +} |
| + |
| +/* |
| + * ToggleViewOnly |
| + */ |
| + |
| +void |
| +ToggleViewOnly(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.viewOnly) { |
| + appData.viewOnly = False; |
| + fprintf(stderr, "viewonly: off\n"); |
| + } else { |
| + appData.viewOnly = True; |
| + fprintf(stderr, "viewonly: on\n"); |
| + } |
| + Xcursors(1); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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; |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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"); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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; |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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"); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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(); |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +TogglePipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.pipelineUpdates) { |
| + appData.pipelineUpdates= False; |
| + fprintf(stderr, "pipeline-update: off\n"); |
| + } else { |
| + appData.pipelineUpdates = True; |
| + fprintf(stderr, "pipeline-update: on\n"); |
| + } |
| + /* XXX request one to be sure? */ |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +ToggleSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.sendClipboard) { |
| + appData.sendClipboard= False; |
| + fprintf(stderr, "Send CLIPBOARD Selection: off (send PRIMARY instead)\n"); |
| + } else { |
| + appData.sendClipboard = True; |
| + fprintf(stderr, "Send CLIPBOARD Selection: on (do not send PRIMARY)\n"); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +ToggleSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.sendAlways) { |
| + appData.sendAlways= False; |
| + fprintf(stderr, "Send Selection Always: off\n"); |
| + } else { |
| + appData.sendAlways = True; |
| + fprintf(stderr, "Send Selection Always: on\n"); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| + |
| +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); |
| + } |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void raiseme(int force); |
| +void AppendChatInput(char *); |
| + |
| +extern void ShowChat(Widget w, XEvent *event, String *params, Cardinal *num_params); |
| +extern void ShowFile(Widget w, XEvent *event, String *params, Cardinal *num_params); |
| +extern Bool SendTextChatFinished(void); |
| + |
| + |
| +void printChat(char *str, Bool raise) { |
| + if (appData.termChat) { |
| + if (raise) { |
| + raiseme(0); |
| + } |
| + fprintf(stderr, str); |
| + } else { |
| + if (raise) { |
| + ShowChat(0, 0, 0, 0); |
| + } |
| + 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(0, 0, 0, 0); |
| + SendTextChatOpen(); |
| + if (appData.termChat) { |
| + printChat("\n*SentOpen*\n\nSend: ", True); |
| + } else { |
| + printChat("\n*SentOpen*\n", True); |
| + } |
| + appData.chatActive = True; |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +extern int filexfer_sock; |
| +extern pid_t java_helper; |
| +#define KILLJAVA |
| +#ifdef KILLJAVA |
| +#include <signal.h> |
| +#endif |
| + |
| +void |
| +ToggleFileXfer(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + static double last_start = 0.0; |
| + if (appData.fileActive) { |
| +#if 0 |
| + HideFile(w, ev, params, num_params); |
| + appData.fileActive = False; |
| +#endif |
| +#ifndef KILLJAVA |
| + if (filexfer_sock >= 0) { |
| + close(filexfer_sock); |
| + } |
| +#else |
| + if (java_helper != 0) { |
| + int i; |
| + if (dnow() < last_start + 6.0) { |
| + fprintf(stderr, "skipping early kill of java helper (less than 5 secs)\n"); |
| + } else { |
| + for (i=1; i<=5; i++) { |
| + pid_t p = java_helper + i; |
| + fprintf(stderr, "trying to kill java helper: %d\n", p); |
| + if (kill(p, SIGTERM) == 0) { |
| + java_helper = 0; |
| + break; |
| + } |
| + } |
| + } |
| + } |
| +#endif |
| + } else { |
| + ShowFile(w, ev, params, num_params); |
| + appData.fileActive = True; |
| + last_start = dnow(); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +static int fooHandler(Display *dpy, XErrorEvent *error) { |
| + if (dpy || 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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +extern void rescale_image(void); |
| +extern void get_scale_values(double *fx, double *fy); |
| + |
| +void |
| +SetScale(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + char *s; |
| + s = DoScaleDialog(); |
| + if (s[0] != '\0') { |
| +#if 0 |
| + int w = si.framebufferWidth; |
| + int h = si.framebufferHeight; |
| +#endif |
| + double fx, fy; |
| + int fs = 0; |
| + if (appData.scale != NULL && !strcmp(s, appData.scale)) { |
| + return; |
| + } |
| + |
| + if (!strcasecmp(s, "none")) { |
| + appData.scale = NULL; |
| + } else if (!strcmp(s, "1.0")) { |
| + appData.scale = NULL; |
| + } else if (!strcmp(s, "1")) { |
| + appData.scale = NULL; |
| + } else { |
| + appData.scale = strdup(s); |
| + } |
| + if (appData.scale != NULL) { |
| + get_scale_values(&fx, &fy); |
| + if (fx <= 0.0 || fy <= 0.0) { |
| + appData.scale = NULL; |
| + return; |
| + } |
| + } |
| + |
| + if (appData.fullScreen) { |
| + fs = 1; |
| + FullScreenOff(); |
| + } |
| + rescale_image(); |
| + if (fs) { |
| + FullScreenOn(); |
| + } |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void set_ycrop(int n) { |
| + if (n >= 1) { |
| + int w = si.framebufferWidth; |
| + int h = si.framebufferHeight; |
| + appData.yCrop = n; |
| + ReDoDesktop(); |
| + SendFramebufferUpdateRequest(0, 0, w, h, False); |
| + schedule_fb_update(); |
| + } |
| +} |
| |
| - Cleanup(); |
| +void |
| +SetYCrop(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + char str[100], *q, *s; |
| + int n; |
| + if (1) { |
| + s = DoYCropDialog(); |
| + } else { |
| + raiseme(1); |
| + fprintf(stderr, "\n\n\a\nEnter pixel size n -ycrop maximum y-height: "); |
| + str[0] = '\0'; |
| + fgets(str, 100, stdin); |
| + s = str; |
| + q = strstr(str, "\n"); |
| + if (q) *q = '\0'; |
| + } |
| + if (s[0] != '\0') { |
| + n = atoi(s); |
| + set_ycrop(n); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (*num_params != 0) { |
| + int n = atoi(params[0]); |
| + set_server_scale(n); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void UpdateQual(void) { |
| + SetFormatAndEncodings(); |
| + UpdateSubsampButtons(); |
| + UpdateQualSlider(); |
| +} |
| + |
| +extern double latency; |
| + |
| +static void LosslessRefresh(void) { |
| + String encodings = appData.encodingsString; |
| + int compressLevel = appData.compressLevel; |
| + int qual = appData.qualityLevel; |
| + Bool enableJPEG = appData.enableJPEG; |
| + appData.qualityLevel = -1; |
| + appData.enableJPEG = False; |
| + appData.encodingsString = "tight copyrect"; |
| + appData.compressLevel = 1; |
| + SetFormatAndEncodings(); |
| + SendFramebufferUpdateRequest(0, 0, si.framebufferWidth, si.framebufferHeight, False); |
| + if (latency > 0.0) { |
| + if (0) usleep((int) latency * 1000); |
| + } |
| + appData.qualityLevel = qual; |
| + appData.enableJPEG = enableJPEG; |
| + appData.encodingsString = encodings; |
| + appData.compressLevel = compressLevel; |
| + SetFormatAndEncodings(); |
| +} |
| + |
| +static void QualHigh(void) { |
| + appData.encodingsString = "tight copyrect"; |
| + if(appData.useBGR233 || appDataNew.useBGR565) { |
| + fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n"); |
| + } else { |
| + appData.enableJPEG = True; |
| + } |
| + appData.subsampLevel = TVNC_1X; |
| + appData.qualityLevel = 95; |
| + UpdateQual(); |
| +} |
| + |
| +static void QualMed(void) { |
| + appData.encodingsString = "tight copyrect"; |
| + if(appData.useBGR233 || appDataNew.useBGR565) { |
| + fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n"); |
| + } else { |
| + appData.enableJPEG = True; |
| + } |
| + appData.subsampLevel = TVNC_2X; |
| + appData.qualityLevel = 80; |
| + UpdateQual(); |
| +} |
| + |
| +static void QualLow(void) { |
| + appData.encodingsString = "tight copyrect"; |
| + if(appData.useBGR233 || appDataNew.useBGR565) { |
| + fprintf(stderr, "WARNING: Cannot enable JPEG because BGR233/BGR565 is enabled.\n"); |
| + } else { |
| + appData.enableJPEG = True; |
| + } |
| + appData.subsampLevel = TVNC_4X; |
| + appData.qualityLevel = 30; |
| + UpdateQual(); |
| +} |
| + |
| +static void QualLossless(void) { |
| + appData.encodingsString = "tight copyrect"; |
| + appData.enableJPEG = False; |
| + appData.compressLevel = 0; |
| + UpdateQual(); |
| +} |
| |
| - return 0; |
| +static void QualLosslessWAN(void) { |
| + appData.encodingsString = "tight copyrect"; |
| + appData.enableJPEG = False; |
| + appData.compressLevel = 1; |
| + UpdateQual(); |
| +} |
| + |
| +void |
| +SetTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (*num_params != 0) { |
| + int n = atoi(params[0]); |
| + if (0) fprintf(stderr, "SetTurboVNC: %d\n", n); |
| + if (n == 1) { |
| + QualHigh(); |
| + } else if (n == 2) { |
| + QualMed(); |
| + } else if (n == 3) { |
| + QualLow(); |
| + } else if (n == 4) { |
| + QualLossless(); |
| + } else if (n == 5) { |
| + QualLosslessWAN(); |
| + } else if (n == 6) { |
| + appData.subsampLevel = TVNC_1X; |
| + UpdateQual(); |
| + } else if (n == 7) { |
| + appData.subsampLevel = TVNC_2X; |
| + UpdateQual(); |
| + } else if (n == 8) { |
| + appData.subsampLevel = TVNC_4X; |
| + UpdateQual(); |
| + } else if (n == 9) { |
| + appData.subsampLevel = TVNC_GRAY; |
| + UpdateQual(); |
| + } else if (n == 10) { |
| + LosslessRefresh(); |
| + } |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (*num_params != 0) { |
| + int n = atoi(params[0]); |
| + set_server_quality(n); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (*num_params != 0) { |
| + int n = atoi(params[0]); |
| + set_server_compress(n); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetNOJPEGState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.enableJPEG) { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +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); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +static void init_state(void) { |
| + static int first = 1; |
| + if (first && appData.encodingsString) { |
| + char *t, *z, *y, *h; |
| + char *str = appData.encodingsString; |
| + int len = strlen(str); |
| + |
| + t = strstr(str, "tight"); |
| + z = strstr(str, "zrle"); |
| + y = strstr(str, "zywrle"); |
| + h = strstr(str, "hextile"); |
| + |
| + if (!t) t = str + len; |
| + if (!z) z = str + len; |
| + if (!y) y = str + len; |
| + if (!h) h = str + len; |
| + |
| + usingZRLE = False; |
| + usingZYWRLE = False; |
| + usingHextile = False; |
| + |
| + if (t < z && t < y && t < h) { |
| + ; |
| + } else if (z < t && z < y && z < h) { |
| + usingZRLE = True; |
| + } else if (y < t && y < z && y < h) { |
| + usingZYWRLE = True; |
| + usingZRLE = True; |
| + } else if (h < t && h < z && h < y) { |
| + usingHextile = True; |
| + } |
| + } |
| + first = 0; |
| + |
| +} |
| + |
| +void |
| +SetZRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + init_state(); |
| + if (usingZRLE) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetHextileState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + init_state(); |
| + if (usingHextile) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetZYWRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + init_state(); |
| + if (usingZYWRLE) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetCursorShapeState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.useRemoteCursor) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetCursorAlphaState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.useCursorAlpha) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetX11CursorState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.useX11Cursor) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetBellState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.useBell) { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetRawLocalState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.useRawLocal) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetServerInputState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (!appData.serverInput) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetPipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (!appData.pipelineUpdates) { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (!appData.sendClipboard) { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (!appData.sendAlways) { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetSingleWindowState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.singleWindow) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.chatActive) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| +} |
| + |
| +void |
| +SetFileXferState(Widget w, XEvent *ev, String *params, Cardinal *num_params) |
| +{ |
| + if (appData.fileActive) { |
| + XtVaSetValues(w, XtNstate, True, NULL); |
| + } else { |
| + XtVaSetValues(w, XtNstate, False, NULL); |
| + } |
| + if (w || ev || params || num_params) {} |
| } |
| 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 2010-04-17 22:29:42.000000000 -0400 |
| @@ -28,6 +28,7 @@ |
| #include <string.h> |
| #include <sys/time.h> |
| #include <sys/types.h> |
| +#include <sys/stat.h> |
| #include <unistd.h> |
| #include <pwd.h> |
| #include <X11/IntrinsicP.h> |
| @@ -51,7 +52,13 @@ |
| (((l) & 0x0000ff00) << 8) | \ |
| (((l) & 0x000000ff) << 24)) : (l)) |
| |
| -#define MAX_ENCODINGS 20 |
| +#define Swap32IfBE(l) \ |
| + (*(char *)&endianTest ? (l) : ((((l) & 0xff000000) >> 24) | \ |
| + (((l) & 0x00ff0000) >> 8) | \ |
| + (((l) & 0x0000ff00) << 8) | \ |
| + (((l) & 0x000000ff) << 24)) ) |
| + |
| +#define MAX_ENCODINGS 24 |
| |
| #define FLASH_PORT_OFFSET 5400 |
| #define LISTEN_PORT_OFFSET 5500 |
| @@ -64,60 +71,133 @@ |
| #define DEFAULT_VIA_CMD \ |
| (DEFAULT_SSH_CMD " -f -L %L:%H:%R %G sleep 20") |
| |
| +#define TVNC_SAMPOPT 4 |
| +enum {TVNC_1X=0, TVNC_4X, TVNC_2X, TVNC_GRAY}; |
| |
| -/* argsresources.c */ |
| - |
| -typedef struct { |
| - Bool shareDesktop; |
| - Bool viewOnly; |
| - Bool fullScreen; |
| - Bool grabKeyboard; |
| - Bool raiseOnBeep; |
| - |
| - String encodingsString; |
| - |
| - Bool useBGR233; |
| - int nColours; |
| - Bool useSharedColours; |
| - Bool forceOwnCmap; |
| - Bool forceTrueColour; |
| - int requestedDepth; |
| - |
| - Bool useShm; |
| - |
| - int wmDecorationWidth; |
| - int wmDecorationHeight; |
| - |
| - char *userLogin; |
| - |
| - char *passwordFile; |
| - Bool passwordDialog; |
| - |
| - int rawDelay; |
| - int copyRectDelay; |
| +#if 0 |
| +static const char *subsampLevel2str[TVNC_SAMPOPT] = { |
| + "1X", "4X", "2X", "Gray" |
| +}; |
| +#endif |
| +#ifdef TURBOVNC |
| +#define rfbTightNoZlib 0x0A |
| +#define rfbTurboVncVendor "TRBO" |
| +#define rfbJpegQualityLevel1 0xFFFFFE01 |
| +#define rfbJpegQualityLevel100 0xFFFFFE64 |
| +#define rfbJpegSubsamp1X 0xFFFFFD00 |
| +#define rfbJpegSubsamp4X 0xFFFFFD01 |
| +#define rfbJpegSubsamp2X 0xFFFFFD02 |
| +#define rfbJpegSubsampGray 0xFFFFFD03 |
| +#endif |
| + |
| +/* for debugging width, height, etc */ |
| +#if 0 |
| +#define XtVaSetValues printf("%s:%d\n", __FILE__, __LINE__); XtVaSetValues |
| +#endif |
| |
| - Bool debug; |
| |
| - int popupButtonCount; |
| +/* argsresources.c */ |
| |
| - int bumpScrollTime; |
| - int bumpScrollPixels; |
| +typedef struct { |
| + Bool shareDesktop; |
| + Bool viewOnly; |
| + Bool fullScreen; |
| + Bool grabKeyboard; |
| + Bool raiseOnBeep; |
| + |
| + String encodingsString; |
| + |
| + int useBGR233; |
| + int nColours; |
| + Bool useSharedColours; |
| + Bool forceOwnCmap; |
| + Bool forceTrueColour; |
| + int requestedDepth; |
| + Bool useBGR565; |
| + Bool useGreyScale; |
| + |
| + Bool grabAll; |
| + Bool useXserverBackingStore; |
| + Bool overrideRedir; |
| + Bool popupFix; |
| + |
| + Bool useShm; |
| + Bool termChat; |
| + |
| + int wmDecorationWidth; |
| + int wmDecorationHeight; |
| + |
| + char *userLogin; |
| + char *unixPW; |
| + char *msLogon; |
| + char *repeaterUltra; |
| + Bool ultraDSM; |
| + Bool acceptPopup; |
| + char *rfbVersion; |
| + |
| + char *passwordFile; |
| + Bool passwordDialog; |
| + Bool notty; |
| + |
| + int rawDelay; |
| + int copyRectDelay; |
| + |
| + int yCrop; |
| + int sbWidth; |
| + Bool useCursorAlpha; |
| + Bool useRawLocal; |
| + |
| + Bool debug; |
| + |
| + int popupButtonCount; |
| + int popupButtonBreak; |
| + |
| + int bumpScrollTime; |
| + int bumpScrollPixels; |
| + |
| + int compressLevel; |
| + int qualityLevel; |
| + Bool enableJPEG; |
| + Bool useRemoteCursor; |
| + Bool useX11Cursor; |
| + Bool useBell; |
| + Bool autoPass; |
| + |
| + Bool serverInput; |
| + Bool singleWindow; |
| + int serverScale; |
| + Bool chatActive; |
| + Bool chatOnly; |
| + Bool fileActive; |
| + |
| + char *scale; |
| + char *escapeKeys; |
| + Bool appShare; |
| + Bool escapeActive; |
| + Bool pipelineUpdates; |
| + |
| + Bool sendClipboard; |
| + Bool sendAlways; |
| + char *recvText; |
| + |
| + /* only for turbovnc mode */ |
| + String subsampString; |
| + int subsampLevel; |
| + Bool doubleBuffer; |
| |
| - int compressLevel; |
| - int qualityLevel; |
| - Bool enableJPEG; |
| - Bool useRemoteCursor; |
| - Bool useX11Cursor; |
| - Bool autoPass; |
| + Bool noipv4; |
| + Bool noipv6; |
| |
| } 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 +210,11 @@ |
| /* colour.c */ |
| |
| extern unsigned long BGR233ToPixel[]; |
| +extern unsigned long BGR565ToPixel[]; |
| |
| extern Colormap cmap; |
| extern Visual *vis; |
| -extern unsigned int visdepth, visbpp; |
| +extern unsigned int visdepth, visbpp, isLSB; |
| |
| extern void SetVisualAndCmap(); |
| |
| @@ -155,15 +236,60 @@ |
| extern GC srcGC, dstGC; |
| extern Dimension dpyWidth, dpyHeight; |
| |
| +extern int appshare_0_hint; |
| +extern int appshare_x_hint; |
| +extern int appshare_y_hint; |
| + |
| extern void DesktopInitBeforeRealization(); |
| extern void DesktopInitAfterRealization(); |
| +extern void Xcursors(int set); |
| extern void SendRFBEvent(Widget w, XEvent *event, String *params, |
| Cardinal *num_params); |
| extern void CopyDataToScreen(char *buf, int x, int y, int width, int height); |
| +extern void FillScreen(int x, int y, int width, int height, unsigned long fill); |
| extern void SynchroniseScreen(); |
| |
| +extern void ReDoDesktop(); |
| +extern void DesktopCursorOff(); |
| +extern void put_image(int x1, int y1, int x2, int y2, int width, int height, int solid); |
| +extern void copy_rect(int x, int y, int width, int height, int src_x, int src_y); |
| + |
| +extern void releaseAllPressedModifiers(void); |
| +extern void fs_grab(int check); |
| +extern void fs_ungrab(int check); |
| + |
| /* dialogs.c */ |
| |
| +extern int use_tty(void); |
| + |
| +extern void ScaleDialogDone(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern char *DoScaleDialog(); |
| + |
| +extern void EscapeDialogDone(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern char *DoEscapeKeysDialog(); |
| + |
| +extern void YCropDialogDone(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern char *DoYCropDialog(); |
| + |
| +extern void ScbarDialogDone(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern char *DoScbarDialog(); |
| + |
| +extern void ScaleNDialogDone(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern char *DoScaleNDialog(); |
| + |
| +extern void QualityDialogDone(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern char *DoQualityDialog(); |
| + |
| +extern void CompressDialogDone(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern char *DoCompressDialog(); |
| + |
| extern void ServerDialogDone(Widget w, XEvent *event, String *params, |
| Cardinal *num_params); |
| extern char *DoServerDialog(); |
| @@ -171,6 +297,10 @@ |
| Cardinal *num_params); |
| extern char *DoPasswordDialog(); |
| |
| +extern void UserDialogDone(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern char *DoUserDialog(); |
| + |
| /* fullscreen.c */ |
| |
| extern void ToggleFullScreen(Widget w, XEvent *event, String *params, |
| @@ -181,6 +311,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 +333,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 +346,29 @@ |
| Cardinal *num_params); |
| extern void CreatePopup(); |
| |
| +extern void HideScaleN(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern void CreateScaleN(); |
| + |
| +extern void HideTurboVNC(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern void CreateTurboVNC(); |
| +extern void UpdateSubsampButtons(); |
| +extern void UpdateQualSlider(); |
| +extern void UpdateQual(); |
| + |
| +extern void HideQuality(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern void CreateQuality(); |
| + |
| +extern void HideCompress(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| +extern void CreateCompress(); |
| + |
| +extern void Noop(Widget w, XEvent *event, String *params, |
| + Cardinal *num_params); |
| + |
| +extern int CreateMsg(char *msg, int wait); |
| /* rfbproto.c */ |
| |
| extern int rfbsock; |
| @@ -229,8 +391,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 +414,10 @@ |
| |
| /* shm.c */ |
| |
| -extern XImage *CreateShmImage(); |
| +extern XImage *CreateShmImage(int do_ycrop); |
| extern void ShmCleanup(); |
| +extern void ShmDetach(); |
| +extern Bool UsingShm(); |
| |
| /* sockets.c */ |
| |
| @@ -252,11 +427,19 @@ |
| extern Bool WriteExact(int sock, char *buf, int n); |
| extern int FindFreeTcpPort(void); |
| extern int ListenAtTcpPort(int port); |
| -extern int ConnectToTcpAddr(unsigned int host, int port); |
| +extern int ListenAtTcpPort6(int port); |
| +extern int dotted_ip(char *host, int partial); |
| +extern int ConnectToTcpAddr(const char *hostname, int port); |
| +extern int ConnectToUnixSocket(char *file); |
| extern int AcceptTcpConnection(int listenSock); |
| +extern int AcceptTcpConnection6(int listenSock); |
| extern Bool SetNonBlocking(int sock); |
| +extern Bool SetNoDelay(int sock); |
| +extern Bool SocketPair(int fd[2]); |
| |
| extern int StringToIPAddr(const char *str, unsigned int *addr); |
| +extern char *get_peer_ip(int sock); |
| +extern char *ip2host(char *ip); |
| extern Bool SameMachine(int sock); |
| |
| /* tunnel.c */ |
| @@ -271,3 +454,82 @@ |
| extern XtAppContext appContext; |
| extern Display* dpy; |
| extern Widget toplevel; |
| + |
| +extern void GotChatText(char *str, int len); |
| +extern void unixpw(char *instr, int vencrypt_plain); |
| + |
| +extern void Toggle8bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Toggle16bpp(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleFullColor(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Toggle256Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Toggle64Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Toggle8Colors(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleGreyScale(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleTightZRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleTightHextile(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleZRLEZYWRLE(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleViewOnly(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleJPEG(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleCursorShape(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleCursorAlpha(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleX11Cursor(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleBell(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleRawLocal(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleServerInput(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void TogglePipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleSingleWindow(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleXGrab(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleEscapeActive(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetEscapeKeys(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void DoServerScale(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void DoServerQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void DoServerCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetScale(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetYCrop(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetScbar(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ShowScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ShowTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ShowQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ShowCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetScaleN(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetTurboVNC(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetQuality(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetCompress(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleTextChat(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleFileXfer(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void ToggleTermTextChat(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| + |
| +extern void scale_check_zrle(void); |
| + |
| +extern void SetViewOnlyState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetNOJPEGState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetScaleNState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetQualityState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetCompressState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Set8bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Set16bppState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetFullColorState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Set256ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Set64ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void Set8ColorsState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetGreyScaleState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetZRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetHextileState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetZYWRLEState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetCursorShapeState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetCursorAlphaState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetX11CursorState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetBellState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetRawLocalState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetServerInputState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetPipelineUpdates(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetSendClipboard(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetSendAlways(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetSingleWindowState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetTermTextChatState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetFileXferState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetXGrabState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| +extern void SetEscapeKeysState(Widget w, XEvent *ev, String *params, Cardinal *num_params); |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/vncviewer.man vnc_unixsrc/vncviewer/vncviewer.man |
| --- vnc_unixsrc.orig/vncviewer/vncviewer.man 2004-03-11 13:14:40.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/vncviewer.man 2010-04-11 23:30:24.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 <const@ce.cctpu.edu.ru> |
| +.\" Copyright (C) 2006-2010 Karl J. Runge <runge@karlrunge.com> |
| .\" |
| .\" 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 "April 2010" "" "SSVNC" |
| .SH NAME |
| -vncviewer \- an X viewer client for VNC |
| +ssvncviewer \- an X viewer client for VNC |
| .SH SYNOPSIS |
| -.B vncviewer |
| +.B ssvncviewer |
| .RI [\| options \|] |
| .RI [\| host \|][\| :display \|] |
| .br |
| -.B vncviewer |
| +.B ssvncviewer |
| .RI [\| options \|] |
| .RI [\| host \|][\| ::port \|] |
| .br |
| -.B vncviewer |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.RI exec=[\| cmd+args... \|] |
| +.br |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.RI fd=n |
| +.br |
| +.B ssvncviewer |
| +.RI [\| options \|] |
| +.RI /path/to/unix/socket |
| +.br |
| +.B ssvncviewer |
| .RI [\| options \|] |
| .IR \-listen |
| .RI [\| display \|] |
| .br |
| -.B vncviewer |
| +.B ssvncviewer |
| .IR \-help |
| .br |
| .SH DESCRIPTION |
| -.B vncviewer |
| +.B ssvncviewer |
| is an Xt\-based client application for the VNC (Virtual Network |
| Computing) system. It can connect to any VNC\-compatible server such |
| -as \fBXvnc\fR or WinVNC, allowing you to control desktop environment |
| +as \fBXvnc\fR, WinVNC, or \fBx11vnc\fR, allowing you to control desktop environment |
| of a different machine. |
| |
| +ssvncviewer is an enhanced version of the tightvnc unix viewer that can |
| +take advantage of features in the \fBx11vnc\fR and UltraVNC VNC servers. |
| +See below for the description of these features. |
| + |
| You can use F8 to display a pop\-up utility menu. Press F8 twice to |
| pass single F8 to the remote side. |
| .SH OPTIONS |
| @@ -102,13 +119,13 @@ |
| TightVNC supports several different compression methods to encode |
| screen updates; this option specifies a set of them to use in order of |
| preference. Encodings are specified separated with spaces, and must |
| -thus be enclosed in quotes if more than one is specified. Available |
| -encodings, in default order for a remote connection, are "copyrect |
| -tight hextile zlib corre rre raw". For a local connection (to the same |
| -machine), the default order to try is "raw copyrect tight hextile zlib |
| -corre rre". Raw encoding is always assumed as a last option if no |
| -other encoding can be used for some reason. For more information on |
| -encodings, see the section ENCODINGS below. |
| +thus be enclosed in quotes if more than one is specified. Commas may be used to avoid spaces. |
| +Available encodings, in default order for a remote connection, are |
| +"copyrect tight hextile zlib corre rre raw". For a local connection |
| +(to the same machine), the default order to try is "raw copyrect tight |
| +hextile zlib corre rre". Raw encoding is always assumed as a last option |
| +if no other encoding can be used for some reason. For more information |
| +on encodings, see the section ENCODINGS below. |
| .TP |
| \fB\-bgr233\fR |
| Always use the BGR233 format to encode pixel data. This reduces |
| @@ -168,6 +185,424 @@ |
| \fB\-autopass\fR |
| Read a plain-text password from stdin. This option affects only the |
| standard VNC authentication. |
| + |
| +.SH Enhanced TightVNC Viewer (SSVNC) OPTIONS |
| +.TP |
| +Enhanced TightVNC Viewer (SSVNC) web page is located at: |
| +.TP |
| +http://www.karlrunge.com/x11vnc/ssvnc.html |
| +.TP |
| +Note: ZRLE and ZYWRLE encodings are now supported. |
| +.TP |
| +Note: F9 is shortcut to Toggle FullScreen mode. |
| +.TP |
| +Note: In -listen mode set the env var. SSVNC_MULTIPLE_LISTEN=1 |
| +to allow more than one incoming VNC server at a time. |
| +This is the same as -multilisten described below. Set |
| +SSVNC_MULTIPLE_LISTEN=MAX:n to allow no more than "n" |
| +simultaneous reverse connections. |
| + |
| +If the host:port is specified as "exec=command args..." |
| +then instead of making a TCP/IP socket connection to the |
| +remote VNC server, "command args..." is executed and the |
| +viewer is attached to its stdio. This enables tunnelling |
| +established via an external command, e.g. an stunnel(8) |
| +that does not involve a listening socket. |
| +This mode does not work for -listen reverse connections. |
| + |
| +If the host:port is specified as "fd=n" then it is assumed |
| +n is an already opened file descriptor to the socket. (i.e |
| +the parent did fork+exec) |
| + |
| +If the host:port contains a '/' it is interpreted as a |
| +unix-domain socket (AF_LOCAL insead of AF_INET) |
| +.TP |
| +\fB\-multilisten\fR |
| +As in -listen (reverse connection listening) except |
| +allow more than one incoming VNC server to be connected |
| +at a time. The default for -listen of only one at a |
| +time tries to play it safe by not allowing anyone on |
| +the network to put (many) desktops on your screen over |
| +a long window of time. Use -multilisten for no limit. |
| +.TP |
| +\fB\-acceptpopup\fR |
| +In \fB\-listen\fR (reverse connection listening) mode when |
| +a reverse VNC connection comes in show a popup asking |
| +whether to Accept or Reject the connection. The IP |
| +address of the connecting host is shown. Same as |
| +setting the env. var. SSVNC_ACCEPT_POPUP=1. |
| +.TP |
| +\fB\-acceptpopupsc\fR |
| +As in \fB\-acceptpopup\fR except assume UltraVNC Single |
| +Click (SC) server. Retrieve User and ComputerName |
| +info from UltraVNC Server and display in the Popup. |
| +.TP |
| +\fB\-use64\fR |
| +In \fB\-bgr233\fR mode, use 64 colors instead of 256. |
| +.TP |
| +\fB\-bgr222\fR |
| +Same as \fB\-use64\fR. |
| +.TP |
| +\fB\-use8\fR |
| +In \fB\-bgr233\fR mode, use 8 colors instead of 256. |
| +.TP |
| +\fB\-bgr111\fR |
| +Same as \fB\-use8\fR. |
| +.TP |
| +\fB\-16bpp\fR |
| +If the vnc viewer X display is depth 24 at 32bpp |
| +request a 16bpp format from the VNC server to cut |
| +network traffic by up to 2X, then tranlate the |
| +pixels to 32bpp locally. |
| +.TP |
| +\fB\-bgr565\fR |
| +Same as \fB\-16bpp\fR. |
| +.TP |
| +\fB\-grey\fR |
| +Use a grey scale for the 16- and 8\fB\-bpp\fR modes. |
| +.TP |
| +\fB\-alpha\fR |
| +Use alphablending transparency for local cursors |
| +requires: x11vnc server, both client and server |
| +must be 32bpp and same endianness. |
| +.TP |
| +\fB\-scale\fR \fIstr\fR |
| +Scale the desktop locally. The string "str" can |
| +a floating point ratio, e.g. "0.9", or a fraction, |
| +e.g. "3/4", or WxH, e.g. 1280x1024. Use "fit" |
| +to fit in the current screen size. Use "auto" to |
| +fit in the window size. "str" can also be set by |
| +the env. var. SSVNC_SCALE. |
| + |
| +If you observe mouse trail painting errors, enable |
| +X11 Cursor mode (either via Popup or \fB\-x11cursor\fR.) |
| + |
| +Note that scaling is done in software and so can be |
| +slow and requires more memory. Some speedup Tips: |
| + |
| +ZRLE is faster than Tight in this mode. When |
| +scaling is first detected, the encoding will |
| +be automatically switched to ZRLE. Use the |
| +Popup menu if you want to go back to Tight. |
| +Set SSVNC_PRESERVE_ENCODING=1 to disable this. |
| + |
| +Use a solid background on the remote side. |
| +(e.g. manually or via x11vnc \fB\-solid\fR ...) |
| + |
| +If the remote server is x11vnc, try client |
| +side caching: x11vnc \fB\-ncache\fR 10 ... |
| +.TP |
| +\fB\-ycrop\fR n |
| +Only show the top n rows of the framebuffer. For |
| +use with x11vnc \fB\-ncache\fR client caching option |
| +to help "hide" the pixel cache region. |
| +Use a negative value (e.g. \fB\-1\fR) for autodetection. |
| +Autodetection will always take place if the remote |
| +fb height is more than 2 times the width. |
| +.TP |
| +\fB\-sbwidth\fR n |
| +Scrollbar width for x11vnc \fB\-ncache\fR mode (\fB\-ycrop\fR), |
| +default is very narrow: 2 pixels, it is narrow to |
| +avoid distraction in \fB\-ycrop\fR mode. |
| +.TP |
| +\fB\-nobell\fR |
| +Disable bell. |
| +.TP |
| +\fB\-rawlocal\fR |
| +Prefer raw encoding for localhost, default is |
| +no, i.e. assumes you have a SSH tunnel instead. |
| +.TP |
| +\fB\-notty\fR |
| +Try to avoid using the terminal for interactive |
| +responses: use windows for messages and prompting |
| +instead. Messages will also be printed to terminal. |
| +.TP |
| +\fB\-sendclipboard\fR |
| +Send the X CLIPBOARD selection (i.e. Ctrl+C, |
| +Ctrl+V) instead of the X PRIMARY selection (mouse |
| +select and middle button paste.) |
| +.TP |
| +\fB\-sendalways\fR |
| +Whenever the mouse enters the VNC viewer main |
| +window, send the selection to the VNC server even if |
| +it has not changed. This is like the Xt resource |
| +translation SelectionToVNC(always) |
| +.TP |
| +\fB\-recvtext\fR |
| +str When cut text is received from the VNC server, |
| +ssvncviewer will set both the X PRIMARY and the |
| +X CLIPBOARD local selections. To control which |
| +is set, specify 'str' as 'primary', 'clipboard', |
| +or 'both' (the default.) |
| +.TP |
| +\fB\-graball\fR |
| +Grab the entire X server when in fullscreen mode, |
| +needed by some old window managers like fvwm2. |
| +.TP |
| +\fB\-popupfix\fR |
| +Warp the popup back to the pointer position, |
| +needed by some old window managers like fvwm2. |
| +.TP |
| +\fB\-grabkbd\fR |
| +Grab the X keyboard when in fullscreen mode, |
| +needed by some window managers. Same as \fB\-grabkeyboard\fR. |
| +\fB\-grabkbd\fR is the default, use \fB\-nograbkbd\fR to disable. |
| +.TP |
| +\fB\-bs\fR, \fB\-nobs\fR |
| +Whether or not to use X server Backingstore for the |
| +main viewer window. The default is to not, mainly |
| +because most Linux, etc, systems X servers disable |
| +*all* Backingstore by default. To re\fB\-enable\fR it put |
| + |
| +Option "Backingstore" |
| + |
| +in the Device section of /etc/X11/xorg.conf. |
| +In \fB\-bs\fR mode with no X server backingstore, whenever an |
| +area of the screen is re\fB\-exposed\fR it must go out to the |
| +VNC server to retrieve the pixels. This is too slow. |
| + |
| +In \fB\-nobs\fR mode, memory is allocated by the viewer to |
| +provide its own backing of the main viewer window. This |
| +actually makes some activities faster (changes in large |
| +regions) but can appear to "flash" too much. |
| +.TP |
| +\fB\-noshm\fR |
| +Disable use of MIT shared memory extension (not recommended) |
| +.TP |
| +\fB\-termchat\fR |
| +Do the UltraVNC chat in the terminal vncviewer is in |
| +instead of in an independent window. |
| +.TP |
| +\fB\-unixpw\fR \fIstr\fR |
| +Useful for logging into x11vnc in \fB\-unixpw\fR mode. "str" is a |
| +string that allows many ways to enter the Unix Username |
| +and Unix Password. These characters: username, newline, |
| +password, newline are sent to the VNC server after any VNC |
| +authentication has taken place. Under x11vnc they are |
| +used for the \fB\-unixpw\fR login. Other VNC servers could do |
| +something similar. |
| + |
| +You can also indicate "str" via the environment |
| +variable SSVNC_UNIXPW. |
| + |
| +Note that the Escape key is actually sent first to tell |
| +x11vnc to not echo the Unix Username back to the VNC |
| +viewer. Set SSVNC_UNIXPW_NOESC=1 to override this. |
| + |
| +If str is ".", then you are prompted at the command line |
| +for the username and password in the normal way. If str is |
| +"-" the stdin is read via getpass(3) for username@password. |
| +Otherwise if str is a file, it is opened and the first line |
| +read is taken as the Unix username and the 2nd as the |
| +password. If str prefixed by "rm:" the file is removed |
| +after reading. Otherwise, if str has a "@" character, |
| +it is taken as username@password. Otherwise, the program |
| +exits with an error. Got all that? |
| +.TP |
| +\fB-repeater\fR \fIstr\fR |
| +This is for use with UltraVNC repeater proxy described |
| +here: http://www.uvnc.com/addons/repeater.html. The "str" |
| +is the ID string to be sent to the repeater. E.g. ID:1234 |
| +It can also be the hostname and port or display of the VNC |
| +server, e.g. 12.34.56.78:0 or snoopy.com:1. Note that when |
| +using -repeater, the host:dpy on the cmdline is the repeater |
| +server, NOT the VNC server. The repeater will connect you. |
| + |
| +Example: vncviewer ... -repeater ID:3333 repeat.host:5900 |
| + |
| +Example: vncviewer ... -repeater vhost:0 repeat.host:5900 |
| + |
| +Use, e.g., '-repeater SCIII=ID:3210' if the repeater is a |
| +Single Click III (SSL) repeater (repeater_SSL.exe) and you |
| +are passing the SSL part of the connection through stunnel, socat, etc. |
| +This way the magic UltraVNC string 'testB' needed to work with the |
| +repeater is sent to it. |
| +.TP |
| +\fB-rfbversion\fR \fIstr\fR |
| +Set the advertised RFB version. E.g.: -rfbversion 3.6 For some |
| +servers, e.g. UltraVNC this needs to be done. |
| +.TP |
| +\fB-ultradsm\fR |
| +UltraVNC has symmetric private encryption DSM plugins. See |
| +http://www.uvnc.com/features/encryption.html. It is assumed |
| +you are using a unix program (e.g. our ultravnc_dsm_helper) to |
| +encrypt and decrypt the UltraVNC DSM stream. IN ADDITION TO |
| +THAT supply -ultradsm to tell THIS viewer to modify the RFB |
| +data sent so as to work with the UltraVNC Server. For some |
| +reason, each RFB msg type must be sent twice under DSM. |
| +.TP |
| +\fB\-mslogon\fR \fIuser\fR |
| +Use Windows MS Logon to an UltraVNC server. Supply the |
| +username or "1" to be prompted. The default is to |
| +autodetect the UltraVNC MS Logon server and prompt for |
| +the username and password. |
| + |
| +IMPORTANT NOTE: The UltraVNC MS-Logon Diffie-Hellman |
| +exchange is very weak and can be brute forced to recover |
| +your username and password in a few seconds of CPU |
| +time. To be safe, be sure to use an additional encrypted |
| +tunnel (e.g. SSL or SSH) for the entire VNC session. |
| +.TP |
| +\fB\-chatonly\fR |
| +Try to be a client that only does UltraVNC text chat. This |
| +mode is used by x11vnc to present a chat window on the physical |
| +X11 console (i.e. to chat with the person at the display). |
| +.TP |
| +\fB-env\fR \fIVAR=VALUE\fR |
| +To save writing a shell script to set environment |
| +variables, specify as many as you need on the command line. For example, |
| +-env SSVNC_MULTIPLE_LISTEN=MAX:5 -env EDITOR=vi |
| +.TP |
| +\fB\-noipv6\fR |
| +Disable all IPv6 sockets. Same as VNCVIEWER_NO_IPV6=1. |
| +.TP |
| +\fB\-noipv4\fR |
| +Disable all IPv4 sockets. Same as VNCVIEWER_NO_IPV4=1. |
| +.TP |
| +\fB\-printres\fR |
| +Print out the Ssvnc X resources (appdefaults) and |
| +then exit. You can save them to a file and customize them (e.g. the |
| +keybindings and Popup menu) Then point to the file via |
| +XENVIRONMENT or XAPPLRESDIR. |
| +.TP |
| +\fB\-pipeline\fR |
| +Like TurboVNC, request the next framebuffer update as soon |
| +as possible instead of waiting until the end of the current |
| +framebuffer update coming in. Helps 'pipeline' the updates. |
| +This is currently the default, use \fB-nopipeline\fR to disable. |
| +.TP |
| +\fB\-appshare\fR |
| +Enable features for use with x11vnc's \fB\-appshare\fR mode where |
| +instead of sharing the full desktop only the application's |
| +windows are shared. Viewer multilisten mode is used to |
| +create the multiple windows: \fB\-multilisten\fR is implied. |
| +See 'x11vnc \fB\-appshare\fR \fB\-help\fR' more information on the mode. |
| +Features enabled in the viewer under \fB\-appshare\fR are: |
| +Minimum extra text in the title, auto \fB\-ycrop\fR is disabled, |
| +x11vnc \fB\-remote_prefix\fR X11VNC_APPSHARE_CMD: message channel, |
| +x11vnc initial window position hints. See also Escape Keys |
| +below for additional key and mouse bindings. |
| +.TP |
| +\fB\-escape \fR\fIstr\fR |
| +This sets the 'Escape Keys' modifier sequence and enables |
| +escape keys mode. When the modifier keys escape sequence |
| +is held down, the next keystroke is interpreted locally |
| +to perform a special action instead of being sent to the |
| +remote VNC server. |
| + |
| +Use '\fB\-escape\fR default' for the default modifier sequence. |
| +(Unix: Alt_L,Super_L and MacOSX: Control_L,Meta_L) |
| + |
| +Here are the 'Escape Keys: Help+Set' instructions from the Popup: |
| + |
| +Escape Keys: Enter a comma separated list of modifier keys to be the 'escape |
| +sequence'. When these keys are held down, the next keystroke is |
| +interpreted locally to invoke a special action instead of being sent to |
| +the remote VNC server. In other words, a set of 'Hot Keys'. |
| + |
| +Here is the list of local key mappings to special actions: |
| + |
| +r: refresh desktop b: toggle bell c: toggle full-color |
| + |
| +f: file transfer x: x11cursor z: toggle Tight/ZRLE |
| + |
| +l: full screen g: graball e: escape keys dialog |
| + |
| +s: scale dialog +: scale up (=) -: scale down (_) |
| + |
| +t: text chat a: alphablend cursor |
| + |
| +V: toggle viewonly Q: quit viewer 123456: UltraVNC scale 1/n |
| + |
| +Arrow keys: pan the viewport about 10% for each keypress. |
| + |
| +PageUp/PageDown: pan the viewport by a screenful vertically. |
| + |
| +Home/End: pan the viewport by a screenful horizontally. |
| + |
| +KeyPad Arrows: pan the viewport by 1 pixel for each keypress. |
| + |
| +Dragging the Mouse with Button1 pressed also pans the viewport. |
| + |
| +Clicking Mouse Button3 brings up the Popup Menu. |
| + |
| +The above mappings are \fBalways\fR active in ViewOnly mode, unless you set |
| +the Escape Keys value to 'never'. |
| + |
| +x11vnc -appshare hot-keys: x11vnc has a simple application sharing mode |
| +that enables the viewer-side to move, resize, or raise the remote toplevel |
| +windows. To enable it, hold down Shift + the Escape Keys and press these: |
| + |
| +Arrow keys: move the remote window around in its desktop. |
| + |
| +PageUp/PageDn/Home/End: resize the remote window. |
| + |
| ++/-: raise or lower the remote window. |
| + |
| +M or Button1 move win to local position; D or Button3: delete remote win. |
| + |
| +If the Escape Keys value below is set to 'default' then a default list of |
| +of modifier keys is used. For Unix it is: Alt_L,Super_L and for MacOSX it |
| +is Control_L,Meta_L. Note: the Super_L key usually has a Windows(TM) Flag |
| +on it. Also note the _L and _R mean the key is on the LEFT or RIGHT side |
| +of the keyboard. |
| + |
| +On Unix the default is Alt and Windows keys on Left side of keyboard. |
| +On MacOSX the default is Control and Command keys on Left side of keyboard. |
| + |
| +Example: Press and hold the Alt and Windows keys on the LEFT side of the |
| +keyboard and then press 'c' to toggle the full-color state. Or press 't' |
| +to toggle the ultravnc Text Chat window, etc. |
| + |
| +To use something besides the default, supply a comma separated list (or a |
| +single one) from: Shift_L Shift_R Control_L Control_R Alt_L Alt_R Meta_L |
| +Meta_R Super_L Super_R Hyper_L Hyper_R or Mode_switch. |
| +.TP |
| +\fB New Popup actions:\fR |
| + |
| + ViewOnly: ~ -viewonly |
| + Disable Bell: ~ -nobell |
| + Cursor Shape: ~ -nocursorshape |
| + X11 Cursor: ~ -x11cursor |
| + Cursor Alphablend: ~ -alpha |
| + Toggle Tight/Hextile: ~ -encodings hextile... |
| + Toggle Tight/ZRLE: ~ -encodings zrle... |
| + Toggle ZRLE/ZYWRLE: ~ -encodings zywrle... |
| + Quality Level ~ -quality (both Tight and ZYWRLE) |
| + Compress Level ~ -compresslevel |
| + Disable JPEG: ~ -nojpeg (Tight) |
| + Pipeline Updates ~ -pipeline |
| + |
| + Full Color as many colors as local screen allows. |
| + Grey scale (16 & 8-bpp) ~ -grey, for low colors 16/8bpp modes only. |
| + 16 bit color (BGR565) ~ -16bpp / -bgr565 |
| + 8 bit color (BGR233) ~ -bgr233 |
| + 256 colors ~ -bgr233 default # of colors. |
| + 64 colors ~ -bgr222 / -use64 |
| + 8 colors ~ -bgr111 / -use8 |
| + Scale Viewer ~ -scale |
| + Escape Keys: Toggle ~ -escape |
| + Escape Keys: Help+Set ~ -escape |
| + Set Y Crop (y-max) ~ -ycrop |
| + Set Scrollbar Width ~ -sbwidth |
| + XGrabServer ~ -graball |
| + |
| + UltraVNC Extensions: |
| + |
| + Set 1/n Server Scale Ultravnc ext. Scale desktop by 1/n. |
| + Text Chat Ultravnc ext. Do Text Chat. |
| + File Transfer Ultravnc ext. File xfer via Java helper. |
| + Single Window Ultravnc ext. Grab and view a single window. |
| + (select then click on the window you want). |
| + Disable Remote Input Ultravnc ext. Try to prevent input and |
| + viewing of monitor at physical display. |
| + |
| + Note: the Ultravnc extensions only apply to servers that support |
| + them. x11vnc/libvncserver supports some of them. |
| + |
| + Send Clipboard not Primary ~ -sendclipboard |
| + Send Selection Every time ~ -sendalways |
| + |
| .SH ENCODINGS |
| The server supplies information in whatever format is desired by the |
| client, in order to make the client as easy as possible to implement. |
| @@ -238,6 +673,15 @@ |
| \-quality and \-nojpeg options above). Tight encoding is usually the |
| best choice for low\-bandwidth network environments (e.g. slow modem |
| connections). |
| +.TP |
| +.B ZRLE |
| +The SSVNC viewer has ported the RealVNC (www.realvnc.com) ZRLE encoding |
| +to the unix tightvnc viewer. |
| +.TP |
| +.B ZYWRLE |
| +The SSVNC viewer has ported the Hitachi lossy wavelet based ZRLE |
| +encoding from http://mobile.hitachi-system.co.jp/publications/ZYWRLE/ |
| +to the unix tightvnc viewer. |
| .SH RESOURCES |
| X resources that \fBvncviewer\fR knows about, aside from the |
| normal Xt resources, are as follows: |
| @@ -364,12 +808,13 @@ |
| .B %R |
| remote TCP port number. |
| .SH SEE ALSO |
| -\fBvncserver\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1), |
| -\fBvncconnect\fR(1), \fBssh\fR(1) |
| +\fBvncserver\fR(1), \fBx11vnc\fR(1), \fBssvnc\fR(1), \fBXvnc\fR(1), \fBvncpasswd\fR(1), |
| +\fBvncconnect\fR(1), \fBssh\fR(1), http://www.karlrunge.com/x11vnc, http://www.karlrunge.com/x11vnc/ssvnc.html |
| .SH AUTHORS |
| Original VNC was developed in AT&T Laboratories Cambridge. TightVNC |
| additions was implemented by Constantin Kaplinsky. Many other people |
| -participated in development, testing and support. |
| +participated in development, testing and support. Karl J. Runge |
| +added all of the SSVNC related features and improvements. |
| |
| \fBMan page authors:\fR |
| .br |
| @@ -380,3 +825,5 @@ |
| Tim Waugh <twaugh@redhat.com>, |
| .br |
| Constantin Kaplinsky <const@ce.cctpu.edu.ru> |
| +.br |
| +Karl J. Runge <runge@karlrunge.com> |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrle.c vnc_unixsrc/vncviewer/zrle.c |
| --- vnc_unixsrc.orig/vncviewer/zrle.c 2007-02-04 18:59:50.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/zrle.c 2010-02-25 23:24:28.000000000 -0500 |
| @@ -0,0 +1,620 @@ |
| +/* |
| + * Copyright (C) 2005 Johannes E. Schindelin. All Rights Reserved. |
| + * |
| + * This is free software; you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License as published by |
| + * the Free Software Foundation; either version 2 of the License, or |
| + * (at your option) any later version. |
| + * |
| + * This software is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with this software; if not, write to the Free Software |
| + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| + * USA. |
| + */ |
| + |
| +/* |
| + * zrle.c - handle zrle encoding. |
| + * |
| + * This file shouldn't be compiled directly. It is included multiple times by |
| + * rfbproto.c, each time with a different definition of the macro BPP. For |
| + * each value of BPP, this file defines a function which handles an zrle |
| + * encoded rectangle with BPP bits per pixel. |
| + */ |
| + |
| +#ifndef REALBPP |
| +#define REALBPP BPP |
| +#endif |
| + |
| +#if !defined(UNCOMP) || UNCOMP==0 |
| +#define HandleZRLE CONCAT2E(HandleZRLE,REALBPP) |
| +#define HandleZRLETile CONCAT2E(HandleZRLETile,REALBPP) |
| +#elif UNCOMP>0 |
| +#define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Down) |
| +#define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Down) |
| +#else |
| +#define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Up) |
| +#define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Up) |
| +#endif |
| +#undef CARDBPP |
| +#undef CARDREALBPP |
| +#define CARDBPP CONCAT2E(CARD, BPP) |
| +#define CARDREALBPP CONCAT2E(CARD,REALBPP) |
| + |
| +#define FillRectangle(x, y, w, h, color) \ |
| + { \ |
| + XGCValues _gcv; \ |
| + _gcv.foreground = color; \ |
| + if (!appData.useXserverBackingStore) { \ |
| + FillScreen(x, y, w, h, _gcv.foreground); \ |
| + } else { \ |
| + XChangeGC(dpy, gc, GCForeground, &_gcv); \ |
| + XFillRectangle(dpy, desktopWin, gc, x, y, w, h); \ |
| + } \ |
| + } |
| + |
| +#if defined(__sparc) || defined(__sparc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN) |
| +#define IS_BIG_ENDIAN 1 |
| +#else |
| +#define IS_BIG_ENDIAN 0 |
| +#endif |
| + |
| +#if DO_ZYWRLE |
| + |
| +#define ENDIAN_LITTLE 0 |
| +#define ENDIAN_BIG 1 |
| +#define ENDIAN_NO 2 |
| +#if IS_BIG_ENDIAN |
| +#define ZYWRLE_ENDIAN ENDIAN_BIG |
| +#else |
| +#define ZYWRLE_ENDIAN ENDIAN_LITTLE |
| +#endif |
| +#undef END_FIX |
| +#if ZYWRLE_ENDIAN == ENDIAN_LITTLE |
| +# define END_FIX LE |
| +#elif ZYWRLE_ENDIAN == ENDIAN_BIG |
| +# define END_FIX BE |
| +#else |
| +# define END_FIX NE |
| +#endif |
| +#define __RFB_CONCAT3E(a,b,c) CONCAT3E(a,b,c) |
| +#define __RFB_CONCAT2E(a,b) CONCAT2E(a,b) |
| +#undef CPIXEL |
| +#if REALBPP != BPP |
| +#if UNCOMP == 0 |
| +#define CPIXEL REALBPP |
| +#elif UNCOMP>0 |
| +#define CPIXEL CONCAT2E(REALBPP,Down) |
| +#else |
| +#define CPIXEL CONCAT2E(REALBPP,Up) |
| +#endif |
| +#endif |
| +#define PIXEL_T CARDBPP |
| +#if BPP!=8 |
| +#define ZYWRLE_DECODE 1 |
| +#include "zywrletemplate.c" |
| +#endif |
| +#undef CPIXEL |
| + |
| +#endif /* DO_ZYWRLE */ |
| + |
| +static int HandleZRLETile( |
| + unsigned char* buffer,size_t buffer_length, |
| + int x,int y,int w,int h); |
| + |
| +static Bool |
| +HandleZRLE (int rx, int ry, int rw, int rh) |
| +{ |
| + rfbZRLEHeader header; |
| + int remaining; |
| + int inflateResult; |
| + int toRead; |
| + int min_buffer_size = rw * rh * (REALBPP / 8) * 2; |
| + |
| + /* First make sure we have a large enough raw buffer to hold the |
| + * decompressed data. In practice, with a fixed REALBPP, fixed frame |
| + * buffer size and the first update containing the entire frame |
| + * buffer, this buffer allocation should only happen once, on the |
| + * first update. |
| + */ |
| + if ( raw_buffer_size < min_buffer_size) { |
| + |
| + if ( raw_buffer != NULL ) { |
| + |
| + free( raw_buffer ); |
| + |
| + } |
| + |
| + raw_buffer_size = min_buffer_size; |
| + raw_buffer = (char*) malloc( raw_buffer_size ); |
| + |
| + } |
| + |
| + if (!ReadFromRFBServer((char *)&header, sz_rfbZRLEHeader)) |
| + return False; |
| + |
| + remaining = Swap32IfLE(header.length); |
| + |
| + /* Need to initialize the decompressor state. */ |
| + decompStream.next_in = ( Bytef * )buffer; |
| + decompStream.avail_in = 0; |
| + decompStream.next_out = ( Bytef * )raw_buffer; |
| + decompStream.avail_out = raw_buffer_size; |
| + decompStream.data_type = Z_BINARY; |
| + |
| + /* Initialize the decompression stream structures on the first invocation. */ |
| + if ( decompStreamInited == False ) { |
| + |
| + inflateResult = inflateInit( &decompStream ); |
| + |
| + if ( inflateResult != Z_OK ) { |
| + fprintf(stderr, |
| + "inflateInit returned error: %d, msg: %s\n", |
| + inflateResult, |
| + decompStream.msg); |
| + return False; |
| + } |
| + |
| + decompStreamInited = True; |
| + |
| + } |
| + |
| + inflateResult = Z_OK; |
| + |
| + /* Process buffer full of data until no more to process, or |
| + * some type of inflater error, or Z_STREAM_END. |
| + */ |
| + while (( remaining > 0 ) && |
| + ( inflateResult == Z_OK )) { |
| + |
| + if ( remaining > BUFFER_SIZE ) { |
| + toRead = BUFFER_SIZE; |
| + } |
| + else { |
| + toRead = remaining; |
| + } |
| + |
| + /* Fill the buffer, obtaining data from the server. */ |
| + if (!ReadFromRFBServer(buffer,toRead)) |
| + return False; |
| + |
| + decompStream.next_in = ( Bytef * )buffer; |
| + decompStream.avail_in = toRead; |
| + |
| + /* Need to uncompress buffer full. */ |
| + inflateResult = inflate( &decompStream, Z_SYNC_FLUSH ); |
| + |
| + /* We never supply a dictionary for compression. */ |
| + if ( inflateResult == Z_NEED_DICT ) { |
| + fprintf(stderr, "zlib inflate needs a dictionary!\n"); |
| + return False; |
| + } |
| + if ( inflateResult < 0 ) { |
| + fprintf(stderr, |
| + "zlib inflate returned error: %d, msg: %s\n", |
| + inflateResult, |
| + decompStream.msg); |
| + return False; |
| + } |
| + |
| + /* Result buffer allocated to be at least large enough. We should |
| + * never run out of space! |
| + */ |
| + if (( decompStream.avail_in > 0 ) && |
| + ( decompStream.avail_out <= 0 )) { |
| + fprintf(stderr, "zlib inflate ran out of space!\n"); |
| + return False; |
| + } |
| + |
| + remaining -= toRead; |
| + |
| + } /* while ( remaining > 0 ) */ |
| + |
| + if ( inflateResult == Z_OK ) { |
| + void* buf=raw_buffer; |
| + int i,j; |
| + |
| + remaining = raw_buffer_size-decompStream.avail_out; |
| + |
| + for(j=0; j<rh; j+=rfbZRLETileHeight) |
| + for(i=0; i<rw; i+=rfbZRLETileWidth) { |
| + int subWidth=(i+rfbZRLETileWidth>rw)?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; i<x+w; i++,buffer+=REALBPP/8) { |
| +# if 0 |
| + ((CARDBPP*)frameBuffer)[j+i] = UncompressCPixel(buffer); |
| + /* alt */ |
| + CARDBPP color = UncompressCPixel(buffer); |
| + CopyDataToScreen((char *)&color, i, j/si.framebufferWidth, 1, 1); |
| +# else |
| + ((CARDBPP*)frameBuffer)[m0++] = UncompressCPixel(buffer); |
| +# endif |
| + } |
| + } |
| + CopyDataToScreen((char *)frameBuffer, x, y, w, h); |
| +if (0) fprintf(stderr, "cha1: %dx%d+%d+%d\n", w, h, x, y); |
| + |
| +#else |
| +# if 0 |
| + CopyRectangle(buffer, x, y, w, h); |
| +# else |
| + CopyDataToScreen((char *)buffer, x, y, w, h); |
| +# endif |
| + buffer+=w*h*REALBPP/8; |
| +#endif |
| + } |
| + break; |
| + } |
| + case 1: /* solid */ |
| + { |
| + CARDBPP color = UncompressCPixel(buffer); |
| + |
| + if(1+REALBPP/8>buffer_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<<bpp)-1, |
| + divider=(8/bpp); |
| + |
| + if(1+type*REALBPP/8+((w+divider-1)/divider)*h>buffer_length) |
| + return -5; |
| + |
| + /* read palette */ |
| + for(i=0; i<type; i++,buffer+=REALBPP/8) |
| + palette[i] = UncompressCPixel(buffer); |
| + |
| + m0 = 0; |
| + /* read palettized pixels */ |
| + for(j=y*si.framebufferWidth; j<(y+h)*si.framebufferWidth; j+=si.framebufferWidth) { |
| + for(i=x,shift=8-bpp; i<x+w; i++) { |
| +# if 0 |
| + ((CARDBPP*)frameBuffer)[j+i] = palette[((*buffer)>>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(j<h) { |
| + int color,length; |
| + /* read color */ |
| + if(buffer+REALBPP/8+1>buffer_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(j<h && length>0) { |
| +# 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<type-128; i++,buffer+=REALBPP/8) |
| + palette[i] = UncompressCPixel(buffer); |
| + /* read palettized pixels */ |
| + i=j=0; |
| + while(j<h) { |
| + int color,length; |
| + /* read color */ |
| + if(buffer>=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(j<h && length>0) { |
| +# if 0 |
| + ((CARDBPP*)frameBuffer)[(y+j)*si.framebufferWidth+x+i] = color; |
| + /* alt */ |
| + CopyDataToScreen((char *)&color, x+i, y+j, 1, 1); |
| +# else |
| + ((CARDBPP*)frameBuffer)[m0++] = color; |
| +# endif |
| + length--; |
| + i++; |
| + if(i>=w) { |
| + i=0; |
| + j++; |
| + } |
| + } |
| + if(length>0) |
| + fprintf(stderr, "Warning: possible ZRLE corruption\n"); |
| + } |
| + CopyDataToScreen((char *)frameBuffer, x, y, w, h); |
| +if (0) fprintf(stderr, "cha5: %dx%d+%d+%d\n", w, h, x, y); |
| + |
| + break; |
| + } |
| + } |
| + |
| +#if DO_ZYWRLE && BPP != 8 |
| + if (zywrle_level & 0x80) { |
| + int th, tx; |
| + int widthInBytes = w * BPP / 8; |
| + int scrWidthInBytes; |
| + char *scr, *buf; |
| + static CARDBPP *ptmp = NULL; |
| + static int ptmp_len = 0; |
| + XImage *im = image_scale ? image_scale : image; |
| + |
| + if (w * h > ptmp_len) { |
| + ptmp_len = w * h; |
| + if (ptmp_len < rfbZRLETileWidth*rfbZRLETileHeight) { |
| + ptmp_len = rfbZRLETileWidth*rfbZRLETileHeight; |
| + } |
| + if (ptmp) { |
| + free(ptmp); |
| + } |
| + ptmp = (CARDBPP *) malloc(ptmp_len * sizeof(CARDBPP)); |
| + } |
| + |
| + zywrle_level &= 0x7F; |
| + /* Reverse copy: screen to buf/ptmp: */ |
| + /* make this CopyDataFromScreen() or something. */ |
| + if (!appData.useBGR565) { |
| + scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8; |
| + if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line; |
| + scr = im->data + y * scrWidthInBytes + x * myFormat.bitsPerPixel / 8; |
| + buf = (char *) ptmp; |
| + |
| + for (th = 0; th < h; th++) { |
| + memcpy(buf, scr, widthInBytes); |
| + buf += widthInBytes; |
| + scr += scrWidthInBytes; |
| + } |
| + } else { |
| + scrWidthInBytes = si.framebufferWidth * 4; |
| + if (scrWidthInBytes != im->bytes_per_line) scrWidthInBytes = im->bytes_per_line; |
| + scr = im->data + y * scrWidthInBytes + x * 4; |
| + buf = (char *) ptmp; |
| + |
| + for (th = 0; th < h; th++) { |
| + for (tx = 0; tx < w; tx++) { |
| + unsigned long pix = *((unsigned int *)scr + tx); |
| + unsigned int r1 = (pix & 0xff0000) >> 16; |
| + unsigned int g1 = (pix & 0x00ff00) >> 8; |
| + unsigned int b1 = (pix & 0x0000ff) >> 0; |
| + int r2, g2, b2, idx; |
| + int rok = 0, gok = 0, bok = 0, is0, sh = 10; |
| + r2 = (31 * r1)/255; |
| + g2 = (63 * g1)/255; |
| + b2 = (31 * b1)/255; |
| + for (is0 = 0; is0 < sh; is0++) { |
| + int is, i, t; |
| + for (i = 0; i < 2; i++) { |
| + if (i == 0) { |
| + is = -is0; |
| + } else { |
| + is = +is0; |
| + } |
| + if (!rok) { |
| + t = r2 + is; |
| + if (r1 == (255 * t)/31) { |
| + r2 = t; rok = 1; |
| + } |
| + } |
| + if (!gok) { |
| + t = g2 + is; |
| + if (g1 == (255 * t)/63) { |
| + g2 = t; gok = 1; |
| + } |
| + } |
| + if (!bok) { |
| + t = b2 + is; |
| + if (b1 == (255 * t)/31) { |
| + b2 = t; bok = 1; |
| + } |
| + } |
| + } |
| + if (rok && gok && bok) { |
| + break; |
| + } |
| + } |
| + idx = (r2 << 11) | (g2 << 5) | (b2 << 0); |
| + *((CARDBPP *)buf + tx) = (CARDBPP) idx; |
| + } |
| + buf += widthInBytes; |
| + scr += scrWidthInBytes; |
| + } |
| + } |
| + ZYWRLE_SYNTHESIZE((PIXEL_T *)ptmp, (PIXEL_T *)ptmp, w, h, w, zywrle_level, zywrleBuf ); |
| + skip_maybe_sync = 1; |
| + |
| + if (appData.yCrop > 0) { |
| + skip_maybe_sync = 0; |
| + } |
| + CopyDataToScreen((char *)ptmp, x, y, w, h); |
| + |
| + } |
| +#endif |
| + |
| + return buffer-buffer_copy; |
| +} |
| + |
| +#undef CARDBPP |
| +#undef CARDREALBPP |
| +#undef HandleZRLE |
| +#undef HandleZRLETile |
| +#undef UncompressCPixel |
| +#undef REALBPP |
| + |
| +#undef UNCOMP |
| + |
| +#undef FillRectangle |
| +#undef IS_BIG_ENDIAN |
| diff -Naur -X ./exclude vnc_unixsrc.orig/vncviewer/zrleencodetemplate.c vnc_unixsrc/vncviewer/zrleencodetemplate.c |
| --- vnc_unixsrc.orig/vncviewer/zrleencodetemplate.c 1969-12-31 19:00:00.000000000 -0500 |
| +++ vnc_unixsrc/vncviewer/zrleencodetemplate.c 2007-02-04 23:18:09.000000000 -0500 |
| @@ -0,0 +1,317 @@ |
| +/* |
| + * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. |
| + * Copyright (C) 2003 Sun Microsystems, Inc. |
| + * |
| + * This is free software; you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License as published by |
| + * the Free Software Foundation; either version 2 of the License, or |
| + * (at your option) any later version. |
| + * |
| + * This software is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with this software; if not, write to the Free Software |
| + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| + * USA. |
| + */ |
| + |
| +/* |
| + * Before including this file, you must define a number of CPP macros. |
| + * |
| + * BPP should be 8, 16 or 32 depending on the bits per pixel. |
| + * GET_IMAGE_INTO_BUF should be some code which gets a rectangle of pixel data |
| + * into the given buffer. EXTRA_ARGS can be defined to pass any other |
| + * arguments needed by GET_IMAGE_INTO_BUF. |
| + * |
| + * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel |
| + * bigger than the largest tile of pixel data, since the ZRLE encoding |
| + * algorithm writes to the position one past the end of the pixel data. |
| + */ |
| + |
| +#include "zrleoutstream.h" |
| +#include "zrlepalettehelper.h" |
| +#include <assert.h> |
| + |
| +/* __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 <stdlib.h> |
| + |
| +#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 <zlib.h> |
| +#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 <assert.h> |
| +#include <string.h> |
| + |
| +#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)*SkipPixel; |
| + end = pX0+(size>>(l+1))*s; |
| + s -= 2; |
| + ofs = (4<<l)*SkipPixel; |
| + while (pX0 < end) { |
| + Harr(pX0, pX0+ofs); |
| + pX0++; |
| + Harr(pX0, pX0+ofs); |
| + pX0++; |
| + Harr(pX0, pX0+ofs); |
| + pX0 += s; |
| + } |
| +} |
| +#define InvWaveletLevel(d,s,l,pix) WaveletLevel(d,s,l,pix) |
| + |
| +#ifdef ZYWRLE_ENCODE |
| +# ifndef ZYWRLE_QUANTIZE |
| +/* Type A:lower bit omitting of EZW style. */ |
| +static InlineX void FilterWaveletSquare(int* pBuf, int width, int height, int level, int l) |
| +{ |
| + int r, s; |
| + int x, y; |
| + int* pH; |
| + const unsigned int* pM; |
| + |
| + pM = &(zywrleParam[level-1][l]); |
| + s = 2<<l; |
| + for (r = 1; r < 4; r++) { |
| + pH = pBuf; |
| + if (r & 0x01) |
| + pH += s>>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<<l; |
| + for (r = 1; r < 4; r++) { |
| + pH = pBuf; |
| + if (r & 0x01) |
| + pH += s>>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<<l; |
| + while (pTop < pEnd) { |
| + WaveletLevel(pTop, width, l, 1); |
| + pTop += s; |
| + } |
| + pTop = pBuf; |
| + pEnd = pBuf+width; |
| + s = 1<<l; |
| + while (pTop < pEnd) { |
| + WaveletLevel(pTop, height,l, width); |
| + pTop += s; |
| + } |
| + FilterWaveletSquare(pBuf, width, height, level, l); |
| + } |
| +} |
| +#endif |
| +#ifdef ZYWRLE_DECODE |
| +static InlineX void InvWavelet(int* pBuf, int width, int height, int level) |
| +{ |
| + int l, s; |
| + int* pTop; |
| + int* pEnd; |
| + |
| + for (l = level - 1; l >= 0; l--) { |
| + pTop = pBuf; |
| + pEnd = pBuf+width; |
| + s = 1<<l; |
| + while (pTop < pEnd) { |
| + InvWaveletLevel(pTop, height,l, width); |
| + pTop += s; |
| + } |
| + pTop = pBuf; |
| + pEnd = pBuf+height*width; |
| + s = width<<l; |
| + while (pTop < pEnd) { |
| + InvWaveletLevel(pTop, width, l, 1); |
| + pTop += s; |
| + } |
| + } |
| +} |
| +#endif |
| + |
| +/* Load/Save coefficients stuffs. |
| + Coefficients manages as 24 bits little-endian pixel. */ |
| +#define ZYWRLE_LOAD_COEFF(pSrc,R,G,B) { \ |
| + R = ((signed char*)pSrc)[2]; \ |
| + G = ((signed char*)pSrc)[1]; \ |
| + B = ((signed char*)pSrc)[0]; \ |
| +} |
| +#define ZYWRLE_SAVE_COEFF(pDst,R,G,B) { \ |
| + ((signed char*)pDst)[2] = (signed char)R; \ |
| + ((signed char*)pDst)[1] = (signed char)G; \ |
| + ((signed char*)pDst)[0] = (signed char)B; \ |
| +} |
| + |
| +/* |
| + RGB <=> 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<<level; \ |
| + if (r & 0x01) \ |
| + pH += s>>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<<level)-1); |
| + *pH &= ~((1<<level)-1); |
| +} |
| + |
| +#endif /* ZYWRLE_ONCE */ |
| + |
| +#ifndef CPIXEL |
| +#ifdef ZYWRLE_ENCODE |
| +static InlineX void ZYWRLE_RGBYUV(int* pBuf, PIXEL_T* data, int width, int height, int scanline) |
| +{ |
| + int R, G, B; |
| + int Y, U, V; |
| + int* pLine; |
| + int* pEnd; |
| + pEnd = pBuf+height*width; |
| + while (pBuf < pEnd) { |
| + pLine = pBuf+width; |
| + while (pBuf < pLine) { |
| + ZYWRLE_LOAD_PIXEL(data,R,G,B); |
| + ZYWRLE_RGBYUV1(R,G,B,Y,U,V,ZYWRLE_YMASK,ZYWRLE_UVMASK); |
| + ZYWRLE_SAVE_COEFF(pBuf,V,Y,U); |
| + pBuf++; |
| + data++; |
| + } |
| + data += scanline-width; |
| + } |
| +} |
| +#endif |
| +#ifdef ZYWRLE_DECODE |
| +static InlineX void ZYWRLE_YUVRGB(int* pBuf, PIXEL_T* data, int width, int height, int scanline) { |
| + int R, G, B; |
| + int Y, U, V; |
| + int* pLine; |
| + int* pEnd; |
| + pEnd = pBuf+height*width; |
| + while (pBuf < pEnd) { |
| + pLine = pBuf+width; |
| + while (pBuf < pLine) { |
| + ZYWRLE_LOAD_COEFF(pBuf,V,Y,U); |
| + ZYWRLE_YUVRGB1(R,G,B,Y,U,V); |
| + ZYWRLE_SAVE_PIXEL(data,R,G,B); |
| + pBuf++; |
| + data++; |
| + } |
| + data += scanline-width; |
| + } |
| +} |
| +#endif |
| + |
| +#ifdef ZYWRLE_ENCODE |
| +PIXEL_T* ZYWRLE_ANALYZE(PIXEL_T* dst, PIXEL_T* src, int w, int h, int scanline, int level, int* pBuf) { |
| + int l; |
| + int uw = w; |
| + int uh = h; |
| + int* pTop; |
| + int* pEnd; |
| + int* pLine; |
| + PIXEL_T* pData; |
| + int R, G, B; |
| + int s; |
| + int* pH; |
| + |
| + zywrleCalcSize(&w, &h, level); |
| + if (w == 0 || h == 0) |
| + return NULL; |
| + uw -= w; |
| + uh -= h; |
| + |
| + pData = dst; |
| + ZYWRLE_LOAD_UNALIGN(src,*(PIXEL_T*)pTop=*pData;) |
| + ZYWRLE_RGBYUV(pBuf, src, w, h, scanline); |
| + Wavelet(pBuf, w, h, level); |
| + for (l = 0; l < level; l++) { |
| + ZYWRLE_PACK_COEFF(pBuf, dst, 3, w, h, scanline, l); |
| + ZYWRLE_PACK_COEFF(pBuf, dst, 2, w, h, scanline, l); |
| + ZYWRLE_PACK_COEFF(pBuf, dst, 1, w, h, scanline, l); |
| + if (l == level - 1) { |
| + ZYWRLE_PACK_COEFF(pBuf, dst, 0, w, h, scanline, l); |
| + } |
| + } |
| + ZYWRLE_SAVE_UNALIGN(dst,*dst=*(PIXEL_T*)pTop;) |
| + return dst; |
| +} |
| +#endif |
| +#ifdef ZYWRLE_DECODE |
| +PIXEL_T* ZYWRLE_SYNTHESIZE(PIXEL_T* dst, PIXEL_T* src, int w, int h, int scanline, int level, int* pBuf) |
| +{ |
| + int l; |
| + int uw = w; |
| + int uh = h; |
| + int* pTop; |
| + int* pEnd; |
| + int* pLine; |
| + PIXEL_T* pData; |
| + int R, G, B; |
| + int s; |
| + int* pH; |
| + |
| + zywrleCalcSize(&w, &h, level); |
| + if (w == 0 || h == 0) |
| + return NULL; |
| + uw -= w; |
| + uh -= h; |
| + |
| + pData = src; |
| + for (l = 0; l < level; l++) { |
| + ZYWRLE_UNPACK_COEFF(pBuf, src, 3, w, h, scanline, l); |
| + ZYWRLE_UNPACK_COEFF(pBuf, src, 2, w, h, scanline, l); |
| + ZYWRLE_UNPACK_COEFF(pBuf, src, 1, w, h, scanline, l); |
| + if (l == level - 1) { |
| + ZYWRLE_UNPACK_COEFF(pBuf, src, 0, w, h, scanline, l); |
| + } |
| + } |
| + ZYWRLE_SAVE_UNALIGN(src,*(PIXEL_T*)pTop=*src;) |
| + InvWavelet(pBuf, w, h, level); |
| + ZYWRLE_YUVRGB(pBuf, dst, w, h, scanline); |
| + ZYWRLE_LOAD_UNALIGN(dst,*pData=*(PIXEL_T*)pTop;) |
| + return src; |
| +} |
| +#endif |
| +#endif /* CPIXEL */ |
| + |
| +#undef ZYWRLE_RGBYUV |
| +#undef ZYWRLE_YUVRGB |
| +#undef ZYWRLE_LOAD_PIXEL |
| +#undef ZYWRLE_SAVE_PIXEL |
| diff -Naur -X ./exclude vnc_unixsrc.orig/include/rfbproto.h vnc_unixsrc/include/rfbproto.h |
| --- vnc_unixsrc.orig/include/rfbproto.h 2004-05-27 03:02:02.000000000 -0400 |
| +++ vnc_unixsrc/include/rfbproto.h 2010-02-25 21:54:58.000000000 -0500 |
| @@ -205,7 +205,22 @@ |
| #define rfbSecTypeInvalid 0 |
| #define rfbSecTypeNone 1 |
| #define rfbSecTypeVncAuth 2 |
| +#define rfbSecTypeRA2 5 |
| +#define rfbSecTypeRA2ne 6 |
| #define rfbSecTypeTight 16 |
| +#define rfbSecTypeUltra 17 |
| + |
| +/* try to support VeNCrypt and TLS */ |
| +#define rfbSecTypeAnonTls 18 |
| +#define rfbSecTypeVencrypt 19 |
| + |
| +#define rfbVencryptPlain 256 |
| +#define rfbVencryptTlsNone 257 |
| +#define rfbVencryptTlsVnc 258 |
| +#define rfbVencryptTlsPlain 259 |
| +#define rfbVencryptX509None 260 |
| +#define rfbVencryptX509Vnc 261 |
| +#define rfbVencryptX509Plain 262 |
| |
| |
| /*----------------------------------------------------------------------------- |
| @@ -381,6 +396,11 @@ |
| #define rfbBell 2 |
| #define rfbServerCutText 3 |
| |
| +#define rfbResizeFrameBuffer 4 /* Modif sf@2002 */ |
| + |
| +/* http://sourceforge.net/projects/vncsessmgr */ |
| +#define rfbRestartConnection 82 |
| + |
| #define rfbFileListData 130 |
| #define rfbFileDownloadData 131 |
| #define rfbFileUploadCancel 132 |
| @@ -403,6 +423,18 @@ |
| #define rfbPointerEvent 5 |
| #define rfbClientCutText 6 |
| |
| +/* ultra */ |
| + |
| +#define rfbFileTransfer 7 |
| +#define rfbSetScale 8 |
| +#define rfbSetServerInput 9 |
| +#define rfbSetSW 10 |
| +#define rfbTextChat 11 |
| +#define rfbKeyFrameRequest 12 |
| +#define rfbPalmVNCSetScaleFactor 0xF |
| + |
| + |
| + |
| #define rfbFileListRequest 130 |
| #define rfbFileDownloadRequest 131 |
| #define rfbFileUploadRequest 132 |
| @@ -435,6 +467,13 @@ |
| #define rfbEncodingTight 7 |
| #define rfbEncodingZlibHex 8 |
| |
| +#define rfbEncodingZRLE 16 |
| +/* |
| +nyama/2006/08/02:new YUV-Wavlet lossy codec based on ZRLE (ZYWRLE) |
| + */ |
| +#define rfbEncodingZYWRLE 17 |
| + |
| + |
| /* signatures for basic encoding types */ |
| #define sig_rfbEncodingRaw "RAW_____" |
| #define sig_rfbEncodingCopyRect "COPYRECT" |
| @@ -955,6 +994,51 @@ |
| #define sz_rfbFileDownloadFailedMsg 4 |
| |
| /*----------------------------------------------------------------------------- |
| + * RestartConnection - the server has restarted the client connection. |
| + */ |
| + |
| +typedef struct _rfbRestartConnectionMsg { |
| + CARD8 type; /* always rfbRestartConnection */ |
| + CARD8 pad1; |
| + CARD16 pad2; |
| + CARD32 length; |
| + /* followed by char text[length] */ |
| +} rfbRestartConnectionMsg; |
| + |
| +#define sz_rfbRestartConnectionMsg 8 |
| + |
| + |
| +typedef struct _rfbTextChatMsg { |
| + CARD8 type; /* always rfbTextChat */ |
| + CARD8 pad1; /* Could be used later as an additionnal param */ |
| + CARD16 pad2; /* Could be used later as text offset, for instance */ |
| + CARD32 length; /* Specific values for Open, close, finished (-1, -2, -3) */ |
| + /* followed by char text[length] */ |
| +} rfbTextChatMsg; |
| + |
| +#define sz_rfbTextChatMsg 8 |
| + |
| +#define rfbTextMaxSize 4096 |
| +#define rfbTextChatOpen 0xFFFFFFFF |
| +#define rfbTextChatClose 0xFFFFFFFE |
| +#define rfbTextChatFinished 0xFFFFFFFD |
| + |
| +/*----------------------------------------------------------------------------- |
| + * Modif sf@2002 |
| + * ResizeFrameBuffer - The Client must change the size of its framebuffer |
| + */ |
| + |
| +typedef struct _rfbResizeFrameBufferMsg { |
| + CARD8 type; /* always rfbResizeFrameBuffer */ |
| + CARD8 pad1; |
| + CARD16 framebufferWidth; /* FrameBuffer width */ |
| + CARD16 framebufferHeight; /* FrameBuffer height */ |
| +} rfbResizeFrameBufferMsg; |
| + |
| +#define sz_rfbResizeFrameBufferMsg 6 |
| + |
| + |
| +/*----------------------------------------------------------------------------- |
| * Union of all server->client messages. |
| */ |
| |
| @@ -968,6 +1052,8 @@ |
| rfbFileDownloadDataMsg fdd; |
| rfbFileUploadCancelMsg fuc; |
| rfbFileDownloadFailedMsg fdf; |
| + rfbRestartConnectionMsg rc; |
| + rfbTextChatMsg tc; |
| } rfbServerToClientMsg; |
| |
| |
| @@ -1221,6 +1307,41 @@ |
| |
| #define sz_rfbFileCreateDirRequestMsg 4 |
| |
| +/* ultra */ |
| +typedef struct _rfbSetScaleMsg { |
| + CARD8 type; /* always rfbSetScale */ |
| + CARD8 scale; /* Scale value 1<sv<n */ |
| + CARD16 pad; |
| +} rfbSetScaleMsg; |
| + |
| +#define sz_rfbSetScaleMsg 4 |
| + |
| +typedef struct { |
| + CARD8 type; /* always rfbSetScaleFactor */ |
| + |
| + CARD8 scale; /* Scale factor (positive non-zero integer) */ |
| + CARD16 pad2; |
| +} rfbPalmVNCSetScaleFactorMsg; |
| + |
| +#define sz_rfbPalmVNCSetScaleFactorMsg (4) |
| + |
| +typedef struct _rfbSetServerInputMsg { |
| + CARD8 type; /* always rfbSetServerInputMsg */ |
| + CARD8 status; /* on or off */ |
| + CARD16 pad; |
| +} rfbSetServerInputMsg; |
| + |
| +#define sz_rfbSetServerInputMsg 4 |
| + |
| +typedef struct _rfbSetSWMsg { |
| + CARD8 type; /* always rfbSetSW */ |
| + CARD8 status; |
| + CARD16 x; |
| + CARD16 y; |
| +} rfbSetSWMsg; |
| + |
| +#define sz_rfbSetSWMsg 6 |
| + |
| /*----------------------------------------------------------------------------- |
| * Union of all client->server messages. |
| */ |
| @@ -1241,4 +1362,9 @@ |
| rfbFileDownloadCancelMsg fdc; |
| rfbFileUploadFailedMsg fuf; |
| rfbFileCreateDirRequestMsg fcdr; |
| + rfbSetScaleMsg ssc; |
| + rfbPalmVNCSetScaleFactorMsg pssf; |
| + rfbSetServerInputMsg sim; |
| + rfbSetSWMsg sw; |
| + rfbTextChatMsg tc; |
| } rfbClientToServerMsg; |
| diff -Naur -X ./exclude vnc_unixsrc.orig/include/vncauth.h vnc_unixsrc/include/vncauth.h |
| --- vnc_unixsrc.orig/include/vncauth.h 2000-06-11 08:00:53.000000000 -0400 |
| +++ vnc_unixsrc/include/vncauth.h 2009-03-21 00:37:23.000000000 -0400 |
| @@ -23,8 +23,11 @@ |
| |
| #define MAXPWLEN 8 |
| #define CHALLENGESIZE 16 |
| +#define CHALLENGESIZE_MSLOGON 64 |
| |
| extern int vncEncryptAndStorePasswd(char *passwd, char *fname); |
| extern char *vncDecryptPasswdFromFile(char *fname); |
| extern void vncRandomBytes(unsigned char *bytes); |
| extern void vncEncryptBytes(unsigned char *bytes, char *passwd); |
| + |
| +extern void vncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd); |
| diff -Naur -X ./exclude vnc_unixsrc.orig/libvncauth/d3des.c vnc_unixsrc/libvncauth/d3des.c |
| --- vnc_unixsrc.orig/libvncauth/d3des.c 2000-06-11 08:00:53.000000000 -0400 |
| +++ vnc_unixsrc/libvncauth/d3des.c 2010-02-25 21:49:02.000000000 -0500 |
| @@ -34,12 +34,15 @@ |
| static void cookey(unsigned long *); |
| |
| static unsigned long KnL[32] = { 0L }; |
| +/* no londer used: */ |
| +#if 0 |
| static unsigned long KnR[32] = { 0L }; |
| static unsigned long Kn3[32] = { 0L }; |
| static unsigned char Df_Key[24] = { |
| 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, |
| 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10, |
| 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 }; |
| +#endif |
| |
| static unsigned short bytebit[8] = { |
| 01, 02, 04, 010, 020, 040, 0100, 0200 }; |
| diff -Naur -X ./exclude vnc_unixsrc.orig/libvncauth/vncauth.c vnc_unixsrc/libvncauth/vncauth.c |
| --- vnc_unixsrc.orig/libvncauth/vncauth.c 2003-03-01 11:48:06.000000000 -0500 |
| +++ vnc_unixsrc/libvncauth/vncauth.c 2010-02-25 21:47:25.000000000 -0500 |
| @@ -27,9 +27,11 @@ |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| +#include <time.h> |
| #include <vncauth.h> |
| #include <d3des.h> |
| |
| +#include <fcntl.h> |
| |
| /* |
| * Make sure we call srandom() only once. |
| @@ -45,6 +47,8 @@ |
| |
| static unsigned char s_fixedkey[8] = {23,82,107,6,35,78,88,7}; |
| |
| +int vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname); |
| +int vncDecryptPasswdFromFile2(char *fname, char *passwdFullControl, char *passwdViewOnly); |
| |
| /* |
| * Encrypt a password and store it in a file. Returns 0 if successful, |
| @@ -73,7 +77,7 @@ |
| vncEncryptAndStorePasswd2(char *passwd, char *passwdViewOnly, char *fname) |
| { |
| FILE *fp; |
| - int i, bytesToWrite, bytesWrote; |
| + int bytesToWrite, bytesWrote; |
| unsigned char encryptedPasswd[16] = { |
| 0,0,0,0,0,0,0,0, |
| 0,0,0,0,0,0,0,0 |
| @@ -195,6 +199,44 @@ |
| return (i < 16) ? 1 : 2; |
| } |
| |
| +unsigned int urandom(void) { |
| + unsigned int val = 0; |
| + struct stat sb; |
| + int fd = -1; |
| + if (fd < 0 && stat("/dev/urandom", &sb) == 0) { |
| + fd = open("/dev/urandom", O_RDONLY); |
| + } |
| + if (fd < 0 && stat("/dev/random", &sb) == 0) { |
| + fd = open("/dev/random", O_RDONLY); |
| + } |
| + if (fd < 0 && stat("/proc/loadavg", &sb) == 0) { |
| + fd = open("/proc/loadavg", O_RDONLY); |
| + } |
| + if (fd < 0 && stat("/bin/bash", &sb) == 0) { |
| + fd = open("/bin/bash", O_RDONLY); |
| + lseek(fd, (off_t) (unsigned int) getpid(), SEEK_SET); |
| + } |
| + if (fd >= 0) { |
| + int i; |
| + for (i=0; i < 3; i++) { |
| + char buf[2]; |
| + if (read(fd, buf, 1) > 0) { |
| + unsigned char uc = (unsigned char) buf[0]; |
| + if (i==0) { |
| + val += uc; |
| + } else if (i==1) { |
| + val += uc * 256; |
| + } else if (i==2) { |
| + val += uc * 256 * 256; |
| + } |
| + } |
| + } |
| + close(fd); |
| + } else { |
| + val = (unsigned int) getpid(); |
| + } |
| + return val; |
| +} |
| |
| /* |
| * Generate CHALLENGESIZE random bytes for use in challenge-response |
| @@ -207,11 +249,13 @@ |
| int i; |
| unsigned int seed; |
| |
| - if (!s_srandom_called) { |
| - seed = (unsigned int)time(0) ^ (unsigned int)getpid(); |
| - srandom(seed); |
| - s_srandom_called = 1; |
| - } |
| + if (!s_srandom_called) { |
| + seed = (unsigned int)time(0) ^ (unsigned int)getpid(); |
| + seed += urandom(); |
| + |
| + srandom(seed); |
| + s_srandom_called = 1; |
| + } |
| |
| for (i = 0; i < CHALLENGESIZE; i++) { |
| bytes[i] = (unsigned char)(random() & 255); |
| @@ -245,3 +289,48 @@ |
| des(bytes+i, bytes+i); |
| } |
| } |
| + |
| +void UvncEncryptPasswd_MSLOGON(unsigned char *encryptedPasswd, char *passwd) { |
| + unsigned int i; |
| + for (i=0; i < 32; i++) { |
| + if (i < strlen(passwd)) { |
| + encryptedPasswd[i] = passwd[i]; |
| + } else { |
| + encryptedPasswd[i] = '\0'; |
| + } |
| + } |
| + deskey(s_fixedkey, EN0); |
| + des(encryptedPasswd, encryptedPasswd); |
| +} |
| + |
| +void UvncEncryptBytes2(unsigned char *where, int length, unsigned char *key) { |
| + int i, j; |
| + deskey(key, EN0); |
| + for (i=0; i < 8; i++) { |
| + where[i] ^= key[i]; |
| + } |
| + des(where, where); |
| + for (i=8; i < length; i += 8) { |
| + for (j=0; j < 8; j++) { |
| + where[i+j] ^= where[i+j-8]; |
| + } |
| + des(where+i, where+i); |
| + } |
| +} |
| + |
| +void UvncDecryptBytes2(unsigned char *where, int length, unsigned char *key) { |
| + int i, j; |
| + deskey(key, DE1); |
| + for (i = length - 8; i > 0; i -= 8) { |
| + des(where + i, where + i); |
| + for (j=0; j < 8; j++) { |
| + where[i+j] ^= where[i+j-8]; |
| + } |
| + } |
| + /* i=0 */ |
| + des(where, where); |
| + for (i=0; i < 8; i++) { |
| + where[i] ^= key[i]; |
| + } |
| +} |
| + |