aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml81
-rw-r--r--.github/workflows/test-report.yml18
-rw-r--r--BUILDING.txt31
-rw-r--r--CMakeLists.txt198
-rw-r--r--README.rst2
-rw-r--r--cmake/Modules/FindAVCodec.cmake47
-rw-r--r--cmake/Modules/FindAVUtil.cmake47
-rw-r--r--cmake/Modules/FindFfmpeg.cmake22
-rw-r--r--cmake/Modules/FindGMP.cmake47
-rw-r--r--cmake/Modules/FindGmp.cmake17
-rw-r--r--cmake/Modules/FindIconv.cmake66
-rw-r--r--cmake/Modules/FindNettle.cmake70
-rw-r--r--cmake/Modules/FindPAM.cmake47
-rw-r--r--cmake/Modules/FindPWQuality.cmake47
-rw-r--r--cmake/Modules/FindPixman.cmake56
-rw-r--r--cmake/Modules/FindSELinux.cmake47
-rw-r--r--cmake/Modules/FindSWScale.cmake47
-rw-r--r--cmake/Modules/FindSystemd.cmake47
-rw-r--r--cmake/StaticBuild.cmake67
-rw-r--r--cmake/TargetLinkDirectories.cmake12
-rw-r--r--common/CMakeLists.txt4
-rw-r--r--common/core/CMakeLists.txt32
-rw-r--r--common/core/Configuration.cxx857
-rw-r--r--common/core/Configuration.h (renamed from common/rfb/Configuration.h)250
-rw-r--r--common/core/Exception.cxx (renamed from common/rdr/Exception.cxx)31
-rw-r--r--common/core/Exception.h (renamed from common/rdr/Exception.h)11
-rw-r--r--common/core/LogWriter.cxx (renamed from common/rfb/LogWriter.cxx)29
-rw-r--r--common/core/LogWriter.h (renamed from common/rfb/LogWriter.h)19
-rw-r--r--common/core/Logger.cxx (renamed from common/rfb/Logger.cxx)6
-rw-r--r--common/core/Logger.h (renamed from common/rfb/Logger.h)8
-rw-r--r--common/core/Logger_file.cxx (renamed from common/rfb/Logger_file.cxx)13
-rw-r--r--common/core/Logger_file.h (renamed from common/rfb/Logger_file.h)11
-rw-r--r--common/core/Logger_stdio.cxx (renamed from common/rfb/Logger_stdio.cxx)7
-rw-r--r--common/core/Logger_stdio.h (renamed from common/rfb/Logger_stdio.h)8
-rw-r--r--common/core/Logger_syslog.cxx (renamed from common/rfb/Logger_syslog.cxx)9
-rw-r--r--common/core/Logger_syslog.h (renamed from common/rfb/Logger_syslog.h)9
-rw-r--r--common/core/Rect.h (renamed from common/rfb/Rect.h)42
-rw-r--r--common/core/Region.cxx (renamed from common/rfb/Region.cxx)74
-rw-r--r--common/core/Region.h (renamed from common/rfb/Region.h)16
-rw-r--r--common/core/Timer.cxx (renamed from common/rfb/Timer.cxx)34
-rw-r--r--common/core/Timer.h (renamed from common/rfb/Timer.h)6
-rw-r--r--common/core/string.cxx (renamed from common/rfb/util.cxx)42
-rw-r--r--common/core/string.h (renamed from common/rfb/util.h)43
-rw-r--r--common/core/time.cxx88
-rw-r--r--common/core/time.h58
-rw-r--r--common/core/winerrno.h (renamed from common/os/winerrno.h)0
-rw-r--r--common/core/xdgdirs.cxx (renamed from common/os/os.cxx)14
-rw-r--r--common/core/xdgdirs.h (renamed from common/os/os.h)8
-rw-r--r--common/network/CMakeLists.txt2
-rw-r--r--common/network/Socket.cxx31
-rw-r--r--common/network/Socket.h11
-rw-r--r--common/network/TcpSocket.cxx144
-rw-r--r--common/network/TcpSocket.h3
-rw-r--r--common/network/UnixSocket.cxx23
-rw-r--r--common/os/CMakeLists.txt15
-rw-r--r--common/os/Mutex.cxx158
-rw-r--r--common/os/Mutex.h64
-rw-r--r--common/os/Thread.cxx173
-rw-r--r--common/os/Thread.h58
-rw-r--r--common/rdr/BufferedInStream.cxx14
-rw-r--r--common/rdr/BufferedOutStream.cxx13
-rw-r--r--common/rdr/CMakeLists.txt11
-rw-r--r--common/rdr/FdInStream.cxx9
-rw-r--r--common/rdr/FdOutStream.cxx14
-rw-r--r--common/rdr/FileInStream.cxx7
-rw-r--r--common/rdr/HexInStream.cxx6
-rw-r--r--common/rdr/HexOutStream.cxx7
-rw-r--r--common/rdr/InStream.h13
-rw-r--r--common/rdr/MemInStream.h1
-rw-r--r--common/rdr/RandomStream.cxx14
-rw-r--r--common/rdr/TLSException.cxx29
-rw-r--r--common/rdr/TLSException.h8
-rw-r--r--common/rdr/TLSInStream.cxx98
-rw-r--r--common/rdr/TLSInStream.h18
-rw-r--r--common/rdr/TLSOutStream.cxx82
-rw-r--r--common/rdr/TLSOutStream.h17
-rw-r--r--common/rdr/TLSSocket.cxx228
-rw-r--r--common/rdr/TLSSocket.h81
-rw-r--r--common/rdr/ZlibOutStream.cxx5
-rw-r--r--common/rfb/Blacklist.cxx32
-rw-r--r--common/rfb/Blacklist.h4
-rw-r--r--common/rfb/CConnection.cxx182
-rw-r--r--common/rfb/CConnection.h199
-rw-r--r--common/rfb/CMakeLists.txt34
-rw-r--r--common/rfb/CMsgHandler.cxx168
-rw-r--r--common/rfb/CMsgHandler.h59
-rw-r--r--common/rfb/CMsgReader.cxx41
-rw-r--r--common/rfb/CMsgReader.h23
-rw-r--r--common/rfb/CMsgWriter.cxx16
-rw-r--r--common/rfb/CMsgWriter.h12
-rw-r--r--common/rfb/CSecurityDH.cxx1
-rw-r--r--common/rfb/CSecurityMSLogonII.cxx1
-rw-r--r--common/rfb/CSecurityRSAAES.cxx24
-rw-r--r--common/rfb/CSecurityRSAAES.h8
-rw-r--r--common/rfb/CSecurityStack.h1
-rw-r--r--common/rfb/CSecurityTLS.cxx450
-rw-r--r--common/rfb/CSecurityTLS.h11
-rw-r--r--common/rfb/CSecurityVeNCrypt.cxx5
-rw-r--r--common/rfb/CSecurityVeNCrypt.h3
-rw-r--r--common/rfb/ClientParams.cxx36
-rw-r--r--common/rfb/ClientParams.h22
-rw-r--r--common/rfb/ComparingUpdateTracker.cxx44
-rw-r--r--common/rfb/ComparingUpdateTracker.h3
-rw-r--r--common/rfb/Configuration.cxx469
-rw-r--r--common/rfb/Congestion.cxx35
-rw-r--r--common/rfb/CopyRectDecoder.cxx19
-rw-r--r--common/rfb/CopyRectDecoder.h8
-rw-r--r--common/rfb/Cursor.cxx30
-rw-r--r--common/rfb/Cursor.h18
-rw-r--r--common/rfb/DecodeManager.cxx126
-rw-r--r--common/rfb/DecodeManager.h37
-rw-r--r--common/rfb/Decoder.cxx12
-rw-r--r--common/rfb/Decoder.h23
-rw-r--r--common/rfb/EncodeManager.cxx159
-rw-r--r--common/rfb/EncodeManager.h73
-rw-r--r--common/rfb/Encoder.h2
-rw-r--r--common/rfb/H264Decoder.cxx24
-rw-r--r--common/rfb/H264Decoder.h12
-rw-r--r--common/rfb/H264DecoderContext.cxx29
-rw-r--r--common/rfb/H264DecoderContext.h23
-rw-r--r--common/rfb/H264LibavDecoderContext.cxx67
-rw-r--r--common/rfb/H264LibavDecoderContext.h8
-rw-r--r--common/rfb/H264WinDecoderContext.cxx80
-rw-r--r--common/rfb/H264WinDecoderContext.h8
-rw-r--r--common/rfb/HextileDecoder.cxx20
-rw-r--r--common/rfb/HextileDecoder.h6
-rw-r--r--common/rfb/HextileEncoder.cxx31
-rw-r--r--common/rfb/Hostname.h120
-rw-r--r--common/rfb/JpegCompressor.cxx6
-rw-r--r--common/rfb/JpegCompressor.h10
-rw-r--r--common/rfb/JpegDecompressor.cxx6
-rw-r--r--common/rfb/JpegDecompressor.h11
-rw-r--r--common/rfb/KeyRemapper.cxx78
-rw-r--r--common/rfb/KeyRemapper.h7
-rw-r--r--common/rfb/PixelBuffer.cxx121
-rw-r--r--common/rfb/PixelBuffer.h47
-rw-r--r--common/rfb/PixelFormat.h2
-rw-r--r--common/rfb/RREDecoder.cxx8
-rw-r--r--common/rfb/RREDecoder.h6
-rw-r--r--common/rfb/RawDecoder.cxx4
-rw-r--r--common/rfb/RawDecoder.h4
-rw-r--r--common/rfb/SConnection.cxx137
-rw-r--r--common/rfb/SConnection.h157
-rw-r--r--common/rfb/SDesktop.h52
-rw-r--r--common/rfb/SMsgHandler.cxx176
-rw-r--r--common/rfb/SMsgHandler.h80
-rw-r--r--common/rfb/SMsgReader.cxx26
-rw-r--r--common/rfb/SMsgWriter.cxx18
-rw-r--r--common/rfb/SMsgWriter.h7
-rw-r--r--common/rfb/SSecurity.h6
-rw-r--r--common/rfb/SSecurityPlain.cxx27
-rw-r--r--common/rfb/SSecurityPlain.h20
-rw-r--r--common/rfb/SSecurityRSAAES.cxx26
-rw-r--r--common/rfb/SSecurityRSAAES.h11
-rw-r--r--common/rfb/SSecurityTLS.cxx117
-rw-r--r--common/rfb/SSecurityTLS.h12
-rw-r--r--common/rfb/SSecurityVeNCrypt.cxx9
-rw-r--r--common/rfb/SSecurityVeNCrypt.h6
-rw-r--r--common/rfb/SSecurityVncAuth.cxx22
-rw-r--r--common/rfb/SSecurityVncAuth.h11
-rw-r--r--common/rfb/ScreenSet.h7
-rw-r--r--common/rfb/Security.cxx34
-rw-r--r--common/rfb/Security.h14
-rw-r--r--common/rfb/SecurityClient.cxx21
-rw-r--r--common/rfb/SecurityClient.h7
-rw-r--r--common/rfb/SecurityServer.cxx20
-rw-r--r--common/rfb/SecurityServer.h3
-rw-r--r--common/rfb/ServerCore.cxx44
-rw-r--r--common/rfb/ServerCore.h34
-rw-r--r--common/rfb/ServerParams.cxx31
-rw-r--r--common/rfb/ServerParams.h16
-rw-r--r--common/rfb/TightDecoder.cxx21
-rw-r--r--common/rfb/TightDecoder.h15
-rw-r--r--common/rfb/UnixPasswordValidator.cxx117
-rw-r--r--common/rfb/UnixPasswordValidator.h14
-rw-r--r--common/rfb/UpdateTracker.cxx43
-rw-r--r--common/rfb/UpdateTracker.h45
-rw-r--r--common/rfb/VNCSConnectionST.cxx83
-rw-r--r--common/rfb/VNCSConnectionST.h30
-rw-r--r--common/rfb/VNCServer.h14
-rw-r--r--common/rfb/VNCServerST.cxx96
-rw-r--r--common/rfb/VNCServerST.h35
-rw-r--r--common/rfb/WinPasswdValidator.cxx3
-rw-r--r--common/rfb/WinPasswdValidator.h6
-rw-r--r--common/rfb/ZRLEDecoder.cxx14
-rw-r--r--common/rfb/ZRLEDecoder.h6
-rw-r--r--common/rfb/ZRLEEncoder.cxx24
-rw-r--r--common/rfb/ZRLEEncoder.h8
-rw-r--r--common/rfb/pam.c95
-rw-r--r--common/rfb/pam.h34
-rw-r--r--contrib/packages/deb/ubuntu-focal/debian/rules8
-rw-r--r--contrib/packages/deb/ubuntu-jammy/debian/rules8
-rw-r--r--contrib/packages/deb/ubuntu-noble/debian/rules8
-rw-r--r--contrib/packages/rpm/el7/SOURCES/10-libvnc.conf19
-rw-r--r--contrib/packages/rpm/el7/SPECS/tigervnc.spec729
-rw-r--r--contrib/packages/rpm/el8/SPECS/tigervnc.spec11
-rw-r--r--contrib/packages/rpm/el9/SPECS/tigervnc.spec11
-rw-r--r--java/CMakeLists.txt2
-rw-r--r--java/com/tigervnc/vncviewer/MANIFEST.MF2
-rw-r--r--java/com/tigervnc/vncviewer/OptionsDialog.java54
-rw-r--r--java/com/tigervnc/vncviewer/Parameters.java83
-rw-r--r--java/com/tigervnc/vncviewer/README2
-rw-r--r--java/com/tigervnc/vncviewer/ServerDialog.java4
-rw-r--r--java/com/tigervnc/vncviewer/UserPreferences.java5
-rw-r--r--java/com/tigervnc/vncviewer/Viewport.java23
-rw-r--r--java/com/tigervnc/vncviewer/VncViewer.java17
-rw-r--r--po/CMakeLists.txt3
-rw-r--r--po/bg.po680
-rw-r--r--po/cs.po689
-rw-r--r--po/de.po691
-rw-r--r--po/es.po701
-rw-r--r--po/fi.po684
-rw-r--r--po/id.po689
-rw-r--r--po/ka.po829
-rw-r--r--po/ro.po722
-rw-r--r--po/ru.po731
-rw-r--r--po/sk.po688
-rw-r--r--po/sr.po686
-rw-r--r--po/sv.po702
-rw-r--r--po/tigervnc.pot624
-rw-r--r--po/uk.po684
-rw-r--r--po/zh_TW.po690
-rw-r--r--release/CMakeLists.txt35
-rw-r--r--release/Info.plist.in12
-rw-r--r--release/makemacapp.in10
-rw-r--r--release/maketarball.in14
-rw-r--r--release/tigervnc.iss.in6
-rw-r--r--release/winvnc.iss.in2
-rw-r--r--tests/CMakeLists.txt4
-rw-r--r--tests/perf/CMakeLists.txt8
-rw-r--r--tests/perf/decperf.cxx11
-rw-r--r--tests/perf/encperf.cxx70
-rw-r--r--tests/perf/fbperf.cxx12
-rw-r--r--tests/unit/CMakeLists.txt42
-rw-r--r--tests/unit/configargs.cxx325
-rw-r--r--tests/unit/conv.cxx187
-rw-r--r--tests/unit/convertlf.cxx137
-rw-r--r--tests/unit/emulatemb.cxx460
-rw-r--r--tests/unit/gesturehandler.cxx856
-rw-r--r--tests/unit/hostport.cxx159
-rw-r--r--tests/unit/parameters.cxx839
-rw-r--r--tests/unit/pixelformat.cxx279
-rw-r--r--tests/unit/shortcuthandler.cxx607
-rw-r--r--tests/unit/unicode.cxx274
-rw-r--r--unix/common/CMakeLists.txt1
-rw-r--r--unix/common/randr.cxx9
-rw-r--r--unix/common/unixcommon.h5
-rw-r--r--unix/tx/CMakeLists.txt2
-rw-r--r--unix/tx/TXButton.h7
-rw-r--r--unix/tx/TXCheckbox.h7
-rw-r--r--unix/tx/TXDialog.h4
-rw-r--r--unix/tx/TXLabel.h9
-rw-r--r--unix/vncconfig/CMakeLists.txt2
-rw-r--r--unix/vncconfig/QueryConnectDialog.cxx15
-rw-r--r--unix/vncconfig/QueryConnectDialog.h9
-rw-r--r--unix/vncconfig/vncExt.c10
-rw-r--r--unix/vncconfig/vncExt.h153
-rw-r--r--unix/vncconfig/vncconfig.cxx106
-rw-r--r--unix/vncconfig/vncconfig.man28
-rw-r--r--unix/vncpasswd/CMakeLists.txt5
-rw-r--r--unix/vncpasswd/vncpasswd.cxx31
-rw-r--r--unix/vncserver/CMakeLists.txt5
-rw-r--r--unix/vncserver/selinux/vncsession.te14
-rw-r--r--unix/vncserver/vncserver@.service.in2
-rw-r--r--unix/vncserver/vncsession.c10
-rw-r--r--unix/x0vncserver/CMakeLists.txt7
-rw-r--r--unix/x0vncserver/Geometry.cxx15
-rw-r--r--unix/x0vncserver/Geometry.h13
-rw-r--r--unix/x0vncserver/Image.cxx5
-rw-r--r--unix/x0vncserver/PollingManager.cxx19
-rw-r--r--unix/x0vncserver/XDesktop.cxx64
-rw-r--r--unix/x0vncserver/XDesktop.h3
-rw-r--r--unix/x0vncserver/XPixelBuffer.cxx36
-rw-r--r--unix/x0vncserver/XPixelBuffer.h10
-rw-r--r--unix/x0vncserver/XSelection.cxx32
-rw-r--r--unix/x0vncserver/x0vncserver.cxx195
-rw-r--r--unix/x0vncserver/x0vncserver.man322
-rw-r--r--unix/xserver/hw/vnc/Makefile.am21
-rw-r--r--unix/xserver/hw/vnc/RFBGlue.cc118
-rw-r--r--unix/xserver/hw/vnc/RFBGlue.h6
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc121
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h23
-rw-r--r--unix/xserver/hw/vnc/Xvnc.man335
-rw-r--r--unix/xserver/hw/vnc/vncExt.c23
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc143
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.h2
-rw-r--r--unix/xserver/hw/vnc/vncInput.c2
-rw-r--r--unix/xserver/hw/vnc/vncModule.c2
-rw-r--r--unix/xserver/hw/vnc/xvnc.c65
-rw-r--r--unix/xserver120.patch2
-rw-r--r--unix/xserver21.patch2
-rw-r--r--vncviewer/BaseTouchHandler.cxx5
-rw-r--r--vncviewer/CConn.cxx354
-rw-r--r--vncviewer/CConn.h26
-rw-r--r--vncviewer/CMakeLists.txt7
-rw-r--r--vncviewer/DesktopWindow.cxx592
-rw-r--r--vncviewer/DesktopWindow.h57
-rw-r--r--vncviewer/EmulateMB.cxx10
-rw-r--r--vncviewer/EmulateMB.h20
-rw-r--r--vncviewer/GestureHandler.cxx14
-rw-r--r--vncviewer/GestureHandler.h10
-rw-r--r--vncviewer/Keyboard.h5
-rw-r--r--vncviewer/KeyboardMacOS.h11
-rw-r--r--vncviewer/KeyboardMacOS.mm202
-rw-r--r--vncviewer/KeyboardWin32.cxx155
-rw-r--r--vncviewer/KeyboardWin32.h4
-rw-r--r--vncviewer/KeyboardX11.cxx130
-rw-r--r--vncviewer/KeyboardX11.h10
-rw-r--r--vncviewer/MonitorIndicesParameter.cxx127
-rw-r--r--vncviewer/MonitorIndicesParameter.h17
-rw-r--r--vncviewer/OptionsDialog.cxx382
-rw-r--r--vncviewer/OptionsDialog.h20
-rw-r--r--vncviewer/PlatformPixelBuffer.cxx12
-rw-r--r--vncviewer/PlatformPixelBuffer.h12
-rw-r--r--vncviewer/ServerDialog.cxx80
-rw-r--r--vncviewer/ShortcutHandler.cxx275
-rw-r--r--vncviewer/ShortcutHandler.h79
-rw-r--r--vncviewer/Surface_Win32.cxx24
-rw-r--r--vncviewer/UserDialog.cxx34
-rw-r--r--vncviewer/UserDialog.h2
-rw-r--r--vncviewer/Viewport.cxx364
-rw-r--r--vncviewer/Viewport.h29
-rw-r--r--vncviewer/Win32TouchHandler.cxx8
-rw-r--r--vncviewer/XInputTouchHandler.cxx5
-rw-r--r--vncviewer/cocoa.h11
-rw-r--r--vncviewer/cocoa.mm234
-rw-r--r--vncviewer/fltk/Fl_Navigation.cxx12
-rw-r--r--vncviewer/fltk/layout.h13
-rw-r--r--vncviewer/menukey.cxx86
-rw-r--r--vncviewer/menukey.h34
-rw-r--r--vncviewer/org.tigervnc.vncviewer.metainfo.xml.in14
-rw-r--r--vncviewer/parameters.cxx593
-rw-r--r--vncviewer/parameters.h79
-rw-r--r--vncviewer/touch.cxx4
-rw-r--r--vncviewer/vncviewer.cxx158
-rw-r--r--vncviewer/vncviewer.desktop.in.in2
-rw-r--r--vncviewer/vncviewer.man310
-rw-r--r--vncviewer/vncviewer.rc.in8
-rw-r--r--vncviewer/win32.c66
-rw-r--r--win/rfb_win32/AboutDialog.cxx5
-rw-r--r--win/rfb_win32/CleanDesktop.cxx12
-rw-r--r--win/rfb_win32/Clipboard.cxx15
-rw-r--r--win/rfb_win32/CompatibleBitmap.h4
-rw-r--r--win/rfb_win32/CurrentUser.cxx13
-rw-r--r--win/rfb_win32/DIBSectionBuffer.cxx10
-rw-r--r--win/rfb_win32/DIBSectionBuffer.h4
-rw-r--r--win/rfb_win32/DeviceContext.cxx22
-rw-r--r--win/rfb_win32/DeviceContext.h8
-rw-r--r--win/rfb_win32/DeviceFrameBuffer.cxx18
-rw-r--r--win/rfb_win32/DeviceFrameBuffer.h19
-rw-r--r--win/rfb_win32/Dialog.cxx13
-rw-r--r--win/rfb_win32/EventManager.cxx5
-rw-r--r--win/rfb_win32/IconInfo.h4
-rw-r--r--win/rfb_win32/IntervalTimer.h4
-rw-r--r--win/rfb_win32/LaunchProcess.cxx10
-rw-r--r--win/rfb_win32/LocalMem.h4
-rw-r--r--win/rfb_win32/MonitorInfo.cxx12
-rw-r--r--win/rfb_win32/MsgWindow.cxx12
-rw-r--r--win/rfb_win32/RegConfig.cxx22
-rw-r--r--win/rfb_win32/RegConfig.h8
-rw-r--r--win/rfb_win32/Registry.cxx46
-rw-r--r--win/rfb_win32/SDisplay.cxx21
-rw-r--r--win/rfb_win32/SDisplay.h25
-rw-r--r--win/rfb_win32/SDisplayCorePolling.cxx11
-rw-r--r--win/rfb_win32/SDisplayCorePolling.h4
-rw-r--r--win/rfb_win32/SDisplayCoreWMHooks.cxx4
-rw-r--r--win/rfb_win32/SInput.cxx8
-rw-r--r--win/rfb_win32/SInput.h12
-rw-r--r--win/rfb_win32/Security.cxx30
-rw-r--r--win/rfb_win32/SecurityPage.cxx8
-rw-r--r--win/rfb_win32/Service.cxx39
-rw-r--r--win/rfb_win32/SocketManager.cxx21
-rw-r--r--win/rfb_win32/TrayIcon.h2
-rw-r--r--win/rfb_win32/TsSessions.cxx12
-rw-r--r--win/rfb_win32/WMCursor.cxx11
-rw-r--r--win/rfb_win32/WMCursor.h2
-rw-r--r--win/rfb_win32/WMHooks.cxx51
-rw-r--r--win/rfb_win32/WMHooks.h5
-rw-r--r--win/rfb_win32/WMNotifier.cxx5
-rw-r--r--win/rfb_win32/WMPoller.cxx11
-rw-r--r--win/rfb_win32/WMPoller.h10
-rw-r--r--win/rfb_win32/WMShatter.cxx5
-rw-r--r--win/rfb_win32/WMWindowCopyRect.cxx9
-rw-r--r--win/rfb_win32/WMWindowCopyRect.h2
-rw-r--r--win/rfb_win32/Win32Util.cxx15
-rw-r--r--win/vncconfig/Authentication.h2
-rw-r--r--win/vncconfig/Connections.h18
-rw-r--r--win/vncconfig/Desktop.h10
-rw-r--r--win/vncconfig/Legacy.cxx12
-rw-r--r--win/vncconfig/vncconfig.cxx26
-rw-r--r--win/vncconfig/vncconfig.rc4
-rw-r--r--win/winvnc/ControlPanel.cxx6
-rw-r--r--win/winvnc/ControlPanel.h2
-rw-r--r--win/winvnc/ManagedListener.cxx4
-rw-r--r--win/winvnc/QueryConnectDialog.cxx22
-rw-r--r--win/winvnc/QueryConnectDialog.h10
-rw-r--r--win/winvnc/STrayIcon.cxx19
-rw-r--r--win/winvnc/STrayIcon.h20
-rw-r--r--win/winvnc/VNCServerService.cxx8
-rw-r--r--win/winvnc/VNCServerWin32.cxx50
-rw-r--r--win/winvnc/VNCServerWin32.h13
-rw-r--r--win/winvnc/winvnc.cxx31
-rw-r--r--win/winvnc/winvnc.rc4
-rw-r--r--win/wm_hooks/wm_hooks.cxx1
-rw-r--r--win/wm_hooks/wm_hooks.rc4
405 files changed, 18625 insertions, 13872 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3c816320..760cab7c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -6,6 +6,8 @@ jobs:
build-linux:
runs-on: ubuntu-latest
timeout-minutes: 10
+ env:
+ VERBOSE: 1
steps:
- uses: actions/checkout@v4
- name: Install dependencies
@@ -16,8 +18,17 @@ jobs:
sudo apt-get install -y libgnutls28-dev nettle-dev libgmp-dev
sudo apt-get install -y libxtst-dev libxdamage-dev libxfixes-dev libxrandr-dev libpam-dev
sudo apt-get install -y libavcodec-dev libavutil-dev libswscale-dev
+ sudo apt-get install -y libgtest-dev
- name: Configure
- run: cmake -DCMAKE_BUILD_TYPE=Debug -S . -B build
+ run: |
+ cmake \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DENABLE_NLS=ON \
+ -DENABLE_H264=ON \
+ -DENABLE_GNUTLS=ON \
+ -DENABLE_NETTLE=ON \
+ -DBUILD_VIEWER=ON \
+ -S . -B build
- name: Build
working-directory: build
run: make
@@ -28,30 +39,49 @@ jobs:
with:
name: Linux (Ubuntu)
path: build/tigervnc-*.tar.gz
+ - name: Test
+ working-directory: build
+ run: ctest --test-dir tests/unit/ --output-junit test-results.xml
+ - name: Upload test results
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: test-results-linux
+ path: build/tests/unit/test-results.xml
build-windows:
runs-on: windows-latest
timeout-minutes: 20
+ env:
+ VERBOSE: 1
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
+ with:
+ update: true
- name: Install dependencies
run: |
pacman --sync --noconfirm --needed \
make mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake
pacman --sync --noconfirm --needed \
- mingw-w64-x86_64-libjpeg-turbo \
+ mingw-w64-x86_64-fltk1.3 mingw-w64-x86_64-libjpeg-turbo \
mingw-w64-x86_64-gnutls mingw-w64-x86_64-pixman \
- mingw-w64-x86_64-nettle mingw-w64-x86_64-gmp
- # MSYS2 only packages FLTK 1.4 now:
- # https://github.com/msys2/MINGW-packages/issues/22769
- pacman --upgrade --noconfirm --needed \
- https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-fltk-1.3.9-2-any.pkg.tar.zst
+ mingw-w64-x86_64-nettle mingw-w64-x86_64-gmp \
+ mingw-w64-x86_64-gtest
- name: Configure
- run: cmake -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug -S . -B build
+ run: |
+ cmake \
+ -G "MSYS Makefiles" \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DENABLE_NLS=ON \
+ -DENABLE_H264=ON \
+ -DENABLE_GNUTLS=ON \
+ -DENABLE_NETTLE=ON \
+ -DBUILD_VIEWER=ON \
+ -S . -B build
- name: Build
working-directory: build
run: make
@@ -64,19 +94,39 @@ jobs:
with:
name: Windows
path: build/release/tigervnc*.exe
+ - name: Test
+ working-directory: build
+ run: ctest --test-dir tests/unit/ --output-junit test-results.xml
+ - name: Upload test results
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: test-results-windows
+ path: build/tests/unit/test-results.xml
build-macos:
runs-on: macos-latest
timeout-minutes: 20
+ env:
+ VERBOSE: 1
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install fltk@1.3 pixman ffmpeg
brew install gnutls nettle gmp
+ brew install googletest
brew link fltk@1.3
- name: Configure
- run: cmake -DCMAKE_BUILD_TYPE=Debug -S . -B build
+ run: |
+ cmake \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DENABLE_NLS=ON \
+ -DENABLE_H264=ON \
+ -DENABLE_GNUTLS=ON \
+ -DENABLE_NETTLE=ON \
+ -DBUILD_VIEWER=ON \
+ -S . -B build
- name: Build
working-directory: build
run: make
@@ -86,11 +136,22 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: macOS
- path: build/TigerVNC-*.dmg
+ path: build/release/TigerVNC-*.dmg
+ - name: Test
+ working-directory: build
+ run: ctest --test-dir tests/unit/ --output-junit test-results.xml
+ - name: Upload test results
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: test-results-macos
+ path: build/tests/unit/test-results.xml
build-java:
runs-on: ubuntu-latest
timeout-minutes: 5
+ env:
+ VERBOSE: 1
strategy:
matrix:
java: [ '8', '11', '17', '21' ]
diff --git a/.github/workflows/test-report.yml b/.github/workflows/test-report.yml
new file mode 100644
index 00000000..8ed986fc
--- /dev/null
+++ b/.github/workflows/test-report.yml
@@ -0,0 +1,18 @@
+name: Test report
+
+on:
+ workflow_run:
+ workflows: ['build']
+ types:
+ - completed
+
+jobs:
+ report:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: dorny/test-reporter@v1
+ with:
+ artifact: /test-results-(.*)/
+ name: Unit tests ($1)
+ path: '*.xml'
+ reporter: java-junit
diff --git a/BUILDING.txt b/BUILDING.txt
index 7e73d72e..8315a1d3 100644
--- a/BUILDING.txt
+++ b/BUILDING.txt
@@ -260,16 +260,6 @@ with MinGW for Windows and can be built from source on OS X and other
Unix variants. However, GnuTLS versions > 2.12.x && < 3.3.x should be
avoided because of potential incompatibilities during initial handshaking.
-You can override the GNUTLS_LIBRARY and GNUTLS_INCLUDE_DIR CMake variables
-to specify the locations of libgnutls and any dependencies. For instance,
-adding
-
- -DGNUTLS_INCLUDE_DIR=/usr/local/include \
- -DGNUTLS_LIBRARY=/usr/local/lib/libgnutls.a
-
-to the CMake command line would link TigerVNC against a static version of
-libgnutls located under /usr/local.
-
======================================
Building native language support (NLS)
@@ -279,23 +269,6 @@ NLS requires gettext, which is supplied with most Linux distributions and
with MinGW for Windows and which can easily be built from source on OS X and
other Unix variants.
-You can override the ICONV_LIBRARIES and LIBINTL_LIBRARY CMake variables to
-specify the locations of libiconv and libintl, respectively. For instance,
-adding
-
- -DLIBINTL_LIBRARY=/opt/gettext/lib/libintl.a
-
-to the CMake command line would link TigerVNC against a static version of
-libintl located under /opt/gettext. Adding
-
- -DICONV_INCLUDE_DIR=/mingw/include \
- -DICONV_LIBRARIES=/mingw/lib/libiconv.a \
- -DGETTEXT_INCLUDE_DIR=/mingw/include \
- -DLIBINTL_LIBRARY=/mingw/lib/libintl.a
-
-to the CMake command line would link TigerVNC against the static versions of
-libiconv and libintl included in the MinGW Developer Toolkit.
-
===================
Installing TigerVNC
@@ -327,9 +300,9 @@ make tarball
Create a binary tarball containing the TigerVNC viewer
-make servertarball
- Create a binary tarball containing both the TigerVNC server and viewer
+macOS
+-----
make dmg
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5b91d84e..b4a28881 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,10 +18,8 @@ include(CheckCSourceRuns)
include(CMakeMacroLibtoolFile)
-include(cmake/TargetLinkDirectories.cmake)
-
project(tigervnc)
-set(VERSION 1.14.80)
+set(VERSION 1.15.80)
# The RC version must always be four comma-separated numbers
string(REPLACE . , RCVERSION "${VERSION}.0")
@@ -66,25 +64,27 @@ set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -UNDEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -UNDEBUG")
# But extra debug checks are still gated by this custom define
-IF(CMAKE_BUILD_TYPE MATCHES Debug)
- add_definitions(-D_DEBUG)
-ENDIF()
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
+
+# Enable debug friendly optimizations for debug builds
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og")
# Make sure we get a sane C and C++ version
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
# Tell the compiler to be stringent
+add_compile_definitions(_FORTIFY_SOURCE=2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat=2 -Wvla")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat=2 -Wvla")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
# Make sure we catch these issues whilst developing
-IF(CMAKE_BUILD_TYPE MATCHES Debug)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
-ENDIF()
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror")
# clang doesn't support format_arg, which breaks this warning
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-nonliteral -Wno-format-security")
@@ -103,10 +103,22 @@ if(ENABLE_TSAN AND NOT WIN32 AND NOT APPLE AND CMAKE_SIZEOF_VOID_P MATCHES 8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
endif()
+if(MSVC)
+ # undef min and max macro
+ target_compile_definitions(rfb PRIVATE NOMINMAX)
+endif()
+
if(NOT DEFINED BUILD_WINVNC)
set(BUILD_WINVNC 1)
endif()
+# libstdc++ doesn't implicitly include this, although it is very much
+# required when using any of the C++ threading features (at least on
+# systems where pthread is a separate library, e.g. glibc < 2.34)
+if(UNIX)
+ link_libraries(pthread)
+endif()
+
# Minimum version is Windows 7
if(WIN32)
add_definitions(-D_WIN32_WINNT=0x0601)
@@ -117,6 +129,13 @@ if(APPLE)
add_definitions(-D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0)
endif()
+#### Check for required and optional libraries ####
+
+macro(trioption VAR DESC)
+ set(${VAR} AUTO CACHE STRING "${DESC}")
+ set_property(CACHE ${VAR} PROPERTY STRINGS AUTO ON OFF)
+endmacro()
+
# X11 stuff. It's in a if() so that we can say REQUIRED
if(UNIX AND NOT APPLE)
find_package(X11 REQUIRED)
@@ -141,47 +160,29 @@ find_package(ZLIB REQUIRED)
find_package(Pixman REQUIRED)
# Check for gettext
-option(ENABLE_NLS "Enable translation of program messages" ON)
+trioption(ENABLE_NLS "Enable translation of program messages")
if(ENABLE_NLS)
# Tools
- find_package(Gettext)
-
- # Gettext needs iconv
- find_package(Iconv)
-
- if(ICONV_FOUND)
- # Headers and libraries (copied from licq)
- set(GETTEXT_FOUND FALSE)
-
- find_path(GETTEXT_INCLUDE_DIR libintl.h)
- if(GETTEXT_INCLUDE_DIR)
- set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
- set(CMAKE_REQUIRED_FLAGS -fno-builtin-dgettext)
- check_function_exists(dgettext LIBC_HAS_DGETTEXT)
- if(LIBC_HAS_DGETTEXT)
- set(GETTEXT_FOUND TRUE)
- else()
- find_library(LIBINTL_LIBRARY NAMES intl libintl)
- if(LIBINTL_LIBRARY)
- check_library_exists(${LIBINTL_LIBRARY} "dgettext" "" LIBINTL_HAS_DGETTEXT)
- if(LIBINTL_HAS_DGETTEXT)
- set(GETTEXT_LIBRARIES ${LIBINTL_LIBRARY} ${ICONV_LIBRARIES})
- set(GETTEXT_FOUND TRUE)
- endif()
- endif()
- endif()
- set(CMAKE_REQUIRED_LIBRARIES)
- set(CMAKE_REQUIRED_FLAGS)
- endif()
+ if(ENABLE_NLS STREQUAL "AUTO")
+ find_package(Gettext)
+ else()
+ find_package(Gettext REQUIRED)
endif()
- if(NOT GETTEXT_FOUND OR NOT ICONV_FOUND)
+ # Runtime library
+ if(ENABLE_NLS STREQUAL "AUTO")
+ find_package(Intl)
+ else()
+ find_package(Intl REQUIRED)
+ endif()
+
+ if(NOT GETTEXT_FOUND OR NOT INTL_FOUND)
message(WARNING "Gettext NOT found. Native Language Support disabled.")
set(ENABLE_NLS 0)
endif()
endif()
-option(ENABLE_H264 "Enable H.264 RFB encoding" ON)
+trioption(ENABLE_H264 "Enable H.264 RFB encoding")
if(ENABLE_H264)
if(WIN32)
add_definitions("-DHAVE_H264")
@@ -195,11 +196,18 @@ if(ENABLE_H264)
add_definitions("-DHAVE_VIDEO_PROCESSOR_MFT")
endif()
else()
- find_package(Ffmpeg)
+ if(ENABLE_H264 STREQUAL "AUTO")
+ find_package(AVCodec)
+ find_package(AVUtil)
+ find_package(SWScale)
+ else()
+ find_package(AVCodec REQUIRED)
+ find_package(AVUtil REQUIRED)
+ find_package(SWScale REQUIRED)
+ endif()
if (AVCODEC_FOUND AND AVUTIL_FOUND AND SWSCALE_FOUND)
set(H264_INCLUDE_DIRS ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS} ${SWSCALE_INCLUDE_DIRS})
set(H264_LIBRARIES ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES} ${SWSCALE_LIBRARIES})
- set(H264_LIBRARY_DIRS ${AVCODEC_LIBRARY_DIRS} ${AVUTIL_LIBRARY_DIRS} ${SWSCALE_LIBRARY_DIRS})
add_definitions("-D__STDC_CONSTANT_MACROS")
add_definitions("-DHAVE_H264")
set(H264_LIBS "LIBAV")
@@ -252,13 +260,23 @@ if(BUILD_JAVA)
add_subdirectory(java)
endif()
-option(BUILD_VIEWER "Build TigerVNC viewer" ON)
+trioption(BUILD_VIEWER "Build TigerVNC viewer")
if(BUILD_VIEWER)
# Check for FLTK
set(FLTK_SKIP_FLUID TRUE)
set(FLTK_SKIP_OPENGL TRUE)
set(FLTK_SKIP_FORMS TRUE)
- find_package(FLTK REQUIRED)
+ if(BUILD_VIEWER STREQUAL "AUTO")
+ find_package(FLTK)
+ else()
+ find_package(FLTK REQUIRED)
+ endif()
+
+ if(NOT FLTK_FOUND)
+ message(WARNING "FLTK NOT found. TigerVNC viewer disabled.")
+ set(BUILD_VIEWER 0)
+ endif()
+
if(UNIX AND NOT APPLE)
# No proper handling for extra X11 libs that FLTK might need...
if(X11_Xft_FOUND)
@@ -280,20 +298,43 @@ if(BUILD_VIEWER)
set(FLTK_LIBRARIES ${FLTK_LIBRARIES} ${X11_Xrender_LIB})
endif()
endif()
+
+ if(FLTK_FOUND)
+ set(CMAKE_REQUIRED_FLAGS "-Wno-error")
+ set(CMAKE_REQUIRED_INCLUDES ${FLTK_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${FLTK_LIBRARIES})
+
+ check_cxx_source_compiles("#include <FL/Fl.H>\n#if FL_MAJOR_VERSION != 1 || FL_MINOR_VERSION != 3\n#error Wrong FLTK version\n#endif\nint main(int, char**) { return 0; }" OK_FLTK_VERSION)
+ if(NOT OK_FLTK_VERSION)
+ message(FATAL_ERROR "Incompatible version of FLTK")
+ endif()
+
+ set(CMAKE_REQUIRED_FLAGS)
+ set(CMAKE_REQUIRED_INCLUDES)
+ set(CMAKE_REQUIRED_LIBRARIES)
+ endif()
endif()
# Check for GNUTLS library
-option(ENABLE_GNUTLS "Enable protocol encryption and advanced authentication" ON)
+trioption(ENABLE_GNUTLS "Enable protocol encryption and advanced authentication")
if(ENABLE_GNUTLS)
- find_package(GnuTLS)
+ if(ENABLE_GNUTLS STREQUAL "AUTO")
+ find_package(GnuTLS)
+ else()
+ find_package(GnuTLS REQUIRED)
+ endif()
if (GNUTLS_FOUND)
add_definitions("-DHAVE_GNUTLS")
endif()
endif()
-option(ENABLE_NETTLE "Enable RSA-AES security types" ON)
+trioption(ENABLE_NETTLE "Enable RSA-AES security types")
if (ENABLE_NETTLE)
- find_package(Nettle)
+ if(ENABLE_NETTLE STREQUAL "AUTO")
+ find_package(Nettle)
+ else()
+ find_package(Nettle REQUIRED)
+ endif()
if (NETTLE_FOUND)
add_definitions("-DHAVE_NETTLE")
endif()
@@ -301,36 +342,34 @@ endif()
# Check for PAM library
if(UNIX AND NOT APPLE)
- check_include_files(security/pam_appl.h HAVE_PAM_H)
- set(CMAKE_REQUIRED_LIBRARIES -lpam)
- check_function_exists(pam_start HAVE_PAM_START)
- set(CMAKE_REQUIRED_LIBRARIES)
- if(HAVE_PAM_H AND HAVE_PAM_START)
- set(PAM_LIBS pam)
- else()
- message(FATAL_ERROR "Could not find PAM development files")
- endif()
+ find_package(PAM REQUIRED)
endif()
# Check for SELinux library
if(UNIX AND NOT APPLE)
- check_include_files(selinux/selinux.h HAVE_SELINUX_H)
- if(HAVE_SELINUX_H)
- set(CMAKE_REQUIRED_LIBRARIES -lselinux)
- set(CMAKE_REQUIRED_LIBRARIES)
- set(SELINUX_LIBS selinux)
- add_definitions("-DHAVE_SELINUX")
- else()
- message(WARNING "Could not find SELinux development files")
+ trioption(ENABLE_SELINUX "Enable SELinux support")
+ if(ENABLE_SELINUX)
+ if(ENABLE_SELINUX STREQUAL "AUTO")
+ find_package(SELinux)
+ else()
+ find_package(SELinux REQUIRED)
+ endif()
+ if(SELINUX_FOUND)
+ add_definitions("-DHAVE_SELINUX")
+ endif()
endif()
endif()
# check for systemd support (socket activation)
if(UNIX AND NOT APPLE)
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(LIBSYSTEMD libsystemd)
- if (LIBSYSTEMD_FOUND)
+ trioption(ENABLE_SYSTEMD "Enable systemd support")
+ if(ENABLE_SYSTEMD)
+ if(ENABLE_SYSTEMD STREQUAL "AUTO")
+ find_package(Systemd)
+ else()
+ find_package(Systemd REQUIRED)
+ endif()
+ if (SYSTEMD_FOUND)
add_definitions(-DHAVE_LIBSYSTEMD)
endif()
endif()
@@ -338,18 +377,21 @@ endif()
# check for password pwquality check support
if(UNIX AND NOT APPLE)
- option(ENABLE_PWQUALITY "Enable password pwquality check" ON)
+ trioption(ENABLE_PWQUALITY "Enable password pwquality check")
if(ENABLE_PWQUALITY)
- find_package(PkgConfig)
- if(PKG_CONFIG_FOUND)
- pkg_check_modules(PWQUALITY pwquality)
- if(PWQUALITY_FOUND)
- add_definitions(-DHAVE_PWQUALITY)
- endif()
+ if(ENABLE_PWQUALITY STREQUAL "AUTO")
+ find_package(PWQuality)
+ else()
+ find_package(PWQuality REQUIRED)
+ endif()
+ if(PWQUALITY_FOUND)
+ add_definitions(-DHAVE_PWQUALITY)
endif()
endif()
endif()
+find_package(GTest)
+
# Generate config.h and make sure the source finds it
configure_file(config.h.in config.h)
add_definitions(-DHAVE_CONFIG_H)
diff --git a/README.rst b/README.rst
index e57536d5..0956660d 100644
--- a/README.rst
+++ b/README.rst
@@ -34,7 +34,7 @@ Incomplete and generally out of date copyright list::
Copyright (C) 2009-2011 D. R. Commander
Copyright (C) 2009-2011 Pierre Ossman for Cendio AB
Copyright (C) 2004, 2009-2011 Red Hat, Inc.
- Copyright (C) 2009-2024 TigerVNC Team
+ Copyright (C) 2009-2025 TigerVNC team
All Rights Reserved.
This software is distributed under the GNU General Public Licence as published
diff --git a/cmake/Modules/FindAVCodec.cmake b/cmake/Modules/FindAVCodec.cmake
new file mode 100644
index 00000000..9667160f
--- /dev/null
+++ b/cmake/Modules/FindAVCodec.cmake
@@ -0,0 +1,47 @@
+#[=======================================================================[.rst:
+FindAVCodec
+-----------
+
+Find the FFmpeg avcodec library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``AVCODEC_INCLUDE_DIRS``
+ where to find libavcodec/avcodec.h, etc.
+``AVCODEC_LIBRARIES``
+ the libraries to link against to use avcodec.
+``AVCODEC_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_AVCodec QUIET libavcodec)
+endif()
+
+find_path(AVCodec_INCLUDE_DIR NAMES libavcodec/avcodec.h
+ HINTS
+ ${PC_AVCodec_INCLUDE_DIRS}
+)
+mark_as_advanced(AVCodec_INCLUDE_DIR)
+
+find_library(AVCodec_LIBRARY NAMES avcodec
+ HINTS
+ ${PC_AVCodec_LIBRARY_DIRS}
+)
+mark_as_advanced(AVCodec_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(AVCodec
+ REQUIRED_VARS
+ AVCodec_LIBRARY AVCodec_INCLUDE_DIR
+)
+
+if(AVCodec_FOUND)
+ set(AVCODEC_INCLUDE_DIRS ${AVCodec_INCLUDE_DIR})
+ set(AVCODEC_LIBRARIES ${AVCodec_LIBRARY})
+endif()
diff --git a/cmake/Modules/FindAVUtil.cmake b/cmake/Modules/FindAVUtil.cmake
new file mode 100644
index 00000000..4b7e17cc
--- /dev/null
+++ b/cmake/Modules/FindAVUtil.cmake
@@ -0,0 +1,47 @@
+#[=======================================================================[.rst:
+FindAVUtil
+----------
+
+Find the FFmpeg avutil library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``AVUTIL_INCLUDE_DIRS``
+ where to find libavutil/avutil.h, etc.
+``AVUTIL_LIBRARIES``
+ the libraries to link against to use avutil.
+``AVUTIL_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_AVUtil QUIET libavutil)
+endif()
+
+find_path(AVUtil_INCLUDE_DIR NAMES libavutil/avutil.h
+ HINTS
+ ${PC_AVUtil_INCLUDE_DIRS}
+)
+mark_as_advanced(AVUtil_INCLUDE_DIR)
+
+find_library(AVUtil_LIBRARY NAMES avutil
+ HINTS
+ ${PC_AVUtil_LIBRARY_DIRS}
+)
+mark_as_advanced(AVUtil_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(AVUtil
+ REQUIRED_VARS
+ AVUtil_LIBRARY AVUtil_INCLUDE_DIR
+)
+
+if(AVUtil_FOUND)
+ set(AVUTIL_INCLUDE_DIRS ${AVUtil_INCLUDE_DIR})
+ set(AVUTIL_LIBRARIES ${AVUtil_LIBRARY})
+endif()
diff --git a/cmake/Modules/FindFfmpeg.cmake b/cmake/Modules/FindFfmpeg.cmake
deleted file mode 100644
index 1a082449..00000000
--- a/cmake/Modules/FindFfmpeg.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-find_package(PkgConfig)
-
-if (PKG_CONFIG_FOUND)
- pkg_check_modules(AVCODEC libavcodec)
- pkg_check_modules(AVUTIL libavutil)
- pkg_check_modules(SWSCALE libswscale)
-else()
- find_path(AVCODEC_INCLUDE_DIRS NAMES avcodec.h PATH_SUFFIXES libavcodec)
- find_library(AVCODEC_LIBRARIES NAMES avcodec)
- find_package_handle_standard_args(AVCODEC DEFAULT_MSG AVCODEC_LIBRARIES AVCODEC_INCLUDE_DIRS)
- find_path(AVUTIL_INCLUDE_DIRS NAMES avutil.h PATH_SUFFIXES libavutil)
- find_library(AVUTIL_LIBRARIES NAMES avutil)
- find_package_handle_standard_args(AVUTIL DEFAULT_MSG AVUTIL_LIBRARIES AVUTIL_INCLUDE_DIRS)
- find_path(SWSCALE_INCLUDE_DIRS NAMES swscale.h PATH_SUFFIXES libswscale)
- find_library(SWSCALE_LIBRARIES NAMES swscale)
- find_package_handle_standard_args(SWSCALE DEFAULT_MSG SWSCALE_LIBRARIES SWSCALE_INCLUDE_DIRS)
-endif()
-
-if(Ffmpeg_FIND_REQUIRED AND
- (NOT AVCODEC_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND))
- message(FATAL_ERROR "Could not find FFMPEG")
-endif()
diff --git a/cmake/Modules/FindGMP.cmake b/cmake/Modules/FindGMP.cmake
new file mode 100644
index 00000000..956d3f19
--- /dev/null
+++ b/cmake/Modules/FindGMP.cmake
@@ -0,0 +1,47 @@
+#[=======================================================================[.rst:
+FindGMP
+-------
+
+Find the GNU MP bignum library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``GMP_INCLUDE_DIRS``
+ where to find gmp.h, etc.
+``GMP_LIBRARIES``
+ the libraries to link against to use GMP.
+``GMP_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_GMP QUIET gmp)
+endif()
+
+find_path(GMP_INCLUDE_DIR NAMES gmp.h
+ HINTS
+ ${PC_GMP_INCLUDE_DIRS}
+)
+mark_as_advanced(GMP_INCLUDE_DIR)
+
+find_library(GMP_LIBRARY NAMES gmp
+ HINTS
+ ${PC_GMP_LIBRARY_DIRS}
+)
+mark_as_advanced(GMP_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GMP
+ REQUIRED_VARS
+ GMP_LIBRARY GMP_INCLUDE_DIR
+)
+
+if(GMP_FOUND)
+ set(GMP_INCLUDE_DIRS ${GMP_INCLUDE_DIR})
+ set(GMP_LIBRARIES ${GMP_LIBRARY})
+endif()
diff --git a/cmake/Modules/FindGmp.cmake b/cmake/Modules/FindGmp.cmake
deleted file mode 100644
index 8711d68e..00000000
--- a/cmake/Modules/FindGmp.cmake
+++ /dev/null
@@ -1,17 +0,0 @@
-find_package(PkgConfig)
-
-if (PKG_CONFIG_FOUND)
- pkg_check_modules(GMP gmp)
-endif()
-
-# Only very recent versions of gmp has pkg-config support, so we have to
-# fall back on a more classical search
-if(NOT GMP_FOUND)
- find_path(GMP_INCLUDE_DIRS NAMES gmp.h PATH_SUFFIXES)
- find_library(GMP_LIBRARIES NAMES gmp)
- find_package_handle_standard_args(GMP DEFAULT_MSG GMP_LIBRARIES GMP_INCLUDE_DIRS)
-endif()
-
-if(Gmp_FIND_REQUIRED AND NOT GMP_FOUND)
- message(FATAL_ERROR "Could not find GMP")
-endif()
diff --git a/cmake/Modules/FindIconv.cmake b/cmake/Modules/FindIconv.cmake
deleted file mode 100644
index cf268ea0..00000000
--- a/cmake/Modules/FindIconv.cmake
+++ /dev/null
@@ -1,66 +0,0 @@
-# From: http://gitorious.org/gammu/mainline/blobs/master/cmake/FindIconv.cmake
-
-# - Try to find Iconv
-# Once done this will define
-#
-# ICONV_FOUND - system has Iconv
-# ICONV_INCLUDE_DIR - the Iconv include directory
-# ICONV_LIBRARIES - Link these to use Iconv
-# ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const
-#
-include(CheckCCompilerFlag)
-include(CheckCXXSourceCompiles)
-
-IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
- # Already in cache, be silent
- SET(ICONV_FIND_QUIETLY TRUE)
-ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
-
-FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
-
-FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv c)
-
-IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
- SET(ICONV_FOUND TRUE)
-ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
-
-set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
-set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
-IF(ICONV_FOUND)
- check_c_compiler_flag("-Werror" ICONV_HAVE_WERROR)
- set (CMAKE_C_FLAGS_BACKUP "${CMAKE_C_FLAGS}")
- if(ICONV_HAVE_WERROR)
- set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
- endif(ICONV_HAVE_WERROR)
- check_c_source_compiles("
- #include <iconv.h>
- int main(){
- iconv_t conv = 0;
- const char* in = 0;
- size_t ilen = 0;
- char* out = 0;
- size_t olen = 0;
- iconv(conv, &in, &ilen, &out, &olen);
- return 0;
- }
-" ICONV_SECOND_ARGUMENT_IS_CONST )
- set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BACKUP}")
-ENDIF(ICONV_FOUND)
-set(CMAKE_REQUIRED_INCLUDES)
-set(CMAKE_REQUIRED_LIBRARIES)
-
-IF(ICONV_FOUND)
- IF(NOT ICONV_FIND_QUIETLY)
- MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
- ENDIF(NOT ICONV_FIND_QUIETLY)
-ELSE(ICONV_FOUND)
- IF(Iconv_FIND_REQUIRED)
- MESSAGE(FATAL_ERROR "Could not find Iconv")
- ENDIF(Iconv_FIND_REQUIRED)
-ENDIF(ICONV_FOUND)
-
-MARK_AS_ADVANCED(
- ICONV_INCLUDE_DIR
- ICONV_LIBRARIES
- ICONV_SECOND_ARGUMENT_IS_CONST
-)
diff --git a/cmake/Modules/FindNettle.cmake b/cmake/Modules/FindNettle.cmake
index f5acf6ac..cdad9754 100644
--- a/cmake/Modules/FindNettle.cmake
+++ b/cmake/Modules/FindNettle.cmake
@@ -1,21 +1,63 @@
-find_package(Gmp)
-find_package(PkgConfig)
+#[=======================================================================[.rst:
+FindNettle
+----------
-if (PKG_CONFIG_FOUND)
- pkg_check_modules(NETTLE nettle>=3.0)
- pkg_check_modules(HOGWEED hogweed)
+Find the Nettle and Hogweed libraries
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``NETTLE_INCLUDE_DIRS``
+ where to find nettle/eax.h, etc.
+``NETTLE_LIBRARIES``
+ the libraries to link against to use Nettle.
+``HOGWEED_LIBRARIES``
+ the libraries to link against to use Hogweed.
+``NETTLE_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+if(Nettle_FIND_REQUIRED)
+ find_package(GMP QUIET REQUIRED)
else()
- find_path(NETTLE_INCLUDE_DIRS NAMES eax.h PATH_SUFFIXES nettle)
- find_library(NETTLE_LIBRARIES NAMES nettle)
- find_package_handle_standard_args(NETTLE DEFAULT_MSG NETTLE_LIBRARIES NETTLE_INCLUDE_DIRS)
- find_library(HOGWEED_LIBRARIES NAMES hogweed)
- find_package_handle_standard_args(HOGWEED DEFAULT_MSG HOGWEED_LIBRARIES)
+ find_package(GMP QUIET)
endif()
-if (NOT HOGWEED_FOUND OR NOT GMP_FOUND)
- set(NETTLE_FOUND 0)
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_Nettle QUIET nettle)
+ pkg_check_modules(PC_Hogweed QUIET hogweed)
endif()
-if(Nettle_FIND_REQUIRED AND NOT NETTLE_FOUND)
- message(FATAL_ERROR "Could not find Nettle")
+find_path(Nettle_INCLUDE_DIR NAMES nettle/eax.h
+ HINTS
+ ${PC_Nettle_INCLUDE_DIRS}
+)
+mark_as_advanced(Nettle_INCLUDE_DIR)
+
+find_library(Nettle_LIBRARY NAMES nettle
+ HINTS
+ ${PC_Nettle_LIBRARY_DIRS}
+)
+mark_as_advanced(Nettle_LIBRARY)
+
+find_library(Hogweed_LIBRARY NAMES hogweed
+ HINTS
+ ${PC_Hogweed_LIBRARY_DIRS}
+)
+mark_as_advanced(Hogweed_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Nettle
+ REQUIRED_VARS
+ Nettle_LIBRARY Nettle_INCLUDE_DIR Hogweed_LIBRARY
+)
+
+if(Nettle_FOUND)
+ set(NETTLE_INCLUDE_DIRS ${Nettle_INCLUDE_DIR} ${GMP_INCLUDE_DIRS})
+ set(NETTLE_LIBRARIES ${Nettle_LIBRARY})
+ set(HOGWEED_LIBRARIES ${Hogweed_LIBRARY} ${GMP_LIBRARIES})
endif()
diff --git a/cmake/Modules/FindPAM.cmake b/cmake/Modules/FindPAM.cmake
new file mode 100644
index 00000000..a41cb421
--- /dev/null
+++ b/cmake/Modules/FindPAM.cmake
@@ -0,0 +1,47 @@
+#[=======================================================================[.rst:
+FindPAM
+-------
+
+Find the Pluggable Authentication Modules library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``PAM_INCLUDE_DIRS``
+ where to find security/pam_appl.h, etc.
+``PAM_LIBRARIES``
+ the libraries to link against to use PAM.
+``PAM_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_PAM QUIET pam)
+endif()
+
+find_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h
+ HINTS
+ ${PC_PAM_INCLUDE_DIRS}
+)
+mark_as_advanced(PAM_INCLUDE_DIR)
+
+find_library(PAM_LIBRARY NAMES pam
+ HINTS
+ ${PC_PAM_LIBRARY_DIRS}
+)
+mark_as_advanced(PAM_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(PAM
+ REQUIRED_VARS
+ PAM_LIBRARY PAM_INCLUDE_DIR
+)
+
+if(PAM_FOUND)
+ set(PAM_INCLUDE_DIRS ${PAM_INCLUDE_DIR})
+ set(PAM_LIBRARIES ${PAM_LIBRARY})
+endif()
diff --git a/cmake/Modules/FindPWQuality.cmake b/cmake/Modules/FindPWQuality.cmake
new file mode 100644
index 00000000..a1e5c1ff
--- /dev/null
+++ b/cmake/Modules/FindPWQuality.cmake
@@ -0,0 +1,47 @@
+#[=======================================================================[.rst:
+FindPWQuality
+-------------
+
+Find the password quality library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``PWQUALITY_INCLUDE_DIRS``
+ where to find pwquality.h, etc.
+``PWQUALITY_LIBRARIES``
+ the libraries to link against to use pwquality.
+``PWQUALITY_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_PWQuality QUIET pwquality)
+endif()
+
+find_path(PWQuality_INCLUDE_DIR NAMES pwquality.h
+ HINTS
+ ${PC_PWQuality_INCLUDE_DIRS}
+)
+mark_as_advanced(PWQuality_INCLUDE_DIR)
+
+find_library(PWQuality_LIBRARY NAMES pwquality
+ HINTS
+ ${PC_PWQuality_LIBRARY_DIRS}
+)
+mark_as_advanced(PWQuality_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(PWQuality
+ REQUIRED_VARS
+ PWQuality_LIBRARY PWQuality_INCLUDE_DIR
+)
+
+if(PWQuality_FOUND)
+ set(PWQUALITY_INCLUDE_DIRS ${PWQuality_INCLUDE_DIR})
+ set(PWQUALITY_LIBRARIES ${PWQuality_LIBRARY})
+endif()
diff --git a/cmake/Modules/FindPixman.cmake b/cmake/Modules/FindPixman.cmake
index f024b71a..a6f2fad2 100644
--- a/cmake/Modules/FindPixman.cmake
+++ b/cmake/Modules/FindPixman.cmake
@@ -1,13 +1,49 @@
-find_package(PkgConfig)
-
-if (PKG_CONFIG_FOUND)
- pkg_check_modules(PIXMAN pixman-1)
-else()
- find_path(PIXMAN_INCLUDE_DIRS NAMES pixman.h PATH_SUFFIXES pixman-1)
- find_library(PIXMAN_LIBRARIES NAMES pixman-1)
- find_package_handle_standard_args(PIXMAN DEFAULT_MSG PIXMAN_LIBRARIES PIXMAN_INCLUDE_DIRS)
+#[=======================================================================[.rst:
+FindPixman
+----------
+
+Find the Pixman library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``PIXMAN_INCLUDE_DIRS``
+ where to find pixman.h, etc.
+``PIXMAN_LIBRARIES``
+ the libraries to link against to use Pixman.
+``PIXMAN_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_Pixman QUIET pixman-1)
endif()
-if(Pixman_FIND_REQUIRED AND NOT PIXMAN_FOUND)
- message(FATAL_ERROR "Could not find Pixman")
+find_path(Pixman_INCLUDE_DIR NAMES pixman.h
+ PATH_SUFFIXES
+ pixman-1
+ HINTS
+ ${PC_Pixman_INCLUDE_DIRS}
+)
+mark_as_advanced(Pixman_INCLUDE_DIR)
+
+find_library(Pixman_LIBRARY NAMES pixman-1
+ HINTS
+ ${PC_Pixman_LIBRARY_DIRS}
+)
+mark_as_advanced(Pixman_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Pixman
+ REQUIRED_VARS
+ Pixman_LIBRARY Pixman_INCLUDE_DIR
+)
+
+if(Pixman_FOUND)
+ set(PIXMAN_INCLUDE_DIRS ${Pixman_INCLUDE_DIR})
+ set(PIXMAN_LIBRARIES ${Pixman_LIBRARY})
endif()
diff --git a/cmake/Modules/FindSELinux.cmake b/cmake/Modules/FindSELinux.cmake
new file mode 100644
index 00000000..10be6736
--- /dev/null
+++ b/cmake/Modules/FindSELinux.cmake
@@ -0,0 +1,47 @@
+#[=======================================================================[.rst:
+FindSELinux
+-----------
+
+Find the SELinux library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``SELINUX_INCLUDE_DIRS``
+ where to find selinux/selinux.h, etc.
+``SELINUX_LIBRARIES``
+ the libraries to link against to use libselinux.
+``SELINUX_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_SELinux QUIET libselinux)
+endif()
+
+find_path(SELinux_INCLUDE_DIR NAMES selinux/selinux.h
+ HINTS
+ ${PC_SELinux_INCLUDE_DIRS}
+)
+mark_as_advanced(SELinux_INCLUDE_DIR)
+
+find_library(SELinux_LIBRARY NAMES selinux
+ HINTS
+ ${PC_SELinux_LIBRARY_DIRS}
+)
+mark_as_advanced(SELinux_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(SELinux
+ REQUIRED_VARS
+ SELinux_LIBRARY SELinux_INCLUDE_DIR
+)
+
+if(SELinux_FOUND)
+ set(SELINUX_INCLUDE_DIRS ${SELinux_INCLUDE_DIR})
+ set(SELINUX_LIBRARIES ${SELinux_LIBRARY})
+endif()
diff --git a/cmake/Modules/FindSWScale.cmake b/cmake/Modules/FindSWScale.cmake
new file mode 100644
index 00000000..61edb595
--- /dev/null
+++ b/cmake/Modules/FindSWScale.cmake
@@ -0,0 +1,47 @@
+#[=======================================================================[.rst:
+FindSWScale
+-----------
+
+Find the FFmpeg swscale library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``SWSCALE_INCLUDE_DIRS``
+ where to find libswscale/swscale.h, etc.
+``SWSCALE_LIBRARIES``
+ the libraries to link against to use swscale.
+``SWSCALE_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_SWScale QUIET libswscale)
+endif()
+
+find_path(SWScale_INCLUDE_DIR NAMES libswscale/swscale.h
+ HINTS
+ ${PC_SWScale_INCLUDE_DIRS}
+)
+mark_as_advanced(SWScale_INCLUDE_DIR)
+
+find_library(SWScale_LIBRARY NAMES swscale
+ HINTS
+ ${PC_SWScale_LIBRARY_DIRS}
+)
+mark_as_advanced(SWScale_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(SWScale
+ REQUIRED_VARS
+ SWScale_LIBRARY SWScale_INCLUDE_DIR
+)
+
+if(SWScale_FOUND)
+ set(SWSCALE_INCLUDE_DIRS ${SWScale_INCLUDE_DIR})
+ set(SWSCALE_LIBRARIES ${SWScale_LIBRARY})
+endif()
diff --git a/cmake/Modules/FindSystemd.cmake b/cmake/Modules/FindSystemd.cmake
new file mode 100644
index 00000000..1a3e40f5
--- /dev/null
+++ b/cmake/Modules/FindSystemd.cmake
@@ -0,0 +1,47 @@
+#[=======================================================================[.rst:
+FindSystemd
+-----------
+
+Find the systemd library
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+This module will set the following variables if found:
+
+``SYSTEMD_INCLUDE_DIRS``
+ where to find systemd/sd-daemon.h, etc.
+``SYSTEMD_LIBRARIES``
+ the libraries to link against to use libsystemd.
+``SYSTEMD_FOUND``
+ TRUE if found
+
+#]=======================================================================]
+
+find_package(PkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_Systemd QUIET libsystemd)
+endif()
+
+find_path(Systemd_INCLUDE_DIR NAMES systemd/sd-daemon.h
+ HINTS
+ ${PC_Systemd_INCLUDE_DIRS}
+)
+mark_as_advanced(Systemd_INCLUDE_DIR)
+
+find_library(Systemd_LIBRARY NAMES systemd
+ HINTS
+ ${PC_Systemd_LIBRARY_DIRS}
+)
+mark_as_advanced(Systemd_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Systemd
+ REQUIRED_VARS
+ Systemd_LIBRARY Systemd_INCLUDE_DIR
+)
+
+if(Systemd_FOUND)
+ set(SYSTEMD_INCLUDE_DIRS ${Systemd_INCLUDE_DIR})
+ set(SYSTEMD_LIBRARIES ${Systemd_LIBRARY})
+endif()
diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake
index d518bc4a..f46e2154 100644
--- a/cmake/StaticBuild.cmake
+++ b/cmake/StaticBuild.cmake
@@ -23,34 +23,20 @@ if(BUILD_STATIC)
set(PIXMAN_LIBRARIES "-Wl,-Bstatic -lpixman-1 -Wl,-Bdynamic")
# gettext is included in libc on many unix systems
+ check_function_exists(dgettext LIBC_HAS_DGETTEXT)
if(NOT LIBC_HAS_DGETTEXT)
- FIND_LIBRARY(UNISTRING_LIBRARY NAMES unistring libunistring
- HINTS ${PC_GETTEXT_LIBDIR} ${PC_GETTEXT_LIBRARY_DIRS})
- FIND_LIBRARY(INTL_LIBRARY NAMES intl libintl
- HINTS ${PC_GETTEXT_LIBDIR} ${PC_GETTEXT_LIBRARY_DIRS})
- FIND_LIBRARY(ICONV_LIBRARY NAMES iconv libiconv
- HINTS ${PC_GETTEXT_LIBDIR} ${PC_GETTEXT_LIBRARY_DIRS})
+ FIND_LIBRARY(UNISTRING_LIBRARY NAMES unistring libunistring)
- set(GETTEXT_LIBRARIES "-Wl,-Bstatic")
+ set(Intl_LIBRARIES "-Wl,-Bstatic -lintl -liconv")
- if(INTL_LIBRARY)
- set(GETTEXT_LIBRARIES "${GETTEXT_LIBRARIES} -lintl")
- endif()
-
- if(ICONV_LIBRARY)
- set(GETTEXT_LIBRARIES "${GETTEXT_LIBRARIES} -liconv")
- endif()
-
- set(GETTEXT_LIBRARIES "${GETTEXT_LIBRARIES} -Wl,-Bdynamic")
-
- # FIXME: MSYS2 doesn't include a static version of this library, so
- # we'll have to link it dynamically for now
if(UNISTRING_LIBRARY)
- set(GETTEXT_LIBRARIES "${GETTEXT_LIBRARIES} -lunistring")
+ set(Intl_LIBRARIES "${Intl_LIBRARIES} -lunistring")
endif()
+ set(Intl_LIBRARIES "${Intl_LIBRARIES} -Wl,-Bdynamic")
+
if(APPLE)
- set(GETTEXT_LIBRARIES "${GETTEXT_LIBRARIES} -framework Carbon")
+ set(Intl_LIBRARIES "${Intl_LIBRARIES} -framework Carbon")
endif()
endif()
@@ -107,7 +93,7 @@ if(BUILD_STATIC)
# GnuTLS uses gettext and zlib, so make sure those are always
# included and in the proper order
set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} ${ZLIB_LIBRARIES}")
- set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} ${GETTEXT_LIBRARIES}")
+ set(GNUTLS_LIBRARIES "${GNUTLS_LIBRARIES} ${Intl_LIBRARIES}")
# The last variables might introduce whitespace, which CMake
# throws a hissy fit about
@@ -116,8 +102,7 @@ if(BUILD_STATIC)
if(NETTLE_FOUND)
set(NETTLE_LIBRARIES "-Wl,-Bstatic -lnettle -Wl,-Bdynamic")
- set(HOGWEED_LIBRARIES "-Wl,-Bstatic -lhogweed -Wl,-Bdynamic")
- set(GMP_LIBRARIES "-Wl,-Bstatic -lgmp -Wl,-Bdynamic")
+ set(HOGWEED_LIBRARIES "-Wl,-Bstatic -lhogweed -lnettle -lgmp -Wl,-Bdynamic")
endif()
if(DEFINED FLTK_LIBRARIES)
@@ -163,32 +148,14 @@ if(BUILD_STATIC)
endif()
if(BUILD_STATIC_GCC)
- set(STATIC_BASE_LIBRARIES "")
- if(ENABLE_ASAN AND NOT WIN32 AND NOT APPLE)
- set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -Wl,-Bstatic -lasan -Wl,-Bdynamic -ldl -lpthread")
- endif()
- if(ENABLE_TSAN AND NOT WIN32 AND NOT APPLE AND CMAKE_SIZEOF_VOID_P MATCHES 8)
- # libtsan redefines some C++ symbols which then conflict with a
- # statically linked libstdc++. Work around this by allowing multiple
- # definitions. The linker will pick the first one (i.e. the one
- # from libtsan).
- set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -Wl,-z -Wl,muldefs -Wl,-Bstatic -ltsan -Wl,-Bdynamic -ldl -lm")
+ set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} -static-libgcc")
+ set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -static-libstdc++ -static-libgcc")
+ if(ENABLE_ASAN)
+ set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} -static-libasan")
+ set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -static-libasan")
endif()
- if(WIN32)
- set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -lmingw32 -lgcc_eh -lgcc -lmoldname -lmingwex -lmsvcrt")
- find_package(Threads)
- if(CMAKE_USE_PTHREADS_INIT)
- # pthread has to be statically linked after libraries above and before kernel32
- set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -Wl,-Bstatic -lpthread -Wl,-Bdynamic")
- endif()
- set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -luser32 -lkernel32 -ladvapi32 -lshell32")
- # mingw has some fun circular dependencies that requires us to link
- # these things again
- set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -lmingw32 -lgcc_eh -lgcc -lmoldname -lmingwex -lmsvcrt")
- else()
- set(STATIC_BASE_LIBRARIES "${STATIC_BASE_LIBRARIES} -lm -lgcc -lgcc_eh -lc")
+ if(ENABLE_TSAN)
+ set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} -static-libtsan")
+ set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -static-libtsan")
endif()
- # -nodefaultlibs ensures that we don't depend on libstdc++ or libgcc_s
- set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} -nodefaultlibs ${STATIC_BASE_LIBRARIES}")
- set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -nodefaultlibs -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic ${STATIC_BASE_LIBRARIES}")
endif()
diff --git a/cmake/TargetLinkDirectories.cmake b/cmake/TargetLinkDirectories.cmake
deleted file mode 100644
index 11b05670..00000000
--- a/cmake/TargetLinkDirectories.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-# Compatibility replacement of target_link_directories() for older cmake
-
-if(${CMAKE_VERSION} VERSION_LESS "3.13.0")
- function(target_link_directories TARGET SCOPE)
- get_target_property(INTERFACE_LINK_LIBRARIES ${TARGET} INTERFACE_LINK_LIBRARIES)
- foreach(DIRECTORY ${ARGN})
- list(INSERT INTERFACE_LINK_LIBRARIES 0 "-L${DIRECTORY}")
- endforeach()
- set_target_properties(${TARGET} PROPERTIES
- INTERFACE_LINK_LIBRARIES "${INTERFACE_LINK_LIBRARIES}")
- endfunction()
-endif()
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 6fd1e106..96b4e6b7 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_subdirectory(os)
+add_subdirectory(core)
add_subdirectory(rdr)
add_subdirectory(network)
add_subdirectory(rfb)
@@ -9,6 +9,6 @@ add_subdirectory(rfb)
# is passed (additionally, libvnc is not used on Windows.)
if(NOT WIN32)
- set_target_properties(os rdr network rfb
+ set_target_properties(core rdr network rfb
PROPERTIES COMPILE_FLAGS -fPIC)
endif()
diff --git a/common/core/CMakeLists.txt b/common/core/CMakeLists.txt
new file mode 100644
index 00000000..7e58acc0
--- /dev/null
+++ b/common/core/CMakeLists.txt
@@ -0,0 +1,32 @@
+add_library(core STATIC
+ Configuration.cxx
+ Exception.cxx
+ Logger.cxx
+ Logger_file.cxx
+ Logger_stdio.cxx
+ LogWriter.cxx
+ Region.cxx
+ Timer.cxx
+ string.cxx
+ time.cxx
+ xdgdirs.cxx)
+
+target_include_directories(core PUBLIC ${CMAKE_SOURCE_DIR}/common)
+target_include_directories(core SYSTEM PUBLIC ${PIXMAN_INCLUDE_DIRS})
+target_link_libraries(core ${PIXMAN_LIBRARIES})
+
+if(UNIX)
+ target_sources(core PRIVATE Logger_syslog.cxx)
+endif()
+
+if(WIN32)
+ target_link_libraries(core ws2_32)
+endif()
+
+if(UNIX)
+ target_sources(core PRIVATE Logger_syslog.cxx)
+endif()
+
+if(UNIX)
+ libtool_create_control_file(core)
+endif()
diff --git a/common/core/Configuration.cxx b/common/core/Configuration.cxx
new file mode 100644
index 00000000..e6affb06
--- /dev/null
+++ b/common/core/Configuration.cxx
@@ -0,0 +1,857 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2004-2005 Cendio AB.
+ * Copyright 2017 Peter Astrand <astrand@cendio.se> for Cendio AB
+ * Copyright 2011-2025 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+// -=- Configuration.cxx
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <algorithm>
+#include <stdexcept>
+
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
+#include <rdr/HexOutStream.h>
+#include <rdr/HexInStream.h>
+
+using namespace core;
+
+static LogWriter vlog("Config");
+
+
+// -=- The Global Configuration object
+Configuration* Configuration::global_ = nullptr;
+
+Configuration* Configuration::global() {
+ if (!global_)
+ global_ = new Configuration();
+ return global_;
+}
+
+// -=- Configuration implementation
+
+bool Configuration::set(const char* paramName, const char* val,
+ bool immutable)
+{
+ for (VoidParameter* current: params) {
+ if (strcasecmp(current->getName(), paramName) == 0) {
+ bool b = current->setParam(val);
+ if (b && immutable)
+ current->setImmutable();
+ return b;
+ }
+ }
+ return false;
+}
+
+VoidParameter* Configuration::get(const char* param)
+{
+ for (VoidParameter* current: params) {
+ if (strcasecmp(current->getName(), param) == 0)
+ return current;
+ }
+ return nullptr;
+}
+
+void Configuration::list(int width, int nameWidth) {
+ for (VoidParameter* current: params) {
+ std::string def_str = current->getDefaultStr();
+ std::string desc_str = current->getDescription();
+ if (!def_str.empty())
+ desc_str += " (default=" + def_str + ")";
+ const char* desc = desc_str.c_str();
+ fprintf(stderr," %-*s -", nameWidth, current->getName());
+ int column = strlen(current->getName());
+ if (column < nameWidth) column = nameWidth;
+ column += 4;
+ while (true) {
+ if (desc[0] == '\0')
+ break;
+
+ int wordLen = strcspn(desc, " \f\n\r\t\v,");
+ if (wordLen == 0) {
+ desc++;
+ continue;
+ }
+
+ if (desc[wordLen] == ',')
+ wordLen++;
+
+ if (column + wordLen + 1 > width) {
+ fprintf(stderr,"\n%*s",nameWidth+4,"");
+ column = nameWidth+4;
+ }
+ fprintf(stderr, " ");
+ column++;
+
+ fprintf(stderr, "%.*s", wordLen, desc);
+ column += wordLen;
+ desc += wordLen;
+ }
+ fprintf(stderr,"\n");
+ }
+}
+
+
+bool Configuration::remove(const char* param) {
+ std::list<VoidParameter*>::iterator iter;
+
+ iter = std::find_if(params.begin(), params.end(),
+ [param](VoidParameter* p) {
+ return strcasecmp(p->getName(), param) == 0;
+ });
+ if (iter == params.end())
+ return false;
+
+ params.erase(iter);
+ return true;
+}
+
+int Configuration::handleArg(int argc, char* argv[], int index)
+{
+ std::string param, val;
+ const char* equal = strchr(argv[index], '=');
+
+ if (equal == argv[index])
+ return 0;
+
+ if (equal) {
+ param.assign(argv[index], equal-argv[index]);
+ val.assign(equal+1);
+ } else {
+ param.assign(argv[index]);
+ }
+
+ if ((param.length() > 0) && (param[0] == '-')) {
+ // allow gnu-style --<option>
+ if ((param.length() > 1) && (param[1] == '-'))
+ param = param.substr(2);
+ else
+ param = param.substr(1);
+ } else {
+ // All command line arguments need either an initial '-', or an '='
+ if (!equal)
+ return 0;
+ }
+
+ if (equal)
+ return set(param.c_str(), val.c_str()) ? 1 : 0;
+
+ for (VoidParameter* current: params) {
+ if (strcasecmp(current->getName(), param.c_str()) != 0)
+ continue;
+
+ // We need to resolve an ambiguity for booleans
+ if (dynamic_cast<BoolParameter*>(current) != nullptr) {
+ if (index+1 < argc) {
+ // FIXME: Should not duplicate the list of values here
+ if ((strcasecmp(argv[index+1], "0") == 0) ||
+ (strcasecmp(argv[index+1], "1") == 0) ||
+ (strcasecmp(argv[index+1], "on") == 0) ||
+ (strcasecmp(argv[index+1], "off") == 0) ||
+ (strcasecmp(argv[index+1], "true") == 0) ||
+ (strcasecmp(argv[index+1], "false") == 0) ||
+ (strcasecmp(argv[index+1], "yes") == 0) ||
+ (strcasecmp(argv[index+1], "no") == 0)) {
+ return current->setParam(argv[index+1]) ? 2 : 0;
+ }
+ }
+ }
+
+ if (current->setParam())
+ return 1;
+
+ if (index+1 >= argc)
+ return 0;
+
+ return current->setParam(argv[index+1]) ? 2 : 0;
+ }
+
+ return 0;
+}
+
+
+// -=- VoidParameter
+
+VoidParameter::VoidParameter(const char* name_, const char* desc_)
+ : immutable(false), name(name_), description(desc_)
+{
+ Configuration *conf;
+
+ conf = Configuration::global();
+ conf->params.push_back(this);
+ conf->params.sort([](const VoidParameter* a, const VoidParameter* b) {
+ return strcasecmp(a->getName(), b->getName()) < 0;
+ });
+}
+
+VoidParameter::~VoidParameter() {
+ Configuration *conf;
+
+ conf = Configuration::global();
+ conf->params.remove(this);
+}
+
+const char*
+VoidParameter::getName() const {
+ return name;
+}
+
+const char*
+VoidParameter::getDescription() const {
+ return description;
+}
+
+bool VoidParameter::setParam() {
+ return false;
+}
+
+bool VoidParameter::isDefault() const {
+ return getDefaultStr() == getValueStr();
+}
+
+void
+VoidParameter::setImmutable() {
+ vlog.debug("Set immutable %s", getName());
+ immutable = true;
+}
+
+// -=- AliasParameter
+
+AliasParameter::AliasParameter(const char* name_, const char* desc_,
+ VoidParameter* param_)
+ : VoidParameter(name_, desc_), param(param_) {
+}
+
+bool
+AliasParameter::setParam(const char* v) {
+ return param->setParam(v);
+}
+
+bool AliasParameter::setParam() {
+ return param->setParam();
+}
+
+std::string AliasParameter::getDefaultStr() const {
+ return "";
+}
+
+std::string AliasParameter::getValueStr() const {
+ return param->getValueStr();
+}
+
+void
+AliasParameter::setImmutable() {
+ vlog.debug("Set immutable %s (Alias)", getName());
+ param->setImmutable();
+}
+
+
+// -=- BoolParameter
+
+BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v)
+: VoidParameter(name_, desc_), value(v), def_value(v) {
+}
+
+bool
+BoolParameter::setParam(const char* v) {
+ if (immutable) return true;
+
+ if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
+ || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
+ setParam(true);
+ else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
+ || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
+ setParam(false);
+ else {
+ vlog.error("Bool parameter %s: Invalid value '%s'", getName(), v);
+ return false;
+ }
+
+ return true;
+}
+
+bool BoolParameter::setParam() {
+ setParam(true);
+ return true;
+}
+
+void BoolParameter::setParam(bool b) {
+ if (immutable) return;
+ value = b;
+ vlog.debug("Set %s(Bool) to %s", getName(), getValueStr().c_str());
+}
+
+std::string BoolParameter::getDefaultStr() const {
+ return def_value ? "on" : "off";
+}
+
+std::string BoolParameter::getValueStr() const {
+ return value ? "on" : "off";
+}
+
+BoolParameter::operator bool() const {
+ return value;
+}
+
+// -=- IntParameter
+
+IntParameter::IntParameter(const char* name_, const char* desc_, int v,
+ int minValue_, int maxValue_)
+ : VoidParameter(name_, desc_), value(v), def_value(v),
+ minValue(minValue_), maxValue(maxValue_)
+{
+ if (v < minValue || v > maxValue) {
+ vlog.error("Invalid default value %d for %s", v, getName());
+ throw std::invalid_argument("Invalid default value");
+ }
+}
+
+bool
+IntParameter::setParam(const char* v) {
+ char* end;
+ long n;
+ if (immutable) return true;
+ n = strtol(v, &end, 0);
+ if ((*end != 0) || (n < INT_MIN) || (n > INT_MAX)) {
+ vlog.error("Int parameter %s: Invalid value '%s'", getName(), v);
+ return false;
+ }
+ return setParam(n);
+}
+
+bool
+IntParameter::setParam(int v) {
+ if (immutable) return true;
+ if (v < minValue || v > maxValue) {
+ vlog.error("Int parameter %s: Invalid value '%d'", getName(), v);
+ return false;
+ }
+ vlog.debug("Set %s(Int) to %d", getName(), v);
+ value = v;
+ return true;
+}
+
+std::string IntParameter::getDefaultStr() const {
+ char result[16];
+ sprintf(result, "%d", def_value);
+ return result;
+}
+
+std::string IntParameter::getValueStr() const {
+ char result[16];
+ sprintf(result, "%d", value);
+ return result;
+}
+
+IntParameter::operator int() const {
+ return value;
+}
+
+// -=- StringParameter
+
+StringParameter::StringParameter(const char* name_, const char* desc_,
+ const char* v)
+ : VoidParameter(name_, desc_), value(v?v:""), def_value(v?v:"")
+{
+ if (!v) {
+ vlog.error("Default value <null> for %s not allowed",name_);
+ throw std::invalid_argument("Default value <null> not allowed");
+ }
+}
+
+bool StringParameter::setParam(const char* v) {
+ if (immutable) return true;
+ if (!v)
+ throw std::invalid_argument("setParam(<null>) not allowed");
+ vlog.debug("Set %s(String) to %s", getName(), v);
+ value = v;
+ return true;
+}
+
+std::string StringParameter::getDefaultStr() const {
+ return def_value;
+}
+
+std::string StringParameter::getValueStr() const {
+ return value;
+}
+
+StringParameter::operator const char *() const {
+ return value.c_str();
+}
+
+// -=- EnumParameter
+
+EnumParameter::EnumParameter(const char* name_, const char* desc_,
+ const std::set<const char*>& enums_,
+ const char* v)
+ : VoidParameter(name_, desc_), value(v?v:""), def_value(v?v:"")
+{
+ if (!v) {
+ vlog.error("Default value <null> for %s not allowed", name_);
+ throw std::invalid_argument("Default value <null> not allowed");
+ }
+
+ for (const char* e: enums_) {
+ if (!e) {
+ vlog.error("Enumeration <null> for %s not allowed", name_);
+ throw std::invalid_argument("Enumeration <null> not allowed");
+ }
+ enums.insert(e);
+ }
+
+ if (std::find(enums.begin(), enums.end(), def_value) == enums.end()) {
+ vlog.error("Default value %s for %s is not in list of valid values",
+ def_value.c_str(), name_);
+ throw std::invalid_argument("Default value is not in list of valid values");
+ }
+}
+
+bool EnumParameter::setParam(const char* v)
+{
+ std::set<std::string>::const_iterator iter;
+ if (immutable) return true;
+ if (!v)
+ throw std::invalid_argument("setParam(<null>) not allowed");
+ iter = std::find_if(enums.begin(), enums.end(),
+ [v](const std::string& e) {
+ return strcasecmp(e.c_str(), v) == 0;
+ });
+ if (iter == enums.end()) {
+ vlog.error("Enum parameter %s: Invalid value '%s'", getName(), v);
+ return false;
+ }
+ vlog.debug("Set %s(Enum) to %s", getName(), iter->c_str());
+ value = *iter;
+ return true;
+}
+
+std::string EnumParameter::getDefaultStr() const
+{
+ return def_value;
+}
+
+std::string EnumParameter::getValueStr() const
+{
+ return value;
+}
+
+bool EnumParameter::operator==(const char* other) const
+{
+ return strcasecmp(value.c_str(), other) == 0;
+}
+
+bool EnumParameter::operator==(const std::string& other) const
+{
+ return *this == other.c_str();
+}
+
+bool EnumParameter::operator!=(const char* other) const
+{
+ return strcasecmp(value.c_str(), other) != 0;
+}
+
+bool EnumParameter::operator!=(const std::string& other) const
+{
+ return *this != other.c_str();
+}
+
+// -=- BinaryParameter
+
+BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
+ const uint8_t* v, size_t l)
+: VoidParameter(name_, desc_),
+ value(nullptr), length(0), def_value(nullptr), def_length(0) {
+ if (l) {
+ assert(v);
+ value = new uint8_t[l];
+ length = l;
+ memcpy(value, v, l);
+ def_value = new uint8_t[l];
+ def_length = l;
+ memcpy(def_value, v, l);
+ }
+}
+BinaryParameter::~BinaryParameter() {
+ delete [] value;
+ delete [] def_value;
+}
+
+bool BinaryParameter::setParam(const char* v) {
+ if (immutable) return true;
+ std::vector<uint8_t> newValue = hexToBin(v, strlen(v));
+ if (newValue.empty() && strlen(v) > 0)
+ return false;
+ setParam(newValue.data(), newValue.size());
+ return true;
+}
+
+void BinaryParameter::setParam(const uint8_t* v, size_t len) {
+ if (immutable) return;
+ vlog.debug("Set %s(Binary)", getName());
+ delete [] value;
+ value = nullptr;
+ length = 0;
+ if (len) {
+ assert(v);
+ value = new uint8_t[len];
+ length = len;
+ memcpy(value, v, len);
+ }
+}
+
+std::string BinaryParameter::getDefaultStr() const {
+ return binToHex(def_value, def_length);
+}
+
+std::string BinaryParameter::getValueStr() const {
+ return binToHex(value, length);
+}
+
+std::vector<uint8_t> BinaryParameter::getData() const {
+ std::vector<uint8_t> out(length);
+ memcpy(out.data(), value, length);
+ return out;
+}
+
+// -=- ListParameter template
+
+template<typename ValueType>
+ListParameter<ValueType>::ListParameter(const char* name_,
+ const char* desc_,
+ const ListType& v)
+ : VoidParameter(name_, desc_), value(v), def_value(v)
+{
+}
+
+template<typename ValueType>
+bool ListParameter<ValueType>::setParam(const char* v)
+{
+ std::vector<std::string> entries;
+ ListType new_value;
+
+ if (immutable)
+ return true;
+
+ // setParam({}) ends up as setParam(nullptr)
+ if (v != nullptr)
+ entries = split(v, ',');
+
+ for (std::string& entry : entries) {
+ ValueType e;
+
+ entry.erase(0, entry.find_first_not_of(" \f\n\r\t\v"));
+ entry.erase(entry.find_last_not_of(" \f\n\r\t\v")+1);
+
+ // Special case, entire v was just whitespace
+ if (entry.empty() && (entries.size() == 1))
+ break;
+
+ if (!decodeEntry(entry.c_str(), &e)) {
+ vlog.error("List parameter %s: Invalid value '%s'",
+ getName(), entry.c_str());
+ return false;
+ }
+
+ new_value.push_back(e);
+ }
+
+ return setParam(new_value);
+}
+
+template<typename ValueType>
+bool ListParameter<ValueType>::setParam(const ListType& v)
+{
+ ListType vnorm;
+ if (immutable)
+ return true;
+ for (const ValueType& entry : v) {
+ if (!validateEntry(entry)) {
+ vlog.error("List parameter %s: Invalid value '%s'", getName(),
+ encodeEntry(entry).c_str());
+ return false;
+ }
+ vnorm.push_back(normaliseEntry(entry));
+ }
+ value = vnorm;
+ vlog.debug("set %s(List) to %s", getName(), getValueStr().c_str());
+ return true;
+}
+
+template<typename ValueType>
+std::string ListParameter<ValueType>::getDefaultStr() const
+{
+ std::string result;
+
+ for (ValueType entry : def_value) {
+ // FIXME: Might want to add a space here as well for readability,
+ // but this would sacrifice backward compatibility
+ if (!result.empty())
+ result += ',';
+ result += encodeEntry(entry);
+ }
+
+ return result;
+}
+
+template<typename ValueType>
+std::string ListParameter<ValueType>::getValueStr() const
+{
+ std::string result;
+
+ for (ValueType entry : value) {
+ // FIXME: Might want to add a space here as well for readability,
+ // but this would sacrifice backward compatibility
+ if (!result.empty())
+ result += ',';
+ result += encodeEntry(entry);
+ }
+
+ return result;
+}
+
+template<typename ValueType>
+typename ListParameter<ValueType>::const_iterator ListParameter<ValueType>::begin() const
+{
+ return value.begin();
+}
+
+template<typename ValueType>
+typename ListParameter<ValueType>::const_iterator ListParameter<ValueType>::end() const
+{
+ return value.end();
+}
+
+template<typename ValueType>
+bool ListParameter<ValueType>::validateEntry(const ValueType& /*entry*/) const
+{
+ return true;
+}
+
+template<typename ValueType>
+ValueType ListParameter<ValueType>::normaliseEntry(const ValueType& entry) const
+{
+ return entry;
+}
+
+// -=- IntListParameter
+
+template class core::ListParameter<int>;
+
+IntListParameter::IntListParameter(const char* name_, const char* desc_,
+ const ListType& v,
+ int minValue_, int maxValue_)
+ : ListParameter<int>(name_, desc_, v),
+ minValue(minValue_), maxValue(maxValue_)
+{
+ for (int entry : v) {
+ if (!validateEntry(entry)) {
+ vlog.error("Invalid default value %d for %s", entry, getName());
+ throw std::invalid_argument("Invalid default value");
+ }
+ }
+}
+
+bool IntListParameter::decodeEntry(const char* entry, int* out) const
+{
+ long n;
+ char *end;
+
+ assert(entry);
+ assert(out);
+
+ if (entry[0] == '\0')
+ return false;
+
+ n = strtol(entry, &end, 0);
+ if ((*end != 0) || (n < INT_MIN) || (n > INT_MAX))
+ return false;
+
+ *out = n;
+
+ return true;
+}
+
+std::string IntListParameter::encodeEntry(const int& entry) const
+{
+ char valstr[16];
+ sprintf(valstr, "%d", entry);
+ return valstr;
+}
+
+bool IntListParameter::validateEntry(const int& entry) const
+{
+ return (entry >= minValue) && (entry <= maxValue);
+}
+
+// -=- StringListParameter
+
+template class core::ListParameter<std::string>;
+
+StringListParameter::StringListParameter(const char* name_,
+ const char* desc_,
+ const std::list<const char*>& v_)
+ : ListParameter<std::string>(name_, desc_, {})
+{
+ for (const char* v: v_) {
+ if (!v) {
+ vlog.error("Default value <null> for %s not allowed", name_);
+ throw std::invalid_argument("Default value <null> not allowed");
+ }
+ value.push_back(v);
+ def_value.push_back(v);
+ }
+}
+
+StringListParameter::const_iterator StringListParameter::begin() const
+{
+ return ListParameter<std::string>::begin();
+}
+
+StringListParameter::const_iterator StringListParameter::end() const
+{
+ return ListParameter<std::string>::end();
+}
+
+bool StringListParameter::decodeEntry(const char* entry, std::string* out) const
+{
+ *out = entry;
+ return true;
+}
+
+std::string StringListParameter::encodeEntry(const std::string& entry) const
+{
+ return entry;
+}
+
+// -=- EnumListEntry
+
+EnumListEntry::EnumListEntry(const std::string& v)
+ : value(v)
+{
+}
+
+std::string EnumListEntry::getValueStr() const
+{
+ return value;
+}
+
+bool EnumListEntry::operator==(const char* other) const
+{
+ return strcasecmp(value.c_str(), other) == 0;
+}
+
+bool EnumListEntry::operator==(const std::string& other) const
+{
+ return *this == other.c_str();
+}
+
+bool EnumListEntry::operator!=(const char* other) const
+{
+ return strcasecmp(value.c_str(), other) != 0;
+}
+
+bool EnumListEntry::operator!=(const std::string& other) const
+{
+ return *this != other.c_str();
+}
+
+// -=- EnumListParameter
+
+EnumListParameter::EnumListParameter(const char* name_,
+ const char* desc_,
+ const std::set<const char*>& enums_,
+ const std::list<const char*>& v_)
+ : ListParameter<std::string>(name_, desc_, {})
+{
+ for (const char* v: v_) {
+ if (!v) {
+ vlog.error("Default value <null> for %s not allowed", name_);
+ throw std::invalid_argument("Default value <null> not allowed");
+ }
+ value.push_back(v);
+ def_value.push_back(v);
+ }
+
+ for (const char* e: enums_) {
+ if (!e) {
+ vlog.error("Enumeration <null> for %s not allowed", name_);
+ throw std::invalid_argument("Enumeration <null> not allowed");
+ }
+ enums.insert(e);
+ }
+
+ for (const std::string& def_entry : def_value) {
+ if (std::find(enums.begin(), enums.end(), def_entry) == enums.end()) {
+ vlog.error("Default value %s for %s is not in list of valid values",
+ def_entry.c_str(), name_);
+ throw std::invalid_argument("Default value is not in list of valid values");
+ }
+ }
+}
+
+EnumListParameter::const_iterator EnumListParameter::begin() const
+{
+ return ListParameter<std::string>::begin();
+}
+
+EnumListParameter::const_iterator EnumListParameter::end() const
+{
+ return ListParameter<std::string>::end();
+}
+
+bool EnumListParameter::decodeEntry(const char* entry, std::string* out) const
+{
+ *out = entry;
+ return true;
+}
+
+std::string EnumListParameter::encodeEntry(const std::string& entry) const
+{
+ return entry;
+}
+
+bool EnumListParameter::validateEntry(const std::string& entry) const
+{
+ for (const std::string& e : enums) {
+ if (strcasecmp(e.c_str(), entry.c_str()) == 0)
+ return true;
+ }
+ return false;
+}
+
+std::string EnumListParameter::normaliseEntry(const std::string& entry) const
+{
+ for (const std::string& e : enums) {
+ if (strcasecmp(e.c_str(), entry.c_str()) == 0)
+ return e;
+ }
+ throw std::logic_error("Entry is not in list of valid values");
+}
diff --git a/common/rfb/Configuration.h b/common/core/Configuration.h
index ec8d789a..431dd0c5 100644
--- a/common/rfb/Configuration.h
+++ b/common/core/Configuration.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2022 Pierre Ossman for Cendio AB
+ * Copyright 2011-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,22 +41,20 @@
// NB: NO LOCKING is performed when linking Configurations to groups
// or when adding Parameters to Configurations.
-#ifndef __RFB_CONFIGURATION_H__
-#define __RFB_CONFIGURATION_H__
+#ifndef __CORE_CONFIGURATION_H__
+#define __CORE_CONFIGURATION_H__
#include <limits.h>
#include <stdint.h>
+#include <list>
+#include <set>
#include <string>
#include <vector>
-namespace os { class Mutex; }
+namespace core {
-namespace rfb {
class VoidParameter;
- struct ParameterIterator;
-
- enum ConfigurationObject { ConfGlobal, ConfServer, ConfViewer };
// -=- Configuration
// Class used to access parameters.
@@ -64,22 +62,11 @@ namespace rfb {
class Configuration {
public:
// - Create a new Configuration object
- Configuration(const char* name_)
- : name(name_), head(nullptr), _next(nullptr) {}
-
- // - Return the buffer containing the Configuration's name
- const char* getName() const { return name.c_str(); }
+ Configuration() {}
// - Set named parameter to value
bool set(const char* param, const char* value, bool immutable=false);
- // - Set parameter to value (separated by "=")
- bool set(const char* config, bool immutable=false);
-
- // - Set named parameter to value, with name truncated at len
- bool set(const char* name, int len,
- const char* val, bool immutable);
-
// - Get named parameter
VoidParameter* get(const char* param);
@@ -89,15 +76,18 @@ namespace rfb {
// - Remove a parameter from this Configuration group
bool remove(const char* param);
- // - readFromFile
- // Read configuration parameters from the specified file.
- void readFromFile(const char* filename);
+ // - handleArg
+ // Parse a command line argument into a parameter, returning how
+ // many arguments were consumed
+ int handleArg(int argc, char* argv[], int index);
+
- // - writeConfigToFile
- // Write a new configuration parameters file, then mv it
- // over the old file.
- void writeToFile(const char* filename);
+ // - Iterate over all parameters
+ std::list<VoidParameter*>::iterator begin() { return params.begin(); }
+ std::list<VoidParameter*>::iterator end() { return params.end(); }
+ // - Returns the number of parameters
+ int size() { return params.size(); }
// - Get the Global Configuration object
// NB: This call does NOT lock the Configuration system.
@@ -106,21 +96,10 @@ namespace rfb {
// global() is called when only the main thread is running.
static Configuration* global();
- // Enable server/viewer specific parameters
- static void enableServerParams() { global()->appendConfiguration(server()); }
- static void enableViewerParams() { global()->appendConfiguration(viewer()); }
-
// - Container for process-wide Global parameters
static bool setParam(const char* param, const char* value, bool immutable=false) {
return global()->set(param, value, immutable);
}
- static bool setParam(const char* config, bool immutable=false) {
- return global()->set(config, immutable);
- }
- static bool setParam(const char* name, int len,
- const char* val, bool immutable) {
- return global()->set(name, len, val, immutable);
- }
static VoidParameter* getParam(const char* param) { return global()->get(param); }
static void listParams(int width=79, int nameWidth=10) {
global()->list(width, nameWidth);
@@ -128,38 +107,18 @@ namespace rfb {
static bool removeParam(const char* param) {
return global()->remove(param);
}
+ static int handleParamArg(int argc, char* argv[], int index) {
+ return global()->handleArg(argc, argv, index);
+ }
private:
friend class VoidParameter;
- friend struct ParameterIterator;
- // Name for this Configuration
- std::string name;
-
- // - Pointer to first Parameter in this group
- VoidParameter* head;
-
- // Pointer to next Configuration in this group
- Configuration* _next;
+ // - List of Parameters
+ std::list<VoidParameter*> params;
// The process-wide, Global Configuration object
static Configuration* global_;
-
- // The server only Configuration object
- static Configuration* server_;
-
- // The viewer only Configuration object
- static Configuration* viewer_;
-
- // Get server/viewer specific configuration object
- static Configuration* server();
- static Configuration* viewer();
-
- // Append configuration object to this instance.
- // NOTE: conf instance can be only one configuration object
- void appendConfiguration(Configuration *conf) {
- conf->_next = _next; _next = conf;
- }
};
// -=- VoidParameter
@@ -167,7 +126,7 @@ namespace rfb {
class VoidParameter {
public:
- VoidParameter(const char* name_, const char* desc_, ConfigurationObject co=ConfGlobal);
+ VoidParameter(const char* name_, const char* desc_);
virtual ~VoidParameter();
const char* getName() const;
const char* getDescription() const;
@@ -176,31 +135,27 @@ namespace rfb {
virtual bool setParam();
virtual std::string getDefaultStr() const = 0;
virtual std::string getValueStr() const = 0;
- virtual bool isBool() const;
+
+ virtual bool isDefault() const;
virtual void setImmutable();
protected:
friend class Configuration;
- friend struct ParameterIterator;
VoidParameter* _next;
bool immutable;
const char* name;
const char* description;
-
- os::Mutex* mutex;
};
class AliasParameter : public VoidParameter {
public:
- AliasParameter(const char* name_, const char* desc_,VoidParameter* param_,
- ConfigurationObject co=ConfGlobal);
+ AliasParameter(const char* name_, const char* desc_,VoidParameter* param_);
bool setParam(const char* value) override;
bool setParam() override;
std::string getDefaultStr() const override;
std::string getValueStr() const override;
- bool isBool() const override;
void setImmutable() override;
private:
VoidParameter* param;
@@ -208,14 +163,12 @@ namespace rfb {
class BoolParameter : public VoidParameter {
public:
- BoolParameter(const char* name_, const char* desc_, bool v,
- ConfigurationObject co=ConfGlobal);
+ BoolParameter(const char* name_, const char* desc_, bool v);
bool setParam(const char* value) override;
bool setParam() override;
virtual void setParam(bool b);
std::string getDefaultStr() const override;
std::string getValueStr() const override;
- bool isBool() const override;
operator bool() const;
protected:
bool value;
@@ -225,8 +178,7 @@ namespace rfb {
class IntParameter : public VoidParameter {
public:
IntParameter(const char* name_, const char* desc_, int v,
- int minValue=INT_MIN, int maxValue=INT_MAX,
- ConfigurationObject co=ConfGlobal);
+ int minValue=INT_MIN, int maxValue=INT_MAX);
using VoidParameter::setParam;
bool setParam(const char* value) override;
virtual bool setParam(int v);
@@ -241,11 +193,7 @@ namespace rfb {
class StringParameter : public VoidParameter {
public:
- // StringParameter contains a null-terminated string, which CANNOT
- // be Null, and so neither can the default value!
- StringParameter(const char* name_, const char* desc_, const char* v,
- ConfigurationObject co=ConfGlobal);
- ~StringParameter() override;
+ StringParameter(const char* name_, const char* desc_, const char* v);
bool setParam(const char* value) override;
std::string getDefaultStr() const override;
std::string getValueStr() const override;
@@ -255,11 +203,29 @@ namespace rfb {
std::string def_value;
};
+ class EnumParameter : public VoidParameter {
+ public:
+ EnumParameter(const char* name_, const char* desc_,
+ const std::set<const char*>& enums, const char* v);
+ bool setParam(const char* value) override;
+ std::string getDefaultStr() const override;
+ std::string getValueStr() const override;
+ bool operator==(const char* other) const;
+ bool operator==(const std::string& other) const;
+ bool operator!=(const char* other) const;
+ bool operator!=(const std::string& other) const;
+ // operator const char*() omitted on purpose to force usage of above
+ // comparison operators
+ protected:
+ std::string value;
+ std::string def_value;
+ std::set<std::string> enums;
+ };
+
class BinaryParameter : public VoidParameter {
public:
BinaryParameter(const char* name_, const char* desc_,
- const uint8_t* v, size_t l,
- ConfigurationObject co=ConfGlobal);
+ const uint8_t* v, size_t l);
using VoidParameter::setParam;
~BinaryParameter() override;
bool setParam(const char* value) override;
@@ -276,25 +242,107 @@ namespace rfb {
size_t def_length;
};
- // -=- ParameterIterator
- // Iterates over all enabled parameters (global + server/viewer).
- // Current Parameter is accessed via param, the current Configuration
- // via config. The next() method moves on to the next Parameter.
-
- struct ParameterIterator {
- ParameterIterator() : config(Configuration::global()), param(config->head) {}
- void next() {
- param = param->_next;
- while (!param) {
- config = config->_next;
- if (!config) break;
- param = config->head;
- }
- }
- Configuration* config;
- VoidParameter* param;
+ template<typename ValueType>
+ class ListParameter : public VoidParameter {
+ public:
+ typedef std::list<ValueType> ListType;
+ typedef typename ListType::const_iterator const_iterator;
+
+ ListParameter(const char* name_, const char* desc_,
+ const ListType& v);
+ using VoidParameter::setParam;
+ bool setParam(const char* value) override;
+ virtual bool setParam(const ListType& v);
+ std::string getDefaultStr() const override;
+ std::string getValueStr() const override;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ protected:
+ virtual bool decodeEntry(const char* entry, ValueType* out) const = 0;
+ virtual std::string encodeEntry(const ValueType& entry) const = 0;
+ virtual bool validateEntry(const ValueType& entry) const;
+ virtual ValueType normaliseEntry(const ValueType& entry) const;
+
+ protected:
+ ListType value;
+ ListType def_value;
+ };
+
+ class IntListParameter : public ListParameter<int> {
+ public:
+ IntListParameter(const char* name_, const char* desc_,
+ const ListType& v,
+ int minValue=INT_MIN, int maxValue=INT_MAX);
+ protected:
+ bool decodeEntry(const char* entry, int* out) const override;
+ std::string encodeEntry(const int& entry) const override;
+ bool validateEntry(const int& entry) const override;
+
+ protected:
+ int minValue, maxValue;
+ };
+
+ class StringListParameter : public ListParameter<std::string> {
+ public:
+ StringListParameter(const char* name_, const char* desc_,
+ const std::list<const char*>& v);
+
+ class const_iterator : public ListType::const_iterator {
+ public:
+ const_iterator(const ListType::const_iterator& it) : ListType::const_iterator(it) {}
+ const char* operator*() const { return (ListType::const_iterator::operator*()).c_str(); }
+ };
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ protected:
+ bool decodeEntry(const char* entry, std::string* out) const override;
+ std::string encodeEntry(const std::string& entry) const override;
+ };
+
+ class EnumListEntry {
+ public:
+ EnumListEntry(const std::string& v);
+ std::string getValueStr() const;
+ bool operator==(const char* other) const;
+ bool operator==(const std::string& other) const;
+ bool operator!=(const char* other) const;
+ bool operator!=(const std::string& other) const;
+ // operator const char*() omitted on purpose to force usage of above
+ // comparison operators
+ protected:
+ std::string value;
+ };
+
+ class EnumListParameter : public ListParameter<std::string> {
+ public:
+ EnumListParameter(const char* name_, const char* desc_,
+ const std::set<const char*>& enums,
+ const std::list<const char*>& v);
+
+ class const_iterator : public ListType::const_iterator {
+ public:
+ const_iterator(const ListType::const_iterator& it) : ListType::const_iterator(it) {}
+ const EnumListEntry operator*() const { return EnumListEntry(ListType::const_iterator::operator*()); }
+ const EnumListEntry operator->() const { return EnumListEntry(*ListType::const_iterator::operator->()); }
+ };
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ protected:
+ bool decodeEntry(const char* entry, std::string* out) const override;
+ std::string encodeEntry(const std::string& entry) const override;
+ bool validateEntry(const std::string& entry) const override;
+ std::string normaliseEntry(const std::string& entry) const override;
+
+ protected:
+ std::set<std::string> enums;
};
};
-#endif // __RFB_CONFIGURATION_H__
+#endif // __CORE_CONFIGURATION_H__
diff --git a/common/rdr/Exception.cxx b/common/core/Exception.cxx
index f0c04a6a..5b4f0599 100644
--- a/common/rdr/Exception.cxx
+++ b/common/core/Exception.cxx
@@ -26,9 +26,8 @@
#include <stdio.h>
#include <stdarg.h>
-#include <rdr/Exception.h>
-#include <rdr/TLSException.h>
-#include <rfb/util.h>
+#include <core/Exception.h>
+#include <core/string.h>
#ifdef _WIN32
#include <winsock2.h>
@@ -40,20 +39,20 @@
#include <string.h>
-using namespace rdr;
+using namespace core;
getaddrinfo_error::getaddrinfo_error(const char* s, int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", s,
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", s,
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
getaddrinfo_error::getaddrinfo_error(const std::string& s,
int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", s.c_str(),
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", s.c_str(),
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
@@ -73,15 +72,15 @@ std::string getaddrinfo_error::strerror(int err_) const noexcept
}
posix_error::posix_error(const char* what_arg, int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", what_arg,
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", what_arg,
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
posix_error::posix_error(const std::string& what_arg, int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", what_arg.c_str(),
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", what_arg.c_str(),
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
@@ -102,16 +101,16 @@ std::string posix_error::strerror(int err_) const noexcept
#ifdef WIN32
win32_error::win32_error(const char* what_arg, unsigned err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", what_arg,
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", what_arg,
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
win32_error::win32_error(const std::string& what_arg,
unsigned err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", what_arg.c_str(),
- strerror(err_).c_str(), err_)),
+ : std::runtime_error(core::format("%s: %s (%d)", what_arg.c_str(),
+ strerror(err_).c_str(), err_)),
err(err_)
{
}
diff --git a/common/rdr/Exception.h b/common/core/Exception.h
index d3cecc18..04463a17 100644
--- a/common/rdr/Exception.h
+++ b/common/core/Exception.h
@@ -19,13 +19,13 @@
* USA.
*/
-#ifndef __RDR_EXCEPTION_H__
-#define __RDR_EXCEPTION_H__
+#ifndef __CORE_EXCEPTION_H__
+#define __CORE_EXCEPTION_H__
#include <stdexcept>
#include <string>
-namespace rdr {
+namespace core {
class posix_error : public std::runtime_error {
public:
@@ -70,11 +70,6 @@ namespace rdr {
std::string strerror(int err_) const noexcept;
};
- class end_of_stream : public std::runtime_error {
- public:
- end_of_stream() noexcept : std::runtime_error("End of stream") {}
- };
-
}
#endif
diff --git a/common/rfb/LogWriter.cxx b/common/core/LogWriter.cxx
index 8e39d544..98e5201c 100644
--- a/common/rfb/LogWriter.cxx
+++ b/common/core/LogWriter.cxx
@@ -22,17 +22,16 @@
#include <config.h>
#endif
-#include <string.h>
-
-#include <rfb/LogWriter.h>
-#include <rfb/Configuration.h>
-#include <rfb/util.h>
#include <stdlib.h>
+#include <string.h>
-rfb::LogParameter rfb::logParams;
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
-using namespace rfb;
+using namespace core;
+LogParameter core::logParams;
LogWriter::LogWriter(const char* name)
: m_name(name), m_level(0), m_log(nullptr), m_next(log_writers) {
@@ -113,23 +112,23 @@ bool LogWriter::setLogParams(const char* params) {
LogParameter::LogParameter()
- : StringParameter("Log",
+ : StringListParameter("Log",
"Specifies which log output should be directed to "
"which target logger, and the level of output to log. "
"Format is <log>:<target>:<level>[, ...].",
- "") {
+ {})
+{
}
bool LogParameter::setParam(const char* v) {
if (immutable) return true;
LogWriter::setLogParams("*::0");
- StringParameter::setParam(v);
- std::vector<std::string> parts;
- parts = split(v, ',');
- for (size_t i = 0; i < parts.size(); i++) {
- if (parts[i].empty())
+ if (!StringListParameter::setParam(v))
+ return false;
+ for (const char* part : *this) {
+ if (part[0] == '\0')
continue;
- if (!LogWriter::setLogParams(parts[i].c_str()))
+ if (!LogWriter::setLogParams(part))
return false;
}
return true;
diff --git a/common/rfb/LogWriter.h b/common/core/LogWriter.h
index d1fd4990..58dcc063 100644
--- a/common/rfb/LogWriter.h
+++ b/common/core/LogWriter.h
@@ -18,12 +18,13 @@
// -=- LogWriter.h - The Log writer class.
-#ifndef __RFB_LOG_WRITER_H__
-#define __RFB_LOG_WRITER_H__
+#ifndef __CORE_LOG_WRITER_H__
+#define __CORE_LOG_WRITER_H__
#include <stdarg.h>
-#include <rfb/Logger.h>
-#include <rfb/Configuration.h>
+
+#include <core/Configuration.h>
+#include <core/Logger.h>
// Each log writer instance has a unique textual name,
// and is attached to a particular Log instance and
@@ -46,9 +47,7 @@
} \
}
-namespace rfb {
-
- class LogWriter;
+namespace core {
class LogWriter {
public:
@@ -101,13 +100,15 @@ namespace rfb {
LogWriter* m_next;
};
- class LogParameter : public StringParameter {
+ class LogParameter : public StringListParameter {
public:
LogParameter();
bool setParam(const char* v) override;
+ // We explicitly don't inherit setParam(std::list) as we want to
+ // force callers to use the above method to parse the values
};
extern LogParameter logParams;
};
-#endif // __RFB_LOG_WRITER_H__
+#endif // __CORE_LOG_WRITER_H__
diff --git a/common/rfb/Logger.cxx b/common/core/Logger.cxx
index 25f7ccb7..ad9a3d63 100644
--- a/common/rfb/Logger.cxx
+++ b/common/core/Logger.cxx
@@ -26,10 +26,10 @@
#include <stdio.h>
#include <string.h>
-#include <rfb/Logger.h>
-#include <rfb/LogWriter.h>
+#include <core/Logger.h>
+#include <core/LogWriter.h>
-using namespace rfb;
+using namespace core;
Logger* Logger::loggers = nullptr;
diff --git a/common/rfb/Logger.h b/common/core/Logger.h
index 76f03535..5291915f 100644
--- a/common/rfb/Logger.h
+++ b/common/core/Logger.h
@@ -18,8 +18,8 @@
// -=- Logger.h - The Logger class.
-#ifndef __RFB_LOGGER_H__
-#define __RFB_LOGGER_H__
+#ifndef __CORE_LOGGER_H__
+#define __CORE_LOGGER_H__
#include <stdarg.h>
#include <stdio.h>
@@ -28,7 +28,7 @@
// and is attached to a particular Logger instance and
// is assigned a particular log level.
-namespace rfb {
+namespace core {
class Logger {
public:
@@ -68,4 +68,4 @@ namespace rfb {
};
-#endif // __RFB_LOGGER_H__
+#endif // __CORE_LOGGER_H__
diff --git a/common/rfb/Logger_file.cxx b/common/core/Logger_file.cxx
index eabe420a..b8c72270 100644
--- a/common/rfb/Logger_file.cxx
+++ b/common/core/Logger_file.cxx
@@ -26,30 +26,24 @@
#include <stdlib.h>
#include <string.h>
-#include <os/Mutex.h>
+#include <core/Logger_file.h>
-#include <rfb/Logger_file.h>
-
-using namespace rfb;
+using namespace core;
Logger_File::Logger_File(const char* loggerName)
: Logger(loggerName), indent(13), width(79), m_file(nullptr),
m_lastLogTime(0)
{
m_filename[0] = '\0';
- mutex = new os::Mutex();
}
Logger_File::~Logger_File()
{
closeFile();
- delete mutex;
}
void Logger_File::write(int /*level*/, const char *logname, const char *message)
{
- os::AutoMutex a(mutex);
-
if (!m_file) {
if (m_filename[0] == '\0')
return;
@@ -121,7 +115,8 @@ void Logger_File::closeFile()
static Logger_File logger("file");
-bool rfb::initFileLogger(const char* filename) {
+bool core::initFileLogger(const char* filename)
+{
logger.setFilename(filename);
logger.registerLogger();
return true;
diff --git a/common/rfb/Logger_file.h b/common/core/Logger_file.h
index 6f2a4ef6..6bce3e2d 100644
--- a/common/rfb/Logger_file.h
+++ b/common/core/Logger_file.h
@@ -18,17 +18,15 @@
// -=- Logger_file - log to a file
-#ifndef __RFB_LOGGER_FILE_H__
-#define __RFB_LOGGER_FILE_H__
+#ifndef __CORE_LOGGER_FILE_H__
+#define __CORE_LOGGER_FILE_H__
#include <time.h>
#include <limits.h>
-#include <rfb/Logger.h>
+#include <core/Logger.h>
-namespace os { class Mutex; }
-
-namespace rfb {
+namespace core {
class Logger_File : public Logger {
public:
@@ -47,7 +45,6 @@ namespace rfb {
char m_filename[PATH_MAX];
FILE* m_file;
time_t m_lastLogTime;
- os::Mutex* mutex;
};
bool initFileLogger(const char* filename);
diff --git a/common/rfb/Logger_stdio.cxx b/common/core/Logger_stdio.cxx
index 5e5c6dea..f27fc35d 100644
--- a/common/rfb/Logger_stdio.cxx
+++ b/common/core/Logger_stdio.cxx
@@ -22,14 +22,15 @@
#include <config.h>
#endif
-#include <rfb/Logger_stdio.h>
+#include <core/Logger_stdio.h>
-using namespace rfb;
+using namespace core;
static Logger_StdIO logStdErr("stderr", stderr);
static Logger_StdIO logStdOut("stdout", stdout);
-bool rfb::initStdIOLoggers() {
+bool core::initStdIOLoggers()
+{
logStdErr.registerLogger();
logStdOut.registerLogger();
return true;
diff --git a/common/rfb/Logger_stdio.h b/common/core/Logger_stdio.h
index a1d17a0f..7613a20b 100644
--- a/common/rfb/Logger_stdio.h
+++ b/common/core/Logger_stdio.h
@@ -18,12 +18,12 @@
// -=- Logger_stdio - standard output logger instances
-#ifndef __RFB_LOGGER_STDIO_H__
-#define __RFB_LOGGER_STDIO_H__
+#ifndef __CORE_LOGGER_STDIO_H__
+#define __CORE_LOGGER_STDIO_H__
-#include <rfb/Logger_file.h>
+#include <core/Logger_file.h>
-namespace rfb {
+namespace core {
class Logger_StdIO : public Logger_File {
public:
diff --git a/common/rfb/Logger_syslog.cxx b/common/core/Logger_syslog.cxx
index de9e425e..cf7d065d 100644
--- a/common/rfb/Logger_syslog.cxx
+++ b/common/core/Logger_syslog.cxx
@@ -26,10 +26,10 @@
#include <string.h>
#include <syslog.h>
-#include <rfb/Logger_syslog.h>
-#include <rfb/LogWriter.h>
+#include <core/Logger_syslog.h>
+#include <core/LogWriter.h>
-using namespace rfb;
+using namespace core;
Logger_Syslog::Logger_Syslog(const char* loggerName)
@@ -62,6 +62,7 @@ void Logger_Syslog::write(int level, const char *logname, const char *message)
static Logger_Syslog logger("syslog");
-void rfb::initSyslogLogger() {
+void core::initSyslogLogger()
+{
logger.registerLogger();
}
diff --git a/common/rfb/Logger_syslog.h b/common/core/Logger_syslog.h
index 20c46a5f..46adf932 100644
--- a/common/rfb/Logger_syslog.h
+++ b/common/core/Logger_syslog.h
@@ -18,13 +18,14 @@
// -=- Logger_syslog - log to syslog
-#ifndef __RFB_LOGGER_SYSLOG_H__
-#define __RFB_LOGGER_SYSLOG_H__
+#ifndef __CORE_LOGGER_SYSLOG_H__
+#define __CORE_LOGGER_SYSLOG_H__
#include <time.h>
-#include <rfb/Logger.h>
-namespace rfb {
+#include <core/Logger.h>
+
+namespace core {
class Logger_Syslog : public Logger {
public:
diff --git a/common/rfb/Rect.h b/common/core/Rect.h
index b82ed274..e4cb1634 100644
--- a/common/rfb/Rect.h
+++ b/common/core/Rect.h
@@ -16,26 +16,16 @@
* USA.
*/
-// rfb::Rect and rfb::Point structures
+// core::Rect and core::Point structures
-#ifndef __RFB_RECT_INCLUDED__
-#define __RFB_RECT_INCLUDED__
+#ifndef __CORE_RECT_INCLUDED__
+#define __CORE_RECT_INCLUDED__
-// Some platforms (e.g. Windows) include max() and min() macros in their
-// standard headers, but they are also standard C++ template functions, so some
-// C++ headers will undefine them. So we steer clear of the names min and max
-// and define __rfbmin and __rfbmax instead.
+#include <algorithm>
-#ifndef __rfbmax
-#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-#ifndef __rfbmin
-#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b))
-#endif
+namespace core {
-namespace rfb {
-
- // rfb::Point
+ // core::Point
//
// Represents a point in 2D space, by X and Y coordinates.
// Can also be used to represent a delta, or offset, between
@@ -61,7 +51,7 @@ namespace rfb {
int x, y;
};
- // rfb::Rect
+ // core::Rect
//
// Represents a rectangular region defined by its top-left (tl)
// and bottom-right (br) Points.
@@ -83,10 +73,10 @@ namespace rfb {
__attribute__ ((warn_unused_result))
{
Rect result;
- result.tl.x = __rfbmax(tl.x, r.tl.x);
- result.tl.y = __rfbmax(tl.y, r.tl.y);
- result.br.x = __rfbmax(__rfbmin(br.x, r.br.x), result.tl.x);
- result.br.y = __rfbmax(__rfbmin(br.y, r.br.y), result.tl.y);
+ result.tl.x = std::max(tl.x, r.tl.x);
+ result.tl.y = std::max(tl.y, r.tl.y);
+ result.br.x = std::max(std::min(br.x, r.br.x), result.tl.x);
+ result.br.y = std::max(std::min(br.y, r.br.y), result.tl.y);
return result;
}
inline Rect union_boundary(const Rect &r) const
@@ -95,10 +85,10 @@ namespace rfb {
if (r.is_empty()) return *this;
if (is_empty()) return r;
Rect result;
- result.tl.x = __rfbmin(tl.x, r.tl.x);
- result.tl.y = __rfbmin(tl.y, r.tl.y);
- result.br.x = __rfbmax(br.x, r.br.x);
- result.br.y = __rfbmax(br.y, r.br.y);
+ result.tl.x = std::min(tl.x, r.tl.x);
+ result.tl.y = std::min(tl.y, r.tl.y);
+ result.br.x = std::max(br.x, r.br.x);
+ result.br.y = std::max(br.y, r.br.y);
return result;
}
inline Rect translate(const Point &p) const
@@ -127,4 +117,4 @@ namespace rfb {
Point br;
};
}
-#endif // __RFB_RECT_INCLUDED__
+#endif // __CORE_RECT_INCLUDED__
diff --git a/common/rfb/Region.cxx b/common/core/Region.cxx
index cfdf0ca2..03d788a9 100644
--- a/common/rfb/Region.cxx
+++ b/common/core/Region.cxx
@@ -21,100 +21,119 @@
#include <config.h>
#endif
-#include <rfb/Region.h>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+#include <core/Region.h>
extern "C" {
#include <pixman.h>
}
-static rfb::LogWriter vlog("Region");
+using namespace core;
-rfb::Region::Region() {
+static LogWriter vlog("Region");
+
+Region::Region()
+{
rgn = new struct pixman_region16;
pixman_region_init(rgn);
}
-rfb::Region::Region(const Rect& r) {
+Region::Region(const Rect& r)
+{
rgn = new struct pixman_region16;
pixman_region_init_rect(rgn, r.tl.x, r.tl.y, r.width(), r.height());
}
-rfb::Region::Region(const rfb::Region& r) {
+Region::Region(const Region& r)
+{
rgn = new struct pixman_region16;
pixman_region_init(rgn);
pixman_region_copy(rgn, r.rgn);
}
-rfb::Region::~Region() {
+Region::~Region()
+{
pixman_region_fini(rgn);
delete rgn;
}
-rfb::Region& rfb::Region::operator=(const rfb::Region& r) {
+Region& Region::operator=(const Region& r)
+{
pixman_region_copy(rgn, r.rgn);
return *this;
}
-void rfb::Region::clear() {
+void Region::clear()
+{
// pixman_region_clear() isn't available on some older systems
pixman_region_fini(rgn);
pixman_region_init(rgn);
}
-void rfb::Region::reset(const Rect& r) {
+void Region::reset(const Rect& r)
+{
pixman_region_fini(rgn);
pixman_region_init_rect(rgn, r.tl.x, r.tl.y, r.width(), r.height());
}
-void rfb::Region::translate(const Point& delta) {
+void Region::translate(const Point& delta)
+{
pixman_region_translate(rgn, delta.x, delta.y);
}
-void rfb::Region::assign_intersect(const rfb::Region& r) {
+void Region::assign_intersect(const Region& r)
+{
pixman_region_intersect(rgn, rgn, r.rgn);
}
-void rfb::Region::assign_union(const rfb::Region& r) {
+void Region::assign_union(const Region& r)
+{
pixman_region_union(rgn, rgn, r.rgn);
}
-void rfb::Region::assign_subtract(const rfb::Region& r) {
+void Region::assign_subtract(const Region& r)
+{
pixman_region_subtract(rgn, rgn, r.rgn);
}
-rfb::Region rfb::Region::intersect(const rfb::Region& r) const {
- rfb::Region ret;
+Region Region::intersect(const Region& r) const
+{
+ Region ret;
pixman_region_intersect(ret.rgn, rgn, r.rgn);
return ret;
}
-rfb::Region rfb::Region::union_(const rfb::Region& r) const {
- rfb::Region ret;
+Region Region::union_(const Region& r) const
+{
+ Region ret;
pixman_region_union(ret.rgn, rgn, r.rgn);
return ret;
}
-rfb::Region rfb::Region::subtract(const rfb::Region& r) const {
- rfb::Region ret;
+Region Region::subtract(const Region& r) const
+{
+ Region ret;
pixman_region_subtract(ret.rgn, rgn, r.rgn);
return ret;
}
-bool rfb::Region::operator==(const rfb::Region& r) const {
+bool Region::operator==(const Region& r) const
+{
return pixman_region_equal(rgn, r.rgn);
}
-bool rfb::Region::operator!=(const rfb::Region& r) const {
+bool Region::operator!=(const Region& r) const
+{
return !pixman_region_equal(rgn, r.rgn);
}
-int rfb::Region::numRects() const {
+int Region::numRects() const
+{
return pixman_region_n_rects(rgn);
}
-bool rfb::Region::get_rects(std::vector<Rect>* rects,
- bool left2right, bool topdown) const
+bool Region::get_rects(std::vector<Rect>* rects,
+ bool left2right, bool topdown) const
{
int nRects;
const pixman_box16_t* boxes;
@@ -156,14 +175,15 @@ bool rfb::Region::get_rects(std::vector<Rect>* rects,
return !rects->empty();
}
-rfb::Rect rfb::Region::get_bounding_rect() const {
+Rect Region::get_bounding_rect() const
+{
const pixman_box16_t* extents;
extents = pixman_region_extents(rgn);
return Rect(extents->x1, extents->y1, extents->x2, extents->y2);
}
-void rfb::Region::debug_print(const char* prefix) const
+void Region::debug_print(const char* prefix) const
{
Rect extents;
std::vector<Rect> rects;
diff --git a/common/rfb/Region.h b/common/core/Region.h
index 38de67ce..729f1475 100644
--- a/common/rfb/Region.h
+++ b/common/core/Region.h
@@ -19,15 +19,19 @@
// Region class wrapper around pixman's region operations
-#ifndef __RFB_REGION_INCLUDED__
-#define __RFB_REGION_INCLUDED__
+#ifndef __CORE_REGION_INCLUDED__
+#define __CORE_REGION_INCLUDED__
-#include <rfb/Rect.h>
#include <vector>
+#include <core/Rect.h>
+
struct pixman_region16;
-namespace rfb {
+namespace core {
+
+ struct Point;
+ struct Rect;
class Region {
public:
@@ -45,7 +49,7 @@ namespace rfb {
void clear();
void reset(const Rect& r);
- void translate(const rfb::Point& delta);
+ void translate(const Point& delta);
void assign_intersect(const Region& r);
void assign_union(const Region& r);
@@ -78,4 +82,4 @@ namespace rfb {
};
-#endif // __RFB_REGION_INCLUDED__
+#endif // __CORE_REGION_INCLUDED__
diff --git a/common/rfb/Timer.cxx b/common/core/Timer.cxx
index 6f7ec7ba..77e98daf 100644
--- a/common/rfb/Timer.cxx
+++ b/common/core/Timer.cxx
@@ -28,38 +28,16 @@
#include <algorithm>
-#include <rfb/Timer.h>
-#include <rfb/util.h>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+#include <core/Timer.h>
+#include <core/time.h>
-using namespace rfb;
+using namespace core;
#ifndef __NO_DEFINE_VLOG__
static LogWriter vlog("Timer");
#endif
-
-// Millisecond timeout processing helper functions
-
-inline static timeval addMillis(timeval inTime, int millis) {
- int secs = millis / 1000;
- millis = millis % 1000;
- inTime.tv_sec += secs;
- inTime.tv_usec += millis * 1000;
- if (inTime.tv_usec >= 1000000) {
- inTime.tv_sec++;
- inTime.tv_usec -= 1000000;
- }
- return inTime;
-}
-
-inline static int diffTimeMillis(timeval later, timeval earlier) {
- long udiff;
- udiff = ((later.tv_sec - earlier.tv_sec) * 1000000) +
- (later.tv_usec - earlier.tv_usec);
- return (udiff + 999) / 1000;
-}
-
std::list<Timer*> Timer::pending;
int Timer::checkTimeouts() {
@@ -167,9 +145,7 @@ int Timer::getTimeoutMs() {
}
int Timer::getRemainingMs() {
- timeval now;
- gettimeofday(&now, nullptr);
- return __rfbmax(0, diffTimeMillis(dueTime, now));
+ return msUntil(&dueTime);
}
bool Timer::isBefore(timeval other) {
diff --git a/common/rfb/Timer.h b/common/core/Timer.h
index 362cb84e..cde672b2 100644
--- a/common/rfb/Timer.h
+++ b/common/core/Timer.h
@@ -17,13 +17,13 @@
* USA.
*/
-#ifndef __RFB_TIMER_H__
-#define __RFB_TIMER_H__
+#ifndef __CORE_TIMER_H__
+#define __CORE_TIMER_H__
#include <list>
#include <sys/time.h>
-namespace rfb {
+namespace core {
/* Timer
diff --git a/common/rfb/util.cxx b/common/core/string.cxx
index 3c62b1df..091836db 100644
--- a/common/rfb/util.cxx
+++ b/common/core/string.cxx
@@ -26,11 +26,10 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
-#include <sys/time.h>
-#include <rfb/util.h>
+#include <core/string.h>
-namespace rfb {
+namespace core {
std::string format(const char *fmt, ...)
{
@@ -65,6 +64,9 @@ namespace rfb {
std::vector<std::string> out;
const char *start, *stop;
+ if (src[0] == '\0')
+ return out;
+
start = src;
do {
stop = strchr(start, delimiter);
@@ -604,40 +606,6 @@ namespace rfb {
return true;
}
- unsigned msBetween(const struct timeval *first,
- const struct timeval *second)
- {
- unsigned diff;
-
- diff = (second->tv_sec - first->tv_sec) * 1000;
-
- diff += second->tv_usec / 1000;
- diff -= first->tv_usec / 1000;
-
- return diff;
- }
-
- unsigned msSince(const struct timeval *then)
- {
- struct timeval now;
-
- gettimeofday(&now, nullptr);
-
- return msBetween(then, &now);
- }
-
- bool isBefore(const struct timeval *first,
- const struct timeval *second)
- {
- if (first->tv_sec < second->tv_sec)
- return true;
- if (first->tv_sec > second->tv_sec)
- return false;
- if (first->tv_usec < second->tv_usec)
- return true;
- return false;
- }
-
static std::string doPrefix(long long value, const char *unit,
unsigned divisor, const char **prefixes,
size_t prefixCount, int precision) {
diff --git a/common/rfb/util.h b/common/core/string.h
index b47ac4c9..1465484d 100644
--- a/common/rfb/util.h
+++ b/common/core/string.h
@@ -18,21 +18,18 @@
*/
//
-// util.h - miscellaneous useful bits
+// string.h - string utility functions
//
-#ifndef __RFB_UTIL_H__
-#define __RFB_UTIL_H__
+#ifndef __CORE_STRING_H__
+#define __CORE_STRING_H__
-#include <limits.h>
#include <stdint.h>
#include <string>
#include <vector>
-struct timeval;
-
-namespace rfb {
+namespace core {
// Formats according to printf(), with a dynamic allocation
std::string format(const char *fmt, ...)
@@ -71,24 +68,8 @@ namespace rfb {
bool isValidUTF8(const char* str, size_t bytes = (size_t)-1);
bool isValidUTF16(const wchar_t* wstr, size_t units = (size_t)-1);
- // HELPER functions for timeout handling
-
- // secsToMillis() turns seconds into milliseconds, capping the value so it
- // can't wrap round and become -ve
- inline int secsToMillis(int secs) {
- return (secs < 0 || secs > (INT_MAX/1000) ? INT_MAX : secs * 1000);
- }
-
- // Returns time elapsed between two moments in milliseconds.
- unsigned msBetween(const struct timeval *first,
- const struct timeval *second);
-
- // Returns time elapsed since given moment in milliseconds.
- unsigned msSince(const struct timeval *then);
-
- // Returns true if first happened before seconds
- bool isBefore(const struct timeval *first,
- const struct timeval *second);
+ // Convert a value to a string using the correct prefix to reduce
+ // the length of the string
std::string siPrefix(long long value, const char *unit,
int precision=6);
@@ -96,16 +77,4 @@ namespace rfb {
int precision=6);
}
-// Some platforms (e.g. Windows) include max() and min() macros in their
-// standard headers, but they are also standard C++ template functions, so some
-// C++ headers will undefine them. So we steer clear of the names min and max
-// and define __rfbmin and __rfbmax instead.
-
-#ifndef __rfbmax
-#define __rfbmax(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-#ifndef __rfbmin
-#define __rfbmin(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
#endif
diff --git a/common/core/time.cxx b/common/core/time.cxx
new file mode 100644
index 00000000..47a0ff8a
--- /dev/null
+++ b/common/core/time.cxx
@@ -0,0 +1,88 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2019 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stddef.h>
+#include <sys/time.h>
+
+#include <core/time.h>
+
+namespace core {
+
+ unsigned msBetween(const struct timeval *first,
+ const struct timeval *second)
+ {
+ unsigned udiff;
+
+ if (isBefore(second, first))
+ return 0;
+
+ udiff = (second->tv_sec - first->tv_sec) * 1000000 +
+ (second->tv_usec - first->tv_usec);
+
+ return (udiff + 999) / 1000;
+ }
+
+ unsigned msSince(const struct timeval *then)
+ {
+ struct timeval now;
+
+ gettimeofday(&now, nullptr);
+
+ return msBetween(then, &now);
+ }
+
+ unsigned msUntil(const struct timeval *then)
+ {
+ struct timeval now;
+
+ gettimeofday(&now, nullptr);
+
+ return msBetween(&now, then);
+ }
+
+ bool isBefore(const struct timeval *first,
+ const struct timeval *second)
+ {
+ if (first->tv_sec < second->tv_sec)
+ return true;
+ if (first->tv_sec > second->tv_sec)
+ return false;
+ if (first->tv_usec < second->tv_usec)
+ return true;
+ return false;
+ }
+
+ struct timeval addMillis(struct timeval inTime, int millis)
+ {
+ int secs = millis / 1000;
+ millis = millis % 1000;
+ inTime.tv_sec += secs;
+ inTime.tv_usec += millis * 1000;
+ if (inTime.tv_usec >= 1000000) {
+ inTime.tv_sec++;
+ inTime.tv_usec -= 1000000;
+ }
+ return inTime;
+ }
+
+}
diff --git a/common/core/time.h b/common/core/time.h
new file mode 100644
index 00000000..319f336f
--- /dev/null
+++ b/common/core/time.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2011-2019 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+//
+// time.h - time helper functions
+//
+
+#ifndef __CORE_TIME_H__
+#define __CORE_TIME_H__
+
+#include <limits.h>
+
+struct timeval;
+
+namespace core {
+
+ // secsToMillis() turns seconds into milliseconds, capping the value so it
+ // can't wrap round and become -ve
+ inline int secsToMillis(int secs) {
+ return (secs < 0 || secs > (INT_MAX/1000) ? INT_MAX : secs * 1000);
+ }
+
+ // Returns time elapsed between two moments in milliseconds.
+ unsigned msBetween(const struct timeval *first,
+ const struct timeval *second);
+
+ // Returns time elapsed since given moment in milliseconds.
+ unsigned msSince(const struct timeval *then);
+
+ // Returns time until the given moment in milliseconds.
+ unsigned msUntil(const struct timeval *then);
+
+ // Returns true if first happened before seconds
+ bool isBefore(const struct timeval *first,
+ const struct timeval *second);
+
+ // Returns a new timeval a specified number of milliseconds later than
+ // the given timeval
+ struct timeval addMillis(struct timeval inTime, int millis);
+}
+
+#endif
diff --git a/common/os/winerrno.h b/common/core/winerrno.h
index a81fdc94..a81fdc94 100644
--- a/common/os/winerrno.h
+++ b/common/core/winerrno.h
diff --git a/common/os/os.cxx b/common/core/xdgdirs.cxx
index 2ac70550..2628f317 100644
--- a/common/os/os.cxx
+++ b/common/core/xdgdirs.cxx
@@ -21,8 +21,6 @@
#include <config.h>
#endif
-#include <os/os.h>
-
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
@@ -43,6 +41,8 @@
#define mkdir(path, mode) mkdir(path)
#endif
+#include <core/xdgdirs.h>
+
static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_def)
{
static char dir[PATH_MAX], legacy[PATH_MAX];
@@ -109,27 +109,27 @@ static const char* getvncdir(bool userDir, const char *xdg_env, const char *xdg_
return (stat(dir, &st) != 0 && stat(legacy, &st) == 0) ? legacy : dir;
}
-const char* os::getuserhomedir()
+const char* core::getuserhomedir()
{
return getvncdir(true, nullptr, nullptr);
}
-const char* os::getvncconfigdir()
+const char* core::getvncconfigdir()
{
return getvncdir(false, "XDG_CONFIG_HOME", ".config");
}
-const char* os::getvncdatadir()
+const char* core::getvncdatadir()
{
return getvncdir(false, "XDG_DATA_HOME", ".local/share");
}
-const char* os::getvncstatedir()
+const char* core::getvncstatedir()
{
return getvncdir(false, "XDG_STATE_HOME", ".local/state");
}
-int os::mkdir_p(const char *path_, mode_t mode)
+int core::mkdir_p(const char *path_, mode_t mode)
{
char *path = strdup(path_);
char *p;
diff --git a/common/os/os.h b/common/core/xdgdirs.h
index a3448070..0769ba8b 100644
--- a/common/os/os.h
+++ b/common/core/xdgdirs.h
@@ -17,12 +17,12 @@
* USA.
*/
-#ifndef OS_OS_H
-#define OS_OS_H
+#ifndef CORE_XDGDIRS_H
+#define CORE_XDGDIRS_H
#include <sys/stat.h>
-namespace os {
+namespace core {
/*
* Get user home directory.
@@ -71,4 +71,4 @@ namespace os {
int mkdir_p(const char *path, mode_t mode);
}
-#endif /* OS_OS_H */
+#endif /* CORE_XDGDIRS_H */
diff --git a/common/network/CMakeLists.txt b/common/network/CMakeLists.txt
index f08eaa31..42472b8d 100644
--- a/common/network/CMakeLists.txt
+++ b/common/network/CMakeLists.txt
@@ -7,7 +7,7 @@ if(NOT WIN32)
endif()
target_include_directories(network PUBLIC ${CMAKE_SOURCE_DIR}/common)
-target_link_libraries(network os rdr rfb)
+target_link_libraries(network core rdr)
if(WIN32)
target_link_libraries(network ws2_32)
diff --git a/common/network/Socket.cxx b/common/network/Socket.cxx
index 49abbc84..7fc39d1e 100644
--- a/common/network/Socket.cxx
+++ b/common/network/Socket.cxx
@@ -32,22 +32,23 @@
#define errorNumber errno
#define closesocket close
#include <sys/socket.h>
-#endif
-
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
+#endif
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
-#include <network/Socket.h>
+#include <rdr/FdInStream.h>
+#include <rdr/FdOutStream.h>
-#include <rfb/LogWriter.h>
+#include <network/Socket.h>
using namespace network;
-static rfb::LogWriter vlog("Socket");
+static core::LogWriter vlog("Socket");
// -=- Socket initialisation
static bool socketsInitialised = false;
@@ -59,7 +60,7 @@ void network::initSockets() {
WSADATA initResult;
if (WSAStartup(requiredVersion, &initResult) != 0)
- throw rdr::socket_error("Unable to initialise Winsock2", errorNumber);
+ throw core::socket_error("Unable to initialise Winsock2", errorNumber);
#else
signal(SIGPIPE, SIG_IGN);
#endif
@@ -99,6 +100,11 @@ Socket::~Socket()
delete outstream;
}
+int Socket::getFd()
+{
+ return outstream->getFd();
+}
+
// if shutdown() is overridden then the override MUST call on to here
void Socket::shutdown()
{
@@ -114,7 +120,7 @@ void Socket::shutdown()
}
isShutdown_ = true;
- ::shutdown(getFd(), SHUT_RDWR);
+ ::shutdown(getFd(), SHUT_WR);
}
bool Socket::isShutdown() const
@@ -122,6 +128,11 @@ bool Socket::isShutdown() const
return isShutdown_;
}
+void Socket::cork(bool enable)
+{
+ outstream->cork(enable);
+}
+
// Was there a "?" in the ConnectionFilter used to accept this Socket?
void Socket::setRequiresQuery()
{
@@ -178,7 +189,7 @@ Socket* SocketListener::accept() {
// Accept an incoming connection
if ((new_sock = ::accept(fd, nullptr, nullptr)) < 0)
- throw rdr::socket_error("Unable to accept new connection", errorNumber);
+ throw core::socket_error("Unable to accept new connection", errorNumber);
// Create the socket object & check connection is allowed
Socket* s = createSocket(new_sock);
@@ -196,7 +207,7 @@ void SocketListener::listen(int sock)
if (::listen(sock, 5) < 0) {
int e = errorNumber;
closesocket(sock);
- throw rdr::socket_error("Unable to set socket to listening mode", e);
+ throw core::socket_error("Unable to set socket to listening mode", e);
}
fd = sock;
diff --git a/common/network/Socket.h b/common/network/Socket.h
index 34b8db8e..f1688c72 100644
--- a/common/network/Socket.h
+++ b/common/network/Socket.h
@@ -24,8 +24,11 @@
#include <list>
#include <limits.h>
-#include <rdr/FdInStream.h>
-#include <rdr/FdOutStream.h>
+
+namespace rdr {
+ class FdInStream;
+ class FdOutStream;
+}
namespace network {
@@ -40,12 +43,12 @@ namespace network {
rdr::FdInStream &inStream() {return *instream;}
rdr::FdOutStream &outStream() {return *outstream;}
- int getFd() {return outstream->getFd();}
+ int getFd();
void shutdown();
bool isShutdown() const;
- void cork(bool enable) { outstream->cork(enable); }
+ void cork(bool enable);
// information about the remote end of the socket
virtual const char* getPeerAddress() = 0; // a string e.g. "192.168.0.1"
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
index c5b86543..bf3a224c 100644
--- a/common/network/TcpSocket.cxx
+++ b/common/network/TcpSocket.cxx
@@ -35,19 +35,21 @@
#include <errno.h>
#endif
+#include <assert.h>
+#include <ctype.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include <rdr/Exception.h>
+#include <core/Configuration.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
#include <network/TcpSocket.h>
-#include <rfb/LogWriter.h>
-#include <rfb/Configuration.h>
-#include <rfb/util.h>
-
#ifdef WIN32
-#include <os/winerrno.h>
+#include <core/winerrno.h>
#endif
#ifndef INADDR_NONE
@@ -68,12 +70,11 @@
#endif
using namespace network;
-using namespace rdr;
-static rfb::LogWriter vlog("TcpSocket");
+static core::LogWriter vlog("TcpSocket");
-static rfb::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true);
-static rfb::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true);
+static core::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true);
+static core::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true);
/* Tunnelling support. */
int network::findFreeTcpPort (void)
@@ -85,20 +86,105 @@ int network::findFreeTcpPort (void)
addr.sin_addr.s_addr = INADDR_ANY;
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
- throw socket_error("Unable to create socket", errorNumber);
+ throw core::socket_error("Unable to create socket", errorNumber);
addr.sin_port = 0;
if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
- throw socket_error("Unable to find free port", errorNumber);
+ throw core::socket_error("Unable to find free port", errorNumber);
socklen_t n = sizeof(addr);
if (getsockname (sock, (struct sockaddr *)&addr, &n) < 0)
- throw socket_error("Unable to get port number", errorNumber);
+ throw core::socket_error("Unable to get port number", errorNumber);
closesocket (sock);
return ntohs(addr.sin_port);
}
+static bool isAllSpace(const char *string) {
+ if (string == nullptr)
+ return false;
+ while(*string != '\0') {
+ if (! isspace(*string))
+ return false;
+ string++;
+ }
+ return true;
+}
+
+void network::getHostAndPort(const char* hi, std::string* host,
+ int* port, int basePort)
+{
+ const char* hostStart;
+ const char* hostEnd;
+ const char* portStart;
+
+ if (hi == nullptr)
+ throw std::invalid_argument("NULL host specified");
+
+ // Trim leading whitespace
+ while(isspace(*hi))
+ hi++;
+
+ assert(host);
+ assert(port);
+
+ if (hi[0] == '[') {
+ hostStart = &hi[1];
+ hostEnd = strchr(hostStart, ']');
+ if (hostEnd == nullptr)
+ throw std::invalid_argument("Unmatched [ in host");
+
+ portStart = hostEnd + 1;
+ if (isAllSpace(portStart))
+ portStart = nullptr;
+ } else {
+ hostStart = &hi[0];
+ hostEnd = strrchr(hostStart, ':');
+
+ if (hostEnd == nullptr) {
+ hostEnd = hostStart + strlen(hostStart);
+ portStart = nullptr;
+ } else {
+ if ((hostEnd > hostStart) && (hostEnd[-1] == ':'))
+ hostEnd--;
+ portStart = strchr(hostStart, ':');
+ if (portStart != hostEnd) {
+ // We found more : in the host. This is probably an IPv6 address
+ hostEnd = hostStart + strlen(hostStart);
+ portStart = nullptr;
+ }
+ }
+ }
+
+ // Back up past trailing space
+ while(isspace(*(hostEnd - 1)) && hostEnd > hostStart)
+ hostEnd--;
+
+ if (hostStart == hostEnd)
+ *host = "localhost";
+ else
+ *host = std::string(hostStart, hostEnd - hostStart);
+
+ if (portStart == nullptr)
+ *port = basePort;
+ else {
+ char* end;
+
+ if (portStart[0] != ':')
+ throw std::invalid_argument("Invalid port specified");
+
+ if (portStart[1] != ':')
+ *port = strtol(portStart + 1, &end, 10);
+ else
+ *port = strtol(portStart + 2, &end, 10);
+ if (*end != '\0' && ! isAllSpace(end))
+ throw std::invalid_argument("Invalid port specified");
+
+ if ((portStart[1] != ':') && (*port < 100))
+ *port += basePort;
+ }
+}
+
int network::getSockPort(int sock)
{
vnc_sockaddr_t sa;
@@ -137,7 +223,7 @@ TcpSocket::TcpSocket(const char *host, int port)
hints.ai_next = nullptr;
if ((result = getaddrinfo(host, nullptr, &hints, &ai)) != 0) {
- throw getaddrinfo_error("Unable to resolve host by name", result);
+ throw core::getaddrinfo_error("Unable to resolve host by name", result);
}
sock = -1;
@@ -178,7 +264,7 @@ TcpSocket::TcpSocket(const char *host, int port)
if (sock == -1) {
err = errorNumber;
freeaddrinfo(ai);
- throw socket_error("Unable to create socket", err);
+ throw core::socket_error("Unable to create socket", err);
}
/* Attempt to connect to the remote host */
@@ -205,7 +291,7 @@ TcpSocket::TcpSocket(const char *host, int port)
if (err == 0)
throw std::runtime_error("No useful address for host");
else
- throw socket_error("Unable to connect to socket", err);
+ throw core::socket_error("Unable to connect to socket", err);
}
// Take proper ownership of the socket
@@ -302,7 +388,7 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr,
int sock;
if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
- throw socket_error("Unable to create listening socket", errorNumber);
+ throw core::socket_error("Unable to create listening socket", errorNumber);
memcpy (&sa, listenaddr, listenaddrlen);
#ifdef IPV6_V6ONLY
@@ -310,7 +396,7 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr,
if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one))) {
int e = errorNumber;
closesocket(sock);
- throw socket_error("Unable to set IPV6_V6ONLY", e);
+ throw core::socket_error("Unable to set IPV6_V6ONLY", e);
}
}
#endif /* defined(IPV6_V6ONLY) */
@@ -328,14 +414,14 @@ TcpListener::TcpListener(const struct sockaddr *listenaddr,
(char *)&one, sizeof(one)) < 0) {
int e = errorNumber;
closesocket(sock);
- throw socket_error("Unable to create listening socket", e);
+ throw core::socket_error("Unable to create listening socket", e);
}
#endif
if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
int e = errorNumber;
closesocket(sock);
- throw socket_error("Failed to bind socket", e);
+ throw core::socket_error("Failed to bind socket", e);
}
listen(sock);
@@ -446,7 +532,7 @@ void network::createTcpListeners(std::list<SocketListener*> *listeners,
snprintf (service, sizeof (service) - 1, "%d", port);
service[sizeof (service) - 1] = '\0';
if ((result = getaddrinfo(addr, service, &hints, &ai)) != 0)
- throw getaddrinfo_error("Unable to resolve listening address", result);
+ throw core::getaddrinfo_error("Unable to resolve listening address", result);
try {
createTcpListeners(listeners, ai);
@@ -485,7 +571,7 @@ void network::createTcpListeners(std::list<SocketListener*> *listeners,
try {
new_listeners.push_back(new TcpListener(current->ai_addr,
current->ai_addrlen));
- } catch (socket_error& e) {
+ } catch (core::socket_error& e) {
// Ignore this if it is due to lack of address family support on
// the interface or on the system
if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
@@ -506,7 +592,7 @@ void network::createTcpListeners(std::list<SocketListener*> *listeners,
TcpFilter::TcpFilter(const char* spec) {
std::vector<std::string> patterns;
- patterns = rfb::split(spec, ',');
+ patterns = core::split(spec, ',');
for (size_t i = 0; i < patterns.size(); i++) {
if (!patterns[i].empty())
@@ -608,11 +694,11 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
initSockets();
- parts = rfb::split(&p[1], '/');
+ parts = core::split(&p[1], '/');
if (parts.size() > 2)
throw std::invalid_argument("Invalid filter specified");
- if (parts[0].empty()) {
+ if (parts.empty() || parts[0].empty()) {
// Match any address
memset (&pattern.address, 0, sizeof (pattern.address));
pattern.address.u.sa.sa_family = AF_UNSPEC;
@@ -633,7 +719,7 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
}
if ((result = getaddrinfo (parts[0].c_str(), nullptr, &hints, &ai)) != 0) {
- throw getaddrinfo_error("Unable to resolve host by name", result);
+ throw core::getaddrinfo_error("Unable to resolve host by name", result);
}
memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen);
@@ -666,9 +752,9 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
family = pattern.address.u.sa.sa_family;
if (pattern.prefixlen > (family == AF_INET ? 32: 128))
- throw std::invalid_argument(rfb::format("Invalid prefix length for "
- "filter address: %u",
- pattern.prefixlen));
+ throw std::invalid_argument(
+ core::format("Invalid prefix length for filter address: %u",
+ pattern.prefixlen));
// Compute mask from address and prefix length
memset (&pattern.mask, 0, sizeof (pattern.mask));
diff --git a/common/network/TcpSocket.h b/common/network/TcpSocket.h
index b029bff2..17854e10 100644
--- a/common/network/TcpSocket.h
+++ b/common/network/TcpSocket.h
@@ -49,6 +49,9 @@ namespace network {
/* Tunnelling support. */
int findFreeTcpPort (void);
+ void getHostAndPort(const char* hi, std::string* host,
+ int* port, int basePort=5900);
+
int getSockPort(int sock);
class TcpSocket : public Socket {
diff --git a/common/network/UnixSocket.cxx b/common/network/UnixSocket.cxx
index 48561245..9691cb23 100644
--- a/common/network/UnixSocket.cxx
+++ b/common/network/UnixSocket.cxx
@@ -28,17 +28,16 @@
#include <errno.h>
#include <stdlib.h>
#include <stddef.h>
+#include <string.h>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
#include <network/UnixSocket.h>
-#include <rfb/LogWriter.h>
-
using namespace network;
-using namespace rdr;
-static rfb::LogWriter vlog("UnixSocket");
+static core::LogWriter vlog("UnixSocket");
// -=- UnixSocket
@@ -53,12 +52,12 @@ UnixSocket::UnixSocket(const char *path)
socklen_t salen;
if (strlen(path) >= sizeof(addr.sun_path))
- throw socket_error("Socket path is too long", ENAMETOOLONG);
+ throw core::socket_error("Socket path is too long", ENAMETOOLONG);
// - Create a socket
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1)
- throw socket_error("Unable to create socket", errno);
+ throw core::socket_error("Unable to create socket", errno);
// - Attempt to connect
memset(&addr, 0, sizeof(addr));
@@ -72,7 +71,7 @@ UnixSocket::UnixSocket(const char *path)
}
if (result == -1)
- throw socket_error("Unable to connect to socket", err);
+ throw core::socket_error("Unable to connect to socket", err);
setFd(sock);
}
@@ -119,11 +118,11 @@ UnixListener::UnixListener(const char *path, int mode)
int err, result;
if (strlen(path) >= sizeof(addr.sun_path))
- throw socket_error("Socket path is too long", ENAMETOOLONG);
+ throw core::socket_error("Socket path is too long", ENAMETOOLONG);
// - Create a socket
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
- throw socket_error("Unable to create listening socket", errno);
+ throw core::socket_error("Unable to create listening socket", errno);
// - Delete existing socket (ignore result)
unlink(path);
@@ -138,14 +137,14 @@ UnixListener::UnixListener(const char *path, int mode)
umask(saved_umask);
if (result < 0) {
close(fd);
- throw socket_error("Unable to bind listening socket", err);
+ throw core::socket_error("Unable to bind listening socket", err);
}
// - Set socket mode
if (chmod(path, mode) < 0) {
err = errno;
close(fd);
- throw socket_error("Unable to set socket mode", err);
+ throw core::socket_error("Unable to set socket mode", err);
}
listen(fd);
diff --git a/common/os/CMakeLists.txt b/common/os/CMakeLists.txt
deleted file mode 100644
index 2573d088..00000000
--- a/common/os/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-add_library(os STATIC
- Mutex.cxx
- Thread.cxx
- os.cxx)
-
-target_include_directories(os PUBLIC ${CMAKE_SOURCE_DIR}/common)
-target_link_libraries(os rdr)
-
-if(UNIX)
- target_link_libraries(os pthread)
-endif()
-
-if(UNIX)
- libtool_create_control_file(os)
-endif()
diff --git a/common/os/Mutex.cxx b/common/os/Mutex.cxx
deleted file mode 100644
index 1889e66b..00000000
--- a/common/os/Mutex.cxx
+++ /dev/null
@@ -1,158 +0,0 @@
-/* Copyright 2015 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#endif
-
-#include <rdr/Exception.h>
-
-#include <os/Mutex.h>
-
-using namespace os;
-
-Mutex::Mutex()
-{
-#ifdef WIN32
- systemMutex = new CRITICAL_SECTION;
- InitializeCriticalSection((CRITICAL_SECTION*)systemMutex);
-#else
- int ret;
-
- systemMutex = new pthread_mutex_t;
- ret = pthread_mutex_init((pthread_mutex_t*)systemMutex, nullptr);
- if (ret != 0)
- throw rdr::posix_error("Failed to create mutex", ret);
-#endif
-}
-
-Mutex::~Mutex()
-{
-#ifdef WIN32
- DeleteCriticalSection((CRITICAL_SECTION*)systemMutex);
- delete (CRITICAL_SECTION*)systemMutex;
-#else
- pthread_mutex_destroy((pthread_mutex_t*)systemMutex);
- delete (pthread_mutex_t*)systemMutex;
-#endif
-}
-
-void Mutex::lock()
-{
-#ifdef WIN32
- EnterCriticalSection((CRITICAL_SECTION*)systemMutex);
-#else
- int ret;
-
- ret = pthread_mutex_lock((pthread_mutex_t*)systemMutex);
- if (ret != 0)
- throw rdr::posix_error("Failed to lock mutex", ret);
-#endif
-}
-
-void Mutex::unlock()
-{
-#ifdef WIN32
- LeaveCriticalSection((CRITICAL_SECTION*)systemMutex);
-#else
- int ret;
-
- ret = pthread_mutex_unlock((pthread_mutex_t*)systemMutex);
- if (ret != 0)
- throw rdr::posix_error("Failed to unlock mutex", ret);
-#endif
-}
-
-Condition::Condition(Mutex* mutex_)
-{
- this->mutex = mutex_;
-
-#ifdef WIN32
- systemCondition = new CONDITION_VARIABLE;
- InitializeConditionVariable((CONDITION_VARIABLE*)systemCondition);
-#else
- int ret;
-
- systemCondition = new pthread_cond_t;
- ret = pthread_cond_init((pthread_cond_t*)systemCondition, nullptr);
- if (ret != 0)
- throw rdr::posix_error("Failed to create condition variable", ret);
-#endif
-}
-
-Condition::~Condition()
-{
-#ifdef WIN32
- delete (CONDITION_VARIABLE*)systemCondition;
-#else
- pthread_cond_destroy((pthread_cond_t*)systemCondition);
- delete (pthread_cond_t*)systemCondition;
-#endif
-}
-
-void Condition::wait()
-{
-#ifdef WIN32
- BOOL ret;
-
- ret = SleepConditionVariableCS((CONDITION_VARIABLE*)systemCondition,
- (CRITICAL_SECTION*)mutex->systemMutex,
- INFINITE);
- if (!ret)
- throw rdr::win32_error("Failed to wait on condition variable", GetLastError());
-#else
- int ret;
-
- ret = pthread_cond_wait((pthread_cond_t*)systemCondition,
- (pthread_mutex_t*)mutex->systemMutex);
- if (ret != 0)
- throw rdr::posix_error("Failed to wait on condition variable", ret);
-#endif
-}
-
-void Condition::signal()
-{
-#ifdef WIN32
- WakeConditionVariable((CONDITION_VARIABLE*)systemCondition);
-#else
- int ret;
-
- ret = pthread_cond_signal((pthread_cond_t*)systemCondition);
- if (ret != 0)
- throw rdr::posix_error("Failed to signal condition variable", ret);
-#endif
-}
-
-void Condition::broadcast()
-{
-#ifdef WIN32
- WakeAllConditionVariable((CONDITION_VARIABLE*)systemCondition);
-#else
- int ret;
-
- ret = pthread_cond_broadcast((pthread_cond_t*)systemCondition);
- if (ret != 0)
- throw rdr::posix_error("Failed to broadcast condition variable", ret);
-#endif
-}
diff --git a/common/os/Mutex.h b/common/os/Mutex.h
deleted file mode 100644
index 63c7e0cc..00000000
--- a/common/os/Mutex.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright 2015 Pierre Ossman for Cendio AB
- *
- * 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 __OS_MUTEX_H__
-#define __OS_MUTEX_H__
-
-namespace os {
- class Condition;
-
- class Mutex {
- public:
- Mutex();
- ~Mutex();
-
- void lock();
- void unlock();
-
- private:
- friend class Condition;
-
- void* systemMutex;
- };
-
- class AutoMutex {
- public:
- AutoMutex(Mutex* mutex) { m = mutex; m->lock(); }
- ~AutoMutex() { m->unlock(); }
- private:
- Mutex* m;
- };
-
- class Condition {
- public:
- Condition(Mutex* mutex);
- ~Condition();
-
- void wait();
-
- void signal();
- void broadcast();
-
- private:
- Mutex* mutex;
- void* systemCondition;
- };
-
-}
-
-#endif
diff --git a/common/os/Thread.cxx b/common/os/Thread.cxx
deleted file mode 100644
index 6dca75a1..00000000
--- a/common/os/Thread.cxx
+++ /dev/null
@@ -1,173 +0,0 @@
-/* Copyright 2015 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#include <signal.h>
-#include <unistd.h>
-#endif
-
-#include <rdr/Exception.h>
-
-#include <os/Mutex.h>
-#include <os/Thread.h>
-
-using namespace os;
-
-Thread::Thread() : running(false), threadId(nullptr)
-{
- mutex = new Mutex;
-
-#ifdef WIN32
- threadId = new HANDLE;
-#else
- threadId = new pthread_t;
-#endif
-}
-
-Thread::~Thread()
-{
-#ifdef WIN32
- delete (HANDLE*)threadId;
-#else
- if (isRunning())
- pthread_cancel(*(pthread_t*)threadId);
- delete (pthread_t*)threadId;
-#endif
-
- delete mutex;
-}
-
-void Thread::start()
-{
- AutoMutex a(mutex);
-
-#ifdef WIN32
- *(HANDLE*)threadId = CreateThread(nullptr, 0, startRoutine, this, 0, nullptr);
- if (*(HANDLE*)threadId == nullptr)
- throw rdr::win32_error("Failed to create thread", GetLastError());
-#else
- int ret;
- sigset_t all, old;
-
- // Creating threads from libraries is a bit evil, so mitigate the
- // issue by at least avoiding signals on these threads
- sigfillset(&all);
- ret = pthread_sigmask(SIG_SETMASK, &all, &old);
- if (ret != 0)
- throw rdr::posix_error("Failed to mask signals", ret);
-
- ret = pthread_create((pthread_t*)threadId, nullptr, startRoutine, this);
-
- pthread_sigmask(SIG_SETMASK, &old, nullptr);
-
- if (ret != 0)
- throw rdr::posix_error("Failed to create thread", ret);
-#endif
-
- running = true;
-}
-
-void Thread::wait()
-{
- if (!isRunning())
- return;
-
-#ifdef WIN32
- DWORD ret;
-
- ret = WaitForSingleObject(*(HANDLE*)threadId, INFINITE);
- if (ret != WAIT_OBJECT_0)
- throw rdr::win32_error("Failed to join thread", GetLastError());
-#else
- int ret;
-
- ret = pthread_join(*(pthread_t*)threadId, nullptr);
- if (ret != 0)
- throw rdr::posix_error("Failed to join thread", ret);
-#endif
-}
-
-bool Thread::isRunning()
-{
- AutoMutex a(mutex);
-
- return running;
-}
-
-size_t Thread::getSystemCPUCount()
-{
-#ifdef WIN32
- SYSTEM_INFO si;
- size_t count;
- DWORD mask;
-
- GetSystemInfo(&si);
-
- count = 0;
- for (mask = si.dwActiveProcessorMask;mask != 0;mask >>= 1) {
- if (mask & 0x1)
- count++;
- }
-
- if (count > si.dwNumberOfProcessors)
- count = si.dwNumberOfProcessors;
-
- return count;
-#else
- long ret;
-
- ret = sysconf(_SC_NPROCESSORS_ONLN);
- if (ret == -1)
- return 0;
-
- return ret;
-#endif
-}
-
-#ifdef WIN32
-long unsigned __stdcall Thread::startRoutine(void* data)
-#else
-void* Thread::startRoutine(void* data)
-#endif
-{
- Thread *self;
-
- self = (Thread*)data;
-
- try {
- self->worker();
- } catch(...) {
- }
-
- self->mutex->lock();
- self->running = false;
- self->mutex->unlock();
-
-#ifdef WIN32
- return 0;
-#else
- return nullptr;
-#endif
-}
diff --git a/common/os/Thread.h b/common/os/Thread.h
deleted file mode 100644
index 4c39884b..00000000
--- a/common/os/Thread.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright 2015 Pierre Ossman for Cendio AB
- *
- * 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 __OS_THREAD_H__
-#define __OS_THREAD_H__
-
-#include <stddef.h>
-
-namespace os {
- class Mutex;
-
- class Thread {
- public:
- Thread();
- virtual ~Thread();
-
- void start();
- void wait();
-
- bool isRunning();
-
- public:
- static size_t getSystemCPUCount();
-
- protected:
- virtual void worker() = 0;
-
- private:
-#ifdef WIN32
- static long unsigned __stdcall startRoutine(void* data);
-#else
- static void* startRoutine(void* data);
-#endif
-
- private:
- Mutex *mutex;
- bool running;
-
- void *threadId;
- };
-}
-
-#endif
diff --git a/common/rdr/BufferedInStream.cxx b/common/rdr/BufferedInStream.cxx
index bf94a950..bcdeef4a 100644
--- a/common/rdr/BufferedInStream.cxx
+++ b/common/rdr/BufferedInStream.cxx
@@ -23,9 +23,9 @@
#include <assert.h>
-#include <rdr/BufferedInStream.h>
+#include <core/string.h>
-#include <rfb/util.h>
+#include <rdr/BufferedInStream.h>
using namespace rdr;
@@ -64,12 +64,10 @@ void BufferedInStream::ensureSpace(size_t needed)
uint8_t* newBuffer;
if (needed > MAX_BUF_SIZE)
- throw std::out_of_range(rfb::format("BufferedInStream overrun: "
- "requested size of %lu bytes "
- "exceeds maximum of %lu "
- "bytes",
- (long unsigned)needed,
- (long unsigned)MAX_BUF_SIZE));
+ throw std::out_of_range(core::format(
+ "BufferedInStream overrun: requested size of %lu bytes exceeds "
+ "maximum of %lu bytes",
+ (long unsigned)needed, (long unsigned)MAX_BUF_SIZE));
newSize = DEFAULT_BUF_SIZE;
while (newSize < needed)
diff --git a/common/rdr/BufferedOutStream.cxx b/common/rdr/BufferedOutStream.cxx
index efb71dd7..e2b756bb 100644
--- a/common/rdr/BufferedOutStream.cxx
+++ b/common/rdr/BufferedOutStream.cxx
@@ -22,9 +22,9 @@
#include <config.h>
#endif
-#include <rdr/BufferedOutStream.h>
+#include <core/string.h>
-#include <rfb/util.h>
+#include <rdr/BufferedOutStream.h>
using namespace rdr;
@@ -138,11 +138,10 @@ void BufferedOutStream::overrun(size_t needed)
// We'll need to allocate more buffer space...
if (totalNeeded > MAX_BUF_SIZE)
- throw std::out_of_range(rfb::format("BufferedOutStream overrun: "
- "requested size of %lu bytes "
- "exceeds maximum of %lu bytes",
- (long unsigned)totalNeeded,
- (long unsigned)MAX_BUF_SIZE));
+ throw std::out_of_range(core::format(
+ "BufferedOutStream overrun: requested size of %lu bytes exceeds "
+ "maximum of %lu bytes",
+ (long unsigned)totalNeeded, (long unsigned)MAX_BUF_SIZE));
newSize = DEFAULT_BUF_SIZE;
while (newSize < totalNeeded)
diff --git a/common/rdr/CMakeLists.txt b/common/rdr/CMakeLists.txt
index 2897119b..526b2971 100644
--- a/common/rdr/CMakeLists.txt
+++ b/common/rdr/CMakeLists.txt
@@ -3,7 +3,6 @@ add_library(rdr STATIC
AESOutStream.cxx
BufferedInStream.cxx
BufferedOutStream.cxx
- Exception.cxx
FdInStream.cxx
FdOutStream.cxx
FileInStream.cxx
@@ -13,17 +12,14 @@ add_library(rdr STATIC
TLSException.cxx
TLSInStream.cxx
TLSOutStream.cxx
+ TLSSocket.cxx
ZlibInStream.cxx
ZlibOutStream.cxx)
target_include_directories(rdr PUBLIC ${CMAKE_SOURCE_DIR}/common)
target_include_directories(rdr SYSTEM PUBLIC ${ZLIB_INCLUDE_DIRS})
-target_link_libraries(rdr ${ZLIB_LIBRARIES} os rfb)
-
-if(MSVC)
- # undef min and max macro
- target_compile_definitions(rfb PRIVATE NOMINMAX)
-endif()
+target_link_libraries(rdr core)
+target_link_libraries(rdr ${ZLIB_LIBRARIES})
if(GNUTLS_FOUND)
target_include_directories(rdr SYSTEM PUBLIC ${GNUTLS_INCLUDE_DIR})
@@ -32,7 +28,6 @@ endif()
if (NETTLE_FOUND)
target_include_directories(rdr SYSTEM PUBLIC ${NETTLE_INCLUDE_DIRS})
target_link_libraries(rdr ${NETTLE_LIBRARIES})
- target_link_directories(rdr PUBLIC ${NETTLE_LIBRARY_DIRS})
endif()
if(WIN32)
target_link_libraries(rdr ws2_32)
diff --git a/common/rdr/FdInStream.cxx b/common/rdr/FdInStream.cxx
index 23ea2f8c..25542a01 100644
--- a/common/rdr/FdInStream.cxx
+++ b/common/rdr/FdInStream.cxx
@@ -28,7 +28,7 @@
#include <winsock2.h>
#define errorNumber WSAGetLastError()
#define close closesocket
-#include <os/winerrno.h>
+#include <core/winerrno.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
@@ -41,8 +41,9 @@
#include <sys/select.h>
#endif
+#include <core/Exception.h>
+
#include <rdr/FdInStream.h>
-#include <rdr/Exception.h>
using namespace rdr;
@@ -92,7 +93,7 @@ size_t FdInStream::readFd(uint8_t* buf, size_t len)
} while (n < 0 && errorNumber == EINTR);
if (n < 0)
- throw socket_error("select", errorNumber);
+ throw core::socket_error("select", errorNumber);
if (n == 0)
return 0;
@@ -102,7 +103,7 @@ size_t FdInStream::readFd(uint8_t* buf, size_t len)
} while (n < 0 && errorNumber == EINTR);
if (n < 0)
- throw socket_error("read", errorNumber);
+ throw core::socket_error("read", errorNumber);
if (n == 0)
throw end_of_stream();
diff --git a/common/rdr/FdOutStream.cxx b/common/rdr/FdOutStream.cxx
index 6db8c0bb..416926c1 100644
--- a/common/rdr/FdOutStream.cxx
+++ b/common/rdr/FdOutStream.cxx
@@ -28,7 +28,7 @@
#ifdef _WIN32
#include <winsock2.h>
#define errorNumber WSAGetLastError()
-#include <os/winerrno.h>
+#include <core/winerrno.h>
#else
#include <sys/types.h>
#include <unistd.h>
@@ -44,10 +44,10 @@
#include <sys/select.h>
#endif
-#include <rdr/FdOutStream.h>
-#include <rdr/Exception.h>
-#include <rfb/util.h>
+#include <core/Exception.h>
+#include <core/time.h>
+#include <rdr/FdOutStream.h>
using namespace rdr;
@@ -68,7 +68,7 @@ FdOutStream::~FdOutStream()
unsigned FdOutStream::getIdleTime()
{
- return rfb::msSince(&lastWrite);
+ return core::msSince(&lastWrite);
}
void FdOutStream::cork(bool enable)
@@ -117,7 +117,7 @@ size_t FdOutStream::writeFd(const uint8_t* data, size_t length)
} while (n < 0 && errorNumber == EINTR);
if (n < 0)
- throw socket_error("select", errorNumber);
+ throw core::socket_error("select", errorNumber);
if (n == 0)
return 0;
@@ -134,7 +134,7 @@ size_t FdOutStream::writeFd(const uint8_t* data, size_t length)
} while (n < 0 && (errorNumber == EINTR));
if (n < 0)
- throw socket_error("write", errorNumber);
+ throw core::socket_error("write", errorNumber);
gettimeofday(&lastWrite, nullptr);
diff --git a/common/rdr/FileInStream.cxx b/common/rdr/FileInStream.cxx
index df09ea76..4dbe2d1f 100644
--- a/common/rdr/FileInStream.cxx
+++ b/common/rdr/FileInStream.cxx
@@ -24,7 +24,8 @@
#include <errno.h>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+
#include <rdr/FileInStream.h>
using namespace rdr;
@@ -33,7 +34,7 @@ FileInStream::FileInStream(const char *fileName)
{
file = fopen(fileName, "rb");
if (!file)
- throw posix_error("fopen", errno);
+ throw core::posix_error("fopen", errno);
}
FileInStream::~FileInStream(void) {
@@ -48,7 +49,7 @@ bool FileInStream::fillBuffer()
size_t n = fread((uint8_t*)end, 1, availSpace(), file);
if (n == 0) {
if (ferror(file))
- throw posix_error("fread", errno);
+ throw core::posix_error("fread", errno);
if (feof(file))
throw end_of_stream();
return false;
diff --git a/common/rdr/HexInStream.cxx b/common/rdr/HexInStream.cxx
index 69c3e260..b5a8826c 100644
--- a/common/rdr/HexInStream.cxx
+++ b/common/rdr/HexInStream.cxx
@@ -22,8 +22,10 @@
#endif
#include <algorithm>
+
+#include <core/string.h>
+
#include <rdr/HexInStream.h>
-#include <rfb/util.h>
using namespace rdr;
@@ -44,7 +46,7 @@ bool HexInStream::fillBuffer() {
uint8_t* optr = (uint8_t*) end;
for (size_t i=0; i<length; i++) {
- if (!rfb::hexToBin((const char*)&iptr[i*2], 2, &optr[i], 1))
+ if (!core::hexToBin((const char*)&iptr[i*2], 2, &optr[i], 1))
throw std::runtime_error("HexInStream: Invalid input data");
}
diff --git a/common/rdr/HexOutStream.cxx b/common/rdr/HexOutStream.cxx
index efab77f8..b3749c0d 100644
--- a/common/rdr/HexOutStream.cxx
+++ b/common/rdr/HexOutStream.cxx
@@ -20,9 +20,12 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
#include <algorithm>
+
+#include <core/string.h>
+
#include <rdr/HexOutStream.h>
-#include <rfb/util.h>
using namespace rdr;
@@ -42,7 +45,7 @@ bool HexOutStream::flushBuffer()
size_t length = std::min((size_t)(ptr-sentUpTo), out_stream.avail()/2);
for (size_t i=0; i<length; i++)
- rfb::binToHex(&sentUpTo[i], 1, (char*)&optr[i*2], 2);
+ core::binToHex(&sentUpTo[i], 1, (char*)&optr[i*2], 2);
out_stream.setptr(length*2);
sentUpTo += length;
diff --git a/common/rdr/InStream.h b/common/rdr/InStream.h
index 5623142c..7ad4996f 100644
--- a/common/rdr/InStream.h
+++ b/common/rdr/InStream.h
@@ -38,6 +38,11 @@
namespace rdr {
+ class end_of_stream : public std::runtime_error {
+ public:
+ end_of_stream() noexcept : std::runtime_error("End of stream") {}
+ };
+
class InStream {
public:
@@ -182,9 +187,7 @@ namespace rdr {
private:
const uint8_t* restorePoint;
-#ifdef RFB_INSTREAM_CHECK
size_t checkedBytes;
-#endif
inline void check(size_t bytes) {
#ifdef RFB_INSTREAM_CHECK
@@ -204,11 +207,7 @@ namespace rdr {
protected:
- InStream() : restorePoint(nullptr)
-#ifdef RFB_INSTREAM_CHECK
- ,checkedBytes(0)
-#endif
- {}
+ InStream() : restorePoint(nullptr), checkedBytes(0) {}
const uint8_t* ptr;
const uint8_t* end;
};
diff --git a/common/rdr/MemInStream.h b/common/rdr/MemInStream.h
index 78ee2dee..a92e18f9 100644
--- a/common/rdr/MemInStream.h
+++ b/common/rdr/MemInStream.h
@@ -28,7 +28,6 @@
#define __RDR_MEMINSTREAM_H__
#include <rdr/InStream.h>
-#include <rdr/Exception.h>
namespace rdr {
diff --git a/common/rdr/RandomStream.cxx b/common/rdr/RandomStream.cxx
index 3a524102..9784c220 100644
--- a/common/rdr/RandomStream.cxx
+++ b/common/rdr/RandomStream.cxx
@@ -20,9 +20,11 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rdr/RandomStream.h>
-#include <rdr/Exception.h>
-#include <rfb/LogWriter.h>
+
#include <time.h>
#include <stdlib.h>
#ifndef WIN32
@@ -35,7 +37,7 @@
#endif
#endif
-static rfb::LogWriter vlog("RandomStream");
+static core::LogWriter vlog("RandomStream");
using namespace rdr;
@@ -89,7 +91,7 @@ bool RandomStream::fillBuffer() {
#ifdef RFB_HAVE_WINCRYPT
if (provider) {
if (!CryptGenRandom(provider, availSpace(), (uint8_t*)end))
- throw rdr::win32_error("Unable to CryptGenRandom", GetLastError());
+ throw core::win32_error("Unable to CryptGenRandom", GetLastError());
end += availSpace();
} else {
#else
@@ -97,8 +99,8 @@ bool RandomStream::fillBuffer() {
if (fp) {
size_t n = fread((uint8_t*)end, 1, availSpace(), fp);
if (n <= 0)
- throw rdr::posix_error("Reading /dev/urandom or /dev/random "
- "failed", errno);
+ throw core::posix_error(
+ "Reading /dev/urandom or /dev/random failed", errno);
end += n;
} else {
#else
diff --git a/common/rdr/TLSException.cxx b/common/rdr/TLSException.cxx
index ee4f587b..8c93a3d3 100644
--- a/common/rdr/TLSException.cxx
+++ b/common/rdr/TLSException.cxx
@@ -22,9 +22,9 @@
#include <config.h>
#endif
-#include <rdr/TLSException.h>
+#include <core/string.h>
-#include <rfb/util.h>
+#include <rdr/TLSException.h>
#include <string.h>
#include <stdio.h>
@@ -35,11 +35,28 @@
using namespace rdr;
#ifdef HAVE_GNUTLS
-tls_error::tls_error(const char* s, int err_) noexcept
- : std::runtime_error(rfb::format("%s: %s (%d)", s,
- gnutls_strerror(err_), err_)),
- err(err_)
+tls_error::tls_error(const char* s, int err_, int alert_) noexcept
+ : std::runtime_error(core::format("%s: %s (%d)", s,
+ strerror(err_, alert_), err_)),
+ err(err_), alert(alert_)
+{
+}
+
+const char* tls_error::strerror(int err_, int alert_) const noexcept
{
+ const char* msg;
+
+ msg = nullptr;
+
+ if ((alert_ != -1) &&
+ ((err_ == GNUTLS_E_WARNING_ALERT_RECEIVED) ||
+ (err_ == GNUTLS_E_FATAL_ALERT_RECEIVED)))
+ msg = gnutls_alert_get_name((gnutls_alert_description_t)alert_);
+
+ if (msg == nullptr)
+ msg = gnutls_strerror(err_);
+
+ return msg;
}
#endif /* HAVE_GNUTLS */
diff --git a/common/rdr/TLSException.h b/common/rdr/TLSException.h
index 62b090ba..75ee94f5 100644
--- a/common/rdr/TLSException.h
+++ b/common/rdr/TLSException.h
@@ -21,14 +21,16 @@
#ifndef __RDR_TLSEXCEPTION_H__
#define __RDR_TLSEXCEPTION_H__
-#include <rdr/Exception.h>
+#include <stdexcept>
namespace rdr {
class tls_error : public std::runtime_error {
public:
- int err;
- tls_error(const char* s, int err_) noexcept;
+ int err, alert;
+ tls_error(const char* s, int err_, int alert_=-1) noexcept;
+ private:
+ const char* strerror(int err_, int alert_) const noexcept;
};
}
diff --git a/common/rdr/TLSInStream.cxx b/common/rdr/TLSInStream.cxx
index ee2739f4..3e5ea2be 100644
--- a/common/rdr/TLSInStream.cxx
+++ b/common/rdr/TLSInStream.cxx
@@ -1,7 +1,7 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
- * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB
+ * Copyright 2012-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,74 +23,25 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
-#include <rdr/TLSException.h>
#include <rdr/TLSInStream.h>
-#include <rfb/LogWriter.h>
-#include <errno.h>
+#include <rdr/TLSSocket.h>
-#ifdef HAVE_GNUTLS
-using namespace rdr;
-
-static rfb::LogWriter vlog("TLSInStream");
-
-ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
-{
- TLSInStream* self= (TLSInStream*) str;
- InStream *in = self->in;
-
- self->streamEmpty = false;
- delete self->saved_exception;
- self->saved_exception = nullptr;
+#ifdef HAVE_GNUTLS
- try {
- if (!in->hasData(1)) {
- self->streamEmpty = true;
- gnutls_transport_set_errno(self->session, EAGAIN);
- return -1;
- }
-
- if (in->avail() < size)
- size = in->avail();
-
- in->readBytes((uint8_t*)data, size);
- } catch (end_of_stream&) {
- return 0;
- } catch (socket_error& e) {
- vlog.error("Failure reading TLS data: %s", e.what());
- gnutls_transport_set_errno(self->session, e.err);
- self->saved_exception = new socket_error(e);
- return -1;
- } catch (std::exception& e) {
- vlog.error("Failure reading TLS data: %s", e.what());
- gnutls_transport_set_errno(self->session, EINVAL);
- self->saved_exception = new std::runtime_error(e.what());
- return -1;
- }
-
- return size;
-}
+using namespace rdr;
-TLSInStream::TLSInStream(InStream* _in, gnutls_session_t _session)
- : session(_session), in(_in), saved_exception(nullptr)
+TLSInStream::TLSInStream(TLSSocket* sock_)
+ : sock(sock_)
{
- gnutls_transport_ptr_t recv, send;
-
- gnutls_transport_set_pull_function(session, pull);
- gnutls_transport_get_ptr2(session, &recv, &send);
- gnutls_transport_set_ptr2(session, this, send);
}
TLSInStream::~TLSInStream()
{
- gnutls_transport_set_pull_function(session, nullptr);
-
- delete saved_exception;
}
bool TLSInStream::fillBuffer()
{
- size_t n = readTLS((uint8_t*) end, availSpace());
+ size_t n = sock->readTLS((uint8_t*) end, availSpace());
if (n == 0)
return false;
end += n;
@@ -98,39 +49,4 @@ bool TLSInStream::fillBuffer()
return true;
}
-size_t TLSInStream::readTLS(uint8_t* buf, size_t len)
-{
- int n;
-
- while (true) {
- streamEmpty = false;
- n = gnutls_record_recv(session, (void *) buf, len);
- if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) {
- // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios
- // other than the pull function returning EAGAIN, so we have to
- // double check that the underlying stream really is empty
- if (!streamEmpty)
- continue;
- else
- return 0;
- }
- break;
- };
-
- if (n == GNUTLS_E_PULL_ERROR) {
- if (dynamic_cast<socket_error*>(saved_exception))
- throw *dynamic_cast<socket_error*>(saved_exception);
- else
- throw std::runtime_error(saved_exception->what());
- }
-
- if (n < 0)
- throw tls_error("readTLS", n);
-
- if (n == 0)
- throw end_of_stream();
-
- return n;
-}
-
#endif
diff --git a/common/rdr/TLSInStream.h b/common/rdr/TLSInStream.h
index 2269b09d..94266e50 100644
--- a/common/rdr/TLSInStream.h
+++ b/common/rdr/TLSInStream.h
@@ -1,5 +1,6 @@
/* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
+ * Copyright 2012-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,28 +23,25 @@
#ifdef HAVE_GNUTLS
-#include <gnutls/gnutls.h>
#include <rdr/BufferedInStream.h>
namespace rdr {
+ class TLSSocket;
+
class TLSInStream : public BufferedInStream {
public:
- TLSInStream(InStream* in, gnutls_session_t session);
+ TLSInStream(TLSSocket* sock);
virtual ~TLSInStream();
private:
bool fillBuffer() override;
- size_t readTLS(uint8_t* buf, size_t len);
- static ssize_t pull(gnutls_transport_ptr_t str, void* data, size_t size);
-
- gnutls_session_t session;
- InStream* in;
- bool streamEmpty;
- std::exception* saved_exception;
+ TLSSocket* sock;
};
-};
+
+}
#endif
+
#endif
diff --git a/common/rdr/TLSOutStream.cxx b/common/rdr/TLSOutStream.cxx
index 365ffd60..ba9d182f 100644
--- a/common/rdr/TLSOutStream.cxx
+++ b/common/rdr/TLSOutStream.cxx
@@ -1,7 +1,7 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
- * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB
+ * Copyright 2012-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,108 +23,42 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
-#include <rdr/TLSException.h>
#include <rdr/TLSOutStream.h>
-#include <rfb/LogWriter.h>
-#include <errno.h>
+#include <rdr/TLSSocket.h>
#ifdef HAVE_GNUTLS
-using namespace rdr;
-
-static rfb::LogWriter vlog("TLSOutStream");
-
-ssize_t TLSOutStream::push(gnutls_transport_ptr_t str, const void* data,
- size_t size)
-{
- TLSOutStream* self= (TLSOutStream*) str;
- OutStream *out = self->out;
-
- delete self->saved_exception;
- self->saved_exception = nullptr;
- try {
- out->writeBytes((const uint8_t*)data, size);
- out->flush();
- } catch (socket_error& e) {
- vlog.error("Failure sending TLS data: %s", e.what());
- gnutls_transport_set_errno(self->session, e.err);
- self->saved_exception = new socket_error(e);
- return -1;
- } catch (std::exception& e) {
- vlog.error("Failure sending TLS data: %s", e.what());
- gnutls_transport_set_errno(self->session, EINVAL);
- self->saved_exception = new std::runtime_error(e.what());
- return -1;
- }
-
- return size;
-}
+using namespace rdr;
-TLSOutStream::TLSOutStream(OutStream* _out, gnutls_session_t _session)
- : session(_session), out(_out), saved_exception(nullptr)
+TLSOutStream::TLSOutStream(TLSSocket* sock_)
+ : sock(sock_)
{
- gnutls_transport_ptr_t recv, send;
-
- gnutls_transport_set_push_function(session, push);
- gnutls_transport_get_ptr2(session, &recv, &send);
- gnutls_transport_set_ptr2(session, recv, this);
}
TLSOutStream::~TLSOutStream()
{
-#if 0
- try {
-// flush();
- } catch (Exception&) {
- }
-#endif
- gnutls_transport_set_push_function(session, nullptr);
-
- delete saved_exception;
}
void TLSOutStream::flush()
{
BufferedOutStream::flush();
- out->flush();
+ sock->out->flush();
}
void TLSOutStream::cork(bool enable)
{
BufferedOutStream::cork(enable);
- out->cork(enable);
+ sock->out->cork(enable);
}
bool TLSOutStream::flushBuffer()
{
while (sentUpTo < ptr) {
- size_t n = writeTLS(sentUpTo, ptr - sentUpTo);
+ size_t n = sock->writeTLS(sentUpTo, ptr - sentUpTo);
sentUpTo += n;
}
return true;
}
-size_t TLSOutStream::writeTLS(const uint8_t* data, size_t length)
-{
- int n;
-
- n = gnutls_record_send(session, data, length);
- if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN)
- return 0;
-
- if (n == GNUTLS_E_PUSH_ERROR) {
- if (dynamic_cast<socket_error*>(saved_exception))
- throw *dynamic_cast<socket_error*>(saved_exception);
- else
- throw std::runtime_error(saved_exception->what());
- }
-
- if (n < 0)
- throw tls_error("writeTLS", n);
-
- return n;
-}
-
#endif
diff --git a/common/rdr/TLSOutStream.h b/common/rdr/TLSOutStream.h
index 659f16f0..aa9572ba 100644
--- a/common/rdr/TLSOutStream.h
+++ b/common/rdr/TLSOutStream.h
@@ -21,14 +21,16 @@
#define __RDR_TLSOUTSTREAM_H__
#ifdef HAVE_GNUTLS
-#include <gnutls/gnutls.h>
+
#include <rdr/BufferedOutStream.h>
namespace rdr {
+ class TLSSocket;
+
class TLSOutStream : public BufferedOutStream {
public:
- TLSOutStream(OutStream* out, gnutls_session_t session);
+ TLSOutStream(TLSSocket* out);
virtual ~TLSOutStream();
void flush() override;
@@ -36,15 +38,12 @@ namespace rdr {
private:
bool flushBuffer() override;
- size_t writeTLS(const uint8_t* data, size_t length);
- static ssize_t push(gnutls_transport_ptr_t str, const void* data, size_t size);
-
- gnutls_session_t session;
- OutStream* out;
- std::exception* saved_exception;
+ TLSSocket* sock;
};
-};
+
+}
#endif
+
#endif
diff --git a/common/rdr/TLSSocket.cxx b/common/rdr/TLSSocket.cxx
new file mode 100644
index 00000000..a29e41c1
--- /dev/null
+++ b/common/rdr/TLSSocket.cxx
@@ -0,0 +1,228 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2005 Martin Koegler
+ * Copyright (C) 2010 TigerVNC Team
+ * Copyright (C) 2012-2025 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rdr/TLSException.h>
+#include <rdr/TLSSocket.h>
+
+#include <errno.h>
+
+#ifdef HAVE_GNUTLS
+
+using namespace rdr;
+
+static core::LogWriter vlog("TLSSocket");
+
+TLSSocket::TLSSocket(InStream* in_, OutStream* out_,
+ gnutls_session_t session_)
+ : session(session_), in(in_), out(out_), tlsin(this), tlsout(this)
+{
+ gnutls_transport_set_pull_function(
+ session, [](gnutls_transport_ptr_t sock, void* data, size_t size) {
+ return ((TLSSocket*)sock)->pull(data, size);
+ });
+ gnutls_transport_set_push_function(
+ session, [](gnutls_transport_ptr_t sock, const void* data, size_t size) {
+ return ((TLSSocket*)sock)->push(data, size);
+ });
+ gnutls_transport_set_ptr(session, this);
+}
+
+TLSSocket::~TLSSocket()
+{
+ gnutls_transport_set_pull_function(session, nullptr);
+ gnutls_transport_set_push_function(session, nullptr);
+ gnutls_transport_set_ptr(session, nullptr);
+}
+
+bool TLSSocket::handshake()
+{
+ int err;
+
+ err = gnutls_handshake(session);
+ if (err != GNUTLS_E_SUCCESS) {
+ gnutls_alert_description_t alert;
+ const char* msg;
+
+ if ((err == GNUTLS_E_PULL_ERROR) || (err == GNUTLS_E_PUSH_ERROR))
+ std::rethrow_exception(saved_exception);
+
+ alert = gnutls_alert_get(session);
+ msg = nullptr;
+
+ if ((err == GNUTLS_E_WARNING_ALERT_RECEIVED) ||
+ (err == GNUTLS_E_FATAL_ALERT_RECEIVED))
+ msg = gnutls_alert_get_name(alert);
+
+ if (msg == nullptr)
+ msg = gnutls_strerror(err);
+
+ if (!gnutls_error_is_fatal(err)) {
+ vlog.debug("Deferring completion of TLS handshake: %s", msg);
+ return false;
+ }
+
+ vlog.error("TLS Handshake failed: %s\n", msg);
+ gnutls_alert_send_appropriate(session, err);
+ throw rdr::tls_error("TLS Handshake failed", err, alert);
+ }
+
+ return true;
+}
+
+void TLSSocket::shutdown()
+{
+ int ret;
+
+ try {
+ if (tlsout.hasBufferedData()) {
+ tlsout.cork(false);
+ tlsout.flush();
+ if (tlsout.hasBufferedData())
+ vlog.error("Failed to flush remaining socket data on close");
+ }
+ } catch (std::exception& e) {
+ vlog.error("Failed to flush remaining socket data on close: %s", e.what());
+ }
+
+ // FIXME: We can't currently wait for the response, so we only send
+ // our close and hope for the best
+ ret = gnutls_bye(session, GNUTLS_SHUT_WR);
+ if ((ret != GNUTLS_E_SUCCESS) && (ret != GNUTLS_E_INVALID_SESSION))
+ vlog.error("TLS shutdown failed: %s", gnutls_strerror(ret));
+}
+
+size_t TLSSocket::readTLS(uint8_t* buf, size_t len)
+{
+ int n;
+
+ while (true) {
+ streamEmpty = false;
+ n = gnutls_record_recv(session, (void *) buf, len);
+ if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) {
+ // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios
+ // other than the pull function returning EAGAIN, so we have to
+ // double check that the underlying stream really is empty
+ if (!streamEmpty)
+ continue;
+ else
+ return 0;
+ }
+ break;
+ };
+
+ if (n == GNUTLS_E_PULL_ERROR)
+ std::rethrow_exception(saved_exception);
+
+ if (n < 0) {
+ gnutls_alert_send_appropriate(session, n);
+ throw tls_error("readTLS", n, gnutls_alert_get(session));
+ }
+
+ if (n == 0)
+ throw end_of_stream();
+
+ return n;
+}
+
+size_t TLSSocket::writeTLS(const uint8_t* data, size_t length)
+{
+ int n;
+
+ n = gnutls_record_send(session, data, length);
+ if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN)
+ return 0;
+
+ if (n == GNUTLS_E_PUSH_ERROR)
+ std::rethrow_exception(saved_exception);
+
+ if (n < 0) {
+ gnutls_alert_send_appropriate(session, n);
+ throw tls_error("writeTLS", n, gnutls_alert_get(session));
+ }
+
+ return n;
+}
+
+ssize_t TLSSocket::pull(void* data, size_t size)
+{
+ streamEmpty = false;
+ saved_exception = nullptr;
+
+ try {
+ if (!in->hasData(1)) {
+ streamEmpty = true;
+ gnutls_transport_set_errno(session, EAGAIN);
+ return -1;
+ }
+
+ if (in->avail() < size)
+ size = in->avail();
+
+ in->readBytes((uint8_t*)data, size);
+ } catch (end_of_stream&) {
+ return 0;
+ } catch (std::exception& e) {
+ core::socket_error* se;
+ vlog.error("Failure reading TLS data: %s", e.what());
+ se = dynamic_cast<core::socket_error*>(&e);
+ if (se)
+ gnutls_transport_set_errno(session, se->err);
+ else
+ gnutls_transport_set_errno(session, EINVAL);
+ saved_exception = std::current_exception();
+ return -1;
+ }
+
+ return size;
+}
+
+ssize_t TLSSocket::push(const void* data, size_t size)
+{
+ saved_exception = nullptr;
+
+ try {
+ out->writeBytes((const uint8_t*)data, size);
+ out->flush();
+ } catch (std::exception& e) {
+ core::socket_error* se;
+ vlog.error("Failure sending TLS data: %s", e.what());
+ se = dynamic_cast<core::socket_error*>(&e);
+ if (se)
+ gnutls_transport_set_errno(session, se->err);
+ else
+ gnutls_transport_set_errno(session, EINVAL);
+ saved_exception = std::current_exception();
+ return -1;
+ }
+
+ return size;
+}
+
+#endif
diff --git a/common/rdr/TLSSocket.h b/common/rdr/TLSSocket.h
new file mode 100644
index 00000000..ca29f8bc
--- /dev/null
+++ b/common/rdr/TLSSocket.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 2005 Martin Koegler
+ * Copyright (C) 2010 TigerVNC Team
+ * Copyright 2012-2025 Pierre Ossman for Cendio AB
+ *
+ * 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 __RDR_TLSSOCKET_H__
+#define __RDR_TLSSOCKET_H__
+
+#ifdef HAVE_GNUTLS
+
+#include <exception>
+
+#include <gnutls/gnutls.h>
+
+#include <rdr/TLSInStream.h>
+#include <rdr/TLSOutStream.h>
+
+namespace rdr {
+
+ class InStream;
+ class OutStream;
+
+ class TLSInStream;
+ class TLSOutStream;
+
+ class TLSSocket {
+ public:
+ TLSSocket(InStream* in, OutStream* out, gnutls_session_t session);
+ virtual ~TLSSocket();
+
+ TLSInStream& inStream() { return tlsin; }
+ TLSOutStream& outStream() { return tlsout; }
+
+ bool handshake();
+ void shutdown();
+
+ protected:
+ /* Used by the stream classes */
+ size_t readTLS(uint8_t* buf, size_t len);
+ size_t writeTLS(const uint8_t* data, size_t length);
+
+ friend TLSInStream;
+ friend TLSOutStream;
+
+ private:
+ ssize_t pull(void* data, size_t size);
+ ssize_t push(const void* data, size_t size);
+
+ gnutls_session_t session;
+
+ InStream* in;
+ OutStream* out;
+
+ TLSInStream tlsin;
+ TLSOutStream tlsout;
+
+ bool streamEmpty;
+
+ std::exception_ptr saved_exception;
+ };
+
+}
+
+#endif
+
+#endif
diff --git a/common/rdr/ZlibOutStream.cxx b/common/rdr/ZlibOutStream.cxx
index 73b5d459..1b8ac307 100644
--- a/common/rdr/ZlibOutStream.cxx
+++ b/common/rdr/ZlibOutStream.cxx
@@ -23,14 +23,15 @@
#include <stdio.h>
+#include <core/LogWriter.h>
+
#include <rdr/ZlibOutStream.h>
-#include <rfb/LogWriter.h>
#include <zlib.h>
#undef ZLIBOUT_DEBUG
-static rfb::LogWriter vlog("ZlibOutStream");
+static core::LogWriter vlog("ZlibOutStream");
using namespace rdr;
diff --git a/common/rfb/Blacklist.cxx b/common/rfb/Blacklist.cxx
index 68420ae2..19a9ed39 100644
--- a/common/rfb/Blacklist.cxx
+++ b/common/rfb/Blacklist.cxx
@@ -21,24 +21,26 @@
#endif
#include <rfb/Blacklist.h>
-#include <rfb/Configuration.h>
+#include <core/Configuration.h>
using namespace rfb;
-BoolParameter enabled("UseBlacklist",
- "Temporarily reject connections from a host if it "
- "repeatedly fails to authenticate.",
- true);
-IntParameter threshold("BlacklistThreshold",
- "The number of unauthenticated connection attempts "
- "allowed from any individual host before that host "
- "is black-listed",
- 5);
-IntParameter initialTimeout("BlacklistTimeout",
- "The initial timeout applied when a host is "
- "first black-listed. The host cannot re-attempt "
- "a connection until the timeout expires.",
- 10);
+core::BoolParameter enabled("UseBlacklist",
+ "Temporarily reject connections from a "
+ "host if it repeatedly fails to "
+ "authenticate.",
+ true);
+core::IntParameter threshold("BlacklistThreshold",
+ "The number of unauthenticated connection "
+ "attempts allowed from any individual "
+ "host before that host is black-listed",
+ 5, 0, INT_MAX);
+core::IntParameter initialTimeout("BlacklistTimeout",
+ "The initial timeout applied when a "
+ "host is first black-listed. The "
+ "host cannot re-attempt a connection "
+ "until the timeout expires.",
+ 10, 0, INT_MAX);
Blacklist::Blacklist() {
diff --git a/common/rfb/Blacklist.h b/common/rfb/Blacklist.h
index c1699f29..3c9660cc 100644
--- a/common/rfb/Blacklist.h
+++ b/common/rfb/Blacklist.h
@@ -27,13 +27,11 @@
#ifndef __RFB_BLACKLIST_H__
#define __RFB_BLACKLIST_H__
-#include <string.h>
#include <time.h>
+
#include <map>
#include <string>
-#include <rfb/Configuration.h>
-
namespace rfb {
//
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx
index 5e7530c8..bbeef385 100644
--- a/common/rfb/CConnection.cxx
+++ b/common/rfb/CConnection.cxx
@@ -27,31 +27,34 @@
#include <algorithm>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb/Exception.h>
#include <rfb/clipboardTypes.h>
#include <rfb/fenceTypes.h>
+#include <rfb/screenTypes.h>
#include <rfb/CMsgReader.h>
#include <rfb/CMsgWriter.h>
#include <rfb/CSecurity.h>
+#include <rfb/Cursor.h>
#include <rfb/Decoder.h>
#include <rfb/KeysymStr.h>
+#include <rfb/PixelBuffer.h>
#include <rfb/Security.h>
#include <rfb/SecurityClient.h>
#include <rfb/CConnection.h>
-#include <rfb/util.h>
#define XK_MISCELLANY
#define XK_XKB_KEYS
#include <rfb/keysymdef.h>
-#include <rfb/LogWriter.h>
-
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
using namespace rfb;
-static LogWriter vlog("CConnection");
+static core::LogWriter vlog("CConnection");
CConnection::CConnection()
: csecurity(nullptr),
@@ -98,7 +101,7 @@ void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
}
if ((framebuffer != nullptr) && (fb != nullptr)) {
- Rect rect;
+ core::Rect rect;
const uint8_t* data;
int stride;
@@ -107,9 +110,8 @@ void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
// Copy still valid area
- rect.setXYWH(0, 0,
- __rfbmin(fb->width(), framebuffer->width()),
- __rfbmin(fb->height(), framebuffer->height()));
+ rect = fb->getRect();
+ rect = rect.intersect(framebuffer->getRect());
data = framebuffer->getBuffer(framebuffer->getRect(), &stride);
fb->imageRect(rect, data, stride);
@@ -189,10 +191,9 @@ bool CConnection::processVersionMsg()
vlog.error("Server gave unsupported RFB protocol version %d.%d",
server.majorVersion, server.minorVersion);
state_ = RFBSTATE_INVALID;
- throw protocol_error(format("Server gave unsupported RFB protocol "
- "version %d.%d",
- server.majorVersion,
- server.minorVersion));
+ throw protocol_error(
+ core::format("Server gave unsupported RFB protocol version %d.%d",
+ server.majorVersion, server.minorVersion));
} else if (server.beforeVersion(3,7)) {
server.setVersion(3,3);
} else if (server.afterVersion(3,8)) {
@@ -379,7 +380,6 @@ void CConnection::securityCompleted()
reader_ = new CMsgReader(this, is);
writer_ = new CMsgWriter(&server, os);
vlog.debug("Authentication success!");
- authSuccess();
writer_->writeClientInit(shared);
}
@@ -410,7 +410,7 @@ void CConnection::setDesktopSize(int w, int h)
{
decoder.flush();
- CMsgHandler::setDesktopSize(w,h);
+ server.setDimensions(w, h);
if (continuousUpdates)
writer()->writeEnableContinuousUpdates(true, 0, 0,
@@ -430,7 +430,15 @@ void CConnection::setExtendedDesktopSize(unsigned reason,
{
decoder.flush();
- CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
+ server.supportsSetDesktopSize = true;
+
+ if ((reason != reasonClient) || (result == resultSuccess))
+ server.setDimensions(w, h, layout);
+
+ if ((reason == reasonClient) && (result != resultSuccess)) {
+ vlog.error("SetDesktopSize failed: %d", result);
+ return;
+ }
if (continuousUpdates)
writer()->writeEnableContinuousUpdates(true, 0, 0,
@@ -443,9 +451,41 @@ void CConnection::setExtendedDesktopSize(unsigned reason,
assert(framebuffer->height() == server.height());
}
+void CConnection::setCursor(int width, int height,
+ const core::Point& hotspot,
+ const uint8_t* data)
+{
+ Cursor cursor(width, height, hotspot, data);
+ server.setCursor(cursor);
+}
+
+void CConnection::setCursorPos(const core::Point& /*pos*/)
+{
+}
+
+void CConnection::setName(const char* name)
+{
+ server.setName(name);
+}
+
+void CConnection::fence(uint32_t flags, unsigned len, const uint8_t data[])
+{
+ server.supportsFence = true;
+
+ if (flags & fenceFlagRequest) {
+ // FIXME: We handle everything synchronously, and we assume anything
+ // using us also does so, which means we automatically handle
+ // these flags
+ flags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter);
+
+ writer()->writeFence(flags, len, data);
+ return;
+ }
+}
+
void CConnection::endOfContinuousUpdates()
{
- CMsgHandler::endOfContinuousUpdates();
+ server.supportsContinuousUpdates = true;
// We've gotten the marker for a format change, so make the pending
// one active
@@ -459,11 +499,23 @@ void CConnection::endOfContinuousUpdates()
}
}
+void CConnection::supportsQEMUKeyEvent()
+{
+ server.supportsQEMUKeyEvent = true;
+}
+
+void CConnection::supportsExtendedMouseButtons()
+{
+ server.supportsExtendedMouseButtons = true;
+}
+
void CConnection::serverInit(int width, int height,
const PixelFormat& pf,
const char* name)
{
- CMsgHandler::serverInit(width, height, pf, name);
+ server.setDimensions(width, height);
+ server.setPF(pf);
+ server.setName(name);
state_ = RFBSTATE_NORMAL;
vlog.debug("Initialisation done");
@@ -486,7 +538,7 @@ void CConnection::serverInit(int width, int height,
}
}
-bool CConnection::readAndDecodeRect(const Rect& r, int encoding,
+bool CConnection::readAndDecodeRect(const core::Rect& r, int encoding,
ModifiablePixelBuffer* pb)
{
if (!decoder.decodeRect(r, encoding, pb))
@@ -497,8 +549,6 @@ bool CConnection::readAndDecodeRect(const Rect& r, int encoding,
void CConnection::framebufferUpdateStart()
{
- CMsgHandler::framebufferUpdateStart();
-
assert(framebuffer != nullptr);
// Note: This might not be true if continuous updates are supported
@@ -511,8 +561,6 @@ void CConnection::framebufferUpdateEnd()
{
decoder.flush();
- CMsgHandler::framebufferUpdateEnd();
-
// A format change has been scheduled and we are now past the update
// with the old format. Time to active the new one.
if (pendingPFChange && !continuousUpdates) {
@@ -533,11 +581,18 @@ void CConnection::framebufferUpdateEnd()
}
}
-bool CConnection::dataRect(const Rect& r, int encoding)
+bool CConnection::dataRect(const core::Rect& r, int encoding)
{
return decoder.decodeRect(r, encoding, framebuffer);
}
+void CConnection::setColourMapEntries(int /*firstColour*/,
+ int /*nColours*/,
+ uint16_t* /*rgbs*/)
+{
+ vlog.error("Invalid SetColourMapEntries from server!");
+}
+
void CConnection::serverCutText(const char* str)
{
hasLocalClipboard = false;
@@ -548,12 +603,53 @@ void CConnection::serverCutText(const char* str)
handleClipboardAnnounce(true);
}
+void CConnection::setLEDState(unsigned int state)
+{
+ server.setLEDState(state);
+}
+
void CConnection::handleClipboardCaps(uint32_t flags,
const uint32_t* lengths)
{
+ int i;
uint32_t sizes[] = { 0 };
- CMsgHandler::handleClipboardCaps(flags, lengths);
+ vlog.debug("Got server clipboard capabilities:");
+ for (i = 0;i < 16;i++) {
+ if (flags & (1 << i)) {
+ const char *type;
+
+ switch (1 << i) {
+ case clipboardUTF8:
+ type = "Plain text";
+ break;
+ case clipboardRTF:
+ type = "Rich text";
+ break;
+ case clipboardHTML:
+ type = "HTML";
+ break;
+ case clipboardDIB:
+ type = "Images";
+ break;
+ case clipboardFiles:
+ type = "Files";
+ break;
+ default:
+ vlog.debug(" Unknown format 0x%x", 1 << i);
+ continue;
+ }
+
+ if (lengths[i] == 0)
+ vlog.debug(" %s (only notify)", type);
+ else {
+ vlog.debug(" %s (automatically send up to %s)",
+ type, core::iecPrefix(lengths[i], "B").c_str());
+ }
+ }
+ }
+
+ server.setClipboardCaps(flags, lengths);
writer()->writeClipboardCaps(rfb::clipboardUTF8 |
rfb::clipboardRequest |
@@ -604,21 +700,17 @@ void CConnection::handleClipboardProvide(uint32_t flags,
}
// FIXME: This conversion magic should be in CMsgReader
- if (!isValidUTF8((const char*)data[0], lengths[0])) {
+ if (!core::isValidUTF8((const char*)data[0], lengths[0])) {
vlog.error("Invalid UTF-8 sequence in clipboard - ignoring");
return;
}
- serverClipboard = convertLF((const char*)data[0], lengths[0]);
+ serverClipboard = core::convertLF((const char*)data[0], lengths[0]);
hasRemoteClipboard = true;
// FIXME: Should probably verify that this data was actually requested
handleClipboardData(serverClipboard.c_str());
}
-void CConnection::authSuccess()
-{
-}
-
void CConnection::initDone()
{
}
@@ -679,7 +771,7 @@ void CConnection::sendClipboardData(const char* data)
{
if (server.clipboardFlags() & rfb::clipboardProvide) {
// FIXME: This conversion magic should be in CMsgWriter
- std::string filtered(convertCRLF(data));
+ std::string filtered(core::convertCRLF(data));
size_t sizes[1] = { filtered.size() + 1 };
const uint8_t* datas[1] = { (const uint8_t*)filtered.c_str() };
@@ -815,6 +907,11 @@ void CConnection::setCompressLevel(int level)
encodingChange = true;
}
+int CConnection::getCompressLevel()
+{
+ return compressLevel;
+}
+
void CConnection::setQualityLevel(int level)
{
if (qualityLevel == level)
@@ -824,6 +921,11 @@ void CConnection::setQualityLevel(int level)
encodingChange = true;
}
+int CConnection::getQualityLevel()
+{
+ return qualityLevel;
+}
+
void CConnection::setPF(const PixelFormat& pf)
{
if (server.pf() == pf && !formatChange)
@@ -833,17 +935,9 @@ void CConnection::setPF(const PixelFormat& pf)
formatChange = true;
}
-void CConnection::fence(uint32_t flags, unsigned len, const uint8_t data[])
+bool CConnection::isSecure() const
{
- CMsgHandler::fence(flags, len, data);
-
- if (!(flags & fenceFlagRequest))
- return;
-
- // We cannot guarantee any synchronisation at this level
- flags = 0;
-
- writer()->writeFence(flags, len, data);
+ return csecurity ? csecurity->isSecure() : false;
}
// requestNewUpdate() requests an update from the server, having set the
@@ -884,9 +978,9 @@ void CConnection::requestNewUpdate()
if (forceNonincremental || !continuousUpdates) {
pendingUpdate = true;
- writer()->writeFramebufferUpdateRequest(Rect(0, 0,
- server.width(),
- server.height()),
+ writer()->writeFramebufferUpdateRequest({0, 0,
+ server.width(),
+ server.height()},
!forceNonincremental);
}
diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h
index 07e47e39..b28c5aa9 100644
--- a/common/rfb/CConnection.h
+++ b/common/rfb/CConnection.h
@@ -29,8 +29,14 @@
#include <rfb/CMsgHandler.h>
#include <rfb/DecodeManager.h>
+#include <rfb/PixelFormat.h>
#include <rfb/SecurityClient.h>
+namespace rdr {
+ class InStream;
+ class OutStream;
+}
+
namespace rfb {
class CMsgReader;
@@ -99,89 +105,6 @@ namespace rfb {
// connection
void close();
-
- // Methods overridden from CMsgHandler
-
- // Note: These must be called by any deriving classes
-
- void setDesktopSize(int w, int h) override;
- void setExtendedDesktopSize(unsigned reason, unsigned result,
- int w, int h,
- const ScreenSet& layout) override;
-
- void endOfContinuousUpdates() override;
-
- void serverInit(int width, int height, const PixelFormat& pf,
- const char* name) override;
-
- bool readAndDecodeRect(const Rect& r, int encoding,
- ModifiablePixelBuffer* pb) override;
-
- void framebufferUpdateStart() override;
- void framebufferUpdateEnd() override;
- bool dataRect(const Rect& r, int encoding) override;
-
- void serverCutText(const char* str) override;
-
- void handleClipboardCaps(uint32_t flags,
- const uint32_t* lengths) override;
- void handleClipboardRequest(uint32_t flags) override;
- void handleClipboardPeek() override;
- void handleClipboardNotify(uint32_t flags) override;
- void handleClipboardProvide(uint32_t flags, const size_t* lengths,
- const uint8_t* const* data) override;
-
-
- // Methods to be overridden in a derived class
-
- // getUserPasswd() gets the username and password. This might
- // involve a dialog, getpass(), etc. The user buffer pointer can be
- // null, in which case no user name will be retrieved.
- virtual void getUserPasswd(bool secure, std::string* user,
- std::string* password) = 0;
-
- // showMsgBox() displays a message box with the specified style and
- // contents. The return value is true if the user clicked OK/Yes.
- virtual bool showMsgBox(MsgBoxFlags flags, const char *title,
- const char *text) = 0;
-
- // authSuccess() is called when authentication has succeeded.
- virtual void authSuccess();
-
- // initDone() is called when the connection is fully established
- // and standard messages can be sent. This is called before the
- // initial FramebufferUpdateRequest giving a derived class the
- // chance to modify pixel format and settings. The derived class
- // must also make sure it has provided a valid framebuffer before
- // returning.
- virtual void initDone() = 0;
-
- // resizeFramebuffer() is called whenever the framebuffer
- // dimensions or the screen layout changes. A subclass must make
- // sure the pixel buffer has been updated once this call returns.
- virtual void resizeFramebuffer();
-
- // handleClipboardRequest() is called whenever the server requests
- // the client to send over its clipboard data. It will only be
- // called after the client has first announced a clipboard change
- // via announceClipboard().
- virtual void handleClipboardRequest();
-
- // handleClipboardAnnounce() is called to indicate a change in the
- // clipboard on the server. Call requestClipboard() to access the
- // actual data.
- virtual void handleClipboardAnnounce(bool available);
-
- // handleClipboardData() is called when the server has sent over
- // the clipboard data as a result of a previous call to
- // requestClipboard(). Note that this function might never be
- // called if the clipboard data was no longer available when the
- // server received the request.
- virtual void handleClipboardData(const char* data);
-
-
- // Other methods
-
// requestClipboard() will result in a request to the server to
// transfer its clipboard data. A call to handleClipboardData()
// will be made once the data is available.
@@ -221,7 +144,9 @@ namespace rfb {
// setCompressLevel()/setQualityLevel() controls the encoding hints
// sent to the server
void setCompressLevel(int level);
+ int getCompressLevel();
void setQualityLevel(int level);
+ int getQualityLevel();
// setPF() controls the pixel format requested from the server.
// server.pf() will automatically be adjusted once the new format
// is active.
@@ -237,7 +162,7 @@ namespace rfb {
// Identities, to determine the unique(ish) name of the server.
const char* getServerName() const { return serverName.c_str(); }
- bool isSecure() const { return csecurity ? csecurity->isSecure() : false; }
+ bool isSecure() const;
enum stateEnum {
RFBSTATE_UNINITIALISED,
@@ -254,8 +179,107 @@ namespace rfb {
stateEnum state() { return state_; }
+ // Methods used by SSecurity classes
+
+ // getUserPasswd() gets the username and password. This might
+ // involve a dialog, getpass(), etc. The user buffer pointer can be
+ // null, in which case no user name will be retrieved.
+ virtual void getUserPasswd(bool secure, std::string* user,
+ std::string* password) = 0;
+
+ // showMsgBox() displays a message box with the specified style and
+ // contents. The return value is true if the user clicked OK/Yes.
+ virtual bool showMsgBox(MsgBoxFlags flags, const char *title,
+ const char *text) = 0;
+
+ protected:
+
+ // Methods overridden from CMsgHandler
+
+ // Note: These must be called by any deriving classes
+
+ void setDesktopSize(int w, int h) override;
+ void setExtendedDesktopSize(unsigned reason, unsigned result,
+ int w, int h,
+ const ScreenSet& layout) override;
+
+ void setCursor(int width, int height, const core::Point& hotspot,
+ const uint8_t* data) override;
+ void setCursorPos(const core::Point& pos) override;
+
+ void setName(const char* name) override;
+
+ void fence(uint32_t flags, unsigned len, const uint8_t data[]) override;
+
+ void endOfContinuousUpdates() override;
+
+ void supportsQEMUKeyEvent() override;
+
+ void supportsExtendedMouseButtons() override;
+
+ void serverInit(int width, int height, const PixelFormat& pf,
+ const char* name) override;
+
+ bool readAndDecodeRect(const core::Rect& r, int encoding,
+ ModifiablePixelBuffer* pb) override;
+
+ void framebufferUpdateStart() override;
+ void framebufferUpdateEnd() override;
+ bool dataRect(const core::Rect& r, int encoding) override;
+
+ void setColourMapEntries(int firstColour, int nColours,
+ uint16_t* rgbs) override;
+
+ void serverCutText(const char* str) override;
+
+ void setLEDState(unsigned int state) override;
+
+ void handleClipboardCaps(uint32_t flags,
+ const uint32_t* lengths) override;
+ void handleClipboardRequest(uint32_t flags) override;
+ void handleClipboardPeek() override;
+ void handleClipboardNotify(uint32_t flags) override;
+ void handleClipboardProvide(uint32_t flags, const size_t* lengths,
+ const uint8_t* const* data) override;
+
+
+ // Methods to be overridden in a derived class
+
+ // initDone() is called when the connection is fully established
+ // and standard messages can be sent. This is called before the
+ // initial FramebufferUpdateRequest giving a derived class the
+ // chance to modify pixel format and settings. The derived class
+ // must also make sure it has provided a valid framebuffer before
+ // returning.
+ virtual void initDone() = 0;
+
+ // resizeFramebuffer() is called whenever the framebuffer
+ // dimensions or the screen layout changes. A subclass must make
+ // sure the pixel buffer has been updated once this call returns.
+ virtual void resizeFramebuffer();
+
+ // handleClipboardRequest() is called whenever the server requests
+ // the client to send over its clipboard data. It will only be
+ // called after the client has first announced a clipboard change
+ // via announceClipboard().
+ virtual void handleClipboardRequest();
+
+ // handleClipboardAnnounce() is called to indicate a change in the
+ // clipboard on the server. Call requestClipboard() to access the
+ // actual data.
+ virtual void handleClipboardAnnounce(bool available);
+
+ // handleClipboardData() is called when the server has sent over
+ // the clipboard data as a result of a previous call to
+ // requestClipboard(). Note that this function might never be
+ // called if the clipboard data was no longer available when the
+ // server received the request.
+ virtual void handleClipboardData(const char* data);
+
+ protected:
CSecurity *csecurity;
SecurityClient security;
+
protected:
void setState(stateEnum s) { state_ = s; }
@@ -273,13 +297,6 @@ namespace rfb {
bool supportsLEDState;
private:
- // This is a default implementation of fences that automatically
- // responds to requests, stating no support for synchronisation.
- // When overriding, call CMsgHandler::fence() directly in order to
- // state correct support for fence flags.
- void fence(uint32_t flags, unsigned len, const uint8_t data[]) override;
-
- private:
bool processVersionMsg();
bool processSecurityTypesMsg();
bool processSecurityMsg();
diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt
index 36535448..d7467421 100644
--- a/common/rfb/CMakeLists.txt
+++ b/common/rfb/CMakeLists.txt
@@ -3,7 +3,6 @@ add_library(rfb STATIC
Blacklist.cxx
Congestion.cxx
CConnection.cxx
- CMsgHandler.cxx
CMsgReader.cxx
CMsgWriter.cxx
CSecurityPlain.cxx
@@ -12,7 +11,6 @@ add_library(rfb STATIC
CSecurityVncAuth.cxx
ClientParams.cxx
ComparingUpdateTracker.cxx
- Configuration.cxx
CopyRectDecoder.cxx
Cursor.cxx
DecodeManager.cxx
@@ -26,19 +24,13 @@ add_library(rfb STATIC
JpegDecompressor.cxx
KeyRemapper.cxx
KeysymStr.c
- LogWriter.cxx
- Logger.cxx
- Logger_file.cxx
- Logger_stdio.cxx
PixelBuffer.cxx
PixelFormat.cxx
RREEncoder.cxx
RREDecoder.cxx
RawDecoder.cxx
RawEncoder.cxx
- Region.cxx
SConnection.cxx
- SMsgHandler.cxx
SMsgReader.cxx
SMsgWriter.cxx
ServerCore.cxx
@@ -50,7 +42,6 @@ add_library(rfb STATIC
SSecurityStack.cxx
SSecurityVncAuth.cxx
SSecurityVeNCrypt.cxx
- Timer.cxx
TightDecoder.cxx
TightEncoder.cxx
TightJPEGEncoder.cxx
@@ -60,15 +51,12 @@ add_library(rfb STATIC
ZRLEEncoder.cxx
ZRLEDecoder.cxx
encodings.cxx
- obfuscate.cxx
- util.cxx)
+ obfuscate.cxx)
target_include_directories(rfb PUBLIC ${CMAKE_SOURCE_DIR}/common)
target_include_directories(rfb SYSTEM PUBLIC ${JPEG_INCLUDE_DIR})
-target_include_directories(rfb SYSTEM PUBLIC ${PIXMAN_INCLUDE_DIRS})
-target_link_libraries(rfb os rdr network)
+target_link_libraries(rfb core rdr network)
target_link_libraries(rfb ${JPEG_LIBRARIES} ${PIXMAN_LIBRARIES})
-target_link_directories(rfb PUBLIC ${PIXMAN_LIBRARY_DIRS})
if(ENABLE_H264 AND NOT H264_LIBS STREQUAL "NONE")
target_sources(rfb PRIVATE H264Decoder.cxx H264DecoderContext.cxx)
@@ -79,11 +67,6 @@ if(ENABLE_H264 AND NOT H264_LIBS STREQUAL "NONE")
endif()
target_include_directories(rfb SYSTEM PUBLIC ${H264_INCLUDE_DIRS})
target_link_libraries(rfb ${H264_LIBRARIES})
- target_link_directories(rfb PUBLIC ${H264_LIBRARY_DIRS})
-endif()
-
-if(UNIX)
- target_sources(rfb PRIVATE Logger_syslog.cxx)
endif()
if(WIN32)
@@ -92,8 +75,9 @@ if(WIN32)
endif(WIN32)
if(UNIX AND NOT APPLE)
- target_sources(rfb PRIVATE UnixPasswordValidator.cxx pam.c)
- target_link_libraries(rfb ${PAM_LIBS})
+ target_sources(rfb PRIVATE UnixPasswordValidator.cxx)
+ target_include_directories(rfb SYSTEM PRIVATE ${PAM_INCLUDE_DIRS})
+ target_link_libraries(rfb ${PAM_LIBRARIES})
endif()
if(GNUTLS_FOUND)
@@ -109,12 +93,8 @@ endif()
if (NETTLE_FOUND)
target_sources(rfb PRIVATE CSecurityDH.cxx CSecurityMSLogonII.cxx
CSecurityRSAAES.cxx SSecurityRSAAES.cxx)
- target_include_directories(rfb SYSTEM PUBLIC ${NETTLE_INCLUDE_DIRS}
- ${GMP_INCLUDE_DIRS})
- target_link_libraries(rfb ${HOGWEED_LIBRARIES}
- ${NETTLE_LIBRARIES} ${GMP_LIBRARIES})
- target_link_directories(rfb PUBLIC ${HOGWEED_LIBRARY_DIRS}
- ${NETTLE_LIBRARY_DIRS} ${GMP_LIBRARY_DIRS})
+ target_include_directories(rfb SYSTEM PUBLIC ${NETTLE_INCLUDE_DIRS})
+ target_link_libraries(rfb ${HOGWEED_LIBRARIES} ${NETTLE_LIBRARIES})
endif()
if(UNIX)
diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx
deleted file mode 100644
index 0f3f6cd5..00000000
--- a/common/rfb/CMsgHandler.cxx
+++ /dev/null
@@ -1,168 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2019 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-
-#include <rfb/Exception.h>
-#include <rfb/LogWriter.h>
-#include <rfb/CMsgHandler.h>
-#include <rfb/clipboardTypes.h>
-#include <rfb/screenTypes.h>
-#include <rfb/util.h>
-
-static rfb::LogWriter vlog("CMsgHandler");
-
-using namespace rfb;
-
-CMsgHandler::CMsgHandler()
-{
-}
-
-CMsgHandler::~CMsgHandler()
-{
-}
-
-void CMsgHandler::setDesktopSize(int width, int height)
-{
- server.setDimensions(width, height);
-}
-
-void CMsgHandler::setExtendedDesktopSize(unsigned reason, unsigned result,
- int width, int height,
- const ScreenSet& layout)
-{
- server.supportsSetDesktopSize = true;
-
- if ((reason == reasonClient) && (result != resultSuccess))
- return;
-
- server.setDimensions(width, height, layout);
-}
-
-void CMsgHandler::setName(const char* name)
-{
- server.setName(name);
-}
-
-void CMsgHandler::fence(uint32_t /*flags*/, unsigned /*len*/,
- const uint8_t /*data*/ [])
-{
- server.supportsFence = true;
-}
-
-void CMsgHandler::endOfContinuousUpdates()
-{
- server.supportsContinuousUpdates = true;
-}
-
-void CMsgHandler::supportsExtendedMouseButtons()
-{
- server.supportsExtendedMouseButtons = true;
-}
-
-void CMsgHandler::supportsQEMUKeyEvent()
-{
- server.supportsQEMUKeyEvent = true;
-}
-
-void CMsgHandler::serverInit(int width, int height,
- const PixelFormat& pf,
- const char* name)
-{
- server.setDimensions(width, height);
- server.setPF(pf);
- server.setName(name);
-}
-
-void CMsgHandler::framebufferUpdateStart()
-{
-}
-
-void CMsgHandler::framebufferUpdateEnd()
-{
-}
-
-void CMsgHandler::setLEDState(unsigned int state)
-{
- server.setLEDState(state);
-}
-
-void CMsgHandler::handleClipboardCaps(uint32_t flags, const uint32_t* lengths)
-{
- int i;
-
- vlog.debug("Got server clipboard capabilities:");
- for (i = 0;i < 16;i++) {
- if (flags & (1 << i)) {
- const char *type;
-
- switch (1 << i) {
- case clipboardUTF8:
- type = "Plain text";
- break;
- case clipboardRTF:
- type = "Rich text";
- break;
- case clipboardHTML:
- type = "HTML";
- break;
- case clipboardDIB:
- type = "Images";
- break;
- case clipboardFiles:
- type = "Files";
- break;
- default:
- vlog.debug(" Unknown format 0x%x", 1 << i);
- continue;
- }
-
- if (lengths[i] == 0)
- vlog.debug(" %s (only notify)", type);
- else {
- vlog.debug(" %s (automatically send up to %s)",
- type, iecPrefix(lengths[i], "B").c_str());
- }
- }
- }
-
- server.setClipboardCaps(flags, lengths);
-}
-
-void CMsgHandler::handleClipboardRequest(uint32_t /*flags*/)
-{
-}
-
-void CMsgHandler::handleClipboardPeek()
-{
-}
-
-void CMsgHandler::handleClipboardNotify(uint32_t /*flags*/)
-{
-}
-
-void CMsgHandler::handleClipboardProvide(uint32_t /*flags*/,
- const size_t* /*lengths*/,
- const uint8_t* const* /*data*/)
-{
-}
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
index b484b695..d267ae47 100644
--- a/common/rfb/CMsgHandler.h
+++ b/common/rfb/CMsgHandler.h
@@ -27,63 +27,62 @@
#include <stdint.h>
#include <rfb/ServerParams.h>
-#include <rfb/Rect.h>
-#include <rfb/ScreenSet.h>
-namespace rdr { class InStream; }
+namespace core {
+ struct Point;
+ struct Rect;
+}
namespace rfb {
+ class ModifiablePixelBuffer;
+ struct ScreenSet;
+
class CMsgHandler {
public:
- CMsgHandler();
- virtual ~CMsgHandler();
-
// The following methods are called as corresponding messages are
- // read. A derived class should override these methods as desired.
- // Note that for the setDesktopSize(), setExtendedDesktopSize(),
- // setName(), serverInit() and handleClipboardCaps() methods, a
- // derived class should call on to CMsgHandler's methods to set the
- // members of "server" appropriately.
+ // read. A derived class must override these methods.
- virtual void setDesktopSize(int w, int h);
+ virtual void setDesktopSize(int w, int h) = 0;
virtual void setExtendedDesktopSize(unsigned reason, unsigned result,
int w, int h,
- const ScreenSet& layout);
- virtual void setCursor(int width, int height, const Point& hotspot,
+ const ScreenSet& layout) = 0;
+ virtual void setCursor(int width, int height, const
+ core::Point& hotspot,
const uint8_t* data) = 0;
- virtual void setCursorPos(const Point& pos) = 0;
- virtual void setName(const char* name);
- virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]);
- virtual void endOfContinuousUpdates();
- virtual void supportsQEMUKeyEvent();
- virtual void supportsExtendedMouseButtons();
+ virtual void setCursorPos(const core::Point& pos) = 0;
+ virtual void setName(const char* name) = 0;
+ virtual void fence(uint32_t flags, unsigned len,
+ const uint8_t data[]) = 0;
+ virtual void endOfContinuousUpdates() = 0;
+ virtual void supportsQEMUKeyEvent() = 0;
+ virtual void supportsExtendedMouseButtons() = 0;
virtual void serverInit(int width, int height,
const PixelFormat& pf,
const char* name) = 0;
- virtual bool readAndDecodeRect(const Rect& r, int encoding,
+ virtual bool readAndDecodeRect(const core::Rect& r, int encoding,
ModifiablePixelBuffer* pb) = 0;
- virtual void framebufferUpdateStart();
- virtual void framebufferUpdateEnd();
- virtual bool dataRect(const Rect& r, int encoding) = 0;
+ virtual void framebufferUpdateStart() = 0;
+ virtual void framebufferUpdateEnd() = 0;
+ virtual bool dataRect(const core::Rect& r, int encoding) = 0;
virtual void setColourMapEntries(int firstColour, int nColours,
uint16_t* rgbs) = 0;
virtual void bell() = 0;
virtual void serverCutText(const char* str) = 0;
- virtual void setLEDState(unsigned int state);
+ virtual void setLEDState(unsigned int state) = 0;
virtual void handleClipboardCaps(uint32_t flags,
- const uint32_t* lengths);
- virtual void handleClipboardRequest(uint32_t flags);
- virtual void handleClipboardPeek();
- virtual void handleClipboardNotify(uint32_t flags);
+ const uint32_t* lengths) = 0;
+ virtual void handleClipboardRequest(uint32_t flags) = 0;
+ virtual void handleClipboardPeek() = 0;
+ virtual void handleClipboardNotify(uint32_t flags) = 0;
virtual void handleClipboardProvide(uint32_t flags,
const size_t* lengths,
- const uint8_t* const* data);
+ const uint8_t* const* data) = 0;
ServerParams server;
};
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
index a10f7c47..a5e28ea5 100644
--- a/common/rfb/CMsgReader.cxx
+++ b/common/rfb/CMsgReader.cxx
@@ -26,20 +26,27 @@
#include <vector>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rdr/InStream.h>
#include <rdr/ZlibInStream.h>
#include <rfb/msgTypes.h>
#include <rfb/clipboardTypes.h>
-#include <rfb/util.h>
#include <rfb/Exception.h>
-#include <rfb/LogWriter.h>
#include <rfb/CMsgHandler.h>
#include <rfb/CMsgReader.h>
+#include <rfb/PixelBuffer.h>
+#include <rfb/ScreenSet.h>
+#include <rfb/encodings.h>
-static rfb::LogWriter vlog("CMsgReader");
+static core::LogWriter vlog("CMsgReader");
-static rfb::IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
+static core::IntParameter maxCutText("MaxCutText",
+ "Maximum permitted length of an "
+ "incoming clipboard update",
+ 256*1024, 0, INT_MAX);
using namespace rfb;
@@ -77,11 +84,11 @@ bool CMsgReader::readServerInit()
is->readBytes((uint8_t*)name.data(), len);
name[len] = '\0';
- if (isValidUTF8(name.data()))
+ if (core::isValidUTF8(name.data()))
handler->serverInit(width, height, pf, name.data());
else
handler->serverInit(width, height, pf,
- latin1ToUTF8(name.data()).c_str());
+ core::latin1ToUTF8(name.data()).c_str());
return true;
}
@@ -119,7 +126,7 @@ bool CMsgReader::readMsg()
ret = readEndOfContinuousUpdates();
break;
default:
- throw protocol_error(format("Unknown message type %d", currentMsgType));
+ throw protocol_error(core::format("Unknown message type %d", currentMsgType));
}
if (ret)
@@ -288,8 +295,8 @@ bool CMsgReader::readServerCutText()
std::vector<char> ca(len);
is->readBytes((uint8_t*)ca.data(), len);
- std::string utf8(latin1ToUTF8(ca.data(), ca.size()));
- std::string filtered(convertLF(utf8.data(), utf8.size()));
+ std::string utf8(core::latin1ToUTF8(ca.data(), ca.size()));
+ std::string filtered(core::convertLF(utf8.data(), utf8.size()));
handler->serverCutText(filtered.c_str());
@@ -470,7 +477,7 @@ bool CMsgReader::readFramebufferUpdate()
return true;
}
-bool CMsgReader::readRect(const Rect& r, int encoding)
+bool CMsgReader::readRect(const core::Rect& r, int encoding)
{
if ((r.br.x > handler->server.width()) ||
(r.br.y > handler->server.height())) {
@@ -486,7 +493,8 @@ bool CMsgReader::readRect(const Rect& r, int encoding)
return handler->dataRect(r, encoding);
}
-bool CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
+bool CMsgReader::readSetXCursor(int width, int height,
+ const core::Point& hotspot)
{
if (width > maxCursorSize || height > maxCursorSize)
throw protocol_error("Too big cursor");
@@ -550,7 +558,8 @@ bool CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
return true;
}
-bool CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
+bool CMsgReader::readSetCursor(int width, int height,
+ const core::Point& hotspot)
{
if (width > maxCursorSize || height > maxCursorSize)
throw protocol_error("Too big cursor");
@@ -596,7 +605,8 @@ bool CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
return true;
}
-bool CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hotspot)
+bool CMsgReader::readSetCursorWithAlpha(int width, int height,
+ const core::Point& hotspot)
{
if (width > maxCursorSize || height > maxCursorSize)
throw protocol_error("Too big cursor");
@@ -657,7 +667,8 @@ bool CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hots
return true;
}
-bool CMsgReader::readSetVMwareCursor(int width, int height, const Point& hotspot)
+bool CMsgReader::readSetVMwareCursor(int width, int height,
+ const core::Point& hotspot)
{
if (width > maxCursorSize || height > maxCursorSize)
throw protocol_error("Too big cursor");
@@ -784,7 +795,7 @@ bool CMsgReader::readSetDesktopName(int x, int y, int w, int h)
return true;
}
- if (!isValidUTF8(name.data())) {
+ if (!core::isValidUTF8(name.data())) {
vlog.error("Ignoring DesktopName rect with invalid UTF-8 sequence");
return true;
}
diff --git a/common/rfb/CMsgReader.h b/common/rfb/CMsgReader.h
index 3b1c0ddb..e33f701d 100644
--- a/common/rfb/CMsgReader.h
+++ b/common/rfb/CMsgReader.h
@@ -26,14 +26,13 @@
#include <stdint.h>
-#include <rfb/Rect.h>
-#include <rfb/encodings.h>
+#include <core/Rect.h>
namespace rdr { class InStream; }
namespace rfb {
+
class CMsgHandler;
- struct Rect;
class CMsgReader {
public:
@@ -59,12 +58,16 @@ namespace rfb {
bool readFramebufferUpdate();
- bool readRect(const Rect& r, int encoding);
+ bool readRect(const core::Rect& r, int encoding);
- bool readSetXCursor(int width, int height, const Point& hotspot);
- bool readSetCursor(int width, int height, const Point& hotspot);
- bool readSetCursorWithAlpha(int width, int height, const Point& hotspot);
- bool readSetVMwareCursor(int width, int height, const Point& hotspot);
+ bool readSetXCursor(int width, int height,
+ const core::Point& hotspot);
+ bool readSetCursor(int width, int height,
+ const core::Point& hotspot);
+ bool readSetCursorWithAlpha(int width, int height,
+ const core::Point& hotspot);
+ bool readSetVMwareCursor(int width, int height,
+ const core::Point& hotspot);
bool readSetDesktopName(int x, int y, int w, int h);
bool readExtendedDesktopSize(int x, int y, int w, int h);
bool readLEDState();
@@ -85,12 +88,14 @@ namespace rfb {
uint8_t currentMsgType;
int nUpdateRectsLeft;
- Rect dataRect;
+ core::Rect dataRect;
int rectEncoding;
int cursorEncoding;
static const int maxCursorSize = 256;
};
+
}
+
#endif
diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx
index 0128c431..c592a25e 100644
--- a/common/rfb/CMsgWriter.cxx
+++ b/common/rfb/CMsgWriter.cxx
@@ -24,6 +24,9 @@
#include <stdio.h>
#include <assert.h>
+#include <core/Rect.h>
+#include <core/string.h>
+
#include <rdr/OutStream.h>
#include <rdr/MemOutStream.h>
#include <rdr/ZlibOutStream.h>
@@ -33,10 +36,9 @@
#include <rfb/qemuTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/PixelFormat.h>
-#include <rfb/Rect.h>
+#include <rfb/ScreenSet.h>
#include <rfb/ServerParams.h>
#include <rfb/CMsgWriter.h>
-#include <rfb/util.h>
using namespace rfb;
@@ -101,7 +103,8 @@ void CMsgWriter::writeSetDesktopSize(int width, int height,
endMsg();
}
-void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
+void CMsgWriter::writeFramebufferUpdateRequest(const core::Rect& r,
+ bool incremental)
{
startMsg(msgTypeFramebufferUpdateRequest);
os->writeU8(incremental);
@@ -173,9 +176,10 @@ void CMsgWriter::writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down)
}
-void CMsgWriter::writePointerEvent(const Point& pos, uint16_t buttonMask)
+void CMsgWriter::writePointerEvent(const core::Point& pos,
+ uint16_t buttonMask)
{
- Point p(pos);
+ core::Point p(pos);
bool extendedMouseButtons;
if (p.x < 0) p.x = 0;
@@ -223,7 +227,7 @@ void CMsgWriter::writeClientCutText(const char* str)
if (strchr(str, '\r') != nullptr)
throw std::invalid_argument("Invalid carriage return in clipboard data");
- std::string latin1(utf8ToLatin1(str));
+ std::string latin1(core::utf8ToLatin1(str));
startMsg(msgTypeClientCutText);
os->pad(3);
diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h
index 9cb4adec..d0378e62 100644
--- a/common/rfb/CMsgWriter.h
+++ b/common/rfb/CMsgWriter.h
@@ -27,6 +27,11 @@
#include <stdint.h>
+namespace core {
+ struct Point;
+ struct Rect;
+}
+
namespace rdr { class OutStream; }
namespace rfb {
@@ -34,8 +39,6 @@ namespace rfb {
class PixelFormat;
class ServerParams;
struct ScreenSet;
- struct Point;
- struct Rect;
class CMsgWriter {
public:
@@ -48,13 +51,14 @@ namespace rfb {
void writeSetEncodings(const std::list<uint32_t> encodings);
void writeSetDesktopSize(int width, int height, const ScreenSet& layout);
- void writeFramebufferUpdateRequest(const Rect& r,bool incremental);
+ void writeFramebufferUpdateRequest(const core::Rect& r,
+ bool incremental);
void writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h);
void writeFence(uint32_t flags, unsigned len, const uint8_t data[]);
void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down);
- void writePointerEvent(const Point& pos, uint16_t buttonMask);
+ void writePointerEvent(const core::Point& pos, uint16_t buttonMask);
void writeClientCutText(const char* str);
diff --git a/common/rfb/CSecurityDH.cxx b/common/rfb/CSecurityDH.cxx
index 2f0365a6..93cf6b26 100644
--- a/common/rfb/CSecurityDH.cxx
+++ b/common/rfb/CSecurityDH.cxx
@@ -40,7 +40,6 @@
#include <rdr/OutStream.h>
#include <rdr/RandomStream.h>
#include <rfb/Exception.h>
-#include <os/os.h>
using namespace rfb;
diff --git a/common/rfb/CSecurityMSLogonII.cxx b/common/rfb/CSecurityMSLogonII.cxx
index a5a99286..dfc0b658 100644
--- a/common/rfb/CSecurityMSLogonII.cxx
+++ b/common/rfb/CSecurityMSLogonII.cxx
@@ -39,7 +39,6 @@
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
#include <rdr/RandomStream.h>
-#include <os/os.h>
using namespace rfb;
diff --git a/common/rfb/CSecurityRSAAES.cxx b/common/rfb/CSecurityRSAAES.cxx
index 0985d0f2..513d5605 100644
--- a/common/rfb/CSecurityRSAAES.cxx
+++ b/common/rfb/CSecurityRSAAES.cxx
@@ -34,14 +34,17 @@
#include <nettle/bignum.h>
#include <nettle/sha1.h>
#include <nettle/sha2.h>
+
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb/CSecurityRSAAES.h>
#include <rfb/CConnection.h>
-#include <rfb/LogWriter.h>
#include <rfb/Exception.h>
-#include <rfb/util.h>
+
#include <rdr/AESInStream.h>
#include <rdr/AESOutStream.h>
-#include <os/os.h>
+#include <rdr/RandomStream.h>
enum {
ReadPublicKey,
@@ -55,7 +58,7 @@ const int MaxKeyLength = 8192;
using namespace rfb;
-static LogWriter vlog("CSecurityRSAAES");
+static core::LogWriter vlog("CSecurityRSAAES");
CSecurityRSAAES::CSecurityRSAAES(CConnection* cc_, uint32_t _secType,
int _keySize, bool _isAllEncrypted)
@@ -147,12 +150,12 @@ bool CSecurityRSAAES::processMsg()
return false;
}
-static void random_func(void* ctx, size_t length, uint8_t* dst)
+static void random_func(void*, size_t length, uint8_t* dst)
{
- rdr::RandomStream* rs = (rdr::RandomStream*)ctx;
- if (!rs->hasData(length))
+ rdr::RandomStream rs;
+ if (!rs.hasData(length))
throw std::runtime_error("Failed to generate random");
- rs->readBytes(dst, length);
+ rs.readBytes(dst, length);
}
void CSecurityRSAAES::writePublicKey()
@@ -170,7 +173,7 @@ void CSecurityRSAAES::writePublicKey()
// set e = 65537
mpz_set_ui(clientPublicKey.e, 65537);
if (!rsa_generate_keypair(&clientPublicKey, &clientKey,
- &rs, random_func, nullptr, nullptr,
+ nullptr, random_func, nullptr, nullptr,
clientKeyLength, 0))
throw std::runtime_error("Failed to generate key");
clientKeyN = new uint8_t[rsaKeySize];
@@ -226,7 +229,7 @@ void CSecurityRSAAES::verifyServer()
sha1_update(&ctx, serverKey.size, serverKeyE);
sha1_digest(&ctx, sizeof(f), f);
const char *title = "Server key fingerprint";
- std::string text = format(
+ std::string text = core::format(
"The server has provided the following identifying information:\n"
"Fingerprint: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n"
"Please verify that the information is correct and press \"Yes\". "
@@ -237,6 +240,7 @@ void CSecurityRSAAES::verifyServer()
void CSecurityRSAAES::writeRandom()
{
+ rdr::RandomStream rs;
rdr::OutStream* os = cc->getOutStream();
if (!rs.hasData(keySize / 8))
throw std::runtime_error("Failed to generate random");
diff --git a/common/rfb/CSecurityRSAAES.h b/common/rfb/CSecurityRSAAES.h
index af380bd3..ecbfdc4f 100644
--- a/common/rfb/CSecurityRSAAES.h
+++ b/common/rfb/CSecurityRSAAES.h
@@ -29,7 +29,7 @@
#include <rfb/CSecurity.h>
#include <rfb/Security.h>
-#include <rdr/RandomStream.h>
+namespace core { class IntParameter; }
namespace rdr {
class InStream;
@@ -39,6 +39,7 @@ namespace rdr {
}
namespace rfb {
+
class CSecurityRSAAES : public CSecurity {
public:
CSecurityRSAAES(CConnection* cc, uint32_t secType,
@@ -48,7 +49,7 @@ namespace rfb {
int getType() const override { return secType; }
bool isSecure() const override { return secType == secTypeRA256; }
- static IntParameter RSAKeyLength;
+ static core::IntParameter RSAKeyLength;
private:
void cleanup();
@@ -86,9 +87,8 @@ namespace rfb {
rdr::InStream* rawis;
rdr::OutStream* rawos;
-
- rdr::RandomStream rs;
};
+
}
#endif
diff --git a/common/rfb/CSecurityStack.h b/common/rfb/CSecurityStack.h
index 521597ec..aec800f9 100644
--- a/common/rfb/CSecurityStack.h
+++ b/common/rfb/CSecurityStack.h
@@ -21,7 +21,6 @@
#define __RFB_CSECURITYSTACK_H__
#include <rfb/CSecurity.h>
-#include <rfb/Security.h>
namespace rfb {
diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx
index 0c10a85d..6eefe73b 100644
--- a/common/rfb/CSecurityTLS.cxx
+++ b/common/rfb/CSecurityTLS.cxx
@@ -3,7 +3,7 @@
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
* Copyright (C) 2010 m-privacy GmbH
- * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB
+ * Copyright 2012-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,15 +34,16 @@
#include <unistd.h>
#endif
+#include <core/LogWriter.h>
+#include <core/string.h>
+#include <core/xdgdirs.h>
+
#include <rfb/CSecurityTLS.h>
#include <rfb/CConnection.h>
-#include <rfb/LogWriter.h>
#include <rfb/Exception.h>
-#include <rfb/util.h>
+
#include <rdr/TLSException.h>
-#include <rdr/TLSInStream.h>
-#include <rdr/TLSOutStream.h>
-#include <os/os.h>
+#include <rdr/TLSSocket.h>
#include <gnutls/x509.h>
@@ -50,21 +51,19 @@ using namespace rfb;
static const char* configdirfn(const char* fn);
-StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate",
- configdirfn("x509_ca.pem"),
- ConfViewer);
-StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file",
- configdirfn("x509_crl.pem"),
- ConfViewer);
+core::StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate",
+ configdirfn("x509_ca.pem"));
+core::StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file",
+ configdirfn("x509_crl.pem"));
-static LogWriter vlog("TLS");
+static core::LogWriter vlog("TLS");
static const char* configdirfn(const char* fn)
{
static char full_path[PATH_MAX];
const char* configdir;
- configdir = os::getvncconfigdir();
+ configdir = core::getvncconfigdir();
if (configdir == nullptr)
return "";
@@ -75,7 +74,7 @@ static const char* configdirfn(const char* fn)
CSecurityTLS::CSecurityTLS(CConnection* cc_, bool _anon)
: CSecurity(cc_), session(nullptr),
anon_cred(nullptr), cert_cred(nullptr),
- anon(_anon), tlsis(nullptr), tlsos(nullptr),
+ anon(_anon), tlssock(nullptr),
rawis(nullptr), rawos(nullptr)
{
int err = gnutls_global_init();
@@ -85,27 +84,8 @@ CSecurityTLS::CSecurityTLS(CConnection* cc_, bool _anon)
void CSecurityTLS::shutdown()
{
- if (tlsos) {
- try {
- if (tlsos->hasBufferedData()) {
- tlsos->cork(false);
- tlsos->flush();
- if (tlsos->hasBufferedData())
- vlog.error("Failed to flush remaining socket data on close");
- }
- } catch (std::exception& e) {
- vlog.error("Failed to flush remaining socket data on close: %s", e.what());
- }
- }
-
- if (session) {
- int ret;
- // FIXME: We can't currently wait for the response, so we only send
- // our close and hope for the best
- ret = gnutls_bye(session, GNUTLS_SHUT_WR);
- if ((ret != GNUTLS_E_SUCCESS) && (ret != GNUTLS_E_INVALID_SESSION))
- vlog.error("TLS shutdown failed: %s", gnutls_strerror(ret));
- }
+ if (tlssock)
+ tlssock->shutdown();
if (anon_cred) {
gnutls_anon_free_client_credentials(anon_cred);
@@ -123,13 +103,9 @@ void CSecurityTLS::shutdown()
rawos = nullptr;
}
- if (tlsis) {
- delete tlsis;
- tlsis = nullptr;
- }
- if (tlsos) {
- delete tlsos;
- tlsos = nullptr;
+ if (tlssock) {
+ delete tlssock;
+ tlssock = nullptr;
}
if (session) {
@@ -171,26 +147,18 @@ bool CSecurityTLS::processMsg()
setParam();
- // Create these early as they set up the push/pull functions
- // for GnuTLS
- tlsis = new rdr::TLSInStream(is, session);
- tlsos = new rdr::TLSOutStream(os, session);
+ tlssock = new rdr::TLSSocket(is, os, session);
rawis = is;
rawos = os;
}
- int err;
- err = gnutls_handshake(session);
- if (err != GNUTLS_E_SUCCESS) {
- if (!gnutls_error_is_fatal(err)) {
- vlog.debug("Deferring completion of TLS handshake: %s", gnutls_strerror(err));
+ try {
+ if (!tlssock->handshake())
return false;
- }
-
- vlog.error("TLS Handshake failed: %s\n", gnutls_strerror (err));
+ } catch (std::exception&) {
shutdown();
- throw rdr::tls_error("TLS Handshake failed", err);
+ throw;
}
vlog.debug("TLS handshake completed with %s",
@@ -198,33 +166,29 @@ bool CSecurityTLS::processMsg()
checkSession();
- cc->setStreams(tlsis, tlsos);
+ cc->setStreams(&tlssock->inStream(), &tlssock->outStream());
return true;
}
void CSecurityTLS::setParam()
{
- static const char kx_anon_priority[] = ":+ANON-ECDH:+ANON-DH";
+ static const char kx_anon_priority[] = "+ANON-ECDH:+ANON-DH";
int ret;
// Custom priority string specified?
if (strcmp(Security::GnuTLSPriority, "") != 0) {
- char *prio;
+ std::string prio;
const char *err;
- prio = new char[strlen(Security::GnuTLSPriority) +
- strlen(kx_anon_priority) + 1];
-
- strcpy(prio, Security::GnuTLSPriority);
- if (anon)
- strcat(prio, kx_anon_priority);
-
- ret = gnutls_priority_set_direct(session, prio, &err);
-
- delete [] prio;
+ prio = (const char*)Security::GnuTLSPriority;
+ if (anon) {
+ prio += ":";
+ prio += kx_anon_priority;
+ }
+ ret = gnutls_priority_set_direct(session, prio.c_str(), &err);
if (ret != GNUTLS_E_SUCCESS) {
if (ret == GNUTLS_E_INVALID_REQUEST)
vlog.error("GnuTLS priority syntax error at: %s", err);
@@ -234,30 +198,22 @@ void CSecurityTLS::setParam()
const char *err;
#if GNUTLS_VERSION_NUMBER >= 0x030603
- // gnutls_set_default_priority_appends() expects a normal priority string that
- // doesn't start with ":".
- ret = gnutls_set_default_priority_append(session, kx_anon_priority + 1, &err, 0);
+ ret = gnutls_set_default_priority_append(session, kx_anon_priority, &err, 0);
if (ret != GNUTLS_E_SUCCESS) {
if (ret == GNUTLS_E_INVALID_REQUEST)
vlog.error("GnuTLS priority syntax error at: %s", err);
throw rdr::tls_error("gnutls_set_default_priority_append()", ret);
}
#else
+ std::string prio;
+
// We don't know what the system default priority is, so we guess
// it's what upstream GnuTLS has
- static const char gnutls_default_priority[] = "NORMAL";
- char *prio;
-
- prio = new char[malloc(strlen(gnutls_default_priority) +
- strlen(kx_anon_priority) + 1];
-
- strcpy(prio, gnutls_default_priority);
- strcat(prio, kx_anon_priority);
-
- ret = gnutls_priority_set_direct(session, prio, &err);
-
- delete [] prio;
+ prio = "NORMAL";
+ prio += ":";
+ prio += kx_anon_priority;
+ ret = gnutls_priority_set_direct(session, prio.c_str(), &err);
if (ret != GNUTLS_E_SUCCESS) {
if (ret == GNUTLS_E_INVALID_REQUEST)
vlog.error("GnuTLS priority syntax error at: %s", err);
@@ -277,6 +233,10 @@ void CSecurityTLS::setParam()
vlog.debug("Anonymous session has been set");
} else {
+ const char* hostname;
+ size_t len;
+ bool valid;
+
ret = gnutls_certificate_allocate_credentials(&cert_cred);
if (ret != GNUTLS_E_SUCCESS)
throw rdr::tls_error("gnutls_certificate_allocate_credentials()", ret);
@@ -294,10 +254,22 @@ void CSecurityTLS::setParam()
if (ret != GNUTLS_E_SUCCESS)
throw rdr::tls_error("gnutls_credentials_set()", ret);
- if (gnutls_server_name_set(session, GNUTLS_NAME_DNS,
- client->getServerName(),
- strlen(client->getServerName())) != GNUTLS_E_SUCCESS)
- vlog.error("Failed to configure the server name for TLS handshake");
+ // Only DNS hostnames are allowed, and some servers will reject the
+ // connection if we provide anything else (e.g. an IPv6 address)
+ hostname = client->getServerName();
+ len = strlen(hostname);
+ valid = true;
+ for (size_t i = 0; i < len; i++) {
+ if (!isalnum(hostname[i]) && hostname[i] != '.')
+ valid = false;
+ }
+
+ if (valid) {
+ if (gnutls_server_name_set(session, GNUTLS_NAME_DNS,
+ client->getServerName(),
+ strlen(client->getServerName())) != GNUTLS_E_SUCCESS)
+ vlog.error("Failed to configure the server name for TLS handshake");
+ }
vlog.debug("X509 session has been set");
}
@@ -324,12 +296,16 @@ void CSecurityTLS::checkSession()
if (anon)
return;
- if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
+ if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_UNSUPPORTED_CERTIFICATE);
throw protocol_error("Unsupported certificate type");
+ }
err = gnutls_certificate_verify_peers2(session, &status);
if (err != 0) {
vlog.error("Server certificate verification failed: %s", gnutls_strerror(err));
+ gnutls_alert_send_appropriate(session, err);
throw rdr::tls_error("Server certificate verification()", err);
}
@@ -346,23 +322,29 @@ void CSecurityTLS::checkSession()
GNUTLS_CRT_X509,
&status_str,
0);
- if (err != GNUTLS_E_SUCCESS)
+ if (err != GNUTLS_E_SUCCESS) {
+ gnutls_alert_send_appropriate(session, err);
throw rdr::tls_error("Failed to get certificate error description", err);
+ }
error = (const char*)status_str.data;
gnutls_free(status_str.data);
- throw protocol_error(format("Invalid server certificate: %s",
- error.c_str()));
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
+ throw protocol_error(
+ core::format("Invalid server certificate: %s", error.c_str()));
}
err = gnutls_certificate_verification_status_print(status,
GNUTLS_CRT_X509,
&status_str,
0);
- if (err != GNUTLS_E_SUCCESS)
+ if (err != GNUTLS_E_SUCCESS) {
+ gnutls_alert_send_appropriate(session, err);
throw rdr::tls_error("Failed to get certificate error description", err);
+ }
vlog.info("Server certificate errors: %s", status_str.data);
@@ -372,16 +354,21 @@ void CSecurityTLS::checkSession()
/* Process overridable errors later */
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
- if (!cert_list_size)
+ if (!cert_list_size) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_UNSUPPORTED_CERTIFICATE);
throw protocol_error("Empty certificate chain");
+ }
/* Process only server's certificate, not issuer's certificate */
gnutls_x509_crt_t crt;
gnutls_x509_crt_init(&crt);
err = gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER);
- if (err != GNUTLS_E_SUCCESS)
+ if (err != GNUTLS_E_SUCCESS) {
+ gnutls_alert_send_appropriate(session, err);
throw rdr::tls_error("Failed to decode server certificate", err);
+ }
if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) {
vlog.info("Server certificate doesn't match given server name");
@@ -398,7 +385,7 @@ void CSecurityTLS::checkSession()
/* Certificate has some user overridable problems, so TOFU time */
- hostsDir = os::getvncstatedir();
+ hostsDir = core::getvncstatedir();
if (hostsDir == nullptr) {
throw std::runtime_error("Could not obtain VNC state directory "
"path for known hosts storage");
@@ -420,12 +407,15 @@ void CSecurityTLS::checkSession()
if ((known != GNUTLS_E_NO_CERTIFICATE_FOUND) &&
(known != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)) {
+ gnutls_alert_send_appropriate(session, known);
throw rdr::tls_error("Could not load known hosts database", known);
}
err = gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info);
- if (err != GNUTLS_E_SUCCESS)
+ if (err != GNUTLS_E_SUCCESS) {
+ gnutls_alert_send_appropriate(session, known);
throw rdr::tls_error("Could not find certificate to display", err);
+ }
len = strlen((char*)info.data);
for (size_t i = 0; i < len - 1; i++) {
@@ -443,21 +433,24 @@ void CSecurityTLS::checkSession()
if (status & (GNUTLS_CERT_INVALID |
GNUTLS_CERT_SIGNER_NOT_FOUND |
GNUTLS_CERT_SIGNER_NOT_CA)) {
- text = format("This certificate has been signed by an unknown "
- "authority:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", info.data);
+ text = core::format(
+ "This certificate has been signed by an unknown authority:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Unknown certificate issuer",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_UNKNOWN_CA);
throw auth_cancelled();
+ }
status &= ~(GNUTLS_CERT_INVALID |
GNUTLS_CERT_SIGNER_NOT_FOUND |
@@ -465,82 +458,101 @@ void CSecurityTLS::checkSession()
}
if (status & GNUTLS_CERT_NOT_ACTIVATED) {
- text = format("This certificate is not yet valid:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", info.data);
+ text = core::format(
+ "This certificate is not yet valid:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ info.data);
+
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Certificate is not yet valid",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw auth_cancelled();
+ }
status &= ~GNUTLS_CERT_NOT_ACTIVATED;
}
if (status & GNUTLS_CERT_EXPIRED) {
- text = format("This certificate has expired:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", info.data);
+ text = core::format(
+ "This certificate has expired:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Expired certificate",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw auth_cancelled();
+ }
status &= ~GNUTLS_CERT_EXPIRED;
}
if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
- text = format("This certificate uses an insecure algorithm:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", info.data);
+ text = core::format(
+ "This certificate uses an insecure algorithm:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Insecure certificate algorithm",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw auth_cancelled();
+ }
status &= ~GNUTLS_CERT_INSECURE_ALGORITHM;
}
if (status != 0) {
vlog.error("Unhandled certificate problems: 0x%x", status);
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw std::logic_error("Unhandled certificate problems");
}
if (!hostname_match) {
- text = format("The specified hostname \"%s\" does not match the "
- "certificate provided by the server:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", client->getServerName(), info.data);
+ text = core::format(
+ "The specified hostname \"%s\" does not match the certificate "
+ "provided by the server:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ client->getServerName(), info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Certificate hostname mismatch",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw auth_cancelled();
+ }
}
} else if (known == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) {
std::string text;
@@ -551,22 +563,26 @@ void CSecurityTLS::checkSession()
if (status & (GNUTLS_CERT_INVALID |
GNUTLS_CERT_SIGNER_NOT_FOUND |
GNUTLS_CERT_SIGNER_NOT_CA)) {
- text = format("This host is previously known with a different "
- "certificate, and the new certificate has been "
- "signed by an unknown authority:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", info.data);
+ text = core::format(
+ "This host is previously known with a different certificate, "
+ "and the new certificate has been signed by an unknown "
+ "authority:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Unexpected server certificate",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_UNKNOWN_CA);
throw auth_cancelled();
+ }
status &= ~(GNUTLS_CERT_INVALID |
GNUTLS_CERT_SIGNER_NOT_FOUND |
@@ -574,91 +590,105 @@ void CSecurityTLS::checkSession()
}
if (status & GNUTLS_CERT_NOT_ACTIVATED) {
- text = format("This host is previously known with a different "
- "certificate, and the new certificate is not yet "
- "valid:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", info.data);
+ text = core::format(
+ "This host is previously known with a different certificate, "
+ "and the new certificate is not yet valid:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Unexpected server certificate",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw auth_cancelled();
+ }
status &= ~GNUTLS_CERT_NOT_ACTIVATED;
}
if (status & GNUTLS_CERT_EXPIRED) {
- text = format("This host is previously known with a different "
- "certificate, and the new certificate has "
- "expired:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", info.data);
+ text = core::format(
+ "This host is previously known with a different certificate, "
+ "and the new certificate has expired:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Unexpected server certificate",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw auth_cancelled();
+ }
status &= ~GNUTLS_CERT_EXPIRED;
}
if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
- text = format("This host is previously known with a different "
- "certificate, and the new certificate uses an "
- "insecure algorithm:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", info.data);
+ text = core::format(
+ "This host is previously known with a different certificate, "
+ "and the new certificate uses an insecure algorithm:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Unexpected server certificate",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw auth_cancelled();
+ }
status &= ~GNUTLS_CERT_INSECURE_ALGORITHM;
}
if (status != 0) {
vlog.error("Unhandled certificate problems: 0x%x", status);
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw std::logic_error("Unhandled certificate problems");
}
if (!hostname_match) {
- text = format("This host is previously known with a different "
- "certificate, and the specified hostname \"%s\" "
- "does not match the new certificate provided by "
- "the server:\n"
- "\n"
- "%s\n"
- "\n"
- "Someone could be trying to impersonate the site "
- "and you should not continue.\n"
- "\n"
- "Do you want to make an exception for this "
- "server?", client->getServerName(), info.data);
+ text = core::format(
+ "This host is previously known with a different certificate, "
+ "and the specified hostname \"%s\" does not match the new "
+ "certificate provided by the server:\n"
+ "\n"
+ "%s\n"
+ "\n"
+ "Someone could be trying to impersonate the site and you "
+ "should not continue.\n"
+ "\n"
+ "Do you want to make an exception for this server?",
+ client->getServerName(), info.data);
if (!cc->showMsgBox(MsgBoxFlags::M_YESNO,
"Unexpected server certificate",
- text.c_str()))
+ text.c_str())) {
+ gnutls_alert_send(session, GNUTLS_AL_FATAL,
+ GNUTLS_A_BAD_CERTIFICATE);
throw auth_cancelled();
+ }
}
}
diff --git a/common/rfb/CSecurityTLS.h b/common/rfb/CSecurityTLS.h
index 2464cb6c..51b7dac1 100644
--- a/common/rfb/CSecurityTLS.h
+++ b/common/rfb/CSecurityTLS.h
@@ -2,6 +2,7 @@
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
+ * Copyright 2012-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,8 +35,7 @@
namespace rdr {
class InStream;
class OutStream;
- class TLSInStream;
- class TLSOutStream;
+ class TLSSocket;
}
namespace rfb {
@@ -47,8 +47,8 @@ namespace rfb {
int getType() const override { return anon ? secTypeTLSNone : secTypeX509None; }
bool isSecure() const override { return !anon; }
- static StringParameter X509CA;
- static StringParameter X509CRL;
+ static core::StringParameter X509CA;
+ static core::StringParameter X509CRL;
protected:
void shutdown();
@@ -63,8 +63,7 @@ namespace rfb {
gnutls_certificate_credentials_t cert_cred;
bool anon;
- rdr::TLSInStream* tlsis;
- rdr::TLSOutStream* tlsos;
+ rdr::TLSSocket* tlssock;
rdr::InStream* rawis;
rdr::OutStream* rawos;
diff --git a/common/rfb/CSecurityVeNCrypt.cxx b/common/rfb/CSecurityVeNCrypt.cxx
index 1b6ecf22..a6e30947 100644
--- a/common/rfb/CSecurityVeNCrypt.cxx
+++ b/common/rfb/CSecurityVeNCrypt.cxx
@@ -29,16 +29,17 @@
#include <algorithm>
#include <list>
+#include <core/LogWriter.h>
+
#include <rfb/Exception.h>
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
#include <rfb/CConnection.h>
#include <rfb/CSecurityVeNCrypt.h>
-#include <rfb/LogWriter.h>
using namespace rfb;
-static LogWriter vlog("CVeNCrypt");
+static core::LogWriter vlog("CVeNCrypt");
CSecurityVeNCrypt::CSecurityVeNCrypt(CConnection* cc_,
SecurityClient* sec)
diff --git a/common/rfb/CSecurityVeNCrypt.h b/common/rfb/CSecurityVeNCrypt.h
index f73e7927..8e2c6d5e 100644
--- a/common/rfb/CSecurityVeNCrypt.h
+++ b/common/rfb/CSecurityVeNCrypt.h
@@ -28,10 +28,11 @@
#include <stdint.h>
#include <rfb/CSecurity.h>
-#include <rfb/SecurityClient.h>
namespace rfb {
+ class SecurityClient;
+
class CSecurityVeNCrypt : public CSecurity {
public:
diff --git a/common/rfb/ClientParams.cxx b/common/rfb/ClientParams.cxx
index e5fd105e..514b0b4e 100644
--- a/common/rfb/ClientParams.cxx
+++ b/common/rfb/ClientParams.cxx
@@ -24,14 +24,20 @@
#include <stdexcept>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb/encodings.h>
#include <rfb/ledStates.h>
#include <rfb/clipboardTypes.h>
#include <rfb/ClientParams.h>
-#include <rfb/util.h>
+#include <rfb/Cursor.h>
+#include <rfb/ScreenSet.h>
using namespace rfb;
+static core::LogWriter vlog("ClientParams");
+
ClientParams::ClientParams()
: majorVersion(0), minorVersion(0),
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
@@ -41,7 +47,11 @@ ClientParams::ClientParams()
{
setName("");
- cursor_ = new Cursor(0, 0, Point(), nullptr);
+ screenLayout_ = new ScreenSet();
+
+ pf_ = new PixelFormat();
+
+ cursor_ = new Cursor(0, 0, {}, nullptr);
clipFlags = clipboardUTF8 | clipboardRTF | clipboardHTML |
clipboardRequest | clipboardNotify | clipboardProvide;
@@ -51,7 +61,9 @@ ClientParams::ClientParams()
ClientParams::~ClientParams()
{
+ delete screenLayout_;
delete cursor_;
+ delete pf_;
}
void ClientParams::setDimensions(int width, int height)
@@ -63,17 +75,25 @@ void ClientParams::setDimensions(int width, int height)
void ClientParams::setDimensions(int width, int height, const ScreenSet& layout)
{
- if (!layout.validate(width, height))
+ if (!layout.validate(width, height)) {
+ char buffer[2048];
+ vlog.debug("Invalid screen layout for %dx%d:", width, height);
+ layout.print(buffer, sizeof(buffer));
+ vlog.debug("%s", buffer);
+
throw std::invalid_argument("Attempted to configure an invalid screen layout");
+ }
width_ = width;
height_ = height;
- screenLayout_ = layout;
+ delete screenLayout_;
+ screenLayout_ = new ScreenSet(layout);
}
void ClientParams::setPF(const PixelFormat& pf)
{
- pf_ = pf;
+ delete pf_;
+ pf_ = new PixelFormat(pf);
if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
throw std::invalid_argument("setPF: Not 8, 16 or 32 bpp?");
@@ -90,7 +110,7 @@ void ClientParams::setCursor(const Cursor& other)
cursor_ = new Cursor(other);
}
-void ClientParams::setCursorPos(const Point& pos)
+void ClientParams::setCursorPos(const core::Point& pos)
{
cursorPos_ = pos;
}
@@ -162,7 +182,7 @@ uint32_t ClientParams::clipboardSize(unsigned int format) const
return clipSizes[i];
}
- throw std::invalid_argument(rfb::format("Invalid clipboard format 0x%x", format));
+ throw std::invalid_argument(core::format("Invalid clipboard format 0x%x", format));
}
void ClientParams::setClipboardCaps(uint32_t flags, const uint32_t* lengths)
@@ -236,4 +256,4 @@ bool ClientParams::supportsExtendedMouseButtons() const
if (supportsEncoding(pseudoEncodingExtendedMouseButtons))
return true;
return false;
-} \ No newline at end of file
+}
diff --git a/common/rfb/ClientParams.h b/common/rfb/ClientParams.h
index f715c47f..0910181b 100644
--- a/common/rfb/ClientParams.h
+++ b/common/rfb/ClientParams.h
@@ -28,12 +28,14 @@
#include <stdint.h>
-#include <rfb/Cursor.h>
-#include <rfb/PixelFormat.h>
-#include <rfb/ScreenSet.h>
+#include <core/Rect.h>
namespace rfb {
+ class Cursor;
+ class PixelFormat;
+ struct ScreenSet;
+
const int subsampleUndefined = -1;
const int subsampleNone = 0;
const int subsampleGray = 1;
@@ -66,11 +68,11 @@ namespace rfb {
int width() const { return width_; }
int height() const { return height_; }
- const ScreenSet& screenLayout() const { return screenLayout_; }
+ const ScreenSet& screenLayout() const { return *screenLayout_; }
void setDimensions(int width, int height);
void setDimensions(int width, int height, const ScreenSet& layout);
- const PixelFormat& pf() const { return pf_; }
+ const PixelFormat& pf() const { return *pf_; }
void setPF(const PixelFormat& pf);
const char* name() const { return name_.c_str(); }
@@ -79,8 +81,8 @@ namespace rfb {
const Cursor& cursor() const { return *cursor_; }
void setCursor(const Cursor& cursor);
- const Point& cursorPos() const { return cursorPos_; }
- void setCursorPos(const Point& pos);
+ const core::Point& cursorPos() const { return cursorPos_; }
+ void setCursorPos(const core::Point& pos);
bool supportsEncoding(int32_t encoding) const;
@@ -112,12 +114,12 @@ namespace rfb {
int width_;
int height_;
- ScreenSet screenLayout_;
+ ScreenSet* screenLayout_;
- PixelFormat pf_;
+ PixelFormat* pf_;
std::string name_;
Cursor* cursor_;
- Point cursorPos_;
+ core::Point cursorPos_;
std::set<int32_t> encodings_;
unsigned int ledState_;
uint32_t clipFlags;
diff --git a/common/rfb/ComparingUpdateTracker.cxx b/common/rfb/ComparingUpdateTracker.cxx
index dab5e6aa..a89c3ec3 100644
--- a/common/rfb/ComparingUpdateTracker.cxx
+++ b/common/rfb/ComparingUpdateTracker.cxx
@@ -22,17 +22,18 @@
#include <stdio.h>
#include <string.h>
+
+#include <algorithm>
#include <vector>
-#include <rfb/Exception.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
#include <rfb/ComparingUpdateTracker.h>
using namespace rfb;
-static LogWriter vlog("ComparingUpdateTracker");
+static core::LogWriter vlog("ComparingUpdateTracker");
ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
: fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true),
@@ -50,8 +51,8 @@ ComparingUpdateTracker::~ComparingUpdateTracker()
bool ComparingUpdateTracker::compare()
{
- std::vector<Rect> rects;
- std::vector<Rect>::iterator i;
+ std::vector<core::Rect> rects;
+ std::vector<core::Rect>::iterator i;
if (!enabled)
return false;
@@ -62,7 +63,7 @@ bool ComparingUpdateTracker::compare()
oldFb.setSize(fb->width(), fb->height());
for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
- Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
+ core::Rect pos(0, y, fb->width(), std::min(fb->height(), y+BLOCK_SIZE));
int srcStride;
const uint8_t* srcData = fb->getBuffer(pos, &srcStride);
oldFb.imageRect(pos, srcData, srcStride);
@@ -79,7 +80,7 @@ bool ComparingUpdateTracker::compare()
changed.get_rects(&rects);
- Region newChanged;
+ core::Region newChanged;
for (i = rects.begin(); i != rects.end(); i++)
compareRect(*i, &newChanged);
@@ -111,10 +112,11 @@ void ComparingUpdateTracker::disable()
firstCompare = true;
}
-void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
+void ComparingUpdateTracker::compareRect(const core::Rect& r,
+ core::Region* newChanged)
{
if (!r.enclosed_by(fb->getRect())) {
- Rect safe;
+ core::Rect safe;
// Crop the rect and try again
safe = r.intersect(fb->getRect());
if (!safe.is_empty())
@@ -134,20 +136,20 @@ void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
{
// Get a strip of the source buffer
- Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
+ core::Rect pos(r.tl.x, blockTop, r.br.x, std::min(r.br.y, blockTop+BLOCK_SIZE));
int fbStride;
const uint8_t* newBlockPtr = fb->getBuffer(pos, &fbStride);
int newStrideBytes = fbStride * bytesPerPixel;
uint8_t* oldBlockPtr = oldData;
- int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
+ int blockBottom = std::min(blockTop+BLOCK_SIZE, r.br.y);
for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
{
const uint8_t* newPtr = newBlockPtr;
uint8_t* oldPtr = oldBlockPtr;
- int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
+ int blockRight = std::min(blockLeft+BLOCK_SIZE, r.br.x);
int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
// Scan the block top to bottom, to identify the first row of change
@@ -223,8 +225,10 @@ void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
}
endOfChangeRight:
- // Block change extends from (changeLeft, y) to (changeRight, y + changeHeight)
- newChanged->assign_union(Region(Rect(changeLeft, y, changeRight, y + changeHeight)));
+ // Block change extends from (changeLeft, y) to (changeRight,
+ // y + changeHeight)
+ newChanged->assign_union({{changeLeft, y,
+ changeRight, y + changeHeight}});
// Copy the change from fb to oldFb to allow future changes to be identified
for (int row = 0; row < changeHeight; row++)
@@ -258,10 +262,12 @@ void ComparingUpdateTracker::logStats()
ratio = (double)totalPixels / missedPixels;
- vlog.info("%s in / %s out",
- siPrefix(totalPixels, "pixels").c_str(),
- siPrefix(missedPixels, "pixels").c_str());
- vlog.info("(1:%g ratio)", ratio);
+ // FIXME: This gets spammed on each session resize, so we'll have to
+ // keep it on a debug level for now
+ vlog.debug("%s in / %s out",
+ core::siPrefix(totalPixels, "pixels").c_str(),
+ core::siPrefix(missedPixels, "pixels").c_str());
+ vlog.debug("(1:%g ratio)", ratio);
totalPixels = missedPixels = 0;
}
diff --git a/common/rfb/ComparingUpdateTracker.h b/common/rfb/ComparingUpdateTracker.h
index ca1dcc30..dbe7a4ef 100644
--- a/common/rfb/ComparingUpdateTracker.h
+++ b/common/rfb/ComparingUpdateTracker.h
@@ -19,6 +19,7 @@
#ifndef __RFB_COMPARINGUPDATETRACKER_H__
#define __RFB_COMPARINGUPDATETRACKER_H__
+#include <rfb/PixelBuffer.h>
#include <rfb/UpdateTracker.h>
namespace rfb {
@@ -44,7 +45,7 @@ namespace rfb {
void logStats();
private:
- void compareRect(const Rect& r, Region* newchanged);
+ void compareRect(const core::Rect& r, core::Region* newchanged);
PixelBuffer* fb;
ManagedPixelBuffer oldFb;
bool firstCompare;
diff --git a/common/rfb/Configuration.cxx b/common/rfb/Configuration.cxx
deleted file mode 100644
index 72947df1..00000000
--- a/common/rfb/Configuration.cxx
+++ /dev/null
@@ -1,469 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2004-2005 Cendio AB.
- * Copyright 2017 Peter Astrand <astrand@cendio.se> for Cendio AB
- * Copyright 2011-2022 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-// -=- Configuration.cxx
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <assert.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-
-#include <stdexcept>
-
-#include <os/Mutex.h>
-
-#include <rfb/util.h>
-#include <rfb/Configuration.h>
-#include <rfb/LogWriter.h>
-
-#define LOCK_CONFIG os::AutoMutex a(mutex)
-
-#include <rdr/HexOutStream.h>
-#include <rdr/HexInStream.h>
-
-using namespace rfb;
-
-static LogWriter vlog("Config");
-
-
-// -=- The Global/server/viewer Configuration objects
-Configuration* Configuration::global_ = nullptr;
-Configuration* Configuration::server_ = nullptr;
-Configuration* Configuration::viewer_ = nullptr;
-
-Configuration* Configuration::global() {
- if (!global_)
- global_ = new Configuration("Global");
- return global_;
-}
-
-Configuration* Configuration::server() {
- if (!server_)
- server_ = new Configuration("Server");
- return server_;
-}
-
-Configuration* Configuration::viewer() {
- if (!viewer_)
- viewer_ = new Configuration("Viewer");
- return viewer_;
-}
-
-// -=- Configuration implementation
-
-bool Configuration::set(const char* n, const char* v, bool immutable) {
- return set(n, strlen(n), v, immutable);
-}
-
-bool Configuration::set(const char* paramName, int len,
- const char* val, bool immutable)
-{
- VoidParameter* current = head;
- while (current) {
- if ((int)strlen(current->getName()) == len &&
- strncasecmp(current->getName(), paramName, len) == 0)
- {
- bool b = current->setParam(val);
- if (b && immutable)
- current->setImmutable();
- return b;
- }
- current = current->_next;
- }
- return _next ? _next->set(paramName, len, val, immutable) : false;
-}
-
-bool Configuration::set(const char* config, bool immutable) {
- bool hyphen = false;
- if (config[0] == '-') {
- hyphen = true;
- config++;
- if (config[0] == '-') config++; // allow gnu-style --<option>
- }
- const char* equal = strchr(config, '=');
- if (equal) {
- return set(config, equal-config, equal+1, immutable);
- } else if (hyphen) {
- VoidParameter* current = head;
- while (current) {
- if (strcasecmp(current->getName(), config) == 0) {
- bool b = current->setParam();
- if (b && immutable)
- current->setImmutable();
- return b;
- }
- current = current->_next;
- }
- }
- return _next ? _next->set(config, immutable) : false;
-}
-
-VoidParameter* Configuration::get(const char* param)
-{
- VoidParameter* current = head;
- while (current) {
- if (strcasecmp(current->getName(), param) == 0)
- return current;
- current = current->_next;
- }
- return _next ? _next->get(param) : nullptr;
-}
-
-void Configuration::list(int width, int nameWidth) {
- VoidParameter* current = head;
-
- fprintf(stderr, "%s Parameters:\n", name.c_str());
- while (current) {
- std::string def_str = current->getDefaultStr();
- const char* desc = current->getDescription();
- fprintf(stderr," %-*s -", nameWidth, current->getName());
- int column = strlen(current->getName());
- if (column < nameWidth) column = nameWidth;
- column += 4;
- while (true) {
- const char* s = strchr(desc, ' ');
- int wordLen;
- if (s) wordLen = s-desc;
- else wordLen = strlen(desc);
-
- if (column + wordLen + 1 > width) {
- fprintf(stderr,"\n%*s",nameWidth+4,"");
- column = nameWidth+4;
- }
- fprintf(stderr," %.*s",wordLen,desc);
- column += wordLen + 1;
- desc += wordLen + 1;
- if (!s) break;
- }
-
- if (!def_str.empty()) {
- if (column + (int)def_str.size() + 11 > width)
- fprintf(stderr,"\n%*s",nameWidth+4,"");
- fprintf(stderr," (default=%s)\n",def_str.c_str());
- } else {
- fprintf(stderr,"\n");
- }
- current = current->_next;
- }
-
- if (_next)
- _next->list(width, nameWidth);
-}
-
-
-bool Configuration::remove(const char* param) {
- VoidParameter *current = head;
- VoidParameter **prevnext = &head;
-
- while (current) {
- if (strcasecmp(current->getName(), param) == 0) {
- *prevnext = current->_next;
- return true;
- }
- prevnext = &current->_next;
- current = current->_next;
- }
-
- return false;
-}
-
-
-// -=- VoidParameter
-
-VoidParameter::VoidParameter(const char* name_, const char* desc_,
- ConfigurationObject co)
- : immutable(false), name(name_), description(desc_)
-{
- Configuration *conf = nullptr;
-
- switch (co) {
- case ConfGlobal: conf = Configuration::global();
- break;
- case ConfServer: conf = Configuration::server();
- break;
- case ConfViewer: conf = Configuration::viewer();
- break;
- }
-
- _next = conf->head;
- conf->head = this;
-
- mutex = new os::Mutex();
-}
-
-VoidParameter::~VoidParameter() {
- delete mutex;
-}
-
-const char*
-VoidParameter::getName() const {
- return name;
-}
-
-const char*
-VoidParameter::getDescription() const {
- return description;
-}
-
-bool VoidParameter::setParam() {
- return false;
-}
-
-bool VoidParameter::isBool() const {
- return false;
-}
-
-void
-VoidParameter::setImmutable() {
- vlog.debug("Set immutable %s", getName());
- immutable = true;
-}
-
-// -=- AliasParameter
-
-AliasParameter::AliasParameter(const char* name_, const char* desc_,
- VoidParameter* param_, ConfigurationObject co)
- : VoidParameter(name_, desc_, co), param(param_) {
-}
-
-bool
-AliasParameter::setParam(const char* v) {
- return param->setParam(v);
-}
-
-bool AliasParameter::setParam() {
- return param->setParam();
-}
-
-std::string AliasParameter::getDefaultStr() const {
- return "";
-}
-
-std::string AliasParameter::getValueStr() const {
- return param->getValueStr();
-}
-
-bool AliasParameter::isBool() const {
- return param->isBool();
-}
-
-void
-AliasParameter::setImmutable() {
- vlog.debug("Set immutable %s (Alias)", getName());
- param->setImmutable();
-}
-
-
-// -=- BoolParameter
-
-BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v,
- ConfigurationObject co)
-: VoidParameter(name_, desc_, co), value(v), def_value(v) {
-}
-
-bool
-BoolParameter::setParam(const char* v) {
- if (immutable) return true;
-
- if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
- || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
- setParam(true);
- else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
- || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
- setParam(false);
- else {
- vlog.error("Bool parameter %s: Invalid value '%s'", getName(), v);
- return false;
- }
-
- return true;
-}
-
-bool BoolParameter::setParam() {
- setParam(true);
- return true;
-}
-
-void BoolParameter::setParam(bool b) {
- if (immutable) return;
- value = b;
- vlog.debug("Set %s(Bool) to %d", getName(), value);
-}
-
-std::string BoolParameter::getDefaultStr() const {
- return def_value ? "1" : "0";
-}
-
-std::string BoolParameter::getValueStr() const {
- return value ? "1" : "0";
-}
-
-bool BoolParameter::isBool() const {
- return true;
-}
-
-BoolParameter::operator bool() const {
- return value;
-}
-
-// -=- IntParameter
-
-IntParameter::IntParameter(const char* name_, const char* desc_, int v,
- int minValue_, int maxValue_, ConfigurationObject co)
- : VoidParameter(name_, desc_, co), value(v), def_value(v),
- minValue(minValue_), maxValue(maxValue_)
-{
-}
-
-bool
-IntParameter::setParam(const char* v) {
- if (immutable) return true;
- return setParam(strtol(v, nullptr, 0));
-}
-
-bool
-IntParameter::setParam(int v) {
- if (immutable) return true;
- vlog.debug("Set %s(Int) to %d", getName(), v);
- if (v < minValue || v > maxValue)
- return false;
- value = v;
- return true;
-}
-
-std::string IntParameter::getDefaultStr() const {
- char result[16];
- sprintf(result, "%d", def_value);
- return result;
-}
-
-std::string IntParameter::getValueStr() const {
- char result[16];
- sprintf(result, "%d", value);
- return result;
-}
-
-IntParameter::operator int() const {
- return value;
-}
-
-// -=- StringParameter
-
-StringParameter::StringParameter(const char* name_, const char* desc_,
- const char* v, ConfigurationObject co)
- : VoidParameter(name_, desc_, co), value(v), def_value(v)
-{
- if (!v) {
- vlog.error("Default value <null> for %s not allowed",name_);
- throw std::invalid_argument("Default value <null> not allowed");
- }
-}
-
-StringParameter::~StringParameter() {
-}
-
-bool StringParameter::setParam(const char* v) {
- LOCK_CONFIG;
- if (immutable) return true;
- if (!v)
- throw std::invalid_argument("setParam(<null>) not allowed");
- vlog.debug("Set %s(String) to %s", getName(), v);
- value = v;
- return true;
-}
-
-std::string StringParameter::getDefaultStr() const {
- return def_value;
-}
-
-std::string StringParameter::getValueStr() const {
- LOCK_CONFIG;
- return value;
-}
-
-StringParameter::operator const char *() const {
- return value.c_str();
-}
-
-// -=- BinaryParameter
-
-BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
- const uint8_t* v, size_t l, ConfigurationObject co)
-: VoidParameter(name_, desc_, co),
- value(nullptr), length(0), def_value(nullptr), def_length(0) {
- if (l) {
- assert(v);
- value = new uint8_t[l];
- length = l;
- memcpy(value, v, l);
- def_value = new uint8_t[l];
- def_length = l;
- memcpy(def_value, v, l);
- }
-}
-BinaryParameter::~BinaryParameter() {
- delete [] value;
- delete [] def_value;
-}
-
-bool BinaryParameter::setParam(const char* v) {
- if (immutable) return true;
- std::vector<uint8_t> newValue = hexToBin(v, strlen(v));
- if (newValue.empty() && strlen(v) > 0)
- return false;
- setParam(newValue.data(), newValue.size());
- return true;
-}
-
-void BinaryParameter::setParam(const uint8_t* v, size_t len) {
- LOCK_CONFIG;
- if (immutable) return;
- vlog.debug("Set %s(Binary)", getName());
- delete [] value;
- value = nullptr;
- length = 0;
- if (len) {
- assert(v);
- value = new uint8_t[len];
- length = len;
- memcpy(value, v, len);
- }
-}
-
-std::string BinaryParameter::getDefaultStr() const {
- return binToHex(def_value, def_length);
-}
-
-std::string BinaryParameter::getValueStr() const {
- LOCK_CONFIG;
- return binToHex(value, length);
-}
-
-std::vector<uint8_t> BinaryParameter::getData() const {
- LOCK_CONFIG;
- std::vector<uint8_t> out(length);
- memcpy(out.data(), value, length);
- return out;
-}
diff --git a/common/rfb/Congestion.cxx b/common/rfb/Congestion.cxx
index 94f07055..46bae00d 100644
--- a/common/rfb/Congestion.cxx
+++ b/common/rfb/Congestion.cxx
@@ -49,9 +49,10 @@
#include <linux/sockios.h>
#endif
+#include <core/LogWriter.h>
+#include <core/time.h>
+
#include <rfb/Congestion.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
// Debug output on what the congestion control is up to
#undef CONGESTION_DEBUG
@@ -78,7 +79,7 @@ static inline bool isAfter(unsigned a, unsigned b) {
return a != b && a - b <= UINT_MAX / 2;
}
-static LogWriter vlog("Congestion");
+static core::LogWriter vlog("Congestion");
Congestion::Congestion() :
lastPosition(0), extraBuffer(0),
@@ -99,7 +100,7 @@ Congestion::~Congestion()
void Congestion::updatePosition(unsigned pos)
{
struct timeval now;
- unsigned delta, consumed;
+ unsigned idle, delta, consumed;
gettimeofday(&now, nullptr);
@@ -110,15 +111,17 @@ void Congestion::updatePosition(unsigned pos)
// Idle for too long?
// We use a very crude RTO calculation in order to keep things simple
// FIXME: should implement RFC 2861
- if (msBetween(&lastSent, &now) > __rfbmax(baseRTT*2, 100)) {
+ idle = core::msBetween(&lastSent, &now);
+ if (idle > 100 && idle > baseRTT*2) {
#ifdef CONGESTION_DEBUG
vlog.debug("Connection idle for %d ms, resetting congestion control",
- msBetween(&lastSent, &now));
+ idle);
#endif
// Close congestion window and redo wire latency measurement
- congWindow = __rfbmin(INITIAL_WINDOW, congWindow);
+ if (congWindow > INITIAL_WINDOW)
+ congWindow = INITIAL_WINDOW;
baseRTT = -1;
measurements = 0;
gettimeofday(&lastAdjustment, nullptr);
@@ -132,7 +135,7 @@ void Congestion::updatePosition(unsigned pos)
// (we cannot do this until we have a RTT measurement though)
if (baseRTT != (unsigned)-1) {
extraBuffer += delta;
- consumed = msBetween(&lastUpdate, &now) * congWindow / baseRTT;
+ consumed = core::msBetween(&lastUpdate, &now) * congWindow / baseRTT;
if (extraBuffer < consumed)
extraBuffer = 0;
else
@@ -174,7 +177,7 @@ void Congestion::gotPong()
lastPong = rttInfo;
lastPongArrival = now;
- rtt = msBetween(&rttInfo.tv, &now);
+ rtt = core::msBetween(&rttInfo.tv, &now);
if (rtt < 1)
rtt = 1;
@@ -184,7 +187,7 @@ void Congestion::gotPong()
// Pings sent before the last adjustment aren't interesting as they
// aren't a measurement of the current congestion window
- if (isBefore(&rttInfo.tv, &lastAdjustment))
+ if (core::isBefore(&rttInfo.tv, &lastAdjustment))
return;
// Estimate added delay because of overtaxed buffers (see above)
@@ -249,7 +252,7 @@ int Congestion::getUncongestedETA()
prevPing = &lastPong;
eta = 0;
- elapsed = msSince(&lastPongArrival);
+ elapsed = core::msSince(&lastPongArrival);
// Walk the ping queue and figure out which one we are waiting for to
// get to an uncongested state
@@ -268,7 +271,7 @@ int Congestion::getUncongestedETA()
curPing = *iter;
}
- etaNext = msBetween(&prevPing->tv, &curPing.tv);
+ etaNext = core::msBetween(&prevPing->tv, &curPing.tv);
// Compensate for buffering delays
delay = curPing.extra * baseRTT / congWindow;
etaNext += delay;
@@ -349,7 +352,7 @@ unsigned Congestion::getExtraBuffer()
if (baseRTT == (unsigned)-1)
return 0;
- elapsed = msSince(&lastUpdate);
+ elapsed = core::msSince(&lastUpdate);
consumed = elapsed * congWindow / baseRTT;
if (consumed >= extraBuffer)
@@ -389,7 +392,7 @@ unsigned Congestion::getInFlight()
// completely. Look at the next ping that should arrive and figure
// out how far behind it should be and interpolate the positions.
- etaNext = msBetween(&lastPong.tv, &nextPong.tv);
+ etaNext = core::msBetween(&lastPong.tv, &nextPong.tv);
// Compensate for buffering delays
delay = nextPong.extra * baseRTT / congWindow;
etaNext += delay;
@@ -399,7 +402,7 @@ unsigned Congestion::getInFlight()
else
etaNext -= delay;
- elapsed = msSince(&lastPongArrival);
+ elapsed = core::msSince(&lastPongArrival);
// The pong should be here any second. Be optimistic and assume
// we can already use its value.
@@ -430,7 +433,7 @@ void Congestion::updateCongestion()
diff = minRTT - baseRTT;
- if (diff > __rfbmax(100, baseRTT/2)) {
+ if (diff > 100 && diff > baseRTT/2) {
// We have no way of detecting loss, so assume massive latency
// spike means packet loss. Adjust the window and go directly
// to congestion avoidance.
diff --git a/common/rfb/CopyRectDecoder.cxx b/common/rfb/CopyRectDecoder.cxx
index a7383881..efc77c99 100644
--- a/common/rfb/CopyRectDecoder.cxx
+++ b/common/rfb/CopyRectDecoder.cxx
@@ -20,10 +20,12 @@
#include <config.h>
#endif
+#include <core/Region.h>
+
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>
+
#include <rfb/PixelBuffer.h>
-#include <rfb/Region.h>
#include <rfb/CopyRectDecoder.h>
using namespace rfb;
@@ -36,7 +38,7 @@ CopyRectDecoder::~CopyRectDecoder()
{
}
-bool CopyRectDecoder::readRect(const Rect& /*r*/,
+bool CopyRectDecoder::readRect(const core::Rect& /*r*/,
rdr::InStream* is,
const ServerParams& /*server*/,
rdr::OutStream* os)
@@ -48,11 +50,11 @@ bool CopyRectDecoder::readRect(const Rect& /*r*/,
}
-void CopyRectDecoder::getAffectedRegion(const Rect& rect,
+void CopyRectDecoder::getAffectedRegion(const core::Rect& rect,
const uint8_t* buffer,
size_t buflen,
const ServerParams& server,
- Region* region)
+ core::Region* region)
{
rdr::MemInStream is(buffer, buflen);
int srcX = is.readU16();
@@ -60,11 +62,12 @@ void CopyRectDecoder::getAffectedRegion(const Rect& rect,
Decoder::getAffectedRegion(rect, buffer, buflen, server, region);
- region->assign_union(Region(rect.translate(Point(srcX-rect.tl.x,
- srcY-rect.tl.y))));
+ region->assign_union(rect.translate({srcX-rect.tl.x,
+ srcY-rect.tl.y}));
}
-void CopyRectDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
+void CopyRectDecoder::decodeRect(const core::Rect& r,
+ const uint8_t* buffer,
size_t buflen,
const ServerParams& /*server*/,
ModifiablePixelBuffer* pb)
@@ -72,5 +75,5 @@ void CopyRectDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
rdr::MemInStream is(buffer, buflen);
int srcX = is.readU16();
int srcY = is.readU16();
- pb->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+ pb->copyRect(r, {r.tl.x-srcX, r.tl.y-srcY});
}
diff --git a/common/rfb/CopyRectDecoder.h b/common/rfb/CopyRectDecoder.h
index 51651196..b1d0d38d 100644
--- a/common/rfb/CopyRectDecoder.h
+++ b/common/rfb/CopyRectDecoder.h
@@ -26,13 +26,13 @@ namespace rfb {
public:
CopyRectDecoder();
virtual ~CopyRectDecoder();
- bool readRect(const Rect& r, rdr::InStream* is,
+ bool readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server,
rdr::OutStream* os) override;
- void getAffectedRegion(const Rect& rect, const uint8_t* buffer,
+ void getAffectedRegion(const core::Rect& rect, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
- Region* region) override;
- void decodeRect(const Rect& r, const uint8_t* buffer,
+ core::Region* region) override;
+ void decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) override;
};
diff --git a/common/rfb/Cursor.cxx b/common/rfb/Cursor.cxx
index 94844144..e094e4ed 100644
--- a/common/rfb/Cursor.cxx
+++ b/common/rfb/Cursor.cxx
@@ -26,14 +26,15 @@
#include <stdexcept>
+#include <core/LogWriter.h>
+
#include <rfb/Cursor.h>
-#include <rfb/LogWriter.h>
using namespace rfb;
-static LogWriter vlog("Cursor");
+static core::LogWriter vlog("Cursor");
-Cursor::Cursor(int width, int height, const Point& hotspot,
+Cursor::Cursor(int width, int height, const core::Point& hotspot,
const uint8_t* data_) :
width_(width), height_(height), hotspot_(hotspot)
{
@@ -215,9 +216,9 @@ std::vector<uint8_t> Cursor::getMask() const
void Cursor::crop()
{
- Rect busy = Rect(0, 0, width_, height_);
- busy = busy.intersect(Rect(hotspot_.x, hotspot_.y,
- hotspot_.x+1, hotspot_.y+1));
+ core::Rect busy(0, 0, width_, height_);
+ busy = busy.intersect({hotspot_.x, hotspot_.y,
+ hotspot_.x+1, hotspot_.y+1});
int x, y;
uint8_t *data_ptr = data;
for (y = 0; y < height(); y++) {
@@ -255,9 +256,10 @@ RenderedCursor::RenderedCursor()
{
}
-const uint8_t* RenderedCursor::getBuffer(const Rect& _r, int* stride) const
+const uint8_t* RenderedCursor::getBuffer(const core::Rect& _r,
+ int* stride) const
{
- Rect r;
+ core::Rect r;
r = _r.translate(offset.negate());
if (!r.enclosed_by(buffer.getRect()))
@@ -267,10 +269,10 @@ const uint8_t* RenderedCursor::getBuffer(const Rect& _r, int* stride) const
}
void RenderedCursor::update(PixelBuffer* framebuffer,
- Cursor* cursor, const Point& pos)
+ Cursor* cursor, const core::Point& pos)
{
- Point rawOffset, diff;
- Rect clippedRect;
+ core::Point rawOffset, diff;
+ core::Rect clippedRect;
const uint8_t* data;
int stride;
@@ -282,7 +284,7 @@ void RenderedCursor::update(PixelBuffer* framebuffer,
setSize(framebuffer->width(), framebuffer->height());
rawOffset = pos.subtract(cursor->hotspot());
- clippedRect = Rect(0, 0, cursor->width(), cursor->height())
+ clippedRect = core::Rect(0, 0, cursor->width(), cursor->height())
.translate(rawOffset)
.intersect(framebuffer->getRect());
offset = clippedRect.tl;
@@ -313,7 +315,7 @@ void RenderedCursor::update(PixelBuffer* framebuffer,
else if (fg[3] == 0xff) {
memcpy(rgb, fg, 3);
} else {
- buffer.getImage(bg, Rect(x, y, x+1, y+1));
+ buffer.getImage(bg, {x, y, x+1, y+1});
format.rgbFromBuffer(rgb, bg, 1);
// FIXME: Gamma aware blending
for (int i = 0;i < 3;i++) {
@@ -323,7 +325,7 @@ void RenderedCursor::update(PixelBuffer* framebuffer,
}
format.bufferFromRGB(bg, rgb, 1);
- buffer.imageRect(Rect(x, y, x+1, y+1), bg);
+ buffer.imageRect({x, y, x+1, y+1}, bg);
}
}
}
diff --git a/common/rfb/Cursor.h b/common/rfb/Cursor.h
index c71f5a77..ef3c1b80 100644
--- a/common/rfb/Cursor.h
+++ b/common/rfb/Cursor.h
@@ -26,19 +26,22 @@
#include <vector>
+#include <core/Rect.h>
+
#include <rfb/PixelBuffer.h>
namespace rfb {
class Cursor {
public:
- Cursor(int width, int height, const Point& hotspot, const uint8_t* data);
+ Cursor(int width, int height, const core::Point& hotspot,
+ const uint8_t* data);
Cursor(const Cursor& other);
~Cursor();
int width() const { return width_; };
int height() const { return height_; };
- const Point& hotspot() const { return hotspot_; };
+ const core::Point& hotspot() const { return hotspot_; };
const uint8_t* getBuffer() const { return data; };
// getBitmap() returns a monochrome version of the cursor
@@ -52,7 +55,7 @@ namespace rfb {
protected:
int width_, height_;
- Point hotspot_;
+ core::Point hotspot_;
uint8_t* data;
};
@@ -60,15 +63,16 @@ namespace rfb {
public:
RenderedCursor();
- Rect getEffectiveRect() const { return buffer.getRect(offset); }
+ core::Rect getEffectiveRect() const { return buffer.getRect(offset); }
- const uint8_t* getBuffer(const Rect& r, int* stride) const override;
+ const uint8_t* getBuffer(const core::Rect& r, int* stride) const override;
- void update(PixelBuffer* framebuffer, Cursor* cursor, const Point& pos);
+ void update(PixelBuffer* framebuffer, Cursor* cursor,
+ const core::Point& pos);
protected:
ManagedPixelBuffer buffer;
- Point offset;
+ core::Point offset;
};
}
diff --git a/common/rfb/DecodeManager.cxx b/common/rfb/DecodeManager.cxx
index 4effe985..48181f94 100644
--- a/common/rfb/DecodeManager.cxx
+++ b/common/rfb/DecodeManager.cxx
@@ -23,22 +23,20 @@
#include <assert.h>
#include <string.h>
+#include <core/LogWriter.h>
+#include <core/Region.h>
+#include <core/string.h>
+
#include <rfb/CConnection.h>
#include <rfb/DecodeManager.h>
#include <rfb/Decoder.h>
#include <rfb/Exception.h>
-#include <rfb/Region.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
-#include <rdr/Exception.h>
#include <rdr/MemOutStream.h>
-#include <os/Mutex.h>
-
using namespace rfb;
-static LogWriter vlog("DecodeManager");
+static core::LogWriter vlog("DecodeManager");
DecodeManager::DecodeManager(CConnection *conn_) :
conn(conn_), threadException(nullptr)
@@ -49,11 +47,7 @@ DecodeManager::DecodeManager(CConnection *conn_) :
memset(stats, 0, sizeof(stats));
- queueMutex = new os::Mutex();
- producerCond = new os::Condition(queueMutex);
- consumerCond = new os::Condition(queueMutex);
-
- cpuCount = os::Thread::getSystemCPUCount();
+ cpuCount = std::thread::hardware_concurrency();
if (cpuCount == 0) {
vlog.error("Unable to determine the number of CPU cores on this system");
cpuCount = 1;
@@ -86,22 +80,16 @@ DecodeManager::~DecodeManager()
threads.pop_back();
}
- delete threadException;
-
while (!freeBuffers.empty()) {
delete freeBuffers.back();
freeBuffers.pop_back();
}
- delete consumerCond;
- delete producerCond;
- delete queueMutex;
-
for (Decoder* decoder : decoders)
delete decoder;
}
-bool DecodeManager::decodeRect(const Rect& r, int encoding,
+bool DecodeManager::decodeRect(const core::Rect& r, int encoding,
ModifiablePixelBuffer* pb)
{
Decoder *decoder;
@@ -128,29 +116,25 @@ bool DecodeManager::decodeRect(const Rect& r, int encoding,
decoder = decoders[encoding];
// Wait for an available memory buffer
- queueMutex->lock();
+ std::unique_lock<std::mutex> lock(queueMutex);
// FIXME: Should we return and let other things run here?
while (freeBuffers.empty())
- producerCond->wait();
+ producerCond.wait(lock);
// Don't pop the buffer in case we throw an exception
// whilst reading
bufferStream = freeBuffers.front();
- queueMutex->unlock();
+ lock.unlock();
// First check if any thread has encountered a problem
throwThreadException();
// Read the rect
bufferStream->clear();
- try {
- if (!decoder->readRect(r, conn->getInStream(), conn->server, bufferStream))
- return false;
- } catch (std::exception& e) {
- throw std::runtime_error(format("Error reading rect: %s", e.what()));
- }
+ if (!decoder->readRect(r, conn->getInStream(), conn->server, bufferStream))
+ return false;
stats[encoding].rects++;
stats[encoding].bytes += 12 + bufferStream->length();
@@ -173,7 +157,7 @@ bool DecodeManager::decodeRect(const Rect& r, int encoding,
bufferStream->length(), conn->server,
&entry->affectedRegion);
- queueMutex->lock();
+ lock.lock();
// The workers add buffers to the end so it's safe to assume
// the front is still the same buffer
@@ -183,21 +167,21 @@ bool DecodeManager::decodeRect(const Rect& r, int encoding,
// We only put a single entry on the queue so waking a single
// thread is sufficient
- consumerCond->signal();
+ consumerCond.notify_one();
- queueMutex->unlock();
+ lock.unlock();
return true;
}
void DecodeManager::flush()
{
- queueMutex->lock();
+ std::unique_lock<std::mutex> lock(queueMutex);
while (!workQueue.empty())
- producerCond->wait();
+ producerCond.wait(lock);
- queueMutex->unlock();
+ lock.unlock();
throwThreadException();
}
@@ -227,49 +211,49 @@ void DecodeManager::logStats()
ratio = (double)stats[i].equivalent / stats[i].bytes;
vlog.info(" %s: %s, %s", encodingName(i),
- siPrefix(stats[i].rects, "rects").c_str(),
- siPrefix(stats[i].pixels, "pixels").c_str());
+ core::siPrefix(stats[i].rects, "rects").c_str(),
+ core::siPrefix(stats[i].pixels, "pixels").c_str());
vlog.info(" %*s %s (1:%g ratio)",
(int)strlen(encodingName(i)), "",
- iecPrefix(stats[i].bytes, "B").c_str(), ratio);
+ core::iecPrefix(stats[i].bytes, "B").c_str(), ratio);
}
ratio = (double)equivalent / bytes;
vlog.info(" Total: %s, %s",
- siPrefix(rects, "rects").c_str(),
- siPrefix(pixels, "pixels").c_str());
+ core::siPrefix(rects, "rects").c_str(),
+ core::siPrefix(pixels, "pixels").c_str());
vlog.info(" %s (1:%g ratio)",
- iecPrefix(bytes, "B").c_str(), ratio);
+ core::iecPrefix(bytes, "B").c_str(), ratio);
}
-void DecodeManager::setThreadException(const std::exception& e)
+void DecodeManager::setThreadException()
{
- os::AutoMutex a(queueMutex);
+ const std::lock_guard<std::mutex> lock(queueMutex);
- if (threadException != nullptr)
+ if (threadException)
return;
- threadException = new std::runtime_error(format("Exception on worker thread: %s", e.what()));
+ threadException = std::current_exception();
}
void DecodeManager::throwThreadException()
{
- os::AutoMutex a(queueMutex);
+ const std::lock_guard<std::mutex> lock(queueMutex);
- if (threadException == nullptr)
+ if (!threadException)
return;
- std::runtime_error e(threadException->what());
-
- delete threadException;
- threadException = nullptr;
-
- throw e;
+ try {
+ std::rethrow_exception(threadException);
+ } catch (...) {
+ threadException = nullptr;
+ throw;
+ }
}
DecodeManager::DecodeThread::DecodeThread(DecodeManager* manager_)
- : manager(manager_), stopRequested(false)
+ : manager(manager_), thread(nullptr), stopRequested(false)
{
start();
}
@@ -277,25 +261,35 @@ DecodeManager::DecodeThread::DecodeThread(DecodeManager* manager_)
DecodeManager::DecodeThread::~DecodeThread()
{
stop();
- wait();
+ if (thread != nullptr) {
+ thread->join();
+ delete thread;
+ }
+}
+
+void DecodeManager::DecodeThread::start()
+{
+ assert(thread == nullptr);
+
+ thread = new std::thread(&DecodeThread::worker, this);
}
void DecodeManager::DecodeThread::stop()
{
- os::AutoMutex a(manager->queueMutex);
+ const std::lock_guard<std::mutex> lock(manager->queueMutex);
- if (!isRunning())
+ if (thread == nullptr)
return;
stopRequested = true;
// We can't wake just this thread, so wake everyone
- manager->consumerCond->broadcast();
+ manager->consumerCond.notify_all();
}
void DecodeManager::DecodeThread::worker()
{
- manager->queueMutex->lock();
+ std::unique_lock<std::mutex> lock(manager->queueMutex);
while (!stopRequested) {
DecodeManager::QueueEntry *entry;
@@ -304,14 +298,14 @@ void DecodeManager::DecodeThread::worker()
entry = findEntry();
if (entry == nullptr) {
// Wait and try again
- manager->consumerCond->wait();
+ manager->consumerCond.wait(lock);
continue;
}
// This is ours now
entry->active = true;
- manager->queueMutex->unlock();
+ lock.unlock();
// Do the actual decoding
try {
@@ -319,12 +313,12 @@ void DecodeManager::DecodeThread::worker()
entry->bufferStream->length(),
*entry->server, entry->pb);
} catch (std::exception& e) {
- manager->setThreadException(e);
+ manager->setThreadException();
} catch(...) {
assert(false);
}
- manager->queueMutex->lock();
+ lock.lock();
// Remove the entry from the queue and give back the memory buffer
manager->freeBuffers.push_back(entry->bufferStream);
@@ -332,19 +326,17 @@ void DecodeManager::DecodeThread::worker()
delete entry;
// Wake the main thread in case it is waiting for a memory buffer
- manager->producerCond->signal();
+ manager->producerCond.notify_one();
// This rect might have been blocking multiple other rects, so
// wake up every worker thread
if (manager->workQueue.size() > 1)
- manager->consumerCond->broadcast();
+ manager->consumerCond.notify_all();
}
-
- manager->queueMutex->unlock();
}
DecodeManager::QueueEntry* DecodeManager::DecodeThread::findEntry()
{
- Region lockedRegion;
+ core::Region lockedRegion;
if (manager->workQueue.empty())
return nullptr;
diff --git a/common/rfb/DecodeManager.h b/common/rfb/DecodeManager.h
index b11b7044..146bf8ae 100644
--- a/common/rfb/DecodeManager.h
+++ b/common/rfb/DecodeManager.h
@@ -19,16 +19,18 @@
#ifndef __RFB_DECODEMANAGER_H__
#define __RFB_DECODEMANAGER_H__
+#include <condition_variable>
+#include <exception>
#include <list>
+#include <mutex>
+#include <thread>
-#include <os/Thread.h>
+#include <core/Region.h>
-#include <rfb/Region.h>
#include <rfb/encodings.h>
-namespace os {
- class Condition;
- class Mutex;
+namespace core {
+ struct Rect;
}
namespace rdr {
@@ -36,17 +38,17 @@ namespace rdr {
}
namespace rfb {
+
class CConnection;
class Decoder;
class ModifiablePixelBuffer;
- struct Rect;
class DecodeManager {
public:
DecodeManager(CConnection *conn);
~DecodeManager();
- bool decodeRect(const Rect& r, int encoding,
+ bool decodeRect(const core::Rect& r, int encoding,
ModifiablePixelBuffer* pb);
void flush();
@@ -54,7 +56,7 @@ namespace rfb {
private:
void logStats();
- void setThreadException(const std::exception& e);
+ void setThreadException();
void throwThreadException();
private:
@@ -72,43 +74,46 @@ namespace rfb {
struct QueueEntry {
bool active;
- Rect rect;
+ core::Rect rect;
int encoding;
Decoder* decoder;
const ServerParams* server;
ModifiablePixelBuffer* pb;
rdr::MemOutStream* bufferStream;
- Region affectedRegion;
+ core::Region affectedRegion;
};
std::list<rdr::MemOutStream*> freeBuffers;
std::list<QueueEntry*> workQueue;
- os::Mutex* queueMutex;
- os::Condition* producerCond;
- os::Condition* consumerCond;
+ std::mutex queueMutex;
+ std::condition_variable producerCond;
+ std::condition_variable consumerCond;
private:
- class DecodeThread : public os::Thread {
+ class DecodeThread {
public:
DecodeThread(DecodeManager* manager);
~DecodeThread();
+ void start();
void stop();
protected:
- void worker() override;
+ void worker();
DecodeManager::QueueEntry* findEntry();
private:
DecodeManager* manager;
+ std::thread* thread;
bool stopRequested;
};
std::list<DecodeThread*> threads;
- std::exception *threadException;
+ std::exception_ptr threadException;
};
+
}
#endif
diff --git a/common/rfb/Decoder.cxx b/common/rfb/Decoder.cxx
index e9bc9a4f..0f1cde89 100644
--- a/common/rfb/Decoder.cxx
+++ b/common/rfb/Decoder.cxx
@@ -22,8 +22,10 @@
#endif
#include <stdio.h>
+
+#include <core/Region.h>
+
#include <rfb/encodings.h>
-#include <rfb/Region.h>
#include <rfb/Decoder.h>
#include <rfb/RawDecoder.h>
#include <rfb/CopyRectDecoder.h>
@@ -45,19 +47,19 @@ Decoder::~Decoder()
{
}
-void Decoder::getAffectedRegion(const Rect& rect,
+void Decoder::getAffectedRegion(const core::Rect& rect,
const uint8_t* /*buffer*/,
size_t /*buflen*/,
const ServerParams& /*server*/,
- Region* region)
+ core::Region* region)
{
region->reset(rect);
}
-bool Decoder::doRectsConflict(const Rect& /*rectA*/,
+bool Decoder::doRectsConflict(const core::Rect& /*rectA*/,
const uint8_t* /*bufferA*/,
size_t /*buflenA*/,
- const Rect& /*rectB*/,
+ const core::Rect& /*rectB*/,
const uint8_t* /*bufferB*/,
size_t /*buflenB*/,
const ServerParams& /*server*/)
diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h
index 77987737..17d5296b 100644
--- a/common/rfb/Decoder.h
+++ b/common/rfb/Decoder.h
@@ -19,19 +19,23 @@
#ifndef __RFB_DECODER_H__
#define __RFB_DECODER_H__
+#include <stddef.h>
#include <stdint.h>
+namespace core {
+ class Region;
+ struct Rect;
+}
+
namespace rdr {
class InStream;
class OutStream;
}
namespace rfb {
+
class ServerParams;
class ModifiablePixelBuffer;
- class Region;
-
- struct Rect;
enum DecoderFlags {
// A constant for decoders that don't need anything special
@@ -54,7 +58,7 @@ namespace rfb {
// InStream to the OutStream, possibly changing it along the way to
// make it easier to decode. This function will always be called in
// a serial manner on the main thread.
- virtual bool readRect(const Rect& r, rdr::InStream* is,
+ virtual bool readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os)=0;
// These functions will be called from any of the worker threads.
@@ -64,17 +68,17 @@ namespace rfb {
// getAffectedRegion() returns the parts of the frame buffer will
// be either read from or written do when decoding this rect. The
// default implementation simply returns the given rectangle.
- virtual void getAffectedRegion(const Rect& rect, const uint8_t* buffer,
+ virtual void getAffectedRegion(const core::Rect& rect, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
- Region* region);
+ core::Region* region);
// doesRectsConflict() determines if two rectangles must be decoded
// in the order they were received. This will only be called if the
// DecoderPartiallyOrdered flag has been set.
- virtual bool doRectsConflict(const Rect& rectA,
+ virtual bool doRectsConflict(const core::Rect& rectA,
const uint8_t* bufferA,
size_t buflenA,
- const Rect& rectB,
+ const core::Rect& rectB,
const uint8_t* bufferB,
size_t buflenB,
const ServerParams& server);
@@ -83,7 +87,7 @@ namespace rfb {
// given buffer, onto the ModifiablePixelBuffer. The PixelFormat of
// the PixelBuffer might not match the ConnParams and it is up to
// the decoder to do any necessary conversion.
- virtual void decodeRect(const Rect& r, const uint8_t* buffer,
+ virtual void decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)=0;
@@ -94,6 +98,7 @@ namespace rfb {
public:
const enum DecoderFlags flags;
};
+
}
#endif
diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx
index 67a32f5b..6a63fa6f 100644
--- a/common/rfb/EncodeManager.cxx
+++ b/common/rfb/EncodeManager.cxx
@@ -25,14 +25,17 @@
#include <stdlib.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
+#include <rfb/Cursor.h>
#include <rfb/EncodeManager.h>
#include <rfb/Encoder.h>
#include <rfb/Palette.h>
#include <rfb/SConnection.h>
#include <rfb/SMsgWriter.h>
#include <rfb/UpdateTracker.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+#include <rfb/encodings.h>
#include <rfb/RawEncoder.h>
#include <rfb/RREEncoder.h>
@@ -43,7 +46,7 @@
using namespace rfb;
-static LogWriter vlog("EncodeManager");
+static core::LogWriter vlog("EncodeManager");
// Split each rectangle into smaller ones no larger than this area,
// and no wider than this width.
@@ -191,11 +194,11 @@ void EncodeManager::logStats()
ratio = (double)copyStats.equivalent / copyStats.bytes;
vlog.info(" %s: %s, %s", "Copies",
- siPrefix(copyStats.rects, "rects").c_str(),
- siPrefix(copyStats.pixels, "pixels").c_str());
+ core::siPrefix(copyStats.rects, "rects").c_str(),
+ core::siPrefix(copyStats.pixels, "pixels").c_str());
vlog.info(" %*s %s (1:%g ratio)",
(int)strlen("Copies"), "",
- iecPrefix(copyStats.bytes, "B").c_str(), ratio);
+ core::iecPrefix(copyStats.bytes, "B").c_str(), ratio);
}
for (i = 0;i < stats.size();i++) {
@@ -221,21 +224,21 @@ void EncodeManager::logStats()
ratio = (double)stats[i][j].equivalent / stats[i][j].bytes;
vlog.info(" %s: %s, %s", encoderTypeName((EncoderType)j),
- siPrefix(stats[i][j].rects, "rects").c_str(),
- siPrefix(stats[i][j].pixels, "pixels").c_str());
+ core::siPrefix(stats[i][j].rects, "rects").c_str(),
+ core::siPrefix(stats[i][j].pixels, "pixels").c_str());
vlog.info(" %*s %s (1:%g ratio)",
(int)strlen(encoderTypeName((EncoderType)j)), "",
- iecPrefix(stats[i][j].bytes, "B").c_str(), ratio);
+ core::iecPrefix(stats[i][j].bytes, "B").c_str(), ratio);
}
}
ratio = (double)equivalent / bytes;
vlog.info(" Total: %s, %s",
- siPrefix(rects, "rects").c_str(),
- siPrefix(pixels, "pixels").c_str());
+ core::siPrefix(rects, "rects").c_str(),
+ core::siPrefix(pixels, "pixels").c_str());
vlog.info(" %s (1:%g ratio)",
- iecPrefix(bytes, "B").c_str(), ratio);
+ core::iecPrefix(bytes, "B").c_str(), ratio);
}
bool EncodeManager::supported(int encoding)
@@ -252,12 +255,12 @@ bool EncodeManager::supported(int encoding)
}
}
-bool EncodeManager::needsLosslessRefresh(const Region& req)
+bool EncodeManager::needsLosslessRefresh(const core::Region& req)
{
return !lossyRegion.intersect(req).is_empty();
}
-int EncodeManager::getNextLosslessRefresh(const Region& req)
+int EncodeManager::getNextLosslessRefresh(const core::Region& req)
{
// Do we have something we can send right away?
if (!pendingRefreshRegion.intersect(req).is_empty())
@@ -269,12 +272,19 @@ int EncodeManager::getNextLosslessRefresh(const Region& req)
return recentChangeTimer.getNextTimeout();
}
-void EncodeManager::pruneLosslessRefresh(const Region& limits)
+void EncodeManager::pruneLosslessRefresh(const core::Region& limits)
{
lossyRegion.assign_intersect(limits);
pendingRefreshRegion.assign_intersect(limits);
}
+void EncodeManager::forceRefresh(const core::Region& req)
+{
+ lossyRegion.assign_union(req);
+ if (!recentChangeTimer.isStarted())
+ pendingRefreshRegion.assign_union(req);
+}
+
void EncodeManager::writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb,
const RenderedCursor* renderedCursor)
{
@@ -286,15 +296,16 @@ void EncodeManager::writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb,
recentChangeTimer.start(RecentChangeTimeout);
}
-void EncodeManager::writeLosslessRefresh(const Region& req, const PixelBuffer* pb,
+void EncodeManager::writeLosslessRefresh(const core::Region& req,
+ const PixelBuffer* pb,
const RenderedCursor* renderedCursor,
size_t maxUpdateSize)
{
doUpdate(false, getLosslessRefresh(req, maxUpdateSize),
- Region(), Point(), pb, renderedCursor);
+ {}, {}, pb, renderedCursor);
}
-void EncodeManager::handleTimeout(Timer* t)
+void EncodeManager::handleTimeout(core::Timer* t)
{
if (t == &recentChangeTimer) {
// Any lossy region that wasn't recently updated can
@@ -308,13 +319,15 @@ void EncodeManager::handleTimeout(Timer* t)
}
}
-void EncodeManager::doUpdate(bool allowLossy, const Region& changed_,
- const Region& copied, const Point& copyDelta,
+void EncodeManager::doUpdate(bool allowLossy, const
+ core::Region& changed_,
+ const core::Region& copied,
+ const core::Point& copyDelta,
const PixelBuffer* pb,
const RenderedCursor* renderedCursor)
{
int nRects;
- Region changed, cursorRegion;
+ core::Region changed, cursorRegion;
updates++;
@@ -475,19 +488,20 @@ void EncodeManager::prepareEncoders(bool allowLossy)
encoder->setFineQualityLevel(conn->client.fineQualityLevel,
conn->client.subsampling);
} else {
- int level = __rfbmax(conn->client.qualityLevel,
- encoder->losslessQuality);
- encoder->setQualityLevel(level);
+ if (conn->client.qualityLevel < encoder->losslessQuality)
+ encoder->setQualityLevel(encoder->losslessQuality);
+ else
+ encoder->setQualityLevel(conn->client.qualityLevel);
encoder->setFineQualityLevel(-1, subsampleUndefined);
}
}
}
-Region EncodeManager::getLosslessRefresh(const Region& req,
- size_t maxUpdateSize)
+core::Region EncodeManager::getLosslessRefresh(const core::Region& req,
+ size_t maxUpdateSize)
{
- std::vector<Rect> rects;
- Region refresh;
+ std::vector<core::Rect> rects;
+ core::Region refresh;
size_t area;
// We make a conservative guess at the compression ratio at 2:1
@@ -500,7 +514,7 @@ Region EncodeManager::getLosslessRefresh(const Region& req,
pendingRefreshRegion.intersect(req).get_rects(&rects);
while (!rects.empty()) {
size_t idx;
- Rect rect;
+ core::Rect rect;
// Grab a random rect so we don't keep damaging and restoring the
// same rect over and over
@@ -514,17 +528,21 @@ Region EncodeManager::getLosslessRefresh(const Region& req,
// Use the narrowest axis to avoid getting to thin rects
if (rect.width() > rect.height()) {
int width = (maxUpdateSize - area) / rect.height();
- rect.br.x = rect.tl.x + __rfbmax(1, width);
+ if (width < 1)
+ width = 1;
+ rect.br.x = rect.tl.x + width;
} else {
int height = (maxUpdateSize - area) / rect.width();
- rect.br.y = rect.tl.y + __rfbmax(1, height);
+ if (height < 1)
+ height = 1;
+ rect.br.y = rect.tl.y + height;
}
- refresh.assign_union(Region(rect));
+ refresh.assign_union(rect);
break;
}
area += rect.area();
- refresh.assign_union(Region(rect));
+ refresh.assign_union(rect);
rects.erase(rects.begin() + idx);
}
@@ -532,11 +550,11 @@ Region EncodeManager::getLosslessRefresh(const Region& req,
return refresh;
}
-int EncodeManager::computeNumRects(const Region& changed)
+int EncodeManager::computeNumRects(const core::Region& changed)
{
int numRects;
- std::vector<Rect> rects;
- std::vector<Rect>::const_iterator rect;
+ std::vector<core::Rect> rects;
+ std::vector<core::Rect>::const_iterator rect;
numRects = 0;
changed.get_rects(&rects);
@@ -566,7 +584,7 @@ int EncodeManager::computeNumRects(const Region& changed)
return numRects;
}
-Encoder *EncodeManager::startRect(const Rect& rect, int type)
+Encoder* EncodeManager::startRect(const core::Rect& rect, int type)
{
Encoder *encoder;
int klass, equiv;
@@ -587,13 +605,13 @@ Encoder *EncodeManager::startRect(const Rect& rect, int type)
if ((encoder->flags & EncoderLossy) &&
((encoder->losslessQuality == -1) ||
(encoder->getQualityLevel() < encoder->losslessQuality)))
- lossyRegion.assign_union(Region(rect));
+ lossyRegion.assign_union(rect);
else
- lossyRegion.assign_subtract(Region(rect));
+ lossyRegion.assign_subtract(rect);
// This was either a rect getting refreshed, or a rect that just got
// new content. Either way we should not try to refresh it anymore.
- pendingRefreshRegion.assign_subtract(Region(rect));
+ pendingRefreshRegion.assign_subtract(rect);
return encoder;
}
@@ -611,12 +629,13 @@ void EncodeManager::endRect()
stats[klass][activeType].bytes += length;
}
-void EncodeManager::writeCopyRects(const Region& copied, const Point& delta)
+void EncodeManager::writeCopyRects(const core::Region& copied,
+ const core::Point& delta)
{
- std::vector<Rect> rects;
- std::vector<Rect>::const_iterator rect;
+ std::vector<core::Rect> rects;
+ std::vector<core::Rect>::const_iterator rect;
- Region lossyCopy;
+ core::Region lossyCopy;
beforeLength = conn->getOutStream()->length();
@@ -645,20 +664,22 @@ void EncodeManager::writeCopyRects(const Region& copied, const Point& delta)
pendingRefreshRegion.assign_subtract(copied);
}
-void EncodeManager::writeSolidRects(Region *changed, const PixelBuffer* pb)
+void EncodeManager::writeSolidRects(core::Region* changed,
+ const PixelBuffer* pb)
{
- std::vector<Rect> rects;
- std::vector<Rect>::const_iterator rect;
+ std::vector<core::Rect> rects;
+ std::vector<core::Rect>::const_iterator rect;
changed->get_rects(&rects);
for (rect = rects.begin(); rect != rects.end(); ++rect)
findSolidRect(*rect, changed, pb);
}
-void EncodeManager::findSolidRect(const Rect& rect, Region *changed,
+void EncodeManager::findSolidRect(const core::Rect& rect,
+ core::Region* changed,
const PixelBuffer* pb)
{
- Rect sr;
+ core::Rect sr;
int dx, dy, dw, dh;
// We start by finding a solid 16x16 block
@@ -677,11 +698,11 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed,
if (dx + dw > rect.br.x)
dw = rect.br.x - dx;
- pb->getImage(colourValue, Rect(dx, dy, dx+1, dy+1));
+ pb->getImage(colourValue, {dx, dy, dx+1, dy+1});
sr.setXYWH(dx, dy, dw, dh);
if (checkSolidTile(sr, colourValue, pb)) {
- Rect erb, erp;
+ core::Rect erb, erp;
Encoder *encoder;
@@ -721,7 +742,7 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed,
}
endRect();
- changed->assign_subtract(Region(erp));
+ changed->assign_subtract(erp);
// Search remaining areas by recursion
// FIXME: Is this the best way to divide things up?
@@ -752,15 +773,16 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed,
}
}
-void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb)
+void EncodeManager::writeRects(const core::Region& changed,
+ const PixelBuffer* pb)
{
- std::vector<Rect> rects;
- std::vector<Rect>::const_iterator rect;
+ std::vector<core::Rect> rects;
+ std::vector<core::Rect>::const_iterator rect;
changed.get_rects(&rects);
for (rect = rects.begin(); rect != rects.end(); ++rect) {
int w, h, sw, sh;
- Rect sr;
+ core::Rect sr;
w = rect->width();
h = rect->height();
@@ -794,7 +816,8 @@ void EncodeManager::writeRects(const Region& changed, const PixelBuffer* pb)
}
}
-void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb)
+void EncodeManager::writeSubRect(const core::Rect& rect,
+ const PixelBuffer* pb)
{
PixelBuffer *ppb;
@@ -878,7 +901,8 @@ void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb)
endRect();
}
-bool EncodeManager::checkSolidTile(const Rect& r, const uint8_t* colourValue,
+bool EncodeManager::checkSolidTile(const core::Rect& r,
+ const uint8_t* colourValue,
const PixelBuffer *pb)
{
const uint8_t* buffer;
@@ -902,13 +926,14 @@ bool EncodeManager::checkSolidTile(const Rect& r, const uint8_t* colourValue,
}
}
-void EncodeManager::extendSolidAreaByBlock(const Rect& r,
+void EncodeManager::extendSolidAreaByBlock(const core::Rect& r,
const uint8_t* colourValue,
- const PixelBuffer *pb, Rect* er)
+ const PixelBuffer* pb,
+ core::Rect* er)
{
int dx, dy, dw, dh;
int w_prev;
- Rect sr;
+ core::Rect sr;
int w_best = 0, h_best = 0;
w_prev = r.width();
@@ -958,12 +983,14 @@ void EncodeManager::extendSolidAreaByBlock(const Rect& r,
er->br.y = er->tl.y + h_best;
}
-void EncodeManager::extendSolidAreaByPixel(const Rect& r, const Rect& sr,
+void EncodeManager::extendSolidAreaByPixel(const core::Rect& r,
+ const core::Rect& sr,
const uint8_t* colourValue,
- const PixelBuffer *pb, Rect* er)
+ const PixelBuffer* pb,
+ core::Rect* er)
{
int cx, cy;
- Rect tr;
+ core::Rect tr;
// Try to extend the area upwards.
for (cy = sr.tl.y - 1; cy >= r.tl.y; cy--) {
@@ -998,7 +1025,7 @@ void EncodeManager::extendSolidAreaByPixel(const Rect& r, const Rect& sr,
er->br.x = cx;
}
-PixelBuffer* EncodeManager::preparePixelBuffer(const Rect& rect,
+PixelBuffer* EncodeManager::preparePixelBuffer(const core::Rect& rect,
const PixelBuffer *pb,
bool convert)
{
@@ -1063,7 +1090,7 @@ void EncodeManager::OffsetPixelBuffer::update(const PixelFormat& pf,
setBuffer(width, height, (uint8_t*)data_, stride_);
}
-uint8_t* EncodeManager::OffsetPixelBuffer::getBufferRW(const Rect& /*r*/, int* /*stride*/)
+uint8_t* EncodeManager::OffsetPixelBuffer::getBufferRW(const core::Rect& /*r*/, int* /*stride*/)
{
throw std::logic_error("Invalid write attempt to OffsetPixelBuffer");
}
diff --git a/common/rfb/EncodeManager.h b/common/rfb/EncodeManager.h
index 7ae9b5b8..4ce6d0ce 100644
--- a/common/rfb/EncodeManager.h
+++ b/common/rfb/EncodeManager.h
@@ -24,21 +24,22 @@
#include <stdint.h>
+#include <core/Region.h>
+#include <core/Timer.h>
+
#include <rfb/PixelBuffer.h>
-#include <rfb/Region.h>
-#include <rfb/Timer.h>
namespace rfb {
+
class SConnection;
class Encoder;
class UpdateInfo;
class PixelBuffer;
class RenderedCursor;
- struct Rect;
struct RectInfo;
- class EncodeManager : public Timer::Callback {
+ class EncodeManager : public core::Timer::Callback {
public:
EncodeManager(SConnection* conn);
~EncodeManager();
@@ -48,51 +49,60 @@ namespace rfb {
// Hack to let ConnParams calculate the client's preferred encoding
static bool supported(int encoding);
- bool needsLosslessRefresh(const Region& req);
- int getNextLosslessRefresh(const Region& req);
+ bool needsLosslessRefresh(const core::Region& req);
+ int getNextLosslessRefresh(const core::Region& req);
+
+ void pruneLosslessRefresh(const core::Region& limits);
- void pruneLosslessRefresh(const Region& limits);
+ void forceRefresh(const core::Region& req);
void writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb,
const RenderedCursor* renderedCursor);
- void writeLosslessRefresh(const Region& req, const PixelBuffer* pb,
+ void writeLosslessRefresh(const core::Region& req,
+ const PixelBuffer* pb,
const RenderedCursor* renderedCursor,
size_t maxUpdateSize);
protected:
- void handleTimeout(Timer* t) override;
+ void handleTimeout(core::Timer* t) override;
- void doUpdate(bool allowLossy, const Region& changed,
- const Region& copied, const Point& copy_delta,
+ void doUpdate(bool allowLossy, const core::Region& changed,
+ const core::Region& copied,
+ const core::Point& copy_delta,
const PixelBuffer* pb,
const RenderedCursor* renderedCursor);
void prepareEncoders(bool allowLossy);
- Region getLosslessRefresh(const Region& req, size_t maxUpdateSize);
+ core::Region getLosslessRefresh(const core::Region& req,
+ size_t maxUpdateSize);
- int computeNumRects(const Region& changed);
+ int computeNumRects(const core::Region& changed);
- Encoder *startRect(const Rect& rect, int type);
+ Encoder* startRect(const core::Rect& rect, int type);
void endRect();
- void writeCopyRects(const Region& copied, const Point& delta);
- void writeSolidRects(Region *changed, const PixelBuffer* pb);
- void findSolidRect(const Rect& rect, Region *changed, const PixelBuffer* pb);
- void writeRects(const Region& changed, const PixelBuffer* pb);
+ void writeCopyRects(const core::Region& copied,
+ const core::Point& delta);
+ void writeSolidRects(core::Region* changed, const PixelBuffer* pb);
+ void findSolidRect(const core::Rect& rect, core::Region* changed,
+ const PixelBuffer* pb);
+ void writeRects(const core::Region& changed, const PixelBuffer* pb);
- void writeSubRect(const Rect& rect, const PixelBuffer *pb);
+ void writeSubRect(const core::Rect& rect, const PixelBuffer* pb);
- bool checkSolidTile(const Rect& r, const uint8_t* colourValue,
+ bool checkSolidTile(const core::Rect& r, const uint8_t* colourValue,
const PixelBuffer *pb);
- void extendSolidAreaByBlock(const Rect& r, const uint8_t* colourValue,
- const PixelBuffer *pb, Rect* er);
- void extendSolidAreaByPixel(const Rect& r, const Rect& sr,
+ void extendSolidAreaByBlock(const core::Rect& r,
const uint8_t* colourValue,
- const PixelBuffer *pb, Rect* er);
+ const PixelBuffer* pb, core::Rect* er);
+ void extendSolidAreaByPixel(const core::Rect& r,
+ const core::Rect& sr,
+ const uint8_t* colourValue,
+ const PixelBuffer* pb, core::Rect* er);
- PixelBuffer* preparePixelBuffer(const Rect& rect,
- const PixelBuffer *pb, bool convert);
+ PixelBuffer* preparePixelBuffer(const core::Rect& rect,
+ const PixelBuffer* pb, bool convert);
bool analyseRect(const PixelBuffer *pb,
struct RectInfo *info, int maxColours);
@@ -114,11 +124,11 @@ namespace rfb {
std::vector<Encoder*> encoders;
std::vector<int> activeEncoders;
- Region lossyRegion;
- Region recentlyChangedRegion;
- Region pendingRefreshRegion;
+ core::Region lossyRegion;
+ core::Region recentlyChangedRegion;
+ core::Region pendingRefreshRegion;
- Timer recentChangeTimer;
+ core::Timer recentChangeTimer;
struct EncoderStats {
unsigned rects;
@@ -143,12 +153,13 @@ namespace rfb {
const uint8_t* data_, int stride);
private:
- uint8_t* getBufferRW(const Rect& r, int* stride) override;
+ uint8_t* getBufferRW(const core::Rect& r, int* stride) override;
};
OffsetPixelBuffer offsetPixelBuffer;
ManagedPixelBuffer convertedPixelBuffer;
};
+
}
#endif
diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h
index 5e066323..7fa2cc75 100644
--- a/common/rfb/Encoder.h
+++ b/common/rfb/Encoder.h
@@ -22,8 +22,6 @@
#include <stdint.h>
-#include <rfb/Rect.h>
-
namespace rfb {
class SConnection;
class PixelBuffer;
diff --git a/common/rfb/H264Decoder.cxx b/common/rfb/H264Decoder.cxx
index 89850ba4..d0d9b4df 100644
--- a/common/rfb/H264Decoder.cxx
+++ b/common/rfb/H264Decoder.cxx
@@ -29,14 +29,11 @@
#include <rdr/MemInStream.h>
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
-#include <rfb/LogWriter.h>
#include <rfb/H264Decoder.h>
#include <rfb/H264DecoderContext.h>
using namespace rfb;
-static LogWriter vlog("H264Decoder");
-
enum rectFlags {
resetContext = 0x1,
resetAllContexts = 0x2,
@@ -53,22 +50,20 @@ H264Decoder::~H264Decoder()
void H264Decoder::resetContexts()
{
- os::AutoMutex lock(&mutex);
for (H264DecoderContext* context : contexts)
delete context;
contexts.clear();
}
-H264DecoderContext* H264Decoder::findContext(const Rect& r)
+H264DecoderContext* H264Decoder::findContext(const core::Rect& r)
{
- os::AutoMutex m(&mutex);
for (H264DecoderContext* context : contexts)
if (context->isEqualRect(r))
return context;
return nullptr;
}
-bool H264Decoder::readRect(const Rect& /*r*/,
+bool H264Decoder::readRect(const core::Rect& /*r*/,
rdr::InStream* is,
const ServerParams& /*server*/,
rdr::OutStream* os)
@@ -96,7 +91,7 @@ bool H264Decoder::readRect(const Rect& /*r*/,
return true;
}
-void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer,
+void H264Decoder::decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen,
const ServerParams& /*server*/,
ModifiablePixelBuffer* pb)
@@ -116,9 +111,14 @@ void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer,
ctx = findContext(r);
}
+ if (ctx && (reset & resetContext)) {
+ contexts.remove(ctx);
+ delete ctx;
+ ctx = nullptr;
+ }
+
if (!ctx)
{
- os::AutoMutex lock(&mutex);
if (contexts.size() >= MAX_H264_INSTANCES)
{
H264DecoderContext* excess_ctx = contexts.front();
@@ -131,12 +131,6 @@ void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer,
contexts.push_back(ctx);
}
- if (!ctx->isReady())
- throw std::runtime_error("H264Decoder: Context is not ready");
-
- if (reset & resetContext)
- ctx->reset();
-
if (!len)
return;
diff --git a/common/rfb/H264Decoder.h b/common/rfb/H264Decoder.h
index 8ba47799..bc1b9281 100644
--- a/common/rfb/H264Decoder.h
+++ b/common/rfb/H264Decoder.h
@@ -21,9 +21,8 @@
#ifndef __RFB_H264DECODER_H__
#define __RFB_H264DECODER_H__
-#include <deque>
+#include <list>
-#include <os/Mutex.h>
#include <rfb/Decoder.h>
namespace rfb {
@@ -33,19 +32,18 @@ namespace rfb {
public:
H264Decoder();
virtual ~H264Decoder();
- bool readRect(const Rect& r, rdr::InStream* is,
+ bool readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server,
rdr::OutStream* os) override;
- void decodeRect(const Rect& r, const uint8_t* buffer,
+ void decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) override;
private:
void resetContexts();
- H264DecoderContext* findContext(const Rect& r);
+ H264DecoderContext* findContext(const core::Rect& r);
- os::Mutex mutex;
- std::deque<H264DecoderContext*> contexts;
+ std::list<H264DecoderContext*> contexts;
};
}
diff --git a/common/rfb/H264DecoderContext.cxx b/common/rfb/H264DecoderContext.cxx
index b2054554..3ad8c343 100644
--- a/common/rfb/H264DecoderContext.cxx
+++ b/common/rfb/H264DecoderContext.cxx
@@ -22,11 +22,6 @@
#include <config.h>
#endif
-#include <stdexcept>
-
-#include <os/Mutex.h>
-#include <rfb/LogWriter.h>
-
#include <rfb/H264DecoderContext.h>
#ifdef H264_LIBAV
@@ -39,31 +34,11 @@
using namespace rfb;
-static LogWriter vlog("H264DecoderContext");
-
-H264DecoderContext *H264DecoderContext::createContext(const Rect &r)
+H264DecoderContext *H264DecoderContext::createContext(const core::Rect &r)
{
- H264DecoderContext *ret = new H264DecoderContextType(r);
- if (!ret->initCodec())
- {
- throw std::runtime_error("H264DecoderContext: Unable to create context");
- }
-
- return ret;
+ return new H264DecoderContextType(r);
}
H264DecoderContext::~H264DecoderContext()
{
}
-
-bool H264DecoderContext::isReady()
-{
- os::AutoMutex lock(&mutex);
- return initialized;
-}
-
-void H264DecoderContext::reset()
-{
- freeCodec();
- initCodec();
-}
diff --git a/common/rfb/H264DecoderContext.h b/common/rfb/H264DecoderContext.h
index 88c2396c..5ef46662 100644
--- a/common/rfb/H264DecoderContext.h
+++ b/common/rfb/H264DecoderContext.h
@@ -23,35 +23,30 @@
#include <stdint.h>
-#include <os/Mutex.h>
-#include <rfb/Rect.h>
-#include <rfb/Decoder.h>
+#include <core/Rect.h>
namespace rfb {
+
+ class ModifiablePixelBuffer;
+
class H264DecoderContext {
public:
- static H264DecoderContext *createContext(const Rect &r);
+ static H264DecoderContext* createContext(const core::Rect& r);
virtual ~H264DecoderContext() = 0;
virtual void decode(const uint8_t* /*h264_buffer*/,
uint32_t /*len*/,
ModifiablePixelBuffer* /*pb*/) {}
- void reset();
- inline bool isEqualRect(const Rect &r) const { return r == rect; }
- bool isReady();
+ inline bool isEqualRect(const core::Rect &r) const { return r == rect; }
protected:
- os::Mutex mutex;
- rfb::Rect rect;
- bool initialized;
+ core::Rect rect;
- H264DecoderContext(const Rect &r) : rect(r) { initialized = false; }
-
- virtual bool initCodec() { return false; }
- virtual void freeCodec() {}
+ H264DecoderContext(const core::Rect &r) : rect(r) {}
};
+
}
#endif
diff --git a/common/rfb/H264LibavDecoderContext.cxx b/common/rfb/H264LibavDecoderContext.cxx
index 2d8d03e7..ba1b1b6d 100644
--- a/common/rfb/H264LibavDecoderContext.cxx
+++ b/common/rfb/H264LibavDecoderContext.cxx
@@ -22,6 +22,9 @@
#include <config.h>
#endif
+#include <new>
+#include <stdexcept>
+
extern "C" {
#include <libavutil/imgutils.h>
#include <libavcodec/version.h>
@@ -33,41 +36,31 @@ extern "C" {
#define FFMPEG_INIT_PACKET_DEPRECATED
#endif
-#include <rfb/LogWriter.h>
#include <rfb/PixelBuffer.h>
#include <rfb/H264LibavDecoderContext.h>
using namespace rfb;
-static LogWriter vlog("H264LibavDecoderContext");
-
-bool H264LibavDecoderContext::initCodec() {
- os::AutoMutex lock(&mutex);
-
+H264LibavDecoderContext::H264LibavDecoderContext(const core::Rect& r)
+ : H264DecoderContext(r)
+{
sws = nullptr;
h264WorkBuffer = nullptr;
h264WorkBufferLength = 0;
const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec)
- {
- vlog.error("Codec not found");
- return false;
- }
+ throw std::runtime_error("Codec not found");
parser = av_parser_init(codec->id);
if (!parser)
- {
- vlog.error("Could not create H264 parser");
- return false;
- }
+ throw std::runtime_error("Could not create H264 parser");
avctx = avcodec_alloc_context3(codec);
if (!avctx)
{
av_parser_close(parser);
- vlog.error("Could not allocate video codec context");
- return false;
+ throw std::runtime_error("Could not allocate video codec context");
}
frame = av_frame_alloc();
@@ -75,8 +68,7 @@ bool H264LibavDecoderContext::initCodec() {
{
av_parser_close(parser);
avcodec_free_context(&avctx);
- vlog.error("Could not allocate video frame");
- return false;
+ throw std::runtime_error("Could not allocate video frame");
}
if (avcodec_open2(avctx, codec, nullptr) < 0)
@@ -84,26 +76,18 @@ bool H264LibavDecoderContext::initCodec() {
av_parser_close(parser);
avcodec_free_context(&avctx);
av_frame_free(&frame);
- vlog.error("Could not open codec");
- return false;
+ throw std::runtime_error("Could not open video codec");
}
-
- initialized = true;
- return true;
}
-void H264LibavDecoderContext::freeCodec() {
- os::AutoMutex lock(&mutex);
-
- if (!initialized)
- return;
+H264LibavDecoderContext::~H264LibavDecoderContext()
+{
av_parser_close(parser);
avcodec_free_context(&avctx);
av_frame_free(&rgbFrame);
av_frame_free(&frame);
sws_freeContext(sws);
free(h264WorkBuffer);
- initialized = false;
}
// We need to reallocate buffer because AVPacket uses non-const pointer.
@@ -130,9 +114,6 @@ uint8_t* H264LibavDecoderContext::makeH264WorkBuffer(const uint8_t* buffer, uint
void H264LibavDecoderContext::decode(const uint8_t* h264_in_buffer,
uint32_t len,
ModifiablePixelBuffer* pb) {
- os::AutoMutex lock(&mutex);
- if (!initialized)
- return;
uint8_t* h264_work_buffer = makeH264WorkBuffer(h264_in_buffer, len);
#ifdef FFMPEG_INIT_PACKET_DEPRECATED
@@ -147,19 +128,15 @@ void H264LibavDecoderContext::decode(const uint8_t* h264_in_buffer,
while (len)
{
ret = av_parser_parse2(parser, avctx, &packet->data, &packet->size, h264_work_buffer, len, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
+ // Silently ignore errors, hoping its a temporary encoding glitch
if (ret < 0)
- {
- vlog.error("Error while parsing");
break;
- }
// We need to slap on tv to make it work here (don't ask me why)
if (!packet->size && len == static_cast<uint32_t>(ret))
ret = av_parser_parse2(parser, avctx, &packet->data, &packet->size, h264_work_buffer, len, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
+ // Silently ignore errors, hoping its a temporary encoding glitch
if (ret < 0)
- {
- vlog.error("Error while parsing");
break;
- }
h264_work_buffer += ret;
len -= ret;
@@ -176,27 +153,21 @@ void H264LibavDecoderContext::decode(const uint8_t* h264_in_buffer,
#ifndef FFMPEG_DECODE_VIDEO2_DEPRECATED
int got_frame;
ret = avcodec_decode_video2(avctx, frame, &got_frame, packet);
+ // Silently ignore errors, hoping its a temporary encoding glitch
if (ret < 0 || !got_frame)
- {
- vlog.error("Error during decoding");
break;
- }
#else
ret = avcodec_send_packet(avctx, packet);
+ // Silently ignore errors, hoping its a temporary encoding glitch
if (ret < 0)
- {
- vlog.error("Error sending a packet to decoding");
break;
- }
ret = avcodec_receive_frame(avctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
- else if (ret < 0)
- {
- vlog.error("Error during decoding");
+ // Silently ignore errors, hoping its a temporary encoding glitch
+ if (ret < 0)
break;
- }
#endif
frames_received++;
}
diff --git a/common/rfb/H264LibavDecoderContext.h b/common/rfb/H264LibavDecoderContext.h
index 96558bee..c23fdf79 100644
--- a/common/rfb/H264LibavDecoderContext.h
+++ b/common/rfb/H264LibavDecoderContext.h
@@ -31,16 +31,12 @@ extern "C" {
namespace rfb {
class H264LibavDecoderContext : public H264DecoderContext {
public:
- H264LibavDecoderContext(const Rect &r) : H264DecoderContext(r) {}
- ~H264LibavDecoderContext() { freeCodec(); }
+ H264LibavDecoderContext(const core::Rect &r);
+ ~H264LibavDecoderContext();
void decode(const uint8_t* h264_buffer, uint32_t len,
ModifiablePixelBuffer* pb) override;
- protected:
- bool initCodec() override;
- void freeCodec() override;
-
private:
uint8_t* makeH264WorkBuffer(const uint8_t* buffer, uint32_t len);
diff --git a/common/rfb/H264WinDecoderContext.cxx b/common/rfb/H264WinDecoderContext.cxx
index a9b13942..71086fad 100644
--- a/common/rfb/H264WinDecoderContext.cxx
+++ b/common/rfb/H264WinDecoderContext.cxx
@@ -22,48 +22,38 @@
#include <config.h>
#endif
+#include <stdexcept>
+
#include <mfapi.h>
#include <mferror.h>
#include <wmcodecdsp.h>
#define SAFE_RELEASE(obj) if (obj) { obj->Release(); obj = nullptr; }
-#include <os/Mutex.h>
-#include <rfb/LogWriter.h>
#include <rfb/PixelBuffer.h>
#include <rfb/H264WinDecoderContext.h>
using namespace rfb;
-static LogWriter vlog("H264WinDecoderContext");
-
// Older MinGW lacks this definition
#ifndef HAVE_VIDEO_PROCESSOR_MFT
static GUID CLSID_VideoProcessorMFT = { 0x88753b26, 0x5b24, 0x49bd, { 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82 } };
#endif
-bool H264WinDecoderContext::initCodec() {
- os::AutoMutex lock(&mutex);
-
+H264WinDecoderContext::H264WinDecoderContext(const core::Rect &r)
+ : H264DecoderContext(r)
+{
if (FAILED(MFStartup(MF_VERSION, MFSTARTUP_LITE)))
- {
- vlog.error("Could not initialize MediaFoundation");
- return false;
- }
+ throw std::runtime_error("Could not initialize MediaFoundation");
if (FAILED(CoCreateInstance(CLSID_CMSH264DecoderMFT, nullptr, CLSCTX_INPROC_SERVER, IID_IMFTransform, (LPVOID*)&decoder)))
- {
- vlog.error("MediaFoundation H264 codec not found");
- return false;
- }
+ throw std::runtime_error("MediaFoundation H264 codec not found");
if (FAILED(CoCreateInstance(CLSID_VideoProcessorMFT, nullptr, CLSCTX_INPROC_SERVER, IID_IMFTransform, (LPVOID*)&converter)))
{
- vlog.error("Cannot create MediaFoundation Video Processor (available only on Windows 8+). Trying ColorConvert DMO.");
if (FAILED(CoCreateInstance(CLSID_CColorConvertDMO, nullptr, CLSCTX_INPROC_SERVER, IID_IMFTransform, (LPVOID*)&converter)))
{
decoder->Release();
- vlog.error("ColorConvert DMO not found");
- return false;
+ throw std::runtime_error("MediaFoundation H264 codec not found");
}
}
@@ -72,10 +62,7 @@ bool H264WinDecoderContext::initCodec() {
if (SUCCEEDED(decoder->GetAttributes(&attributes)))
{
GUID MF_LOW_LATENCY = { 0x9c27891a, 0xed7a, 0x40e1, { 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee } };
- if (SUCCEEDED(attributes->SetUINT32(MF_LOW_LATENCY, TRUE)))
- {
- vlog.info("Enabled low latency mode");
- }
+ attributes->SetUINT32(MF_LOW_LATENCY, TRUE);
attributes->Release();
}
@@ -85,8 +72,7 @@ bool H264WinDecoderContext::initCodec() {
{
decoder->Release();
converter->Release();
- vlog.error("Could not create MF MediaType");
- return false;
+ throw std::runtime_error("Could not create MF MediaType");
}
input_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
input_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
@@ -113,8 +99,7 @@ bool H264WinDecoderContext::initCodec() {
decoder->Release();
converter->Release();
input_type->Release();
- vlog.error("Could not start H264 decoder");
- return false;
+ throw std::runtime_error("Could not start H264 decoder");
}
MFT_OUTPUT_STREAM_INFO info;
@@ -134,22 +119,14 @@ bool H264WinDecoderContext::initCodec() {
SAFE_RELEASE(converted_sample);
SAFE_RELEASE(input_buffer);
SAFE_RELEASE(decoded_buffer);
- vlog.error("Could not allocate media samples/buffers");
- return false;
+ throw std::runtime_error("Could not allocate media samples/buffers");
}
input_sample->AddBuffer(input_buffer);
decoded_sample->AddBuffer(decoded_buffer);
-
- initialized = true;
- return true;
}
-void H264WinDecoderContext::freeCodec() {
- os::AutoMutex lock(&mutex);
-
- if (!initialized)
- return;
+H264WinDecoderContext::~H264WinDecoderContext() {
SAFE_RELEASE(decoder)
SAFE_RELEASE(converter)
SAFE_RELEASE(input_sample)
@@ -159,24 +136,16 @@ void H264WinDecoderContext::freeCodec() {
SAFE_RELEASE(decoded_buffer)
SAFE_RELEASE(converted_buffer)
MFShutdown();
- initialized = false;
}
void H264WinDecoderContext::decode(const uint8_t* h264_buffer,
uint32_t len,
ModifiablePixelBuffer* pb) {
- os::AutoMutex lock(&mutex);
- if (!initialized)
- return;
-
if (FAILED(input_buffer->SetCurrentLength(len)))
{
input_buffer->Release();
if (FAILED(MFCreateMemoryBuffer(len, &input_buffer)))
- {
- vlog.error("Could not allocate media buffer");
- return;
- }
+ throw std::runtime_error("Could not allocate media buffer");
input_buffer->SetCurrentLength(len);
input_sample->RemoveAllBuffers();
input_sample->AddBuffer(input_buffer);
@@ -187,14 +156,12 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer,
memcpy(locked, h264_buffer, len);
input_buffer->Unlock();
- vlog.debug("Received %u bytes, decoding", len);
-
// extract actual size, including possible cropping
ParseSPS(h264_buffer, len);
if (FAILED(decoder->ProcessInput(0, input_sample, 0)))
{
- vlog.error("Error sending a packet to decoding");
+ // Silently ignore errors, hoping its a temporary encoding glitch
return;
}
@@ -219,7 +186,6 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer,
if (SUCCEEDED(hr))
{
- vlog.debug("Frame decoded");
// successfully decoded next frame
// but do not exit loop, try again if there is next frame
decoded = true;
@@ -259,7 +225,7 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer,
UINT32 width, height;
if FAILED(MFGetAttributeSize(output_type, MF_MT_FRAME_SIZE, &width, &height))
{
- vlog.error("Error getting output type size");
+ // Silently ignore errors, hoping its a temporary encoding glitch
output_type->Release();
break;
}
@@ -279,13 +245,11 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer,
crop_height = height;
}
- vlog.debug("Setting up decoded output with %ux%u size", crop_width, crop_height);
-
// input type to converter, BGRX pixel format
IMFMediaType* converted_type;
if (FAILED(MFCreateMediaType(&converted_type)))
{
- vlog.error("Error creating media type");
+ // Silently ignore errors, hoping its a temporary encoding glitch
}
else
{
@@ -310,7 +274,7 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer,
if (FAILED(MFCreateMemoryBuffer(info.cbSize, &converted_buffer)))
{
- vlog.error("Error creating media buffer");
+ // Silently ignore errors, hoping its a temporary encoding glitch
}
else
{
@@ -327,7 +291,7 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer,
{
if (FAILED(converter->ProcessInput(0, decoded_sample, 0)))
{
- vlog.error("Error sending a packet to converter");
+ // Silently ignore errors, hoping its a temporary encoding glitch
return;
}
@@ -343,12 +307,10 @@ void H264WinDecoderContext::decode(const uint8_t* h264_buffer,
if (FAILED(hr))
{
- vlog.error("Error converting to RGB");
+ // Silently ignore errors, hoping its a temporary encoding glitch
}
else
{
- vlog.debug("Frame converted to RGB");
-
BYTE* out;
DWORD buflen;
converted_buffer->Lock(&out, nullptr, &buflen);
@@ -528,8 +490,6 @@ void H264WinDecoderContext::ParseSPS(const uint8_t* buffer, int length)
offset_x = frame_crop_left_offset;
offset_y = frame_crop_bottom_offset;
- vlog.debug("SPS parsing - full=%dx%d, cropped=%dx%d, offset=%d,%d", full_width, full_height, crop_width, crop_height, offset_x, offset_y);
-
#undef SKIP_BITS
#undef SKIP_UE
#undef GET_BITS
diff --git a/common/rfb/H264WinDecoderContext.h b/common/rfb/H264WinDecoderContext.h
index 92041781..b1dbf0e1 100644
--- a/common/rfb/H264WinDecoderContext.h
+++ b/common/rfb/H264WinDecoderContext.h
@@ -30,16 +30,12 @@
namespace rfb {
class H264WinDecoderContext : public H264DecoderContext {
public:
- H264WinDecoderContext(const Rect &r) : H264DecoderContext(r) {};
- ~H264WinDecoderContext() { freeCodec(); }
+ H264WinDecoderContext(const core::Rect &r);
+ ~H264WinDecoderContext();
void decode(const uint8_t* h264_buffer, uint32_t len,
ModifiablePixelBuffer* pb) override;
- protected:
- bool initCodec() override;
- void freeCodec() override;
-
private:
LONG stride;
uint32_t full_width = 0;
diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx
index 35ec7928..c6eb428b 100644
--- a/common/rfb/HextileDecoder.cxx
+++ b/common/rfb/HextileDecoder.cxx
@@ -21,6 +21,8 @@
#include <config.h>
#endif
+#include <algorithm>
+
#include <rdr/InStream.h>
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>
@@ -41,10 +43,10 @@ HextileDecoder::~HextileDecoder()
{
}
-bool HextileDecoder::readRect(const Rect& r, rdr::InStream* is,
+bool HextileDecoder::readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os)
{
- Rect t;
+ core::Rect t;
size_t bytesPerPixel;
is->setRestorePoint();
@@ -53,12 +55,12 @@ bool HextileDecoder::readRect(const Rect& r, rdr::InStream* is,
for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
- t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
+ t.br.y = std::min(r.br.y, t.tl.y + 16);
for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
uint8_t tileType;
- t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
+ t.br.x = std::min(r.br.x, t.tl.x + 16);
if (!is->hasDataOrRestore(1))
return false;
@@ -113,7 +115,7 @@ bool HextileDecoder::readRect(const Rect& r, rdr::InStream* is,
return true;
}
-void HextileDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
+void HextileDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
@@ -138,22 +140,22 @@ inline T HextileDecoder::readPixel(rdr::InStream* is)
}
template<class T>
-void HextileDecoder::hextileDecode(const Rect& r, rdr::InStream* is,
+void HextileDecoder::hextileDecode(const core::Rect& r, rdr::InStream* is,
const PixelFormat& pf,
ModifiablePixelBuffer* pb)
{
- Rect t;
+ core::Rect t;
T bg = 0;
T fg = 0;
T buf[16 * 16];
for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
- t.br.y = __rfbmin(r.br.y, t.tl.y + 16);
+ t.br.y = std::min(r.br.y, t.tl.y + 16);
for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
- t.br.x = __rfbmin(r.br.x, t.tl.x + 16);
+ t.br.x = std::min(r.br.x, t.tl.x + 16);
int tileType = is->readU8();
diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h
index 38e8b776..6ff94a1f 100644
--- a/common/rfb/HextileDecoder.h
+++ b/common/rfb/HextileDecoder.h
@@ -29,17 +29,17 @@ namespace rfb {
public:
HextileDecoder();
virtual ~HextileDecoder();
- bool readRect(const Rect& r, rdr::InStream* is,
+ bool readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server,
rdr::OutStream* os) override;
- void decodeRect(const Rect& r, const uint8_t* buffer,
+ void decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) override;
private:
template<class T>
inline T readPixel(rdr::InStream* is);
template<class T>
- void hextileDecode(const Rect& r, rdr::InStream* is,
+ void hextileDecode(const core::Rect& r, rdr::InStream* is,
const PixelFormat& pf,
ModifiablePixelBuffer* pb);
};
diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx
index 0666d02d..5ee07a2d 100644
--- a/common/rfb/HextileEncoder.cxx
+++ b/common/rfb/HextileEncoder.cxx
@@ -22,21 +22,28 @@
#include <config.h>
#endif
+#include <algorithm>
+
+#include <core/Configuration.h>
+
+#include <rdr/OutStream.h>
+
#include <rfb/encodings.h>
#include <rfb/SConnection.h>
#include <rfb/HextileEncoder.h>
#include <rfb/Palette.h>
#include <rfb/PixelBuffer.h>
-#include <rfb/Configuration.h>
#include <rfb/hextileConstants.h>
using namespace rfb;
-BoolParameter improvedHextile("ImprovedHextile",
- "Use improved compression algorithm for Hextile "
- "encoding which achieves better compression "
- "ratios by the cost of using more CPU time",
- true);
+core::BoolParameter improvedHextile("ImprovedHextile",
+ "Use improved compression "
+ "algorithm for Hextile encoding "
+ "which achieves better compression "
+ "ratios by the cost of using more "
+ "CPU time",
+ true);
HextileEncoder::HextileEncoder(SConnection* conn_) :
Encoder(conn_, encodingHextile, EncoderPlain)
@@ -115,7 +122,7 @@ template<class T>
void HextileEncoder::hextileEncode(rdr::OutStream* os,
const PixelBuffer* pb)
{
- Rect t;
+ core::Rect t;
T buf[256];
T oldBg = 0, oldFg = 0;
bool oldBgValid = false;
@@ -124,11 +131,11 @@ void HextileEncoder::hextileEncode(rdr::OutStream* os,
for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) {
- t.br.y = __rfbmin(pb->height(), t.tl.y + 16);
+ t.br.y = std::min(pb->height(), t.tl.y + 16);
for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) {
- t.br.x = __rfbmin(pb->width(), t.tl.x + 16);
+ t.br.x = std::min(pb->width(), t.tl.x + 16);
pb->getImage(buf, t);
@@ -532,7 +539,7 @@ template<class T>
void HextileEncoder::hextileEncodeBetter(rdr::OutStream* os,
const PixelBuffer* pb)
{
- Rect t;
+ core::Rect t;
T buf[256];
T oldBg = 0, oldFg = 0;
bool oldBgValid = false;
@@ -543,11 +550,11 @@ void HextileEncoder::hextileEncodeBetter(rdr::OutStream* os,
for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) {
- t.br.y = __rfbmin(pb->height(), t.tl.y + 16);
+ t.br.y = std::min(pb->height(), t.tl.y + 16);
for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) {
- t.br.x = __rfbmin(pb->width(), t.tl.x + 16);
+ t.br.x = std::min(pb->width(), t.tl.x + 16);
pb->getImage(buf, t);
diff --git a/common/rfb/Hostname.h b/common/rfb/Hostname.h
deleted file mode 100644
index f43e5067..00000000
--- a/common/rfb/Hostname.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* Copyright (C) 2002-2005 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 __RFB_HOSTNAME_H__
-#define __RFB_HOSTNAME_H__
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <stdexcept>
-
-#include <rfb/util.h>
-
-namespace rfb {
-
- static bool isAllSpace(const char *string) {
- if (string == nullptr)
- return false;
- while(*string != '\0') {
- if (! isspace(*string))
- return false;
- string++;
- }
- return true;
- }
-
- static inline void getHostAndPort(const char* hi, std::string* host,
- int* port, int basePort=5900)
- {
- const char* hostStart;
- const char* hostEnd;
- const char* portStart;
-
- if (hi == nullptr)
- throw std::invalid_argument("NULL host specified");
-
- // Trim leading whitespace
- while(isspace(*hi))
- hi++;
-
- assert(host);
- assert(port);
-
- if (hi[0] == '[') {
- hostStart = &hi[1];
- hostEnd = strchr(hostStart, ']');
- if (hostEnd == nullptr)
- throw std::invalid_argument("Unmatched [ in host");
-
- portStart = hostEnd + 1;
- if (isAllSpace(portStart))
- portStart = nullptr;
- } else {
- hostStart = &hi[0];
- hostEnd = strrchr(hostStart, ':');
-
- if (hostEnd == nullptr) {
- hostEnd = hostStart + strlen(hostStart);
- portStart = nullptr;
- } else {
- if ((hostEnd > hostStart) && (hostEnd[-1] == ':'))
- hostEnd--;
- portStart = strchr(hostStart, ':');
- if (portStart != hostEnd) {
- // We found more : in the host. This is probably an IPv6 address
- hostEnd = hostStart + strlen(hostStart);
- portStart = nullptr;
- }
- }
- }
-
- // Back up past trailing space
- while(isspace(*(hostEnd - 1)) && hostEnd > hostStart)
- hostEnd--;
-
- if (hostStart == hostEnd)
- *host = "localhost";
- else
- *host = std::string(hostStart, hostEnd - hostStart);
-
- if (portStart == nullptr)
- *port = basePort;
- else {
- char* end;
-
- if (portStart[0] != ':')
- throw std::invalid_argument("Invalid port specified");
-
- if (portStart[1] != ':')
- *port = strtol(portStart + 1, &end, 10);
- else
- *port = strtol(portStart + 2, &end, 10);
- if (*end != '\0' && ! isAllSpace(end))
- throw std::invalid_argument("Invalid port specified");
-
- if ((portStart[1] != ':') && (*port < 100))
- *port += basePort;
- }
- }
-
-};
-
-#endif // __RFB_HOSTNAME_H__
diff --git a/common/rfb/JpegCompressor.cxx b/common/rfb/JpegCompressor.cxx
index 67a86cd9..d8216c99 100644
--- a/common/rfb/JpegCompressor.cxx
+++ b/common/rfb/JpegCompressor.cxx
@@ -24,8 +24,9 @@
#include <stdexcept>
+#include <core/Rect.h>
+
#include <rfb/JpegCompressor.h>
-#include <rfb/Rect.h>
#include <rfb/PixelFormat.h>
#include <rfb/ClientParams.h>
@@ -157,7 +158,8 @@ JpegCompressor::~JpegCompressor(void)
}
void JpegCompressor::compress(const uint8_t *buf, volatile int stride,
- const Rect& r, const PixelFormat& pf,
+ const core::Rect& r,
+ const PixelFormat& pf,
int quality, int subsamp)
{
int w = r.width();
diff --git a/common/rfb/JpegCompressor.h b/common/rfb/JpegCompressor.h
index 26194204..2460f62b 100644
--- a/common/rfb/JpegCompressor.h
+++ b/common/rfb/JpegCompressor.h
@@ -25,9 +25,9 @@
#ifndef __RFB_JPEGCOMPRESSOR_H__
#define __RFB_JPEGCOMPRESSOR_H__
+#include <core/Rect.h>
+
#include <rdr/MemOutStream.h>
-#include <rfb/PixelFormat.h>
-#include <rfb/Rect.h>
struct jpeg_compress_struct;
@@ -36,6 +36,9 @@ struct JPEG_DEST_MGR;
namespace rfb {
+ class PixelFormat;
+ struct Rect;
+
class JpegCompressor : public rdr::MemOutStream {
public:
@@ -43,7 +46,8 @@ namespace rfb {
JpegCompressor(int bufferLen = 128*1024);
virtual ~JpegCompressor();
- void compress(const uint8_t *, int, const Rect&, const PixelFormat&, int, int);
+ void compress(const uint8_t*, int, const core::Rect&,
+ const PixelFormat&, int, int);
void writeBytes(const uint8_t*, int);
diff --git a/common/rfb/JpegDecompressor.cxx b/common/rfb/JpegDecompressor.cxx
index 10c9e49c..ef548be0 100644
--- a/common/rfb/JpegDecompressor.cxx
+++ b/common/rfb/JpegDecompressor.cxx
@@ -23,9 +23,10 @@
#include <config.h>
#endif
+#include <core/Rect.h>
+
#include <rfb/JpegDecompressor.h>
#include <rfb/Exception.h>
-#include <rfb/Rect.h>
#include <rfb/PixelFormat.h>
#include <stdio.h>
@@ -153,7 +154,8 @@ JpegDecompressor::~JpegDecompressor(void)
void JpegDecompressor::decompress(const uint8_t *jpegBuf,
int jpegBufLen, uint8_t *buf,
volatile int stride,
- const Rect& r, const PixelFormat& pf)
+ const core::Rect& r,
+ const PixelFormat& pf)
{
int w = r.width();
int h = r.height();
diff --git a/common/rfb/JpegDecompressor.h b/common/rfb/JpegDecompressor.h
index 5d4f0c21..8e651b1c 100644
--- a/common/rfb/JpegDecompressor.h
+++ b/common/rfb/JpegDecompressor.h
@@ -26,16 +26,19 @@
#ifndef __RFB_JPEGDECOMPRESSOR_H__
#define __RFB_JPEGDECOMPRESSOR_H__
-#include <rfb/PixelFormat.h>
-#include <rfb/Rect.h>
+#include <stdint.h>
struct jpeg_decompress_struct;
struct JPEG_ERROR_MGR;
struct JPEG_SRC_MGR;
+namespace core { struct Rect; }
+
namespace rfb {
+ class PixelFormat;
+
class JpegDecompressor {
public:
@@ -43,8 +46,8 @@ namespace rfb {
JpegDecompressor(void);
virtual ~JpegDecompressor();
- void decompress(const uint8_t *, int, uint8_t *, int, const Rect&,
- const PixelFormat&);
+ void decompress(const uint8_t*, int, uint8_t*, int,
+ const core::Rect&, const PixelFormat&);
private:
diff --git a/common/rfb/KeyRemapper.cxx b/common/rfb/KeyRemapper.cxx
index 1c478178..24740321 100644
--- a/common/rfb/KeyRemapper.cxx
+++ b/common/rfb/KeyRemapper.cxx
@@ -23,59 +23,31 @@
#include <stdio.h>
#include <string.h>
-#include <os/Mutex.h>
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
#include <rfb/KeyRemapper.h>
-#include <rfb/Configuration.h>
-#include <rfb/LogWriter.h>
using namespace rfb;
-static LogWriter vlog("KeyRemapper");
+static core::LogWriter vlog("KeyRemapper");
KeyRemapper KeyRemapper::defInstance;
-KeyRemapper::KeyRemapper(const char* m)
+KeyRemapper::KeyRemapper()
{
- mutex = new os::Mutex;
-
- setMapping(m);
}
KeyRemapper::~KeyRemapper()
{
- delete mutex;
}
-void KeyRemapper::setMapping(const char* m) {
- os::AutoMutex a(mutex);
-
- mapping.clear();
- while (m[0]) {
- int from, to;
- char bidi;
- const char* nextComma = strchr(m, ',');
- if (!nextComma)
- nextComma = m + strlen(m);
- if (sscanf(m, "0x%x%c>0x%x", &from,
- &bidi, &to) == 3) {
- if (bidi != '-' && bidi != '<')
- vlog.error("Warning: Unknown operation %c>, assuming ->", bidi);
- mapping[from] = to;
- if (bidi == '<')
- mapping[to] = from;
- } else {
- vlog.error("Warning: Bad mapping %.*s", (int)(nextComma-m), m);
- }
- m = nextComma;
- if (nextComma[0])
- m++;
- }
+void KeyRemapper::setMapping(const std::map<uint32_t,uint32_t>& m)
+{
+ mapping = m;
}
uint32_t KeyRemapper::remapKey(uint32_t key) const {
- os::AutoMutex a(mutex);
-
std::map<uint32_t,uint32_t>::const_iterator i = mapping.find(key);
if (i != mapping.end())
return i->second;
@@ -83,15 +55,41 @@ uint32_t KeyRemapper::remapKey(uint32_t key) const {
}
-class KeyMapParameter : public StringParameter {
+class KeyMapParameter : public core::StringListParameter {
public:
KeyMapParameter()
- : StringParameter("RemapKeys", "Comma-separated list of incoming keysyms to remap. Mappings are expressed as two hex values, prefixed by 0x, and separated by ->", "") {
- KeyRemapper::defInstance.setMapping("");
+ : core::StringListParameter("RemapKeys",
+ "Comma-separated list of incoming "
+ "keysyms to remap. Mappings are "
+ "expressed as two hex values, prefixed "
+ "by 0x, and separated by ->",
+ {}) {
+ KeyRemapper::defInstance.setMapping({});
}
bool setParam(const char* v) override {
- KeyRemapper::defInstance.setMapping(v);
- return StringParameter::setParam(v);
+ std::map<uint32_t,uint32_t> mapping;
+
+ if (!core::StringListParameter::setParam(v))
+ return false;
+
+ for (const char* m : *this) {
+ int from, to;
+ char bidi;
+ if (sscanf(m, "0x%x%c>0x%x", &from,
+ &bidi, &to) == 3) {
+ if (bidi != '-' && bidi != '<')
+ vlog.error("Warning: Unknown operation %c>, assuming ->", bidi);
+ mapping[from] = to;
+ if (bidi == '<')
+ mapping[to] = from;
+ } else {
+ vlog.error("Warning: Bad mapping %s", m);
+ }
+ }
+
+ KeyRemapper::defInstance.setMapping(mapping);
+
+ return true;
}
} defaultParam;
diff --git a/common/rfb/KeyRemapper.h b/common/rfb/KeyRemapper.h
index 89853721..71ef0a87 100644
--- a/common/rfb/KeyRemapper.h
+++ b/common/rfb/KeyRemapper.h
@@ -23,20 +23,17 @@
#include <stdint.h>
-namespace os { class Mutex; }
-
namespace rfb {
class KeyRemapper {
public:
- KeyRemapper(const char* m="");
+ KeyRemapper();
~KeyRemapper();
- void setMapping(const char* m);
+ void setMapping(const std::map<uint32_t,uint32_t>& m);
uint32_t remapKey(uint32_t key) const;
static KeyRemapper defInstance;
private:
std::map<uint32_t,uint32_t> mapping;
- os::Mutex* mutex;
};
};
diff --git a/common/rfb/PixelBuffer.cxx b/common/rfb/PixelBuffer.cxx
index 5590c214..32b0ce2f 100644
--- a/common/rfb/PixelBuffer.cxx
+++ b/common/rfb/PixelBuffer.cxx
@@ -30,13 +30,14 @@
#include <stdexcept>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb/PixelBuffer.h>
-#include <rfb/util.h>
using namespace rfb;
-static LogWriter vlog("PixelBuffer");
+static core::LogWriter vlog("PixelBuffer");
// We do a lot of byte offset calculations that assume the result fits
// inside a signed 32 bit integer. Limit the maximum size of pixel
@@ -63,7 +64,8 @@ PixelBuffer::~PixelBuffer() {}
void
-PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) const
+PixelBuffer::getImage(void* imageBuf, const core::Rect& r,
+ int outStride) const
{
int inStride;
const uint8_t* data;
@@ -72,10 +74,9 @@ PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) const
const uint8_t* end;
if (!r.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- r.width(), r.height(),
- r.tl.x, r.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
+ r.width(), r.height(), r.tl.x, r.tl.y, width(), height()));
data = getBuffer(r, &inStride);
@@ -98,7 +99,7 @@ PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) const
}
void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf,
- const Rect& r, int stride) const
+ const core::Rect& r, int stride) const
{
const uint8_t* srcBuffer;
int srcStride;
@@ -109,10 +110,9 @@ void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf,
}
if (!r.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- r.width(), r.height(),
- r.tl.x, r.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
+ r.width(), r.height(), r.tl.x, r.tl.y, width(), height()));
if (stride == 0)
stride = r.width();
@@ -126,9 +126,11 @@ void PixelBuffer::getImage(const PixelFormat& pf, void* imageBuf,
void PixelBuffer::setSize(int width, int height)
{
if ((width < 0) || (width > maxPixelBufferWidth))
- throw std::out_of_range(rfb::format("Invalid PixelBuffer width of %d pixels requested", width));
+ throw std::out_of_range(core::format(
+ "Invalid PixelBuffer width of %d pixels requested", width));
if ((height < 0) || (height > maxPixelBufferHeight))
- throw std::out_of_range(rfb::format("Invalid PixelBuffer height of %d pixels requested", height));
+ throw std::out_of_range(core::format(
+ "Invalid PixelBuffer height of %d pixels requested", height));
width_ = width;
height_ = height;
@@ -150,17 +152,17 @@ ModifiablePixelBuffer::~ModifiablePixelBuffer()
{
}
-void ModifiablePixelBuffer::fillRect(const Rect& r, const void* pix)
+void ModifiablePixelBuffer::fillRect(const core::Rect& r,
+ const void* pix)
{
int stride;
uint8_t *buf;
int w, h, b;
if (!r.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- r.width(), r.height(),
- r.tl.x, r.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
+ r.width(), r.height(), r.tl.x, r.tl.y, width(), height()));
w = r.width();
h = r.height();
@@ -199,7 +201,7 @@ void ModifiablePixelBuffer::fillRect(const Rect& r, const void* pix)
commitBufferRW(r);
}
-void ModifiablePixelBuffer::imageRect(const Rect& r,
+void ModifiablePixelBuffer::imageRect(const core::Rect& r,
const void* pixels, int srcStride)
{
uint8_t* dest;
@@ -209,10 +211,9 @@ void ModifiablePixelBuffer::imageRect(const Rect& r,
uint8_t* end;
if (!r.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- r.width(), r.height(),
- r.tl.x, r.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
+ r.width(), r.height(), r.tl.x, r.tl.y, width(), height()));
bytesPerPixel = getPF().bpp/8;
@@ -237,29 +238,29 @@ void ModifiablePixelBuffer::imageRect(const Rect& r,
commitBufferRW(r);
}
-void ModifiablePixelBuffer::copyRect(const Rect &rect,
- const Point &move_by_delta)
+void ModifiablePixelBuffer::copyRect(const core::Rect& rect,
+ const core::Point& move_by_delta)
{
int srcStride, dstStride;
int bytesPerPixel;
const uint8_t* srcData;
uint8_t* dstData;
- Rect drect, srect;
+ core::Rect drect, srect;
drect = rect;
if (!drect.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- drect.width(), drect.height(),
- drect.tl.x, drect.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
+ drect.width(), drect.height(), drect.tl.x, drect.tl.y,
+ width(), height()));
srect = drect.translate(move_by_delta.negate());
if (!srect.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- srect.width(), srect.height(),
- srect.tl.x, srect.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Source rect %dx%d at %d,%d exceeds framebuffer %dx%d",
+ srect.width(), srect.height(), srect.tl.x, srect.tl.y,
+ width(), height()));
bytesPerPixel = format.bpp/8;
@@ -297,7 +298,8 @@ void ModifiablePixelBuffer::copyRect(const Rect &rect,
commitBufferRW(drect);
}
-void ModifiablePixelBuffer::fillRect(const PixelFormat& pf, const Rect &dest,
+void ModifiablePixelBuffer::fillRect(const PixelFormat& pf,
+ const core::Rect& dest,
const void* pix)
{
uint8_t buf[4];
@@ -305,17 +307,18 @@ void ModifiablePixelBuffer::fillRect(const PixelFormat& pf, const Rect &dest,
fillRect(dest, buf);
}
-void ModifiablePixelBuffer::imageRect(const PixelFormat& pf, const Rect &dest,
+void ModifiablePixelBuffer::imageRect(const PixelFormat& pf,
+ const core::Rect& dest,
const void* pixels, int stride)
{
uint8_t* dstBuffer;
int dstStride;
if (!dest.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
- dest.width(), dest.height(),
- dest.tl.x, dest.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Destination rect %dx%d at %d,%d exceeds framebuffer %dx%d",
+ dest.width(), dest.height(), dest.tl.x, dest.tl.y,
+ width(), height()));
if (stride == 0)
stride = dest.width();
@@ -339,29 +342,29 @@ FullFramePixelBuffer::FullFramePixelBuffer() : data(nullptr) {}
FullFramePixelBuffer::~FullFramePixelBuffer() {}
-uint8_t* FullFramePixelBuffer::getBufferRW(const Rect& r, int* stride_)
+uint8_t* FullFramePixelBuffer::getBufferRW(const core::Rect& r,
+ int* stride_)
{
if (!r.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d",
- r.width(), r.height(),
- r.tl.x, r.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d",
+ r.width(), r.height(), r.tl.x, r.tl.y, width(), height()));
*stride_ = stride;
return &data[(r.tl.x + (r.tl.y * stride)) * (format.bpp/8)];
}
-void FullFramePixelBuffer::commitBufferRW(const Rect& /*r*/)
+void FullFramePixelBuffer::commitBufferRW(const core::Rect& /*r*/)
{
}
-const uint8_t* FullFramePixelBuffer::getBuffer(const Rect& r, int* stride_) const
+const uint8_t* FullFramePixelBuffer::getBuffer(const core::Rect& r,
+ int* stride_) const
{
if (!r.enclosed_by(getRect()))
- throw std::out_of_range(rfb::format("Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d",
- r.width(), r.height(),
- r.tl.x, r.tl.y,
- width(), height()));
+ throw std::out_of_range(core::format(
+ "Pixel buffer request %dx%d at %d,%d exceeds framebuffer %dx%d",
+ r.width(), r.height(), r.tl.x, r.tl.y, width(), height()));
*stride_ = stride;
return &data[(r.tl.x + (r.tl.y * stride)) * (format.bpp/8)];
@@ -371,13 +374,17 @@ void FullFramePixelBuffer::setBuffer(int width, int height,
uint8_t* data_, int stride_)
{
if ((width < 0) || (width > maxPixelBufferWidth))
- throw std::out_of_range(rfb::format("Invalid PixelBuffer width of %d pixels requested", width));
+ throw std::out_of_range(core::format(
+ "Invalid PixelBuffer width of %d pixels requested", width));
if ((height < 0) || (height > maxPixelBufferHeight))
- throw std::out_of_range(rfb::format("Invalid PixelBuffer height of %d pixels requested", height));
+ throw std::out_of_range(core::format(
+ "Invalid PixelBuffer height of %d pixels requested", height));
if ((stride_ < 0) || (stride_ > maxPixelBufferStride) || (stride_ < width))
- throw std::invalid_argument(rfb::format("Invalid PixelBuffer stride of %d pixels requested", stride_));
+ throw std::invalid_argument(core::format(
+ "Invalid PixelBuffer stride of %d pixels requested", stride_));
if ((width != 0) && (height != 0) && (data_ == nullptr))
- throw std::logic_error(rfb::format("PixelBuffer requested without a valid memory area"));
+ throw std::logic_error(core::format(
+ "PixelBuffer requested without a valid memory area"));
ModifiablePixelBuffer::setSize(width, height);
stride = stride_;
diff --git a/common/rfb/PixelBuffer.h b/common/rfb/PixelBuffer.h
index 963fbbf6..9fbea611 100644
--- a/common/rfb/PixelBuffer.h
+++ b/common/rfb/PixelBuffer.h
@@ -25,12 +25,13 @@
#ifndef __RFB_PIXEL_BUFFER_H__
#define __RFB_PIXEL_BUFFER_H__
+#include <core/Rect.h>
+
#include <rfb/PixelFormat.h>
-#include <rfb/Rect.h>
-namespace rfb {
+namespace core { class Region; }
- class Region;
+namespace rfb {
class PixelBuffer {
public:
@@ -52,9 +53,9 @@ namespace rfb {
// Get rectangle encompassing this buffer
// Top-left of rectangle is either at (0,0), or the specified point.
- Rect getRect() const { return Rect(0, 0, width_, height_); }
- Rect getRect(const Point& pos) const {
- return Rect(pos, pos.translate(Point(width_, height_)));
+ core::Rect getRect() const { return {0, 0, width_, height_}; }
+ core::Rect getRect(const core::Point& pos) const {
+ return {pos, pos.translate({width_, height_})};
}
///////////////////////////////////////////////
@@ -64,18 +65,20 @@ namespace rfb {
// Get a pointer into the buffer
// The pointer is to the top-left pixel of the specified Rect.
// The buffer stride (in pixels) is returned.
- virtual const uint8_t* getBuffer(const Rect& r, int* stride) const = 0;
+ virtual const uint8_t* getBuffer(const core::Rect& r,
+ int* stride) const = 0;
// Get pixel data for a given part of the buffer
// Data is copied into the supplied buffer, with the specified
// stride. Try to avoid using this though as getBuffer() will in
// most cases avoid the extra memory copy.
- void getImage(void* imageBuf, const Rect& r, int stride=0) const;
+ void getImage(void* imageBuf, const core::Rect& r,
+ int stride=0) const;
// Get pixel data in a given format
// Works just the same as getImage(), but guaranteed to be in a
// specific format.
void getImage(const PixelFormat& pf, void* imageBuf,
- const Rect& r, int stride=0) const;
+ const core::Rect& r, int stride=0) const;
///////////////////////////////////////////////
// Framebuffer update methods
@@ -84,7 +87,7 @@ namespace rfb {
// Ensure that the specified rectangle of buffer is up to date.
// Overridden by derived classes implementing framebuffer access
// to copy the required display data into place.
- virtual void grabRegion(const Region& /*region*/) {}
+ virtual void grabRegion(const core::Region& /*region*/) {}
protected:
PixelBuffer();
@@ -110,32 +113,35 @@ namespace rfb {
// Get a writeable pointer into the buffer
// Like getBuffer(), the pointer is to the top-left pixel of the
// specified Rect and the stride in pixels is returned.
- virtual uint8_t* getBufferRW(const Rect& r, int* stride) = 0;
+ virtual uint8_t* getBufferRW(const core::Rect& r, int* stride) = 0;
// Commit the modified contents
// Ensures that the changes to the specified Rect is properly
// stored away and any temporary buffers are freed. The Rect given
// here needs to match the Rect given to the earlier call to
// getBufferRW().
- virtual void commitBufferRW(const Rect& r) = 0;
+ virtual void commitBufferRW(const core::Rect& r) = 0;
///////////////////////////////////////////////
// Basic rendering operations
// These operations DO NOT clip to the pixelbuffer area, or trap overruns.
// Fill a rectangle
- void fillRect(const Rect &dest, const void* pix);
+ void fillRect(const core::Rect& dest, const void* pix);
// Copy pixel data to the buffer
- void imageRect(const Rect &dest, const void* pixels, int stride=0);
+ void imageRect(const core::Rect& dest, const void* pixels,
+ int stride=0);
// Copy pixel data from one PixelBuffer location to another
- void copyRect(const Rect &dest, const Point& move_by_delta);
+ void copyRect(const core::Rect& dest,
+ const core::Point& move_by_delta);
// Render in a specific format
// Does the exact same thing as the above methods, but the given
// pixel values are defined by the given PixelFormat.
- void fillRect(const PixelFormat& pf, const Rect &dest, const void* pix);
- void imageRect(const PixelFormat& pf, const Rect &dest,
+ void fillRect(const PixelFormat& pf, const core::Rect& dest,
+ const void* pix);
+ void imageRect(const PixelFormat& pf, const core::Rect& dest,
const void* pixels, int stride=0);
protected:
@@ -151,9 +157,10 @@ namespace rfb {
virtual ~FullFramePixelBuffer();
public:
- const uint8_t* getBuffer(const Rect& r, int* stride) const override;
- uint8_t* getBufferRW(const Rect& r, int* stride) override;
- void commitBufferRW(const Rect& r) override;
+ const uint8_t* getBuffer(const core::Rect& r,
+ int* stride) const override;
+ uint8_t* getBufferRW(const core::Rect& r, int* stride) override;
+ void commitBufferRW(const core::Rect& r) override;
protected:
FullFramePixelBuffer();
diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h
index f0a16767..7b754da8 100644
--- a/common/rfb/PixelFormat.h
+++ b/common/rfb/PixelFormat.h
@@ -136,7 +136,7 @@ namespace rfb {
/* Only for testing this class */
friend void makePixel(const rfb::PixelFormat &, uint8_t *);
- friend bool verifyPixel(const rfb::PixelFormat &,
+ friend void verifyPixel(const rfb::PixelFormat &,
const rfb::PixelFormat &,
const uint8_t *);
};
diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx
index 53ddc2da..d2c3d3e6 100644
--- a/common/rfb/RREDecoder.cxx
+++ b/common/rfb/RREDecoder.cxx
@@ -40,7 +40,7 @@ RREDecoder::~RREDecoder()
{
}
-bool RREDecoder::readRect(const Rect& /*r*/, rdr::InStream* is,
+bool RREDecoder::readRect(const core::Rect& /*r*/, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os)
{
uint32_t numRects;
@@ -66,7 +66,7 @@ bool RREDecoder::readRect(const Rect& /*r*/, rdr::InStream* is,
return true;
}
-void RREDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
+void RREDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
@@ -91,7 +91,7 @@ inline T RREDecoder::readPixel(rdr::InStream* is)
}
template<class T>
-void RREDecoder::rreDecode(const Rect& r, rdr::InStream* is,
+void RREDecoder::rreDecode(const core::Rect& r, rdr::InStream* is,
const PixelFormat& pf,
ModifiablePixelBuffer* pb)
{
@@ -109,6 +109,6 @@ void RREDecoder::rreDecode(const Rect& r, rdr::InStream* is,
if (((x+w) > r.width()) || ((y+h) > r.height()))
throw protocol_error("RRE decode error");
- pb->fillRect(pf, Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), &pix);
+ pb->fillRect(pf, {r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h}, &pix);
}
}
diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h
index 8490146c..3fdcdd85 100644
--- a/common/rfb/RREDecoder.h
+++ b/common/rfb/RREDecoder.h
@@ -29,17 +29,17 @@ namespace rfb {
public:
RREDecoder();
virtual ~RREDecoder();
- bool readRect(const Rect& r, rdr::InStream* is,
+ bool readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server,
rdr::OutStream* os) override;
- void decodeRect(const Rect& r, const uint8_t* buffer,
+ void decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) override;
private:
template<class T>
inline T readPixel(rdr::InStream* is);
template<class T>
- void rreDecode(const Rect& r, rdr::InStream* is,
+ void rreDecode(const core::Rect& r, rdr::InStream* is,
const PixelFormat& pf, ModifiablePixelBuffer* pb);
};
}
diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx
index f2ea586b..43ce15a4 100644
--- a/common/rfb/RawDecoder.cxx
+++ b/common/rfb/RawDecoder.cxx
@@ -37,7 +37,7 @@ RawDecoder::~RawDecoder()
{
}
-bool RawDecoder::readRect(const Rect& r, rdr::InStream* is,
+bool RawDecoder::readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os)
{
if (!is->hasData(r.area() * (server.pf().bpp/8)))
@@ -46,7 +46,7 @@ bool RawDecoder::readRect(const Rect& r, rdr::InStream* is,
return true;
}
-void RawDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
+void RawDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h
index 2ac8b0bd..6c3a6357 100644
--- a/common/rfb/RawDecoder.h
+++ b/common/rfb/RawDecoder.h
@@ -25,10 +25,10 @@ namespace rfb {
public:
RawDecoder();
virtual ~RawDecoder();
- bool readRect(const Rect& r, rdr::InStream* is,
+ bool readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server,
rdr::OutStream* os) override;
- void decodeRect(const Rect& r, const uint8_t* buffer,
+ void decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) override;
};
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index a0a1c373..c698b991 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -26,6 +26,11 @@
#include <algorithm>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
+#include <rdr/OutStream.h>
+
#include <rfb/Exception.h>
#include <rfb/Security.h>
#include <rfb/clipboardTypes.h>
@@ -38,13 +43,10 @@
#include <rfb/encodings.h>
#include <rfb/EncodeManager.h>
#include <rfb/SSecurity.h>
-#include <rfb/util.h>
-
-#include <rfb/LogWriter.h>
using namespace rfb;
-static LogWriter vlog("SConnection");
+static core::LogWriter vlog("SConnection");
SConnection::SConnection(AccessRights accessRights_)
: readyForSetColourMapEntries(false), is(nullptr), os(nullptr),
@@ -133,10 +135,10 @@ bool SConnection::processVersionMsg()
if (client.majorVersion != 3) {
// unknown protocol version
- failConnection(format("Client needs protocol version %d.%d, "
- "server has %d.%d",
- client.majorVersion, client.minorVersion,
- defaultMajorVersion, defaultMinorVersion));
+ failConnection(core::format(
+ "Client needs protocol version %d.%d, server has %d.%d",
+ client.majorVersion, client.minorVersion,
+ defaultMajorVersion, defaultMinorVersion));
}
if (client.minorVersion != 3 && client.minorVersion != 7 && client.minorVersion != 8) {
@@ -152,8 +154,6 @@ bool SConnection::processVersionMsg()
client.majorVersion,client.minorVersion);
}
- versionReceived();
-
std::list<uint8_t> secTypes;
std::list<uint8_t>::iterator i;
secTypes = security.GetEnabledSecTypes();
@@ -166,9 +166,9 @@ bool SConnection::processVersionMsg()
if (*i == secTypeNone || *i == secTypeVncAuth) break;
}
if (i == secTypes.end()) {
- failConnection(format("No supported security type for "
- "%d.%d client",
- client.majorVersion, client.minorVersion));
+ failConnection(
+ core::format("No supported security type for %d.%d client",
+ client.majorVersion, client.minorVersion));
}
os->writeU32(*i);
@@ -278,7 +278,7 @@ bool SConnection::processInitMsg()
return reader_->readClientInit();
}
-void SConnection::handleAuthFailureTimeout(Timer* /*t*/)
+void SConnection::handleAuthFailureTimeout(core::Timer* /*t*/)
{
if (state_ != RFBSTATE_SECURITY_FAILURE) {
close("SConnection::handleAuthFailureTimeout: Invalid state");
@@ -344,6 +344,8 @@ bool SConnection::accessCheck(AccessRights ar) const
void SConnection::setEncodings(int nEncodings, const int32_t* encodings)
{
int i;
+ bool firstFence, firstContinuousUpdates, firstLEDState,
+ firstQEMUKeyEvent, firstExtMouseButtonsEvent;
preferredEncoding = encodingRaw;
for (i = 0;i < nEncodings;i++) {
@@ -353,7 +355,26 @@ void SConnection::setEncodings(int nEncodings, const int32_t* encodings)
}
}
- SMsgHandler::setEncodings(nEncodings, encodings);
+ firstFence = !client.supportsFence();
+ firstContinuousUpdates = !client.supportsContinuousUpdates();
+ firstLEDState = !client.supportsLEDState();
+ firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent);
+ firstExtMouseButtonsEvent = !client.supportsEncoding(pseudoEncodingExtendedMouseButtons);
+
+ client.setEncodings(nEncodings, encodings);
+
+ supportsLocalCursor();
+
+ if (client.supportsFence() && firstFence)
+ supportsFence();
+ if (client.supportsContinuousUpdates() && firstContinuousUpdates)
+ supportsContinuousUpdates();
+ if (client.supportsLEDState() && firstLEDState)
+ supportsLEDState();
+ if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent)
+ writer()->writeQEMUKeyEvent();
+ if (client.supportsEncoding(pseudoEncodingExtendedMouseButtons) && firstExtMouseButtonsEvent)
+ writer()->writeExtendedMouseButtonsSupport();
if (client.supportsEncoding(pseudoEncodingExtendedClipboard)) {
uint32_t sizes[] = { 0 };
@@ -373,9 +394,54 @@ void SConnection::clientCutText(const char* str)
clientClipboard = str;
hasRemoteClipboard = true;
+ if (!accessCheck(AccessCutText))
+ return;
+
handleClipboardAnnounce(true);
}
+void SConnection::handleClipboardCaps(uint32_t flags, const uint32_t* lengths)
+{
+ int i;
+
+ vlog.debug("Got client clipboard capabilities:");
+ for (i = 0;i < 16;i++) {
+ if (flags & (1 << i)) {
+ const char *type;
+
+ switch (1 << i) {
+ case clipboardUTF8:
+ type = "Plain text";
+ break;
+ case clipboardRTF:
+ type = "Rich text";
+ break;
+ case clipboardHTML:
+ type = "HTML";
+ break;
+ case clipboardDIB:
+ type = "Images";
+ break;
+ case clipboardFiles:
+ type = "Files";
+ break;
+ default:
+ vlog.debug(" Unknown format 0x%x", 1 << i);
+ continue;
+ }
+
+ if (lengths[i] == 0)
+ vlog.debug(" %s (only notify)", type);
+ else {
+ vlog.debug(" %s (automatically send up to %s)",
+ type, core::iecPrefix(lengths[i], "B").c_str());
+ }
+ }
+ }
+
+ client.setClipboardCaps(flags, lengths);
+}
+
void SConnection::handleClipboardRequest(uint32_t flags)
{
if (!(flags & rfb::clipboardUTF8)) {
@@ -386,6 +452,8 @@ void SConnection::handleClipboardRequest(uint32_t flags)
vlog.debug("Ignoring unexpected clipboard request");
return;
}
+ if (!accessCheck(AccessCutText))
+ return;
handleClipboardRequest();
}
@@ -401,10 +469,15 @@ void SConnection::handleClipboardNotify(uint32_t flags)
if (flags & rfb::clipboardUTF8) {
hasLocalClipboard = false;
+ if (!accessCheck(AccessCutText))
+ return;
handleClipboardAnnounce(true);
} else {
+ if (!accessCheck(AccessCutText))
+ return;
handleClipboardAnnounce(false);
}
+
}
void SConnection::handleClipboardProvide(uint32_t flags,
@@ -417,28 +490,33 @@ void SConnection::handleClipboardProvide(uint32_t flags,
}
// FIXME: This conversion magic should be in SMsgReader
- if (!isValidUTF8((const char*)data[0], lengths[0])) {
+ if (!core::isValidUTF8((const char*)data[0], lengths[0])) {
vlog.error("Invalid UTF-8 sequence in clipboard - ignoring");
return;
}
- clientClipboard = convertLF((const char*)data[0], lengths[0]);
+ clientClipboard = core::convertLF((const char*)data[0], lengths[0]);
hasRemoteClipboard = true;
+ if (!accessCheck(AccessCutText))
+ return;
+
// FIXME: Should probably verify that this data was actually requested
handleClipboardData(clientClipboard.c_str());
}
-void SConnection::supportsQEMUKeyEvent()
+void SConnection::supportsLocalCursor()
{
- writer()->writeQEMUKeyEvent();
}
-void SConnection::supportsExtendedMouseButtons()
+void SConnection::supportsFence()
{
- writer()->writeExtendedMouseButtonsSupport();
}
-void SConnection::versionReceived()
+void SConnection::supportsContinuousUpdates()
+{
+}
+
+void SConnection::supportsLEDState()
{
}
@@ -500,13 +578,13 @@ void SConnection::close(const char* /*reason*/)
void SConnection::setPixelFormat(const PixelFormat& pf)
{
- SMsgHandler::setPixelFormat(pf);
+ client.setPF(pf);
readyForSetColourMapEntries = true;
if (!pf.trueColour)
writeFakeColourMap();
}
-void SConnection::framebufferUpdateRequest(const Rect& /*r*/,
+void SConnection::framebufferUpdateRequest(const core::Rect& /*r*/,
bool /*incremental*/)
{
if (!readyForSetColourMapEntries) {
@@ -549,6 +627,9 @@ void SConnection::handleClipboardData(const char* /*data*/)
void SConnection::requestClipboard()
{
+ if (!accessCheck(AccessCutText))
+ return;
+
if (hasRemoteClipboard) {
handleClipboardData(clientClipboard.c_str());
return;
@@ -561,6 +642,9 @@ void SConnection::requestClipboard()
void SConnection::announceClipboard(bool available)
{
+ if (!accessCheck(AccessCutText))
+ return;
+
hasLocalClipboard = available;
unsolicitedClipboardAttempt = false;
@@ -587,10 +671,13 @@ void SConnection::announceClipboard(bool available)
void SConnection::sendClipboardData(const char* data)
{
+ if (!accessCheck(AccessCutText))
+ return;
+
if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
(client.clipboardFlags() & rfb::clipboardProvide)) {
// FIXME: This conversion magic should be in SMsgWriter
- std::string filtered(convertCRLF(data));
+ std::string filtered(core::convertCRLF(data));
size_t sizes[1] = { filtered.size() + 1 };
const uint8_t* datas[1] = { (const uint8_t*)filtered.c_str() };
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
index f030ae05..a90b37ca 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -26,13 +26,16 @@
#include <string>
-#include <rdr/InStream.h>
-#include <rdr/OutStream.h>
+#include <core/Timer.h>
#include <rfb/AccessRights.h>
#include <rfb/SMsgHandler.h>
#include <rfb/SecurityServer.h>
-#include <rfb/Timer.h>
+
+namespace rdr {
+ class InStream;
+ class OutStream;
+}
namespace rfb {
@@ -84,6 +87,59 @@ namespace rfb {
// cleanup of the SConnection object by the server
virtual void close(const char* reason);
+ // requestClipboard() will result in a request to the client to
+ // transfer its clipboard data. A call to handleClipboardData()
+ // will be made once the data is available.
+ virtual void requestClipboard();
+
+ // announceClipboard() informs the client of changes to the
+ // clipboard on the server. The client may later request the
+ // clipboard data via handleClipboardRequest().
+ virtual void announceClipboard(bool available);
+
+ // sendClipboardData() transfers the clipboard data to the client
+ // and should be called whenever the client has requested the
+ // clipboard via handleClipboardRequest().
+ virtual void sendClipboardData(const char* data);
+
+ // getAccessRights() returns the access rights of a SConnection to the server.
+ AccessRights getAccessRights() { return accessRights; }
+
+ // setAccessRights() allows a security package to limit the access rights
+ // of a SConnection to the server. How the access rights are treated
+ // is up to the derived class.
+ virtual void setAccessRights(AccessRights ar);
+ virtual bool accessCheck(AccessRights ar) const;
+
+ // authenticated() returns true if the client has authenticated
+ // successfully.
+ bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
+ state_ == RFBSTATE_NORMAL); }
+
+ SMsgReader* reader() { return reader_; }
+ SMsgWriter* writer() { return writer_; }
+
+ rdr::InStream* getInStream() { return is; }
+ rdr::OutStream* getOutStream() { return os; }
+
+ enum stateEnum {
+ RFBSTATE_UNINITIALISED,
+ RFBSTATE_PROTOCOL_VERSION,
+ RFBSTATE_SECURITY_TYPE,
+ RFBSTATE_SECURITY,
+ RFBSTATE_SECURITY_FAILURE,
+ RFBSTATE_QUERYING,
+ RFBSTATE_INITIALISATION,
+ RFBSTATE_NORMAL,
+ RFBSTATE_CLOSING,
+ RFBSTATE_INVALID
+ };
+
+ stateEnum state() { return state_; }
+
+ int32_t getPreferredEncoding() { return preferredEncoding; }
+
+ protected:
// Overridden from SMsgHandler
@@ -91,23 +147,38 @@ namespace rfb {
void clientCutText(const char* str) override;
+ void handleClipboardCaps(uint32_t flags,
+ const uint32_t* lengths) override;
void handleClipboardRequest(uint32_t flags) override;
void handleClipboardPeek() override;
void handleClipboardNotify(uint32_t flags) override;
void handleClipboardProvide(uint32_t flags, const size_t* lengths,
const uint8_t* const* data) override;
- void supportsQEMUKeyEvent() override;
-
- virtual void supportsExtendedMouseButtons() override;
-
-
// Methods to be overridden in a derived class
- // versionReceived() indicates that the version number has just been read
- // from the client. The version will already have been "cooked"
- // to deal with unknown/bogus viewer protocol numbers.
- virtual void versionReceived();
+ // supportsLocalCursor() is called whenever the status of
+ // cp.supportsLocalCursor has changed. At the moment this happens on a
+ // setEncodings message, but in the future this may be due to a message
+ // specially for this purpose.
+ virtual void supportsLocalCursor();
+
+ // supportsFence() is called the first time we detect support for fences
+ // in the client. A fence message should be sent at this point to notify
+ // the client of server support.
+ virtual void supportsFence();
+
+ // supportsContinuousUpdates() is called the first time we detect that
+ // the client wants the continuous updates extension. A
+ // EndOfContinuousUpdates message should be sent back to the client at
+ // this point if it is supported.
+ virtual void supportsContinuousUpdates();
+
+ // supportsLEDState() is called the first time we detect that the
+ // client supports the LED state extension. A LEDState message
+ // should be sent back to the client to inform it of the current
+ // server state.
+ virtual void supportsLEDState();
// authSuccess() is called when authentication has succeeded.
virtual void authSuccess();
@@ -132,7 +203,7 @@ namespace rfb {
// framebufferUpdateRequest() is called when a FramebufferUpdateRequest
// message is received. The derived class must call on to
// SConnection::framebufferUpdateRequest().
- void framebufferUpdateRequest(const Rect& r, bool incremental) override;
+ void framebufferUpdateRequest(const core::Rect& r, bool incremental) override;
// fence() is called when we get a fence request or response. By default
// it responds directly to requests (stating it doesn't support any
@@ -163,62 +234,6 @@ namespace rfb {
// client received the request.
virtual void handleClipboardData(const char* data);
-
- // Other methods
-
- // requestClipboard() will result in a request to the client to
- // transfer its clipboard data. A call to handleClipboardData()
- // will be made once the data is available.
- virtual void requestClipboard();
-
- // announceClipboard() informs the client of changes to the
- // clipboard on the server. The client may later request the
- // clipboard data via handleClipboardRequest().
- virtual void announceClipboard(bool available);
-
- // sendClipboardData() transfers the clipboard data to the client
- // and should be called whenever the client has requested the
- // clipboard via handleClipboardRequest().
- virtual void sendClipboardData(const char* data);
-
- // getAccessRights() returns the access rights of a SConnection to the server.
- AccessRights getAccessRights() { return accessRights; }
-
- // setAccessRights() allows a security package to limit the access rights
- // of a SConnection to the server. How the access rights are treated
- // is up to the derived class.
- virtual void setAccessRights(AccessRights ar);
- virtual bool accessCheck(AccessRights ar) const;
-
- // authenticated() returns true if the client has authenticated
- // successfully.
- bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
- state_ == RFBSTATE_NORMAL); }
-
- SMsgReader* reader() { return reader_; }
- SMsgWriter* writer() { return writer_; }
-
- rdr::InStream* getInStream() { return is; }
- rdr::OutStream* getOutStream() { return os; }
-
- enum stateEnum {
- RFBSTATE_UNINITIALISED,
- RFBSTATE_PROTOCOL_VERSION,
- RFBSTATE_SECURITY_TYPE,
- RFBSTATE_SECURITY,
- RFBSTATE_SECURITY_FAILURE,
- RFBSTATE_QUERYING,
- RFBSTATE_INITIALISATION,
- RFBSTATE_NORMAL,
- RFBSTATE_CLOSING,
- RFBSTATE_INVALID
- };
-
- stateEnum state() { return state_; }
-
- int32_t getPreferredEncoding() { return preferredEncoding; }
-
- protected:
// failConnection() prints a message to the log, sends a connection
// failed message to the client (if possible) and throws an
// Exception.
@@ -243,7 +258,7 @@ namespace rfb {
bool processSecurityFailure();
bool processInitMsg();
- void handleAuthFailureTimeout(Timer* t);
+ void handleAuthFailureTimeout(core::Timer* t);
int defaultMajorVersion, defaultMinorVersion;
@@ -256,7 +271,7 @@ namespace rfb {
SecurityServer security;
SSecurity* ssecurity;
- MethodTimer<SConnection> authFailureTimer;
+ core::MethodTimer<SConnection> authFailureTimer;
std::string authFailureMsg;
stateEnum state_;
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
index c97e788a..402a13af 100644
--- a/common/rfb/SDesktop.h
+++ b/common/rfb/SDesktop.h
@@ -38,14 +38,19 @@
#ifndef __RFB_SDESKTOP_H__
#define __RFB_SDESKTOP_H__
-#include <rfb/PixelBuffer.h>
-#include <rfb/VNCServer.h>
+#include <stdint.h>
+
#include <rfb/screenTypes.h>
+namespace core { struct Point; }
+
namespace network { class Socket; }
namespace rfb {
+ struct ScreenSet;
+ class VNCServer;
+
class SDesktop {
public:
// init() is called immediately when the VNCServer gets a reference
@@ -97,7 +102,7 @@ namespace rfb {
// pointerEvent() is called whenever a client sends an event that
// the pointer moved, or a button was pressed or released.
- virtual void pointerEvent(const Point& /*pos*/,
+ virtual void pointerEvent(const core::Point& /*pos*/,
uint16_t /*buttonMask*/) {};
// handleClipboardRequest() is called whenever a client requests
@@ -122,47 +127,6 @@ namespace rfb {
virtual ~SDesktop() {}
};
- // -=- SStaticDesktop
- // Trivial implementation of the SDesktop interface, which provides
- // dummy input handlers and event processing routine, and exports
- // a plain black desktop of the specified format.
- class SStaticDesktop : public SDesktop {
- public:
- SStaticDesktop(const Point& size)
- : server(nullptr), buffer(nullptr)
- {
- PixelFormat pf;
- const uint8_t black[4] = { 0, 0, 0, 0 };
- buffer = new ManagedPixelBuffer(pf, size.x, size.y);
- if (buffer)
- buffer->fillRect(buffer->getRect(), black);
- }
- SStaticDesktop(const Point& size, const PixelFormat& pf)
- : buffer(nullptr)
- {
- const uint8_t black[4] = { 0, 0, 0, 0 };
- buffer = new ManagedPixelBuffer(pf, size.x, size.y);
- if (buffer)
- buffer->fillRect(buffer->getRect(), black);
- }
- virtual ~SStaticDesktop() {
- if (buffer) delete buffer;
- }
-
- void init(VNCServer* vs) override {
- server = vs;
- server->setPixelBuffer(buffer);
- }
- void queryConnection(network::Socket* sock,
- const char* /*userName*/) override {
- server->approveConnection(sock, true, nullptr);
- }
-
- protected:
- VNCServer* server;
- ManagedPixelBuffer* buffer;
- };
-
};
#endif // __RFB_SDESKTOP_H__
diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx
deleted file mode 100644
index 1dce634d..00000000
--- a/common/rfb/SMsgHandler.cxx
+++ /dev/null
@@ -1,176 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2009-2019 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <rfb/Exception.h>
-#include <rfb/LogWriter.h>
-#include <rfb/SMsgHandler.h>
-#include <rfb/ScreenSet.h>
-#include <rfb/clipboardTypes.h>
-#include <rfb/encodings.h>
-#include <rfb/util.h>
-
-using namespace rfb;
-
-static LogWriter vlog("SMsgHandler");
-
-SMsgHandler::SMsgHandler()
-{
-}
-
-SMsgHandler::~SMsgHandler()
-{
-}
-
-void SMsgHandler::clientInit(bool /*shared*/)
-{
-}
-
-void SMsgHandler::setPixelFormat(const PixelFormat& pf)
-{
- client.setPF(pf);
-}
-
-void SMsgHandler::setEncodings(int nEncodings, const int32_t* encodings)
-{
- bool firstFence, firstContinuousUpdates, firstLEDState,
- firstQEMUKeyEvent, firstExtMouseButtonsEvent;
-
- firstFence = !client.supportsFence();
- firstContinuousUpdates = !client.supportsContinuousUpdates();
- firstLEDState = !client.supportsLEDState();
- firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent);
- firstExtMouseButtonsEvent = !client.supportsEncoding(pseudoEncodingExtendedMouseButtons);
-
- client.setEncodings(nEncodings, encodings);
-
- supportsLocalCursor();
-
- if (client.supportsFence() && firstFence)
- supportsFence();
- if (client.supportsContinuousUpdates() && firstContinuousUpdates)
- supportsContinuousUpdates();
- if (client.supportsLEDState() && firstLEDState)
- supportsLEDState();
- if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent)
- supportsQEMUKeyEvent();
- if (client.supportsEncoding(pseudoEncodingExtendedMouseButtons) && firstExtMouseButtonsEvent)
- supportsExtendedMouseButtons();
-}
-
-void SMsgHandler::keyEvent(uint32_t /*keysym*/, uint32_t /*keycode*/,
- bool /*down*/)
-{
-}
-
-void SMsgHandler::pointerEvent(const Point& /*pos*/,
- uint16_t /*buttonMask*/)
-{
-}
-
-void SMsgHandler::clientCutText(const char* /*str*/)
-{
-}
-
-void SMsgHandler::handleClipboardCaps(uint32_t flags, const uint32_t* lengths)
-{
- int i;
-
- vlog.debug("Got client clipboard capabilities:");
- for (i = 0;i < 16;i++) {
- if (flags & (1 << i)) {
- const char *type;
-
- switch (1 << i) {
- case clipboardUTF8:
- type = "Plain text";
- break;
- case clipboardRTF:
- type = "Rich text";
- break;
- case clipboardHTML:
- type = "HTML";
- break;
- case clipboardDIB:
- type = "Images";
- break;
- case clipboardFiles:
- type = "Files";
- break;
- default:
- vlog.debug(" Unknown format 0x%x", 1 << i);
- continue;
- }
-
- if (lengths[i] == 0)
- vlog.debug(" %s (only notify)", type);
- else {
- vlog.debug(" %s (automatically send up to %s)",
- type, iecPrefix(lengths[i], "B").c_str());
- }
- }
- }
-
- client.setClipboardCaps(flags, lengths);
-}
-
-void SMsgHandler::handleClipboardRequest(uint32_t /*flags*/)
-{
-}
-
-void SMsgHandler::handleClipboardPeek()
-{
-}
-
-void SMsgHandler::handleClipboardNotify(uint32_t /*flags*/)
-{
-}
-
-void SMsgHandler::handleClipboardProvide(uint32_t /*flags*/,
- const size_t* /*lengths*/,
- const uint8_t* const* /*data*/)
-{
-}
-
-void SMsgHandler::supportsLocalCursor()
-{
-}
-
-void SMsgHandler::supportsFence()
-{
-}
-
-void SMsgHandler::supportsContinuousUpdates()
-{
-}
-
-void SMsgHandler::supportsLEDState()
-{
-}
-
-void SMsgHandler::supportsQEMUKeyEvent()
-{
-}
-
-void SMsgHandler::supportsExtendedMouseButtons()
-{
-} \ No newline at end of file
diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h
index c5d13d78..d14a21c0 100644
--- a/common/rfb/SMsgHandler.h
+++ b/common/rfb/SMsgHandler.h
@@ -25,83 +25,47 @@
#include <stdint.h>
-#include <rfb/PixelFormat.h>
#include <rfb/ClientParams.h>
-#include <rfb/ScreenSet.h>
-
-namespace rdr { class InStream; }
namespace rfb {
class SMsgHandler {
public:
- SMsgHandler();
- virtual ~SMsgHandler();
+ virtual ~SMsgHandler() {}
- // The following methods are called as corresponding messages are read. A
- // derived class should override these methods as desired. Note that for
- // the setPixelFormat(), setEncodings() and clipboardCaps() methods, a
- // derived class must call on to SMsgHandler's methods.
+ // The following methods are called as corresponding messages are
+ // read. A derived class must override these methods.
- virtual void clientInit(bool shared);
+ virtual void clientInit(bool shared) = 0;
- virtual void setPixelFormat(const PixelFormat& pf);
- virtual void setEncodings(int nEncodings, const int32_t* encodings);
- virtual void framebufferUpdateRequest(const Rect& r, bool incremental) = 0;
+ virtual void setPixelFormat(const PixelFormat& pf) = 0;
+ virtual void setEncodings(int nEncodings,
+ const int32_t* encodings) = 0;
+ virtual void framebufferUpdateRequest(const core::Rect& r,
+ bool incremental) = 0;
virtual void setDesktopSize(int fb_width, int fb_height,
const ScreenSet& layout) = 0;
- virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]) = 0;
+ virtual void fence(uint32_t flags, unsigned len,
+ const uint8_t data[]) = 0;
virtual void enableContinuousUpdates(bool enable,
- int x, int y, int w, int h) = 0;
+ int x, int y,
+ int w, int h) = 0;
virtual void keyEvent(uint32_t keysym, uint32_t keycode,
- bool down);
- virtual void pointerEvent(const Point& pos,
- uint16_t buttonMask);
+ bool down) = 0;
+ virtual void pointerEvent(const core::Point& pos,
+ uint16_t buttonMask) = 0;
- virtual void clientCutText(const char* str);
+ virtual void clientCutText(const char* str) = 0;
virtual void handleClipboardCaps(uint32_t flags,
- const uint32_t* lengths);
- virtual void handleClipboardRequest(uint32_t flags);
- virtual void handleClipboardPeek();
- virtual void handleClipboardNotify(uint32_t flags);
+ const uint32_t* lengths) = 0;
+ virtual void handleClipboardRequest(uint32_t flags) = 0;
+ virtual void handleClipboardPeek() = 0;
+ virtual void handleClipboardNotify(uint32_t flags) = 0;
virtual void handleClipboardProvide(uint32_t flags,
const size_t* lengths,
- const uint8_t* const* data);
-
- // supportsLocalCursor() is called whenever the status of
- // cp.supportsLocalCursor has changed. At the moment this happens on a
- // setEncodings message, but in the future this may be due to a message
- // specially for this purpose.
- virtual void supportsLocalCursor();
-
- // supportsFence() is called the first time we detect support for fences
- // in the client. A fence message should be sent at this point to notify
- // the client of server support.
- virtual void supportsFence();
-
- // supportsContinuousUpdates() is called the first time we detect that
- // the client wants the continuous updates extension. A
- // EndOfContinuousUpdates message should be sent back to the client at
- // this point if it is supported.
- virtual void supportsContinuousUpdates();
-
- // supportsLEDState() is called the first time we detect that the
- // client supports the LED state extension. A LEDState message
- // should be sent back to the client to inform it of the current
- // server state.
- virtual void supportsLEDState();
-
- // supportsQEMUKeyEvent() is called the first time we detect that the
- // client wants the QEMU Extended Key Event extension. The default
- // handler will send a pseudo-rect back, signalling server support.
- virtual void supportsQEMUKeyEvent();
-
- // supportsExtendedMouseButtons() is called the first time we detect that the
- // client supports sending 16 bit mouse button state. This lets us pass more button
- // states between server and client.
- virtual void supportsExtendedMouseButtons();
+ const uint8_t* const* data) = 0;
ClientParams client;
};
diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx
index 5df11153..9054bcc3 100644
--- a/common/rfb/SMsgReader.cxx
+++ b/common/rfb/SMsgReader.cxx
@@ -25,6 +25,10 @@
#include <vector>
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rdr/InStream.h>
#include <rdr/ZlibInStream.h>
@@ -32,17 +36,19 @@
#include <rfb/qemuTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h>
+#include <rfb/PixelFormat.h>
+#include <rfb/ScreenSet.h>
#include <rfb/SMsgHandler.h>
#include <rfb/SMsgReader.h>
-#include <rfb/Configuration.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
using namespace rfb;
-static LogWriter vlog("SMsgReader");
+static core::LogWriter vlog("SMsgReader");
-static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
+static core::IntParameter maxCutText("MaxCutText",
+ "Maximum permitted length of an "
+ "incoming clipboard update",
+ 256*1024, 0, INT_MAX);
SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
: handler(handler_), is(is_), state(MSGSTATE_IDLE)
@@ -201,7 +207,7 @@ bool SMsgReader::readFramebufferUpdateRequest()
int y = is->readU16();
int w = is->readU16();
int h = is->readU16();
- handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc);
+ handler->framebufferUpdateRequest({x, y, x+w, y+h}, inc);
return true;
}
@@ -298,7 +304,7 @@ bool SMsgReader::readPointerEvent()
}
is->clearRestorePoint();
- handler->pointerEvent(Point(x, y), mask);
+ handler->pointerEvent({x, y}, mask);
return true;
}
@@ -338,8 +344,8 @@ bool SMsgReader::readClientCutText()
std::vector<char> ca(len);
is->readBytes((uint8_t*)ca.data(), len);
- std::string utf8(latin1ToUTF8(ca.data(), ca.size()));
- std::string filtered(convertLF(utf8.data(), utf8.size()));
+ std::string utf8(core::latin1ToUTF8(ca.data(), ca.size()));
+ std::string filtered(core::convertLF(utf8.data(), utf8.size()));
handler->clientCutText(filtered.c_str());
@@ -485,7 +491,7 @@ bool SMsgReader::readQEMUMessage()
ret = readQEMUKeyEvent();
break;
default:
- throw protocol_error(format("Unknown QEMU submessage type %d", subType));
+ throw protocol_error(core::format("Unknown QEMU submessage type %d", subType));
}
if (!ret) {
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index 5ee0905b..d52df511 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -24,6 +24,9 @@
#include <stdio.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rdr/OutStream.h>
#include <rdr/MemOutStream.h>
#include <rdr/ZlibOutStream.h>
@@ -32,16 +35,17 @@
#include <rfb/fenceTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/ClientParams.h>
+#include <rfb/Cursor.h>
#include <rfb/UpdateTracker.h>
#include <rfb/Encoder.h>
+#include <rfb/ScreenSet.h>
#include <rfb/SMsgWriter.h>
-#include <rfb/LogWriter.h>
+#include <rfb/encodings.h>
#include <rfb/ledStates.h>
-#include <rfb/util.h>
using namespace rfb;
-static LogWriter vlog("SMsgWriter");
+static core::LogWriter vlog("SMsgWriter");
SMsgWriter::SMsgWriter(ClientParams* client_, rdr::OutStream* os_)
: client(client_), os(os_),
@@ -95,7 +99,7 @@ void SMsgWriter::writeServerCutText(const char* str)
if (strchr(str, '\r') != nullptr)
throw std::invalid_argument("Invalid carriage return in clipboard data");
- std::string latin1(utf8ToLatin1(str));
+ std::string latin1(core::utf8ToLatin1(str));
startMsg(msgTypeServerCutText);
os->pad(3);
@@ -405,7 +409,7 @@ void SMsgWriter::writeFramebufferUpdateEnd()
endMsg();
}
-void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY)
+void SMsgWriter::writeCopyRect(const core::Rect& r, int srcX, int srcY)
{
startRect(r,encodingCopyRect);
os->writeU16(srcX);
@@ -413,7 +417,7 @@ void SMsgWriter::writeCopyRect(const Rect& r, int srcX, int srcY)
endRect();
}
-void SMsgWriter::startRect(const Rect& r, int encoding)
+void SMsgWriter::startRect(const core::Rect& r, int encoding)
{
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw std::logic_error("SMsgWriter::startRect: nRects out of sync");
@@ -488,7 +492,7 @@ void SMsgWriter::writePseudoRects()
}
if (needCursorPos) {
- const Point& cursorPos = client->cursorPos();
+ const core::Point& cursorPos = client->cursorPos();
if (client->supportsEncoding(pseudoEncodingVMwareCursorPosition)) {
writeSetVMwareCursorPositionRect(cursorPos.x, cursorPos.y);
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index 7bc0ed6a..113a9370 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -25,8 +25,7 @@
#include <stdint.h>
-#include <rfb/encodings.h>
-#include <rfb/ScreenSet.h>
+namespace core { struct Rect; }
namespace rdr { class OutStream; }
@@ -117,11 +116,11 @@ namespace rfb {
void writeFramebufferUpdateEnd();
// There is no explicit encoder for CopyRect rects.
- void writeCopyRect(const Rect& r, int srcX, int srcY);
+ void writeCopyRect(const core::Rect& r, int srcX, int srcY);
// Encoders should call these to mark the start and stop of individual
// rects.
- void startRect(const Rect& r, int enc);
+ void startRect(const core::Rect& r, int enc);
void endRect();
protected:
diff --git a/common/rfb/SSecurity.h b/common/rfb/SSecurity.h
index 0911ecd8..edbe8185 100644
--- a/common/rfb/SSecurity.h
+++ b/common/rfb/SSecurity.h
@@ -44,12 +44,12 @@
#ifndef __RFB_SSECURITY_H__
#define __RFB_SSECURITY_H__
-#include <rfb/SConnection.h>
-
-#include <list>
+#include <rfb/AccessRights.h>
namespace rfb {
+ class SConnection;
+
class SSecurity {
public:
SSecurity(SConnection* sc_) : sc(sc_) {}
diff --git a/common/rfb/SSecurityPlain.cxx b/common/rfb/SSecurityPlain.cxx
index e62e6d60..4fa63250 100644
--- a/common/rfb/SSecurityPlain.cxx
+++ b/common/rfb/SSecurityPlain.cxx
@@ -21,10 +21,12 @@
#include <config.h>
#endif
+#include <core/Configuration.h>
+#include <core/string.h>
+
#include <rfb/SSecurityPlain.h>
#include <rfb/SConnection.h>
#include <rfb/Exception.h>
-#include <rfb/util.h>
#include <rdr/InStream.h>
#if !defined(WIN32) && !defined(__APPLE__)
#include <rfb/UnixPasswordValidator.h>
@@ -37,32 +39,30 @@
using namespace rfb;
-StringParameter PasswordValidator::plainUsers
+core::StringListParameter PasswordValidator::plainUsers
("PlainUsers",
"Users permitted to access via Plain security type (including TLSPlain, X509Plain etc.)"
#ifdef HAVE_NETTLE
" or RSA-AES security types (RA2, RA2ne, RA2_256, RA2ne_256)"
#endif
,
- "");
+ {});
bool PasswordValidator::validUser(const char* username)
{
- std::vector<std::string> users;
-
- users = split(plainUsers, ',');
-
- for (size_t i = 0; i < users.size(); i++) {
- if (users[i] == "*")
+ for (const char* user : plainUsers) {
+ if (strcmp(user, "*") == 0)
return true;
#if !defined(WIN32) && !defined(__APPLE__)
- if (users[i] == "%u") {
+ if (strcmp(user, "%u") == 0) {
struct passwd *pw = getpwnam(username);
if (pw && pw->pw_uid == getuid())
return true;
}
#endif
- if (users[i] == username)
+ // FIXME: We should compare uid, as the usernames might not be case
+ // sensitive, or have other normalisation
+ if (strcmp(user, username) == 0)
return true;
}
return false;
@@ -113,8 +113,9 @@ bool SSecurityPlain::processMsg()
password[plen] = 0;
username[ulen] = 0;
plen = 0;
- if (!valid->validate(sc, username, password))
- throw auth_error("Authentication failed");
+ std::string msg = "Authentication failed";
+ if (!valid->validate(sc, username, password, msg))
+ throw auth_error(msg);
}
return true;
diff --git a/common/rfb/SSecurityPlain.h b/common/rfb/SSecurityPlain.h
index c0ac049b..4c030455 100644
--- a/common/rfb/SSecurityPlain.h
+++ b/common/rfb/SSecurityPlain.h
@@ -20,23 +20,29 @@
#ifndef __RFB_SSECURITYPLAIN_H__
#define __RFB_SSECURITYPLAIN_H__
-#include <rfb/SConnection.h>
+#include <rfb/Security.h>
#include <rfb/SSecurity.h>
-#include <rfb/SSecurityVeNCrypt.h>
-#include <rfb/Configuration.h>
+
+namespace core { class StringListParameter; }
namespace rfb {
class PasswordValidator {
public:
- bool validate(SConnection* sc, const char *username, const char *password)
- { return validUser(username) ? validateInternal(sc, username, password) : false; }
- static StringParameter plainUsers;
+ bool validate(SConnection* sc,
+ const char *username,
+ const char *password,
+ std::string &msg)
+ { return validUser(username) ? validateInternal(sc, username, password, msg) : false; }
+ static core::StringListParameter plainUsers;
virtual ~PasswordValidator() { }
protected:
- virtual bool validateInternal(SConnection* sc, const char *username, const char *password)=0;
+ virtual bool validateInternal(SConnection* sc,
+ const char *username,
+ const char *password,
+ std::string &msg) = 0;
static bool validUser(const char* username);
};
diff --git a/common/rfb/SSecurityRSAAES.cxx b/common/rfb/SSecurityRSAAES.cxx
index d7e7cc4c..405005ab 100644
--- a/common/rfb/SSecurityRSAAES.cxx
+++ b/common/rfb/SSecurityRSAAES.cxx
@@ -37,13 +37,15 @@
#include <nettle/base64.h>
#include <nettle/asn1.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rdr/AESInStream.h>
#include <rdr/AESOutStream.h>
-#include <rdr/Exception.h>
+#include <rdr/RandomStream.h>
#include <rfb/SSecurityRSAAES.h>
#include <rfb/SConnection.h>
-#include <rfb/LogWriter.h>
#include <rfb/Exception.h>
#if !defined(WIN32) && !defined(__APPLE__)
#include <rfb/UnixPasswordValidator.h>
@@ -67,14 +69,14 @@ const size_t MaxKeyFileSize = 32 * 1024;
using namespace rfb;
-StringParameter SSecurityRSAAES::keyFile
+core::StringParameter SSecurityRSAAES::keyFile
("RSAKey", "Path to the RSA key for the RSA-AES security types in "
- "PEM format", "", ConfServer);
-BoolParameter SSecurityRSAAES::requireUsername
+ "PEM format", "");
+core::BoolParameter SSecurityRSAAES::requireUsername
("RequireUsername", "Require username for the RSA-AES security types",
- false, ConfServer);
+ false);
-static LogWriter vlog("SSecurityRSAAES");
+static core::LogWriter vlog("SSecurityRSAAES");
SSecurityRSAAES::SSecurityRSAAES(SConnection* sc_, uint32_t _secType,
int _keySize, bool _isAllEncrypted)
@@ -174,7 +176,7 @@ void SSecurityRSAAES::loadPrivateKey()
{
FILE* file = fopen(keyFile, "rb");
if (!file)
- throw rdr::posix_error("Failed to open key file", errno);
+ throw core::posix_error("Failed to open key file", errno);
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
if (size == 0 || size > MaxKeyFileSize) {
@@ -185,7 +187,7 @@ void SSecurityRSAAES::loadPrivateKey()
std::vector<uint8_t> data(size);
if (fread(data.data(), 1, data.size(), file) != size) {
fclose(file);
- throw rdr::posix_error("Failed to read key", errno);
+ throw core::posix_error("Failed to read key", errno);
}
fclose(file);
@@ -345,6 +347,7 @@ static void random_func(void* ctx, size_t length, uint8_t* dst)
void SSecurityRSAAES::writeRandom()
{
+ rdr::RandomStream rs;
rdr::OutStream* os = sc->getOutStream();
if (!rs.hasData(keySize / 8))
throw std::runtime_error("Failed to generate random");
@@ -580,9 +583,10 @@ void SSecurityRSAAES::verifyUserPass()
#elif !defined(__APPLE__)
UnixPasswordValidator *valid = new UnixPasswordValidator();
#endif
- if (!valid->validate(sc, username, password)) {
+ std::string msg = "Authentication failed";
+ if (!valid->validate(sc, username, password, msg)) {
delete valid;
- throw auth_error("Authentication failed");
+ throw auth_error(msg);
}
delete valid;
#else
diff --git a/common/rfb/SSecurityRSAAES.h b/common/rfb/SSecurityRSAAES.h
index e3300cb7..283134db 100644
--- a/common/rfb/SSecurityRSAAES.h
+++ b/common/rfb/SSecurityRSAAES.h
@@ -27,7 +27,10 @@
#include <rfb/SSecurity.h>
-#include <rdr/RandomStream.h>
+namespace core {
+ class BoolParameter;
+ class StringParameter;
+}
namespace rdr {
class InStream;
@@ -51,8 +54,8 @@ namespace rfb {
return accessRights;
}
- static StringParameter keyFile;
- static BoolParameter requireUsername;
+ static core::StringParameter keyFile;
+ static core::BoolParameter requireUsername;
private:
void cleanup();
@@ -96,8 +99,6 @@ namespace rfb {
rdr::InStream* rawis;
rdr::OutStream* rawos;
-
- rdr::RandomStream rs;
};
}
diff --git a/common/rfb/SSecurityTLS.cxx b/common/rfb/SSecurityTLS.cxx
index b297242b..17497b8e 100644
--- a/common/rfb/SSecurityTLS.cxx
+++ b/common/rfb/SSecurityTLS.cxx
@@ -2,7 +2,7 @@
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
- * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB
+ * Copyright 2012-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,13 +30,15 @@
#include <stdlib.h>
+#include <core/LogWriter.h>
+
#include <rfb/SSecurityTLS.h>
#include <rfb/SConnection.h>
-#include <rfb/LogWriter.h>
#include <rfb/Exception.h>
+
#include <rdr/TLSException.h>
-#include <rdr/TLSInStream.h>
-#include <rdr/TLSOutStream.h>
+#include <rdr/TLSSocket.h>
+
#include <gnutls/x509.h>
#if defined (SSECURITYTLS__USE_DEPRECATED_DH)
@@ -59,17 +61,17 @@ static const gnutls_datum_t ffdhe_pkcs3_param = {
using namespace rfb;
-StringParameter SSecurityTLS::X509_CertFile
-("X509Cert", "Path to the X509 certificate in PEM format", "", ConfServer);
+core::StringParameter SSecurityTLS::X509_CertFile
+("X509Cert", "Path to the X509 certificate in PEM format", "");
-StringParameter SSecurityTLS::X509_KeyFile
-("X509Key", "Path to the key of the X509 certificate in PEM format", "", ConfServer);
+core::StringParameter SSecurityTLS::X509_KeyFile
+("X509Key", "Path to the key of the X509 certificate in PEM format", "");
-static LogWriter vlog("TLS");
+static core::LogWriter vlog("TLS");
SSecurityTLS::SSecurityTLS(SConnection* sc_, bool _anon)
: SSecurity(sc_), session(nullptr), anon_cred(nullptr),
- cert_cred(nullptr), anon(_anon), tlsis(nullptr), tlsos(nullptr),
+ cert_cred(nullptr), anon(_anon), tlssock(nullptr),
rawis(nullptr), rawos(nullptr)
{
int ret;
@@ -85,32 +87,13 @@ SSecurityTLS::SSecurityTLS(SConnection* sc_, bool _anon)
void SSecurityTLS::shutdown()
{
- if (tlsos) {
- try {
- if (tlsos->hasBufferedData()) {
- tlsos->cork(false);
- tlsos->flush();
- if (tlsos->hasBufferedData())
- vlog.error("Failed to flush remaining socket data on close");
- }
- } catch (std::exception& e) {
- vlog.error("Failed to flush remaining socket data on close: %s", e.what());
- }
- }
-
- if (session) {
- int ret;
- // FIXME: We can't currently wait for the response, so we only send
- // our close and hope for the best
- ret = gnutls_bye(session, GNUTLS_SHUT_WR);
- if ((ret != GNUTLS_E_SUCCESS) && (ret != GNUTLS_E_INVALID_SESSION))
- vlog.error("TLS shutdown failed: %s", gnutls_strerror(ret));
- }
+ if (tlssock)
+ tlssock->shutdown();
#if defined (SSECURITYTLS__USE_DEPRECATED_DH)
if (dh_params) {
gnutls_dh_params_deinit(dh_params);
- dh_params = 0;
+ dh_params = nullptr;
}
#endif
@@ -130,13 +113,9 @@ void SSecurityTLS::shutdown()
rawos = nullptr;
}
- if (tlsis) {
- delete tlsis;
- tlsis = nullptr;
- }
- if (tlsos) {
- delete tlsos;
- tlsos = nullptr;
+ if (tlssock) {
+ delete tlssock;
+ tlssock = nullptr;
}
if (session) {
@@ -182,56 +161,46 @@ bool SSecurityTLS::processMsg()
os->writeU8(1);
os->flush();
- // Create these early as they set up the push/pull functions
- // for GnuTLS
- tlsis = new rdr::TLSInStream(is, session);
- tlsos = new rdr::TLSOutStream(os, session);
+ tlssock = new rdr::TLSSocket(is, os, session);
rawis = is;
rawos = os;
}
- err = gnutls_handshake(session);
- if (err != GNUTLS_E_SUCCESS) {
- if (!gnutls_error_is_fatal(err)) {
- vlog.debug("Deferring completion of TLS handshake: %s", gnutls_strerror(err));
+ try {
+ if (!tlssock->handshake())
return false;
- }
- vlog.error("TLS Handshake failed: %s", gnutls_strerror (err));
+ } catch (std::exception&) {
shutdown();
- throw rdr::tls_error("TLS Handshake failed", err);
+ throw;
}
vlog.debug("TLS handshake completed with %s",
gnutls_session_get_desc(session));
- sc->setStreams(tlsis, tlsos);
+ sc->setStreams(&tlssock->inStream(), &tlssock->outStream());
return true;
}
void SSecurityTLS::setParams()
{
- static const char kx_anon_priority[] = ":+ANON-ECDH:+ANON-DH";
+ static const char kx_anon_priority[] = "+ANON-ECDH:+ANON-DH";
int ret;
// Custom priority string specified?
if (strcmp(Security::GnuTLSPriority, "") != 0) {
- char *prio;
+ std::string prio;
const char *err;
- prio = new char[strlen(Security::GnuTLSPriority) +
- strlen(kx_anon_priority) + 1];
-
- strcpy(prio, Security::GnuTLSPriority);
- if (anon)
- strcat(prio, kx_anon_priority);
-
- ret = gnutls_priority_set_direct(session, prio, &err);
-
- delete [] prio;
+ prio = (const char*)Security::GnuTLSPriority;
+ if (anon) {
+ prio += ":";
+ prio += kx_anon_priority;
+ }
+ ret = gnutls_priority_set_direct(session, prio.c_str(), &err);
if (ret != GNUTLS_E_SUCCESS) {
if (ret == GNUTLS_E_INVALID_REQUEST)
vlog.error("GnuTLS priority syntax error at: %s", err);
@@ -241,30 +210,22 @@ void SSecurityTLS::setParams()
const char *err;
#if GNUTLS_VERSION_NUMBER >= 0x030603
- // gnutls_set_default_priority_appends() expects a normal priority string that
- // doesn't start with ":".
- ret = gnutls_set_default_priority_append(session, kx_anon_priority + 1, &err, 0);
+ ret = gnutls_set_default_priority_append(session, kx_anon_priority, &err, 0);
if (ret != GNUTLS_E_SUCCESS) {
if (ret == GNUTLS_E_INVALID_REQUEST)
vlog.error("GnuTLS priority syntax error at: %s", err);
throw rdr::tls_error("gnutls_set_default_priority_append()", ret);
}
#else
+ std::string prio;
+
// We don't know what the system default priority is, so we guess
// it's what upstream GnuTLS has
- static const char gnutls_default_priority[] = "NORMAL";
- char *prio;
-
- prio = new char[strlen(gnutls_default_priority) +
- strlen(kx_anon_priority) + 1];
-
- strcpy(prio, gnutls_default_priority);
- strcat(prio, kx_anon_priority);
-
- ret = gnutls_priority_set_direct(session, prio, &err);
-
- delete [] prio;
+ prio = "NORMAL";
+ prio += ":";
+ prio += kx_anon_priority;
+ ret = gnutls_priority_set_direct(session, prio.c_str(), &err);
if (ret != GNUTLS_E_SUCCESS) {
if (ret == GNUTLS_E_INVALID_REQUEST)
vlog.error("GnuTLS priority syntax error at: %s", err);
diff --git a/common/rfb/SSecurityTLS.h b/common/rfb/SSecurityTLS.h
index 1dc33cfd..61eec2a8 100644
--- a/common/rfb/SSecurityTLS.h
+++ b/common/rfb/SSecurityTLS.h
@@ -2,6 +2,7 @@
* Copyright (C) 2004 Red Hat Inc.
* Copyright (C) 2005 Martin Koegler
* Copyright (C) 2010 TigerVNC Team
+ * Copyright 2012-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +27,7 @@
#error "This header should not be included without HAVE_GNUTLS defined"
#endif
+#include <rfb/Security.h>
#include <rfb/SSecurity.h>
#include <gnutls/gnutls.h>
@@ -40,8 +42,7 @@
namespace rdr {
class InStream;
class OutStream;
- class TLSInStream;
- class TLSOutStream;
+ class TLSSocket;
}
namespace rfb {
@@ -54,8 +55,8 @@ namespace rfb {
const char* getUserName() const override {return nullptr;}
int getType() const override { return anon ? secTypeTLSNone : secTypeX509None;}
- static StringParameter X509_CertFile;
- static StringParameter X509_KeyFile;
+ static core::StringParameter X509_CertFile;
+ static core::StringParameter X509_KeyFile;
protected:
void shutdown();
@@ -71,8 +72,7 @@ namespace rfb {
bool anon;
- rdr::TLSInStream* tlsis;
- rdr::TLSOutStream* tlsos;
+ rdr::TLSSocket* tlssock;
rdr::InStream* rawis;
rdr::OutStream* rawos;
diff --git a/common/rfb/SSecurityVeNCrypt.cxx b/common/rfb/SSecurityVeNCrypt.cxx
index 4617fddb..757acc06 100644
--- a/common/rfb/SSecurityVeNCrypt.cxx
+++ b/common/rfb/SSecurityVeNCrypt.cxx
@@ -26,15 +26,20 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
+#include <rfb/SConnection.h>
+#include <rfb/SecurityServer.h>
#include <rfb/SSecurityVeNCrypt.h>
#include <rfb/Exception.h>
-#include <rfb/LogWriter.h>
+#include <rfb/Security.h>
+
#include <rdr/InStream.h>
#include <rdr/OutStream.h>
using namespace rfb;
-static LogWriter vlog("SVeNCrypt");
+static core::LogWriter vlog("SVeNCrypt");
SSecurityVeNCrypt::SSecurityVeNCrypt(SConnection* sc_,
SecurityServer *sec)
diff --git a/common/rfb/SSecurityVeNCrypt.h b/common/rfb/SSecurityVeNCrypt.h
index ea2bb6fb..534f94a6 100644
--- a/common/rfb/SSecurityVeNCrypt.h
+++ b/common/rfb/SSecurityVeNCrypt.h
@@ -25,11 +25,13 @@
#ifndef __SSECURITYVENCRYPT_H__
#define __SSECURITYVENCRYPT_H__
-#include <rfb/SSecurityStack.h>
-#include <rfb/SConnection.h>
+#include <rfb/SSecurity.h>
namespace rfb {
+ class SConnection;
+ class SecurityServer;
+
class SSecurityVeNCrypt : public SSecurity {
public:
SSecurityVeNCrypt(SConnection* sc, SecurityServer *sec);
diff --git a/common/rfb/SSecurityVncAuth.cxx b/common/rfb/SSecurityVncAuth.cxx
index 22d88079..b267d5a0 100644
--- a/common/rfb/SSecurityVncAuth.cxx
+++ b/common/rfb/SSecurityVncAuth.cxx
@@ -25,13 +25,17 @@
#include <config.h>
#endif
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+
+#include <rdr/OutStream.h>
+
#include <rfb/SSecurityVncAuth.h>
#include <rdr/RandomStream.h>
#include <rfb/SConnection.h>
-#include <rfb/Configuration.h>
-#include <rfb/LogWriter.h>
#include <rfb/Exception.h>
#include <rfb/obfuscate.h>
+
#include <assert.h>
#include <string.h>
#include <stdio.h>
@@ -42,12 +46,12 @@ extern "C" {
using namespace rfb;
-static LogWriter vlog("SVncAuth");
+static core::LogWriter vlog("SVncAuth");
-StringParameter SSecurityVncAuth::vncAuthPasswdFile
-("PasswordFile", "Password file for VNC authentication", "", ConfServer);
-AliasParameter rfbauth("rfbauth", "Alias for PasswordFile",
- &SSecurityVncAuth::vncAuthPasswdFile, ConfServer);
+core::StringParameter SSecurityVncAuth::vncAuthPasswdFile
+("PasswordFile", "Password file for VNC authentication", "");
+core::AliasParameter rfbauth("rfbauth", "Alias for PasswordFile",
+ &SSecurityVncAuth::vncAuthPasswdFile);
VncAuthPasswdParameter SSecurityVncAuth::vncAuthPasswd
("Password", "Obfuscated binary encoding of the password which clients must supply to "
"access the server", &SSecurityVncAuth::vncAuthPasswdFile);
@@ -118,8 +122,8 @@ bool SSecurityVncAuth::processMsg()
VncAuthPasswdParameter::VncAuthPasswdParameter(const char* name_,
const char* desc,
- StringParameter* passwdFile_)
-: BinaryParameter(name_, desc, nullptr, 0, ConfServer),
+ core::StringParameter* passwdFile_)
+: core::BinaryParameter(name_, desc, nullptr, 0),
passwdFile(passwdFile_)
{
}
diff --git a/common/rfb/SSecurityVncAuth.h b/common/rfb/SSecurityVncAuth.h
index 532abe0a..e2845337 100644
--- a/common/rfb/SSecurityVncAuth.h
+++ b/common/rfb/SSecurityVncAuth.h
@@ -26,7 +26,8 @@
#include <stdint.h>
-#include <rfb/Configuration.h>
+#include <core/Configuration.h>
+
#include <rfb/SSecurity.h>
#include <rfb/Security.h>
@@ -41,12 +42,12 @@ namespace rfb {
virtual ~VncAuthPasswdGetter() { }
};
- class VncAuthPasswdParameter : public VncAuthPasswdGetter, BinaryParameter {
+ class VncAuthPasswdParameter : public VncAuthPasswdGetter, core::BinaryParameter {
public:
- VncAuthPasswdParameter(const char* name, const char* desc, StringParameter* passwdFile_);
+ VncAuthPasswdParameter(const char* name, const char* desc, core::StringParameter* passwdFile_);
void getVncAuthPasswd(std::string *password, std::string *readOnlyPassword) override;
protected:
- StringParameter* passwdFile;
+ core::StringParameter* passwdFile;
};
class SSecurityVncAuth : public SSecurity {
@@ -56,7 +57,7 @@ namespace rfb {
int getType() const override {return secTypeVncAuth;}
const char* getUserName() const override {return nullptr;}
AccessRights getAccessRights() const override { return accessRights; }
- static StringParameter vncAuthPasswdFile;
+ static core::StringParameter vncAuthPasswdFile;
static VncAuthPasswdParameter vncAuthPasswd;
private:
bool verifyResponse(const char* password);
diff --git a/common/rfb/ScreenSet.h b/common/rfb/ScreenSet.h
index fb93e5c2..10753b17 100644
--- a/common/rfb/ScreenSet.h
+++ b/common/rfb/ScreenSet.h
@@ -25,10 +25,11 @@
#include <string.h>
#include <stdint.h>
-#include <rfb/Rect.h>
#include <list>
#include <set>
+#include <core/Rect.h>
+
namespace rfb {
// rfb::Screen
@@ -52,7 +53,7 @@ namespace rfb {
}
uint32_t id;
- Rect dimensions;
+ core::Rect dimensions;
uint32_t flags;
};
@@ -87,7 +88,7 @@ namespace rfb {
inline bool validate(int fb_width, int fb_height) const {
std::list<Screen>::const_iterator iter;
std::set<uint32_t> seen_ids;
- Rect fb_rect;
+ core::Rect fb_rect;
if (screens.empty())
return false;
diff --git a/common/rfb/Security.cxx b/common/rfb/Security.cxx
index 3b0d95bf..1d4124f9 100644
--- a/common/rfb/Security.cxx
+++ b/common/rfb/Security.cxx
@@ -24,17 +24,19 @@
#include <string.h>
#include <algorithm>
+#include <stdexcept>
+
+#include <core/LogWriter.h>
+#include <core/string.h>
-#include <rfb/LogWriter.h>
#include <rfb/Security.h>
-#include <rfb/util.h>
using namespace rfb;
-static LogWriter vlog("Security");
+static core::LogWriter vlog("Security");
#ifdef HAVE_GNUTLS
-StringParameter Security::GnuTLSPriority("GnuTLSPriority",
+core::StringParameter Security::GnuTLSPriority("GnuTLSPriority",
"GnuTLS priority string that controls the TLS session’s handshake algorithms",
"");
#endif
@@ -43,9 +45,16 @@ Security::Security()
{
}
-Security::Security(StringParameter &secTypes)
+Security::Security(core::EnumListParameter &secTypes)
{
- enabledSecTypes = parseSecTypes(secTypes);
+ for (core::EnumListEntry type : secTypes) {
+ uint32_t typeNum = secTypeNum(type.getValueStr().c_str());
+ // Should have been filtered by EnumListParameter, but let's have
+ // a safety net
+ if (typeNum == secTypeInvalid)
+ throw std::logic_error("Unknown security type");
+ enabledSecTypes.push_back(typeNum);
+ }
}
const std::list<uint8_t> Security::GetEnabledSecTypes(void)
@@ -179,16 +188,3 @@ const char* rfb::secTypeName(uint32_t num)
default: return "[unknown secType]";
}
}
-
-std::list<uint32_t> rfb::parseSecTypes(const char* types_)
-{
- std::list<uint32_t> result;
- std::vector<std::string> types;
- types = split(types_, ',');
- for (size_t i = 0; i < types.size(); i++) {
- uint32_t typeNum = secTypeNum(types[i].c_str());
- if (typeNum != secTypeInvalid)
- result.push_back(typeNum);
- }
- return result;
-}
diff --git a/common/rfb/Security.h b/common/rfb/Security.h
index 430a1d89..40f54c36 100644
--- a/common/rfb/Security.h
+++ b/common/rfb/Security.h
@@ -24,11 +24,15 @@
#include <stdint.h>
-#include <rfb/Configuration.h>
-
#include <list>
+namespace core {
+ class EnumListParameter;
+ class StringParameter;
+}
+
namespace rfb {
+
const uint8_t secTypeInvalid = 0;
const uint8_t secTypeNone = 1;
const uint8_t secTypeVncAuth = 2;
@@ -76,7 +80,7 @@ namespace rfb {
* Create Security instance.
*/
Security();
- Security(StringParameter &secTypes);
+ Security(core::EnumListParameter& secTypes);
/*
* Note about security types.
@@ -105,7 +109,7 @@ namespace rfb {
char *ToString(void);
#ifdef HAVE_GNUTLS
- static StringParameter GnuTLSPriority;
+ static core::StringParameter GnuTLSPriority;
#endif
private:
@@ -114,7 +118,7 @@ namespace rfb {
const char* secTypeName(uint32_t num);
uint32_t secTypeNum(const char* name);
- std::list<uint32_t> parseSecTypes(const char* types);
+
}
#endif
diff --git a/common/rfb/SecurityClient.cxx b/common/rfb/SecurityClient.cxx
index 027d47df..d71941b5 100644
--- a/common/rfb/SecurityClient.cxx
+++ b/common/rfb/SecurityClient.cxx
@@ -25,12 +25,15 @@
#include <stdexcept>
+#include <core/Configuration.h>
+
#include <rfb/CSecurityNone.h>
#include <rfb/CSecurityStack.h>
#include <rfb/CSecurityVeNCrypt.h>
#include <rfb/CSecurityVncAuth.h>
#include <rfb/CSecurityPlain.h>
#include <rfb/Security.h>
+#include <rfb/SecurityClient.h>
#ifdef HAVE_GNUTLS
#include <rfb/CSecurityTLS.h>
#endif
@@ -42,7 +45,7 @@
using namespace rfb;
-StringParameter SecurityClient::secTypes
+core::EnumListParameter SecurityClient::secTypes
("SecurityTypes",
"Specify which security scheme to use (None, VncAuth, Plain"
#ifdef HAVE_GNUTLS
@@ -52,14 +55,22 @@ StringParameter SecurityClient::secTypes
", RA2, RA2ne, RA2_256, RA2ne_256, DH, MSLogonII"
#endif
")",
+ { "None", "VncAuth", "Plain",
+#ifdef HAVE_GNUTLS
+ "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain",
+#endif
+#ifdef HAVE_NETTLE
+ "RA2", "RA2ne", "RA2_256", "RA2ne_256", "DH", "MSLogonII",
+#endif
+ },
+ { "None", "VncAuth", "Plain",
#ifdef HAVE_GNUTLS
- "X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone,"
+ "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain",
#endif
#ifdef HAVE_NETTLE
- "RA2,RA2_256,RA2ne,RA2ne_256,DH,MSLogonII,"
+ "RA2", "RA2ne", "RA2_256", "RA2ne_256", "DH", "MSLogonII",
#endif
- "VncAuth,None",
-ConfViewer);
+ });
CSecurity* SecurityClient::GetCSecurity(CConnection* cc, uint32_t secType)
{
diff --git a/common/rfb/SecurityClient.h b/common/rfb/SecurityClient.h
index b86fcb35..11fea417 100644
--- a/common/rfb/SecurityClient.h
+++ b/common/rfb/SecurityClient.h
@@ -22,12 +22,13 @@
#ifndef __RFB_SECURITYCLIENT_H__
#define __RFB_SECURITYCLIENT_H__
-#include <rfb/Configuration.h>
#include <rfb/Security.h>
-#include <rfb/CSecurity.h>
namespace rfb {
+ class CConnection;
+ class CSecurity;
+
class SecurityClient : public Security {
public:
SecurityClient(void) : Security(secTypes) {}
@@ -35,7 +36,7 @@ namespace rfb {
/* Create client side CSecurity class instance */
CSecurity* GetCSecurity(CConnection* cc, uint32_t secType);
- static StringParameter secTypes;
+ static core::EnumListParameter secTypes;
};
}
diff --git a/common/rfb/SecurityServer.cxx b/common/rfb/SecurityServer.cxx
index d692f4fc..207e70f8 100644
--- a/common/rfb/SecurityServer.cxx
+++ b/common/rfb/SecurityServer.cxx
@@ -21,7 +21,11 @@
#include <config.h>
#endif
+#include <stdexcept>
+
#include <rfb/Security.h>
+#include <rfb/SecurityServer.h>
+
#include <rfb/SSecurityNone.h>
#include <rfb/SSecurityStack.h>
#include <rfb/SSecurityPlain.h>
@@ -36,7 +40,7 @@
using namespace rfb;
-StringParameter SecurityServer::secTypes
+core::EnumListParameter SecurityServer::secTypes
("SecurityTypes",
"Specify which security scheme to use (None, VncAuth, Plain"
#ifdef HAVE_GNUTLS
@@ -46,11 +50,19 @@ StringParameter SecurityServer::secTypes
", RA2, RA2ne, RA2_256, RA2ne_256"
#endif
")",
+ { "None", "VncAuth", "Plain",
+#ifdef HAVE_GNUTLS
+ "TLSNone", "TLSVnc", "TLSPlain", "X509None", "X509Vnc", "X509Plain",
+#endif
+#ifdef HAVE_NETTLE
+ "RA2", "RA2ne", "RA2_256", "RA2ne_256",
+#endif
+ },
+ {
#ifdef HAVE_GNUTLS
- "TLSVnc,"
+ "TLSVnc",
#endif
- "VncAuth",
-ConfServer);
+ "VncAuth"});
SSecurity* SecurityServer::GetSSecurity(SConnection* sc, uint32_t secType)
{
diff --git a/common/rfb/SecurityServer.h b/common/rfb/SecurityServer.h
index a51ee23c..0239b36d 100644
--- a/common/rfb/SecurityServer.h
+++ b/common/rfb/SecurityServer.h
@@ -20,7 +20,6 @@
#ifndef __RFB_SECURITYSERVER_H__
#define __RFB_SECURITYSERVER_H__
-#include <rfb/Configuration.h>
#include <rfb/Security.h>
namespace rfb {
@@ -35,7 +34,7 @@ namespace rfb {
/* Create server side SSecurity class instance */
SSecurity* GetSSecurity(SConnection* sc, uint32_t secType);
- static StringParameter secTypes;
+ static core::EnumListParameter secTypes;
};
}
diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx
index 1a80dc0c..302dad71 100644
--- a/common/rfb/ServerCore.cxx
+++ b/common/rfb/ServerCore.cxx
@@ -28,74 +28,74 @@
#include <string.h>
#include <rfb/ServerCore.h>
-rfb::IntParameter rfb::Server::idleTimeout
+core::IntParameter rfb::Server::idleTimeout
("IdleTimeout",
"The number of seconds after which an idle VNC connection will be dropped "
"(zero means no timeout)",
- 0, 0);
-rfb::IntParameter rfb::Server::maxDisconnectionTime
+ 0, 0, INT_MAX);
+core::IntParameter rfb::Server::maxDisconnectionTime
("MaxDisconnectionTime",
"Terminate when no client has been connected for s seconds",
- 0, 0);
-rfb::IntParameter rfb::Server::maxConnectionTime
+ 0, 0, INT_MAX);
+core::IntParameter rfb::Server::maxConnectionTime
("MaxConnectionTime",
"Terminate when a client has been connected for s seconds",
- 0, 0);
-rfb::IntParameter rfb::Server::maxIdleTime
+ 0, 0, INT_MAX);
+core::IntParameter rfb::Server::maxIdleTime
("MaxIdleTime",
"Terminate after s seconds of user inactivity",
- 0, 0);
-rfb::IntParameter rfb::Server::compareFB
+ 0, 0, INT_MAX);
+core::IntParameter rfb::Server::compareFB
("CompareFB",
"Perform pixel comparison on framebuffer to reduce unnecessary updates "
"(0: never, 1: always, 2: auto)",
- 2);
-rfb::IntParameter rfb::Server::frameRate
+ 2, 0, 2);
+core::IntParameter rfb::Server::frameRate
("FrameRate",
"The maximum number of updates per second sent to each client",
- 60);
-rfb::BoolParameter rfb::Server::protocol3_3
+ 60, 0, INT_MAX);
+core::BoolParameter rfb::Server::protocol3_3
("Protocol3.3",
"Always use protocol version 3.3 for backwards compatibility with "
"badly-behaved clients",
false);
-rfb::BoolParameter rfb::Server::alwaysShared
+core::BoolParameter rfb::Server::alwaysShared
("AlwaysShared",
"Always treat incoming connections as shared, regardless of the client-"
"specified setting",
false);
-rfb::BoolParameter rfb::Server::neverShared
+core::BoolParameter rfb::Server::neverShared
("NeverShared",
"Never treat incoming connections as shared, regardless of the client-"
"specified setting",
false);
-rfb::BoolParameter rfb::Server::disconnectClients
+core::BoolParameter rfb::Server::disconnectClients
("DisconnectClients",
"Disconnect existing clients if an incoming connection is non-shared. "
"If combined with NeverShared then new connections will be refused "
"while there is a client active",
true);
-rfb::BoolParameter rfb::Server::acceptKeyEvents
+core::BoolParameter rfb::Server::acceptKeyEvents
("AcceptKeyEvents",
"Accept key press and release events from clients.",
true);
-rfb::BoolParameter rfb::Server::acceptPointerEvents
+core::BoolParameter rfb::Server::acceptPointerEvents
("AcceptPointerEvents",
"Accept pointer movement and button events from clients.",
true);
-rfb::BoolParameter rfb::Server::acceptCutText
+core::BoolParameter rfb::Server::acceptCutText
("AcceptCutText",
"Accept clipboard updates from clients.",
true);
-rfb::BoolParameter rfb::Server::sendCutText
+core::BoolParameter rfb::Server::sendCutText
("SendCutText",
"Send clipboard changes to clients.",
true);
-rfb::BoolParameter rfb::Server::acceptSetDesktopSize
+core::BoolParameter rfb::Server::acceptSetDesktopSize
("AcceptSetDesktopSize",
"Accept set desktop size events from clients.",
true);
-rfb::BoolParameter rfb::Server::queryConnect
+core::BoolParameter rfb::Server::queryConnect
("QueryConnect",
"Prompt the local user to accept or reject incoming connections.",
false);
diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h
index 69cad39f..a7c7f309 100644
--- a/common/rfb/ServerCore.h
+++ b/common/rfb/ServerCore.h
@@ -24,29 +24,29 @@
#ifndef __RFB_SERVER_CORE_H__
#define __RFB_SERVER_CORE_H__
-#include <rfb/Configuration.h>
+#include <core/Configuration.h>
namespace rfb {
class Server {
public:
- static IntParameter idleTimeout;
- static IntParameter maxDisconnectionTime;
- static IntParameter maxConnectionTime;
- static IntParameter maxIdleTime;
- static IntParameter compareFB;
- static IntParameter frameRate;
- static BoolParameter protocol3_3;
- static BoolParameter alwaysShared;
- static BoolParameter neverShared;
- static BoolParameter disconnectClients;
- static BoolParameter acceptKeyEvents;
- static BoolParameter acceptPointerEvents;
- static BoolParameter acceptCutText;
- static BoolParameter sendCutText;
- static BoolParameter acceptSetDesktopSize;
- static BoolParameter queryConnect;
+ static core::IntParameter idleTimeout;
+ static core::IntParameter maxDisconnectionTime;
+ static core::IntParameter maxConnectionTime;
+ static core::IntParameter maxIdleTime;
+ static core::IntParameter compareFB;
+ static core::IntParameter frameRate;
+ static core::BoolParameter protocol3_3;
+ static core::BoolParameter alwaysShared;
+ static core::BoolParameter neverShared;
+ static core::BoolParameter disconnectClients;
+ static core::BoolParameter acceptKeyEvents;
+ static core::BoolParameter acceptPointerEvents;
+ static core::BoolParameter acceptCutText;
+ static core::BoolParameter sendCutText;
+ static core::BoolParameter acceptSetDesktopSize;
+ static core::BoolParameter queryConnect;
};
diff --git a/common/rfb/ServerParams.cxx b/common/rfb/ServerParams.cxx
index b7432b8f..4b8f6136 100644
--- a/common/rfb/ServerParams.cxx
+++ b/common/rfb/ServerParams.cxx
@@ -24,12 +24,18 @@
#include <stdexcept>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb/ledStates.h>
+#include <rfb/Cursor.h>
+#include <rfb/ScreenSet.h>
#include <rfb/ServerParams.h>
-#include <rfb/util.h>
using namespace rfb;
+static core::LogWriter vlog("ServerParams");
+
ServerParams::ServerParams()
: majorVersion(0), minorVersion(0),
supportsQEMUKeyEvent(false),
@@ -40,7 +46,11 @@ ServerParams::ServerParams()
{
setName("");
- cursor_ = new Cursor(0, 0, Point(), nullptr);
+ screenLayout_ = new ScreenSet();
+
+ pf_ = new PixelFormat();
+
+ cursor_ = new Cursor(0, 0, {}, nullptr);
clipFlags = 0;
memset(clipSizes, 0, sizeof(clipSizes));
@@ -60,17 +70,25 @@ void ServerParams::setDimensions(int width, int height)
void ServerParams::setDimensions(int width, int height, const ScreenSet& layout)
{
- if (!layout.validate(width, height))
+ if (!layout.validate(width, height)) {
+ char buffer[2048];
+ vlog.debug("Invalid screen layout for %dx%d:", width, height);
+ layout.print(buffer, sizeof(buffer));
+ vlog.debug("%s", buffer);
+
throw std::invalid_argument("Attempted to configure an invalid screen layout");
+ }
width_ = width;
height_ = height;
- screenLayout_ = layout;
+ delete screenLayout_;
+ screenLayout_ = new ScreenSet(layout);
}
void ServerParams::setPF(const PixelFormat& pf)
{
- pf_ = pf;
+ delete pf_;
+ pf_ = new PixelFormat(pf);
if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32)
throw std::invalid_argument("setPF: Not 8, 16 or 32 bpp?");
@@ -101,7 +119,8 @@ uint32_t ServerParams::clipboardSize(unsigned int format) const
return clipSizes[i];
}
- throw std::invalid_argument(rfb::format("Invalid clipboard format 0x%x", format));
+ throw std::invalid_argument(
+ core::format("Invalid clipboard format 0x%x", format));
}
void ServerParams::setClipboardCaps(uint32_t flags, const uint32_t* lengths)
diff --git a/common/rfb/ServerParams.h b/common/rfb/ServerParams.h
index d730b891..6be9acd6 100644
--- a/common/rfb/ServerParams.h
+++ b/common/rfb/ServerParams.h
@@ -25,12 +25,12 @@
#include <string>
-#include <rfb/Cursor.h>
-#include <rfb/PixelFormat.h>
-#include <rfb/ScreenSet.h>
-
namespace rfb {
+ class Cursor;
+ class PixelFormat;
+ struct ScreenSet;
+
class ServerParams {
public:
ServerParams();
@@ -55,11 +55,11 @@ namespace rfb {
int width() const { return width_; }
int height() const { return height_; }
- const ScreenSet& screenLayout() const { return screenLayout_; }
+ const ScreenSet& screenLayout() const { return *screenLayout_; }
void setDimensions(int width, int height);
void setDimensions(int width, int height, const ScreenSet& layout);
- const PixelFormat& pf() const { return pf_; }
+ const PixelFormat& pf() const { return *pf_; }
void setPF(const PixelFormat& pf);
const char* name() const { return name_.c_str(); }
@@ -85,9 +85,9 @@ namespace rfb {
int width_;
int height_;
- ScreenSet screenLayout_;
+ ScreenSet* screenLayout_;
- PixelFormat pf_;
+ PixelFormat* pf_;
std::string name_;
Cursor* cursor_;
unsigned int ledState_;
diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx
index a26c0bfe..da0d5865 100644
--- a/common/rfb/TightDecoder.cxx
+++ b/common/rfb/TightDecoder.cxx
@@ -27,16 +27,18 @@
#include <vector>
+#include <core/string.h>
+
#include <rdr/InStream.h>
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>
#include <rfb/ServerParams.h>
#include <rfb/Exception.h>
+#include <rfb/JpegDecompressor.h>
#include <rfb/PixelBuffer.h>
#include <rfb/TightConstants.h>
#include <rfb/TightDecoder.h>
-#include <rfb/util.h>
using namespace rfb;
@@ -51,7 +53,7 @@ TightDecoder::~TightDecoder()
{
}
-bool TightDecoder::readRect(const Rect& r, rdr::InStream* is,
+bool TightDecoder::readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server, rdr::OutStream* os)
{
uint8_t comp_ctl;
@@ -111,7 +113,8 @@ bool TightDecoder::readRect(const Rect& r, rdr::InStream* is,
int palSize = 0;
if (r.width() > TIGHT_MAX_WIDTH)
- throw protocol_error(format("TightDecoder: Too large rectangle (%d pixels)", r.width()));
+ throw protocol_error(core::format(
+ "TightDecoder: Too large rectangle (%d pixels)", r.width()));
// Possible palette
if ((comp_ctl & tightExplicitFilter) != 0) {
@@ -192,10 +195,10 @@ bool TightDecoder::readRect(const Rect& r, rdr::InStream* is,
return true;
}
-bool TightDecoder::doRectsConflict(const Rect& /*rectA*/,
+bool TightDecoder::doRectsConflict(const core::Rect& /*rectA*/,
const uint8_t* bufferA,
size_t buflenA,
- const Rect& /*rectB*/,
+ const core::Rect& /*rectB*/,
const uint8_t* bufferB,
size_t buflenB,
const ServerParams& /*server*/)
@@ -220,7 +223,7 @@ bool TightDecoder::doRectsConflict(const Rect& /*rectA*/,
return false;
}
-void TightDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
+void TightDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
@@ -506,7 +509,7 @@ uint32_t TightDecoder::readCompact(rdr::InStream* is)
void
TightDecoder::FilterGradient24(const uint8_t *inbuf,
const PixelFormat& pf, uint32_t* outbuf,
- int stride, const Rect& r)
+ int stride, const core::Rect& r)
{
int x, y, c;
uint8_t prevRow[TIGHT_MAX_WIDTH*3];
@@ -552,7 +555,7 @@ TightDecoder::FilterGradient24(const uint8_t *inbuf,
template<class T>
void TightDecoder::FilterGradient(const uint8_t* inbuf,
const PixelFormat& pf, T* outbuf,
- int stride, const Rect& r)
+ int stride, const core::Rect& r)
{
int x, y, c;
static uint8_t prevRow[TIGHT_MAX_WIDTH*3];
@@ -606,7 +609,7 @@ void TightDecoder::FilterGradient(const uint8_t* inbuf,
template<class T>
void TightDecoder::FilterPalette(const T* palette, int palSize,
const uint8_t* inbuf, T* outbuf,
- int stride, const Rect& r)
+ int stride, const core::Rect& r)
{
// Indexed color
int x, h = r.height(), w = r.width(), b, pad = stride - w;
diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h
index d569a7fd..a75fc7da 100644
--- a/common/rfb/TightDecoder.h
+++ b/common/rfb/TightDecoder.h
@@ -22,7 +22,6 @@
#include <rdr/ZlibInStream.h>
#include <rfb/Decoder.h>
-#include <rfb/JpegDecompressor.h>
namespace rfb {
@@ -31,15 +30,15 @@ namespace rfb {
public:
TightDecoder();
virtual ~TightDecoder();
- bool readRect(const Rect& r, rdr::InStream* is,
+ bool readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server,
rdr::OutStream* os) override;
- bool doRectsConflict(const Rect& rectA,
+ bool doRectsConflict(const core::Rect& rectA,
const uint8_t* bufferA, size_t buflenA,
- const Rect& rectB,
+ const core::Rect& rectB,
const uint8_t* bufferB, size_t buflenB,
const ServerParams& server) override;
- void decodeRect(const Rect& r, const uint8_t* buffer,
+ void decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) override;
@@ -47,16 +46,16 @@ namespace rfb {
uint32_t readCompact(rdr::InStream* is);
void FilterGradient24(const uint8_t* inbuf, const PixelFormat& pf,
- uint32_t* outbuf, int stride, const Rect& r);
+ uint32_t* outbuf, int stride, const core::Rect& r);
template<class T>
void FilterGradient(const uint8_t* inbuf, const PixelFormat& pf,
- T* outbuf, int stride, const Rect& r);
+ T* outbuf, int stride, const core::Rect& r);
template<class T>
void FilterPalette(const T* palette, int palSize,
const uint8_t* inbuf, T* outbuf,
- int stride, const Rect& r);
+ int stride, const core::Rect& r);
private:
rdr::ZlibInStream zis[4];
diff --git a/common/rfb/UnixPasswordValidator.cxx b/common/rfb/UnixPasswordValidator.cxx
index 57fa9b39..8239463a 100644
--- a/common/rfb/UnixPasswordValidator.cxx
+++ b/common/rfb/UnixPasswordValidator.cxx
@@ -22,24 +22,119 @@
#include <config.h>
#endif
-#include <rfb/Configuration.h>
-#include <rfb/Exception.h>
+#include <assert.h>
+#include <string.h>
+#include <security/pam_appl.h>
+
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+
#include <rfb/UnixPasswordValidator.h>
-#include <rfb/pam.h>
using namespace rfb;
-static StringParameter pamService
+static core::LogWriter vlog("UnixPasswordValidator");
+
+static core::StringParameter pamService
("PAMService", "Service name for PAM password validation", "vnc");
-AliasParameter pam_service("pam_service", "Alias for PAMService",
- &pamService);
+core::AliasParameter pam_service("pam_service", "Alias for PAMService",
+ &pamService);
-int do_pam_auth(const char *service, const char *username,
- const char *password);
+std::string UnixPasswordValidator::displayName;
-bool UnixPasswordValidator::validateInternal(SConnection * /*sc*/,
+typedef struct
+{
+ const char *username;
+ const char *password;
+ std::string &msg;
+} AuthData;
+
+#if defined(__sun)
+static int pam_callback(int count, struct pam_message **in,
+ struct pam_response **out, void *ptr)
+#else
+static int pam_callback(int count, const struct pam_message **in,
+ struct pam_response **out, void *ptr)
+#endif
+{
+ int i;
+ AuthData *auth = (AuthData *) ptr;
+ struct pam_response *resp =
+ (struct pam_response *) malloc (sizeof (struct pam_response) * count);
+
+ if (!resp && count)
+ return PAM_CONV_ERR;
+
+ for (i = 0; i < count; i++) {
+ resp[i].resp_retcode = PAM_SUCCESS;
+ switch (in[i]->msg_style) {
+ case PAM_TEXT_INFO:
+ vlog.info("%s info: %s", (const char *) pamService, in[i]->msg);
+ auth->msg = in[i]->msg;
+ resp[i].resp = nullptr;
+ break;
+ case PAM_ERROR_MSG:
+ vlog.error("%s error: %s", (const char *) pamService, in[i]->msg);
+ auth->msg = in[i]->msg;
+ resp[i].resp = nullptr;
+ break;
+ case PAM_PROMPT_ECHO_ON: /* Send Username */
+ resp[i].resp = strdup(auth->username);
+ break;
+ case PAM_PROMPT_ECHO_OFF: /* Send Password */
+ resp[i].resp = strdup(auth->password);
+ break;
+ default:
+ free(resp);
+ return PAM_CONV_ERR;
+ }
+ }
+
+ *out = resp;
+ return PAM_SUCCESS;
+}
+
+bool UnixPasswordValidator::validateInternal(SConnection * /* sc */,
const char *username,
- const char *password)
+ const char *password,
+ std::string &msg)
{
- return do_pam_auth(pamService, username, password);
+ int ret;
+ AuthData auth = { username, password, msg };
+ struct pam_conv conv = {
+ pam_callback,
+ &auth
+ };
+ pam_handle_t *pamh = nullptr;
+ ret = pam_start(pamService, username, &conv, &pamh);
+ if (ret != PAM_SUCCESS) {
+ /* Can't call pam_strerror() here because the content of pamh undefined */
+ vlog.error("pam_start(%s) failed: %d", (const char *) pamService, ret);
+ return false;
+ }
+#ifdef PAM_XDISPLAY
+ /* At this point, displayName should never be empty */
+ assert(displayName.length() > 0);
+ /* Pass the display name to PAM modules but PAM_XDISPLAY may not be
+ * recognized by modules built with old versions of PAM */
+ ret = pam_set_item(pamh, PAM_XDISPLAY, displayName.c_str());
+ if (ret != PAM_SUCCESS && ret != PAM_BAD_ITEM) {
+ vlog.error("pam_set_item(PAM_XDISPLAY) failed: %d (%s)", ret, pam_strerror(pamh, ret));
+ goto error;
+ }
+#endif
+ ret = pam_authenticate(pamh, 0);
+ if (ret != PAM_SUCCESS) {
+ vlog.error("pam_authenticate() failed: %d (%s)", ret, pam_strerror(pamh, ret));
+ goto error;
+ }
+ ret = pam_acct_mgmt(pamh, 0);
+ if (ret != PAM_SUCCESS) {
+ vlog.error("pam_acct_mgmt() failed: %d (%s)", ret, pam_strerror(pamh, ret));
+ goto error;
+ }
+ return true;
+error:
+ pam_end(pamh, ret);
+ return false;
}
diff --git a/common/rfb/UnixPasswordValidator.h b/common/rfb/UnixPasswordValidator.h
index 4d623d6c..a2cc89c5 100644
--- a/common/rfb/UnixPasswordValidator.h
+++ b/common/rfb/UnixPasswordValidator.h
@@ -26,9 +26,19 @@
namespace rfb
{
class UnixPasswordValidator: public PasswordValidator {
+ public:
+ static void setDisplayName(const std::string& display) {
+ displayName = display;
+ }
+
protected:
- bool validateInternal(SConnection * sc, const char *username,
- const char *password) override;
+ bool validateInternal(SConnection *sc,
+ const char *username,
+ const char *password,
+ std::string &msg) override;
+
+ private:
+ static std::string displayName;
};
}
diff --git a/common/rfb/UpdateTracker.cxx b/common/rfb/UpdateTracker.cxx
index 7c97a6b8..1aedf491 100644
--- a/common/rfb/UpdateTracker.cxx
+++ b/common/rfb/UpdateTracker.cxx
@@ -25,27 +25,31 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
#include <rfb/UpdateTracker.h>
-#include <rfb/LogWriter.h>
using namespace rfb;
-static LogWriter vlog("UpdateTracker");
+static core::LogWriter vlog("UpdateTracker");
// -=- ClippingUpdateTracker
-void ClippingUpdateTracker::add_changed(const Region &region) {
+void ClippingUpdateTracker::add_changed(const core::Region& region)
+{
ut->add_changed(region.intersect(clipRect));
}
-void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) {
+void ClippingUpdateTracker::add_copied(const core::Region& dest,
+ const core::Point& delta)
+{
// Clip the destination to the display area
- Region clipdest = dest.intersect(clipRect);
+ core::Region clipdest = dest.intersect(clipRect);
if (clipdest.is_empty()) return;
// Clip the source to the screen
- Region tmp = clipdest;
+ core::Region tmp = clipdest;
tmp.translate(delta.negate());
tmp.assign_intersect(clipRect);
if (!tmp.is_empty()) {
@@ -70,25 +74,28 @@ SimpleUpdateTracker::SimpleUpdateTracker() {
SimpleUpdateTracker::~SimpleUpdateTracker() {
}
-void SimpleUpdateTracker::add_changed(const Region &region) {
+void SimpleUpdateTracker::add_changed(const core::Region& region)
+{
changed.assign_union(region);
}
-void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
+void SimpleUpdateTracker::add_copied(const core::Region& dest,
+ const core::Point& delta)
+{
// Is there anything to do?
if (dest.is_empty()) return;
// Calculate whether any of this copy can be treated as a continuation
// of an earlier one
- Region src = dest;
+ core::Region src = dest;
src.translate(delta.negate());
- Region overlap = src.intersect(copied);
+ core::Region overlap = src.intersect(copied);
if (overlap.is_empty()) {
// There is no overlap
- Rect newbr = dest.get_bounding_rect();
- Rect oldbr = copied.get_bounding_rect();
+ core::Rect newbr = dest.get_bounding_rect();
+ core::Rect oldbr = copied.get_bounding_rect();
if (oldbr.area() > newbr.area()) {
// Old copyrect is (probably) bigger - use it
changed.assign_union(dest);
@@ -97,7 +104,7 @@ void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
// Use the new one
// But be careful not to copy stuff that still needs
// to be updated.
- Region invalid_src = src.intersect(changed);
+ core::Region invalid_src = src.intersect(changed);
invalid_src.translate(delta);
changed.assign_union(invalid_src);
changed.assign_union(copied);
@@ -107,13 +114,13 @@ void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
return;
}
- Region invalid_src = overlap.intersect(changed);
+ core::Region invalid_src = overlap.intersect(changed);
invalid_src.translate(delta);
changed.assign_union(invalid_src);
overlap.translate(delta);
- Region nonoverlapped_copied = dest.union_(copied).subtract(overlap);
+ core::Region nonoverlapped_copied = dest.union_(copied).subtract(overlap);
changed.assign_union(nonoverlapped_copied);
copied = overlap;
@@ -122,12 +129,14 @@ void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) {
return;
}
-void SimpleUpdateTracker::subtract(const Region& region) {
+void SimpleUpdateTracker::subtract(const core::Region& region)
+{
copied.assign_subtract(region);
changed.assign_subtract(region);
}
-void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info, const Region& clip)
+void SimpleUpdateTracker::getUpdateInfo(UpdateInfo* info,
+ const core::Region& clip)
{
copied.assign_subtract(changed);
info->changed = changed.intersect(clip);
diff --git a/common/rfb/UpdateTracker.h b/common/rfb/UpdateTracker.h
index e91b9621..3d7a2fcd 100644
--- a/common/rfb/UpdateTracker.h
+++ b/common/rfb/UpdateTracker.h
@@ -19,17 +19,16 @@
#ifndef __RFB_UPDATETRACKER_INCLUDED__
#define __RFB_UPDATETRACKER_INCLUDED__
-#include <rfb/Rect.h>
-#include <rfb/Region.h>
-#include <rfb/PixelBuffer.h>
+#include <core/Rect.h>
+#include <core/Region.h>
namespace rfb {
class UpdateInfo {
public:
- Region changed;
- Region copied;
- Point copy_delta;
+ core::Region changed;
+ core::Region copied;
+ core::Point copy_delta;
bool is_empty() const {
return copied.is_empty() && changed.is_empty();
}
@@ -47,23 +46,25 @@ namespace rfb {
UpdateTracker() {};
virtual ~UpdateTracker() {};
- virtual void add_changed(const Region &region) = 0;
- virtual void add_copied(const Region &dest, const Point &delta) = 0;
+ virtual void add_changed(const core::Region& region) = 0;
+ virtual void add_copied(const core::Region& dest,
+ const core::Point& delta) = 0;
};
class ClippingUpdateTracker : public UpdateTracker {
public:
ClippingUpdateTracker() : ut(nullptr) {}
- ClippingUpdateTracker(UpdateTracker* ut_, const Rect& r=Rect()) : ut(ut_), clipRect(r) {}
+ ClippingUpdateTracker(UpdateTracker* ut_, const core::Rect& r={}) : ut(ut_), clipRect(r) {}
void setUpdateTracker(UpdateTracker* ut_) {ut = ut_;}
- void setClipRect(const Rect& cr) {clipRect = cr;}
+ void setClipRect(const core::Rect& cr) {clipRect = cr;}
- void add_changed(const Region &region) override;
- void add_copied(const Region &dest, const Point &delta) override;
+ void add_changed(const core::Region& region) override;
+ void add_copied(const core::Region& dest,
+ const core::Point& delta) override;
protected:
UpdateTracker* ut;
- Rect clipRect;
+ core::Rect clipRect;
};
class SimpleUpdateTracker : public UpdateTracker {
@@ -71,27 +72,29 @@ namespace rfb {
SimpleUpdateTracker();
virtual ~SimpleUpdateTracker();
- void add_changed(const Region &region) override;
- void add_copied(const Region &dest, const Point &delta) override;
- virtual void subtract(const Region& region);
+ void add_changed(const core::Region& region) override;
+ void add_copied(const core::Region& dest,
+ const core::Point& delta) override;
+ virtual void subtract(const core::Region& region);
// Fill the supplied UpdateInfo structure with update information
// FIXME: Provide getUpdateInfo() with no clipping, for better efficiency.
- virtual void getUpdateInfo(UpdateInfo* info, const Region& cliprgn);
+ virtual void getUpdateInfo(UpdateInfo* info,
+ const core::Region& cliprgn);
// Copy the contained updates to another tracker
virtual void copyTo(UpdateTracker* to) const;
// Move the entire update region by an offset
- void translate(const Point& p) {changed.translate(p); copied.translate(p);}
+ void translate(const core::Point& p) {changed.translate(p); copied.translate(p);}
virtual bool is_empty() const {return changed.is_empty() && copied.is_empty();}
virtual void clear() {changed.clear(); copied.clear();};
protected:
- Region changed;
- Region copied;
- Point copy_delta;
+ core::Region changed;
+ core::Region copied;
+ core::Point copy_delta;
};
}
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index a354f636..2d77fae6 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -22,7 +22,12 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+#include <core/time.h>
+
+#include <rdr/FdInStream.h>
+#include <rdr/FdOutStream.h>
#include <network/TcpSocket.h>
@@ -31,12 +36,12 @@
#include <rfb/Exception.h>
#include <rfb/KeyRemapper.h>
#include <rfb/KeysymStr.h>
-#include <rfb/LogWriter.h>
#include <rfb/Security.h>
#include <rfb/ServerCore.h>
#include <rfb/SMsgWriter.h>
#include <rfb/VNCServerST.h>
#include <rfb/VNCSConnectionST.h>
+#include <rfb/encodings.h>
#include <rfb/screenTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/ledStates.h>
@@ -44,13 +49,12 @@
#define XK_MISCELLANY
#define XK_XKB_KEYS
#include <rfb/keysymdef.h>
-#include <rfb/util.h>
using namespace rfb;
-static LogWriter vlog("VNCSConnST");
+static core::LogWriter vlog("VNCSConnST");
-static Cursor emptyCursor(0, 0, Point(0, 0), nullptr);
+static Cursor emptyCursor(0, 0, {0, 0}, nullptr);
VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
bool reverse, AccessRights ar)
@@ -71,9 +75,9 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
if (rfb::Server::idleTimeout) {
// minimum of 15 seconds while authenticating
if (rfb::Server::idleTimeout < 15)
- idleTimer.start(secsToMillis(15));
+ idleTimer.start(core::secsToMillis(15));
else
- idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout));
}
}
@@ -216,11 +220,11 @@ void VNCSConnectionST::pixelBufferChange()
//updates.intersect(server->pb->getRect());
//
//if (server->pb->width() > client.width())
- // updates.add_changed(Rect(client.width(), 0, server->pb->width(),
- // server->pb->height()));
+ // updates.add_changed({client.width(), 0, server->pb->width(),
+ // server->pb->height()});
//if (server->pb->height() > client.height())
- // updates.add_changed(Rect(0, client.height(), client.width(),
- // server->pb->height()));
+ // updates.add_changed({0, client.height(), client.width(),
+ // server->pb->height()});
damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect());
@@ -236,7 +240,7 @@ void VNCSConnectionST::pixelBufferChange()
}
// Drop any lossy tracking that is now outside the framebuffer
- encodeManager.pruneLosslessRefresh(Region(server->getPixelBuffer()->getRect()));
+ encodeManager.pruneLosslessRefresh(server->getPixelBuffer()->getRect());
}
// Just update the whole screen at the moment because we're too lazy to
// work out what's actually changed.
@@ -310,8 +314,6 @@ void VNCSConnectionST::requestClipboardOrClose()
{
try {
if (state() != RFBSTATE_NORMAL) return;
- if (!accessCheck(AccessCutText)) return;
- if (!rfb::Server::acceptCutText) return;
requestClipboard();
} catch(std::exception& e) {
close(e.what());
@@ -322,8 +324,6 @@ void VNCSConnectionST::announceClipboardOrClose(bool available)
{
try {
if (state() != RFBSTATE_NORMAL) return;
- if (!accessCheck(AccessCutText)) return;
- if (!rfb::Server::sendCutText) return;
announceClipboard(available);
} catch(std::exception& e) {
close(e.what());
@@ -334,8 +334,6 @@ void VNCSConnectionST::sendClipboardDataOrClose(const char* data)
{
try {
if (state() != RFBSTATE_NORMAL) return;
- if (!accessCheck(AccessCutText)) return;
- if (!rfb::Server::sendCutText) return;
sendClipboardData(data);
} catch(std::exception& e) {
close(e.what());
@@ -421,7 +419,7 @@ void VNCSConnectionST::approveConnectionOrClose(bool accept,
void VNCSConnectionST::authSuccess()
{
if (rfb::Server::idleTimeout)
- idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout));
// - Set the connection parameters appropriately
client.setDimensions(server->getPixelBuffer()->width(),
@@ -448,7 +446,7 @@ void VNCSConnectionST::queryConnection(const char* userName)
void VNCSConnectionST::clientInit(bool shared)
{
if (rfb::Server::idleTimeout)
- idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout));
if (rfb::Server::alwaysShared || reverseConnection) shared = true;
if (!accessCheck(AccessNonShared)) shared = true;
if (rfb::Server::neverShared) shared = false;
@@ -463,15 +461,16 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
pf.print(buffer, 256);
vlog.info("Client pixel format %s", buffer);
setCursor();
+ encodeManager.forceRefresh(server->getPixelBuffer()->getRect());
}
-void VNCSConnectionST::pointerEvent(const Point& pos, uint16_t buttonMask)
+void VNCSConnectionST::pointerEvent(const core::Point& pos,
+ uint16_t buttonMask)
{
if (rfb::Server::idleTimeout)
- idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout));
pointerEventTime = time(nullptr);
if (!accessCheck(AccessPtrEvents)) return;
- if (!rfb::Server::acceptPointerEvents) return;
pointerEventPos = pos;
server->pointerEvent(this, pointerEventPos, buttonMask);
}
@@ -502,8 +501,10 @@ void VNCSConnectionST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) {
uint32_t lookup;
if (rfb::Server::idleTimeout)
- idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
+ idleTimer.start(core::secsToMillis(rfb::Server::idleTimeout));
if (!accessCheck(AccessKeyEvents)) return;
+ // FIXME: This check isn't strictly needed, but we get a lot of
+ // confusing debug logging without it
if (!rfb::Server::acceptKeyEvents) return;
if (down)
@@ -605,27 +606,28 @@ void VNCSConnectionST::keyEvent(uint32_t keysym, uint32_t keycode, bool down) {
server->keyEvent(keysym, keycode, down);
}
-void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
+void VNCSConnectionST::framebufferUpdateRequest(const core::Rect& r,
+ bool incremental)
{
- Rect safeRect;
+ core::Rect safeRect;
if (!accessCheck(AccessView)) return;
SConnection::framebufferUpdateRequest(r, incremental);
// Check that the client isn't sending crappy requests
- if (!r.enclosed_by(Rect(0, 0, client.width(), client.height()))) {
+ if (!r.enclosed_by({0, 0, client.width(), client.height()})) {
vlog.error("FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
r.width(), r.height(), r.tl.x, r.tl.y,
client.width(), client.height());
- safeRect = r.intersect(Rect(0, 0, client.width(), client.height()));
+ safeRect = r.intersect({0, 0, client.width(), client.height()});
} else {
safeRect = r;
}
// Just update the requested region.
// Framebuffer update will be sent a bit later, see processMessages().
- Region reqRgn(safeRect);
+ core::Region reqRgn(safeRect);
if (!incremental || !continuousUpdates)
requested.assign_union(reqRgn);
@@ -656,8 +658,7 @@ void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height,
layout.print(buffer, sizeof(buffer));
vlog.debug("%s", buffer);
- if (!accessCheck(AccessSetDesktopSize) ||
- !rfb::Server::acceptSetDesktopSize) {
+ if (!accessCheck(AccessSetDesktopSize)) {
vlog.debug("Rejecting unauthorized framebuffer resize request");
result = resultProhibited;
} else {
@@ -716,7 +717,10 @@ void VNCSConnectionST::fence(uint32_t flags, unsigned len, const uint8_t data[])
void VNCSConnectionST::enableContinuousUpdates(bool enable,
int x, int y, int w, int h)
{
- Rect rect;
+ core::Rect rect;
+
+ if (!accessCheck(AccessView))
+ return;
if (!client.supportsFence() || !client.supportsContinuousUpdates())
throw protocol_error("Client tried to enable continuous updates when not allowed");
@@ -735,21 +739,16 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable,
void VNCSConnectionST::handleClipboardRequest()
{
- if (!accessCheck(AccessCutText)) return;
server->handleClipboardRequest(this);
}
void VNCSConnectionST::handleClipboardAnnounce(bool available)
{
- if (!accessCheck(AccessCutText)) return;
- if (!rfb::Server::acceptCutText) return;
server->handleClipboardAnnounce(this, available);
}
void VNCSConnectionST::handleClipboardData(const char* data)
{
- if (!accessCheck(AccessCutText)) return;
- if (!rfb::Server::acceptCutText) return;
server->handleClipboardData(this, data);
}
@@ -790,7 +789,7 @@ void VNCSConnectionST::supportsLEDState()
writer()->writeLEDState();
}
-void VNCSConnectionST::handleTimeout(Timer* t)
+void VNCSConnectionST::handleTimeout(core::Timer* t)
{
try {
if ((t == &congestionTimer) ||
@@ -921,7 +920,7 @@ void VNCSConnectionST::writeNoDataUpdate()
void VNCSConnectionST::writeDataUpdate()
{
- Region req;
+ core::Region req;
UpdateInfo ui;
bool needNewUpdateInfo;
const RenderedCursor *cursor;
@@ -946,7 +945,7 @@ void VNCSConnectionST::writeDataUpdate()
// destination will be wrong, so add it to the changed region.
if (!ui.copied.is_empty() && !damagedCursorRegion.is_empty()) {
- Region bogusCopiedCursor;
+ core::Region bogusCopiedCursor;
bogusCopiedCursor = damagedCursorRegion;
bogusCopiedCursor.translate(ui.copy_delta);
@@ -993,7 +992,7 @@ void VNCSConnectionST::writeDataUpdate()
cursor = nullptr;
if (needRenderedCursor()) {
- Rect renderedCursorRect;
+ core::Rect renderedCursorRect;
cursor = server->getRenderedCursor();
renderedCursorRect = cursor->getEffectiveRect();
@@ -1033,7 +1032,7 @@ void VNCSConnectionST::writeDataUpdate()
void VNCSConnectionST::writeLosslessRefresh()
{
- Region req, pending;
+ core::Region req, pending;
const RenderedCursor *cursor;
int nextRefresh, nextUpdate;
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 17de9d01..b618923f 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -29,16 +29,17 @@
#include <map>
+#include <core/Timer.h>
+
#include <rfb/Congestion.h>
#include <rfb/EncodeManager.h>
#include <rfb/SConnection.h>
-#include <rfb/Timer.h>
namespace rfb {
class VNCServerST;
class VNCSConnectionST : private SConnection,
- public Timer::Callback {
+ public core::Timer::Callback {
public:
VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse,
AccessRights ar);
@@ -108,8 +109,8 @@ namespace rfb {
// Change tracking
- void add_changed(const Region& region) { updates.add_changed(region); }
- void add_copied(const Region& dest, const Point& delta) {
+ void add_changed(const core::Region& region) { updates.add_changed(region); }
+ void add_copied(const core::Region& dest, const core::Point& delta) {
updates.add_copied(dest, delta);
}
@@ -123,10 +124,11 @@ namespace rfb {
void queryConnection(const char* userName) override;
void clientInit(bool shared) override;
void setPixelFormat(const PixelFormat& pf) override;
- void pointerEvent(const Point& pos, uint16_t buttonMask) override;
+ void pointerEvent(const core::Point& pos,
+ uint16_t buttonMask) override;
void keyEvent(uint32_t keysym, uint32_t keycode,
bool down) override;
- void framebufferUpdateRequest(const Rect& r,
+ void framebufferUpdateRequest(const core::Rect& r,
bool incremental) override;
void setDesktopSize(int fb_width, int fb_height,
const ScreenSet& layout) override;
@@ -143,7 +145,7 @@ namespace rfb {
void supportsLEDState() override;
// Timer callbacks
- void handleTimeout(Timer* t) override;
+ void handleTimeout(core::Timer* t) override;
// Internal methods
@@ -180,24 +182,24 @@ namespace rfb {
uint8_t *fenceData;
Congestion congestion;
- Timer congestionTimer;
- Timer losslessTimer;
+ core::Timer congestionTimer;
+ core::Timer losslessTimer;
VNCServerST* server;
SimpleUpdateTracker updates;
- Region requested;
+ core::Region requested;
bool updateRenderedCursor, removeRenderedCursor;
- Region damagedCursorRegion;
+ core::Region damagedCursorRegion;
bool continuousUpdates;
- Region cuRegion;
+ core::Region cuRegion;
EncodeManager encodeManager;
std::map<uint32_t, uint32_t> pressedKeys;
- Timer idleTimer;
+ core::Timer idleTimer;
time_t pointerEventTime;
- Point pointerEventPos;
+ core::Point pointerEventPos;
bool clientHasCursor;
std::string closeReason;
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index 4e3a5b23..4d9b31ed 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -23,14 +23,19 @@
#ifndef __RFB_VNCSERVER_H__
#define __RFB_VNCSERVER_H__
+#include <list>
+
+#include <rfb/AccessRights.h>
#include <rfb/UpdateTracker.h>
-#include <rfb/SSecurity.h>
-#include <rfb/ScreenSet.h>
namespace network { class Socket; }
namespace rfb {
+ class PixelBuffer;
+ class SConnection;
+ struct ScreenSet;
+
class VNCServer : public UpdateTracker {
public:
// addSocket() tells the server to serve the Socket. The caller
@@ -128,13 +133,14 @@ namespace rfb {
// setCursor() tells the server that the cursor has changed. The
// cursorData argument contains width*height rgba quadruplets with
// non-premultiplied alpha.
- virtual void setCursor(int width, int height, const Point& hotspot,
+ virtual void setCursor(int width, int height,
+ const core::Point& hotspot,
const uint8_t* cursorData) = 0;
// setCursorPos() tells the server the current position of the cursor, and
// whether the server initiated that change (e.g. through another X11
// client calling XWarpPointer()).
- virtual void setCursorPos(const Point& p, bool warped) = 0;
+ virtual void setCursorPos(const core::Point& p, bool warped) = 0;
// setName() tells the server what desktop title to supply to clients
virtual void setName(const char* name) = 0;
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index b99d33b0..77d652b9 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -55,24 +55,28 @@
#include <assert.h>
#include <stdlib.h>
+#include <core/LogWriter.h>
+#include <core/time.h>
+
+#include <rdr/FdOutStream.h>
+
#include <network/Socket.h>
#include <rfb/ComparingUpdateTracker.h>
#include <rfb/KeyRemapper.h>
#include <rfb/KeysymStr.h>
-#include <rfb/LogWriter.h>
+#include <rfb/SDesktop.h>
#include <rfb/Security.h>
#include <rfb/ServerCore.h>
#include <rfb/VNCServerST.h>
#include <rfb/VNCSConnectionST.h>
-#include <rfb/util.h>
#include <rfb/ledStates.h>
using namespace rfb;
-static LogWriter slog("VNCServerST");
-static LogWriter connectionsLog("Connections");
+static core::LogWriter slog("VNCServerST");
+static core::LogWriter connectionsLog("Connections");
//
// -=- VNCServerST Implementation
@@ -85,7 +89,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
blockCounter(0), pb(nullptr), ledState(ledUnknown),
name(name_), pointerClient(nullptr), clipboardClient(nullptr),
pointerClientTime(0),
- comparer(nullptr), cursor(new Cursor(0, 0, Point(), nullptr)),
+ comparer(nullptr), cursor(new Cursor(0, 0, {}, nullptr)),
renderedCursorInvalid(false),
keyRemapper(&KeyRemapper::defInstance),
idleTimer(this), disconnectTimer(this), connectTimer(this),
@@ -97,9 +101,9 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
// FIXME: Do we really want to kick off these right away?
if (rfb::Server::maxIdleTime)
- idleTimer.start(secsToMillis(rfb::Server::maxIdleTime));
+ idleTimer.start(core::secsToMillis(rfb::Server::maxIdleTime));
if (rfb::Server::maxDisconnectionTime)
- disconnectTimer.start(secsToMillis(rfb::Server::maxDisconnectionTime));
+ disconnectTimer.start(core::secsToMillis(rfb::Server::maxDisconnectionTime));
}
VNCServerST::~VNCServerST()
@@ -161,12 +165,18 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing, AccessRights a
// Adjust the exit timers
if (rfb::Server::maxConnectionTime && clients.empty())
- connectTimer.start(secsToMillis(rfb::Server::maxConnectionTime));
+ connectTimer.start(core::secsToMillis(rfb::Server::maxConnectionTime));
disconnectTimer.stop();
- VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing, accessRights);
- clients.push_front(client);
- client->init();
+ try {
+ VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing, accessRights);
+ clients.push_front(client);
+ client->init();
+ } catch (std::exception& e) {
+ connectionsLog.error("Error accepting client: %s", e.what());
+ sock->shutdown();
+ closingSockets.push_back(sock);
+ }
}
void VNCServerST::removeSocket(network::Socket* sock) {
@@ -203,7 +213,7 @@ void VNCServerST::removeSocket(network::Socket* sock) {
// Adjust the exit timers
connectTimer.stop();
if (rfb::Server::maxDisconnectionTime && clients.empty())
- disconnectTimer.start(secsToMillis(rfb::Server::maxDisconnectionTime));
+ disconnectTimer.start(core::secsToMillis(rfb::Server::maxDisconnectionTime));
return;
}
@@ -313,7 +323,7 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_)
// Check that the screen layout is still valid
if (pb_ && !layout.validate(pb_->width(), pb_->height())) {
- Rect fbRect;
+ core::Rect fbRect;
ScreenSet::iterator iter, iter_next;
fbRect.setXYWH(0, 0, pb_->width(), pb_->height());
@@ -354,6 +364,9 @@ void VNCServerST::setScreenLayout(const ScreenSet& layout)
void VNCServerST::requestClipboard()
{
+ if (!rfb::Server::acceptCutText)
+ return;
+
if (clipboardClient == nullptr) {
slog.debug("Got request for client clipboard but no client currently owns the clipboard");
return;
@@ -368,6 +381,9 @@ void VNCServerST::announceClipboard(bool available)
clipboardRequestors.clear();
+ if (!rfb::Server::sendCutText)
+ return;
+
for (ci = clients.begin(); ci != clients.end(); ++ci)
(*ci)->announceClipboardOrClose(available);
}
@@ -376,6 +392,9 @@ void VNCServerST::sendClipboardData(const char* data)
{
std::list<VNCSConnectionST*>::iterator ci;
+ if (!rfb::Server::sendCutText)
+ return;
+
if (strchr(data, '\r') != nullptr)
throw std::invalid_argument("Invalid carriage return in clipboard data");
@@ -401,7 +420,7 @@ void VNCServerST::setName(const char* name_)
(*ci)->setDesktopNameOrClose(name_);
}
-void VNCServerST::add_changed(const Region& region)
+void VNCServerST::add_changed(const core::Region& region)
{
if (comparer == nullptr)
return;
@@ -410,7 +429,8 @@ void VNCServerST::add_changed(const Region& region)
startFrameClock();
}
-void VNCServerST::add_copied(const Region& dest, const Point& delta)
+void VNCServerST::add_copied(const core::Region& dest,
+ const core::Point& delta)
{
if (comparer == nullptr)
return;
@@ -419,7 +439,8 @@ void VNCServerST::add_copied(const Region& dest, const Point& delta)
startFrameClock();
}
-void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
+void VNCServerST::setCursor(int width, int height,
+ const core::Point& newHotspot,
const uint8_t* data)
{
delete cursor;
@@ -435,7 +456,7 @@ void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
}
}
-void VNCServerST::setCursorPos(const Point& pos, bool warped)
+void VNCServerST::setCursorPos(const core::Point& pos, bool warped)
{
if (cursorPos != pos) {
cursorPos = pos;
@@ -466,8 +487,11 @@ void VNCServerST::setLEDState(unsigned int state)
void VNCServerST::keyEvent(uint32_t keysym, uint32_t keycode, bool down)
{
+ if (!rfb::Server::acceptKeyEvents)
+ return;
+
if (rfb::Server::maxIdleTime)
- idleTimer.start(secsToMillis(rfb::Server::maxIdleTime));
+ idleTimer.start(core::secsToMillis(rfb::Server::maxIdleTime));
// Remap the key if required
if (keyRemapper) {
@@ -484,11 +508,16 @@ void VNCServerST::keyEvent(uint32_t keysym, uint32_t keycode, bool down)
}
void VNCServerST::pointerEvent(VNCSConnectionST* client,
- const Point& pos, uint16_t buttonMask)
+ const core::Point& pos,
+ uint16_t buttonMask)
{
time_t now = time(nullptr);
+
+ if (!rfb::Server::acceptPointerEvents)
+ return;
+
if (rfb::Server::maxIdleTime)
- idleTimer.start(secsToMillis(rfb::Server::maxIdleTime));
+ idleTimer.start(core::secsToMillis(rfb::Server::maxIdleTime));
// Let one client own the cursor whilst buttons are pressed in order
// to provide a bit more sane user experience. But limit the time to
@@ -516,9 +545,11 @@ void VNCServerST::handleClipboardRequest(VNCSConnectionST* client)
void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
bool available)
{
- if (available)
+ if (available) {
+ if (!rfb::Server::acceptCutText)
+ return;
clipboardClient = client;
- else {
+ } else {
if (client != clipboardClient)
return;
clipboardClient = nullptr;
@@ -529,6 +560,8 @@ void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
void VNCServerST::handleClipboardData(VNCSConnectionST* client,
const char* data)
{
+ if (!rfb::Server::acceptCutText)
+ return;
if (client != clipboardClient) {
slog.debug("Ignoring unexpected clipboard data");
return;
@@ -543,6 +576,11 @@ unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester,
unsigned int result;
std::list<VNCSConnectionST*>::iterator ci;
+ if (!rfb::Server::acceptSetDesktopSize) {
+ slog.debug("Rejecting unauthorized framebuffer resize request");
+ return resultProhibited;
+ }
+
// We can't handle a framebuffer larger than this, so don't let a
// client set one (see PixelBuffer.cxx)
if ((fb_width > 16384) || (fb_height > 16384)) {
@@ -622,7 +660,7 @@ SConnection* VNCServerST::getConnection(network::Socket* sock) {
return nullptr;
}
-void VNCServerST::handleTimeout(Timer* t)
+void VNCServerST::handleTimeout(core::Timer* t)
{
if (t == &frameTimer) {
int timeout;
@@ -822,7 +860,7 @@ int VNCServerST::msToNextUpdate()
void VNCServerST::writeUpdate()
{
UpdateInfo ui;
- Region toCheck;
+ core::Region toCheck;
std::list<VNCSConnectionST*>::iterator ci;
@@ -834,9 +872,9 @@ void VNCServerST::writeUpdate()
toCheck = ui.changed.union_(ui.copied);
if (needRenderedCursor()) {
- Rect clippedCursorRect = Rect(0, 0, cursor->width(), cursor->height())
- .translate(cursorPos.subtract(cursor->hotspot()))
- .intersect(pb->getRect());
+ core::Rect clippedCursorRect = core::Rect(0, 0, cursor->width(), cursor->height())
+ .translate(cursorPos.subtract(cursor->hotspot()))
+ .intersect(pb->getRect());
if (!toCheck.intersect(clippedCursorRect).is_empty())
renderedCursorInvalid = true;
@@ -864,7 +902,7 @@ void VNCServerST::writeUpdate()
// checkUpdate() is called by clients to see if it is safe to read from
// the framebuffer at this time.
-Region VNCServerST::getPendingRegion()
+core::Region VNCServerST::getPendingRegion()
{
UpdateInfo ui;
@@ -876,7 +914,7 @@ Region VNCServerST::getPendingRegion()
// Block client from updating if there are pending updates
if (comparer->is_empty())
- return Region();
+ return {};
comparer->getUpdateInfo(&ui, pb->getRect());
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index dc4f9aad..5db4513a 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -26,11 +26,11 @@
#include <sys/time.h>
-#include <rfb/SDesktop.h>
+#include <core/Timer.h>
+
#include <rfb/VNCServer.h>
#include <rfb/Blacklist.h>
#include <rfb/Cursor.h>
-#include <rfb/Timer.h>
#include <rfb/ScreenSet.h>
namespace rfb {
@@ -40,9 +40,10 @@ namespace rfb {
class ListConnInfo;
class PixelBuffer;
class KeyRemapper;
+ class SDesktop;
class VNCServerST : public VNCServer,
- public Timer::Callback {
+ public core::Timer::Callback {
public:
// -=- Constructors
@@ -95,11 +96,12 @@ namespace rfb {
void closeClients(const char* reason) override {closeClients(reason, nullptr);}
SConnection* getConnection(network::Socket* sock) override;
- void add_changed(const Region &region) override;
- void add_copied(const Region &dest, const Point &delta) override;
- void setCursor(int width, int height, const Point& hotspot,
+ void add_changed(const core::Region& region) override;
+ void add_copied(const core::Region& dest,
+ const core::Point& delta) override;
+ void setCursor(int width, int height, const core::Point& hotspot,
const uint8_t* data) override;
- void setCursorPos(const Point& p, bool warped) override;
+ void setCursorPos(const core::Point& p, bool warped) override;
void setName(const char* name_) override;
void setLEDState(unsigned state) override;
@@ -111,13 +113,14 @@ namespace rfb {
const ScreenSet& getScreenLayout() const { return screenLayout; }
const Cursor* getCursor() const { return cursor; }
- const Point& getCursorPos() const { return cursorPos; }
+ const core::Point& getCursorPos() const { return cursorPos; }
const char* getName() const { return name.c_str(); }
unsigned getLEDState() const { return ledState; }
// Event handlers
void keyEvent(uint32_t keysym, uint32_t keycode, bool down);
- void pointerEvent(VNCSConnectionST* client, const Point& pos, uint16_t buttonMask);
+ void pointerEvent(VNCSConnectionST* client,
+ const core::Point& pos, uint16_t buttonMask);
void handleClipboardRequest(VNCSConnectionST* client);
void handleClipboardAnnounce(VNCSConnectionST* client, bool available);
@@ -146,7 +149,7 @@ namespace rfb {
// Part of the framebuffer that has been modified but is not yet
// ready to be sent to clients
- Region getPendingRegion();
+ core::Region getPendingRegion();
// getRenderedCursor() returns an up to date version of the server
// side rendered cursor buffer
@@ -155,7 +158,7 @@ namespace rfb {
protected:
// Timer callbacks
- void handleTimeout(Timer* t) override;
+ void handleTimeout(core::Timer* t) override;
// - Internal methods
@@ -195,19 +198,19 @@ namespace rfb {
ComparingUpdateTracker* comparer;
- Point cursorPos;
+ core::Point cursorPos;
Cursor* cursor;
RenderedCursor renderedCursor;
bool renderedCursorInvalid;
KeyRemapper* keyRemapper;
- Timer idleTimer;
- Timer disconnectTimer;
- Timer connectTimer;
+ core::Timer idleTimer;
+ core::Timer disconnectTimer;
+ core::Timer connectTimer;
uint64_t msc, queuedMsc;
- Timer frameTimer;
+ core::Timer frameTimer;
};
};
diff --git a/common/rfb/WinPasswdValidator.cxx b/common/rfb/WinPasswdValidator.cxx
index 84832e81..a6281950 100644
--- a/common/rfb/WinPasswdValidator.cxx
+++ b/common/rfb/WinPasswdValidator.cxx
@@ -30,7 +30,8 @@ using namespace rfb;
// This method will only work for Windows NT, 2000, and XP (and possibly Vista)
bool WinPasswdValidator::validateInternal(rfb::SConnection* /*sc*/,
const char* username,
- const char* password)
+ const char* password,
+ std::string & /* msg */)
{
HANDLE handle;
diff --git a/common/rfb/WinPasswdValidator.h b/common/rfb/WinPasswdValidator.h
index 340a6234..993cafea 100644
--- a/common/rfb/WinPasswdValidator.h
+++ b/common/rfb/WinPasswdValidator.h
@@ -21,6 +21,7 @@
#ifndef __RFB_WINPASSWDVALIDATOR_H__
#define __RFB_WINPASSWDVALIDATOR_H__
+#include <string>
#include <rfb/SSecurityPlain.h>
namespace rfb
@@ -30,7 +31,10 @@ namespace rfb
WinPasswdValidator() {};
virtual ~WinPasswdValidator() {};
protected:
- bool validateInternal(SConnection *sc, const char* username, const char* password) override;
+ bool validateInternal(SConnection *sc,
+ const char *username,
+ const char *password,
+ std::string &msg) override;
};
}
diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx
index 633d1c36..845bf4dc 100644
--- a/common/rfb/ZRLEDecoder.cxx
+++ b/common/rfb/ZRLEDecoder.cxx
@@ -21,6 +21,8 @@
#include <config.h>
#endif
+#include <algorithm>
+
#include <rdr/InStream.h>
#include <rdr/MemInStream.h>
#include <rdr/OutStream.h>
@@ -75,7 +77,7 @@ ZRLEDecoder::~ZRLEDecoder()
{
}
-bool ZRLEDecoder::readRect(const Rect& /*r*/, rdr::InStream* is,
+bool ZRLEDecoder::readRect(const core::Rect& /*r*/, rdr::InStream* is,
const ServerParams& /*server*/,
rdr::OutStream* os)
{
@@ -99,7 +101,7 @@ bool ZRLEDecoder::readRect(const Rect& /*r*/, rdr::InStream* is,
return true;
}
-void ZRLEDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
+void ZRLEDecoder::decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb)
{
@@ -113,13 +115,13 @@ void ZRLEDecoder::decodeRect(const Rect& r, const uint8_t* buffer,
}
template<class T>
-void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is,
+void ZRLEDecoder::zrleDecode(const core::Rect& r, rdr::InStream* is,
const PixelFormat& pf,
ModifiablePixelBuffer* pb)
{
int length = is->readU32();
zis.setUnderlying(is, length);
- Rect t;
+ core::Rect t;
T buf[64 * 64];
Pixel maxPixel = pf.pixelFromRGB((uint16_t)-1, (uint16_t)-1, (uint16_t)-1);
@@ -134,11 +136,11 @@ void ZRLEDecoder::zrleDecode(const Rect& r, rdr::InStream* is,
for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
- t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
+ t.br.y = std::min(r.br.y, t.tl.y + 64);
for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
- t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
+ t.br.x = std::min(r.br.x, t.tl.x + 64);
zlibHasData(&zis, 1);
int mode = zis.readU8();
diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h
index facf0adc..b9ebf771 100644
--- a/common/rfb/ZRLEDecoder.h
+++ b/common/rfb/ZRLEDecoder.h
@@ -30,16 +30,16 @@ namespace rfb {
public:
ZRLEDecoder();
virtual ~ZRLEDecoder();
- bool readRect(const Rect& r, rdr::InStream* is,
+ bool readRect(const core::Rect& r, rdr::InStream* is,
const ServerParams& server,
rdr::OutStream* os) override;
- void decodeRect(const Rect& r, const uint8_t* buffer,
+ void decodeRect(const core::Rect& r, const uint8_t* buffer,
size_t buflen, const ServerParams& server,
ModifiablePixelBuffer* pb) override;
private:
template<class T>
- void zrleDecode(const Rect& r, rdr::InStream* is,
+ void zrleDecode(const core::Rect& r, rdr::InStream* is,
const PixelFormat& pf, ModifiablePixelBuffer* pb);
private:
diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx
index 1e2c6ef4..1908d7e3 100644
--- a/common/rfb/ZRLEEncoder.cxx
+++ b/common/rfb/ZRLEEncoder.cxx
@@ -21,20 +21,23 @@
#include <config.h>
#endif
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+
#include <rdr/OutStream.h>
-#include <rfb/Exception.h>
#include <rfb/encodings.h>
#include <rfb/Palette.h>
+#include <rfb/PixelBuffer.h>
#include <rfb/SConnection.h>
#include <rfb/ZRLEEncoder.h>
-#include <rfb/Configuration.h>
-#include <rfb/LogWriter.h>
using namespace rfb;
-static LogWriter vlog("ZRLEEncoder");
+static core::LogWriter vlog("ZRLEEncoder");
-IntParameter zlibLevel("ZlibLevel","[DEPRECATED] Zlib compression level",-1);
+core::IntParameter zlibLevel("ZlibLevel",
+ "[DEPRECATED] Zlib compression level",
+ -1, -1, -1);
ZRLEEncoder::ZRLEEncoder(SConnection* conn_)
: Encoder(conn_, encodingZRLE, EncoderPlain, 127),
@@ -66,7 +69,7 @@ void ZRLEEncoder::setCompressLevel(int level)
void ZRLEEncoder::writeRect(const PixelBuffer* pb, const Palette& palette)
{
int x, y;
- Rect tile;
+ core::Rect tile;
rdr::OutStream* os;
@@ -132,7 +135,8 @@ void ZRLEEncoder::writeSolidRect(int width, int height,
mos.clear();
}
-void ZRLEEncoder::writePaletteTile(const Rect& tile, const PixelBuffer* pb,
+void ZRLEEncoder::writePaletteTile(const core::Rect& tile,
+ const PixelBuffer* pb,
const Palette& palette)
{
const uint8_t* buffer;
@@ -158,7 +162,8 @@ void ZRLEEncoder::writePaletteTile(const Rect& tile, const PixelBuffer* pb,
}
}
-void ZRLEEncoder::writePaletteRLETile(const Rect& tile, const PixelBuffer* pb,
+void ZRLEEncoder::writePaletteRLETile(const core::Rect& tile,
+ const PixelBuffer* pb,
const Palette& palette)
{
const uint8_t* buffer;
@@ -184,7 +189,8 @@ void ZRLEEncoder::writePaletteRLETile(const Rect& tile, const PixelBuffer* pb,
}
}
-void ZRLEEncoder::writeRawTile(const Rect& tile, const PixelBuffer* pb)
+void ZRLEEncoder::writeRawTile(const core::Rect& tile,
+ const PixelBuffer* pb)
{
const uint8_t* buffer;
int stride;
diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h
index 87d87e94..3be81ba3 100644
--- a/common/rfb/ZRLEEncoder.h
+++ b/common/rfb/ZRLEEncoder.h
@@ -40,11 +40,13 @@ namespace rfb {
const uint8_t* colour) override;
protected:
- void writePaletteTile(const Rect& tile, const PixelBuffer* pb,
+ void writePaletteTile(const core::Rect& tile,
+ const PixelBuffer* pb,
const Palette& palette);
- void writePaletteRLETile(const Rect& tile, const PixelBuffer* pb,
+ void writePaletteRLETile(const core::Rect& tile,
+ const PixelBuffer* pb,
const Palette& palette);
- void writeRawTile(const Rect& tile, const PixelBuffer* pb);
+ void writeRawTile(const core::Rect& tile, const PixelBuffer* pb);
void writePalette(const PixelFormat& pf, const Palette& palette);
diff --git a/common/rfb/pam.c b/common/rfb/pam.c
deleted file mode 100644
index f9e5ce74..00000000
--- a/common/rfb/pam.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2006 Martin Koegler
- * Copyright (C) 2010 TigerVNC Team
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <security/pam_appl.h>
-
-#include <rfb/pam.h>
-
-typedef struct
-{
- const char *username;
- const char *password;
-} AuthData;
-
-#if defined(__sun)
-static int pam_callback(int count, struct pam_message **in,
- struct pam_response **out, void *ptr)
-#else
-static int pam_callback(int count, const struct pam_message **in,
- struct pam_response **out, void *ptr)
-#endif
-{
- int i;
- AuthData *auth = (AuthData *) ptr;
- struct pam_response *resp =
- (struct pam_response *) malloc (sizeof (struct pam_response) * count);
-
- if (!resp && count)
- return PAM_CONV_ERR;
-
- for (i = 0; i < count; i++) {
- resp[i].resp_retcode = PAM_SUCCESS;
- switch (in[i]->msg_style) {
- case PAM_TEXT_INFO:
- case PAM_ERROR_MSG:
- resp[i].resp = 0;
- break;
- case PAM_PROMPT_ECHO_ON: /* Send Username */
- resp[i].resp = strdup(auth->username);
- break;
- case PAM_PROMPT_ECHO_OFF: /* Send Password */
- resp[i].resp = strdup(auth->password);
- break;
- default:
- free(resp);
- return PAM_CONV_ERR;
- }
- }
-
- *out = resp;
- return PAM_SUCCESS;
-}
-
-
-int do_pam_auth(const char *service, const char *username, const char *password)
-{
- int ret;
- AuthData auth = { username, password };
- struct pam_conv conv = {
- pam_callback,
- &auth
- };
- pam_handle_t *h = 0;
- ret = pam_start(service, username, &conv, &h);
- if (ret == PAM_SUCCESS)
- ret = pam_authenticate(h, 0);
- if (ret == PAM_SUCCESS)
- ret = pam_acct_mgmt(h, 0);
- pam_end(h, ret);
-
- return ret == PAM_SUCCESS ? 1 : 0;
-}
-
diff --git a/common/rfb/pam.h b/common/rfb/pam.h
deleted file mode 100644
index d378d19c..00000000
--- a/common/rfb/pam.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2006 Martin Koegler
- * Copyright (C) 2010 TigerVNC Team
- *
- * 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 __RFB_PAM_H__
-#define __RFB_PAM_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int do_pam_auth(const char *service, const char *username, const char *password);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/contrib/packages/deb/ubuntu-focal/debian/rules b/contrib/packages/deb/ubuntu-focal/debian/rules
index 0245a065..92150cd3 100644
--- a/contrib/packages/deb/ubuntu-focal/debian/rules
+++ b/contrib/packages/deb/ubuntu-focal/debian/rules
@@ -55,6 +55,12 @@ config-stamp: xorg-source-stamp
# Add here commands to configure the package.
cmake -G"Unix Makefiles" \
-DBUILD_STATIC=off \
+ -DENABLE_NLS=ON \
+ -DENABLE_H264=ON \
+ -DENABLE_GNUTLS=ON \
+ -DENABLE_NETTLE=ON \
+ -DENABLE_SYSTEMD=ON \
+ -DBUILD_VIEWER=ON \
-DCMAKE_INSTALL_PREFIX:PATH=/usr \
-DCMAKE_INSTALL_LIBEXECDIR:PATH=lib/$(DEB_HOST_MULTIARCH) \
-DCMAKE_INSTALL_UNITDIR:PATH=/lib/systemd/system
@@ -126,7 +132,7 @@ build-arch-stamp:
# Add here command to compile/build the package.
# Build first things.
# Build Xvnc
- make $(NUMJOBS) LDFLAGS="-lpng"
+ make $(NUMJOBS) LDFLAGS="-lpng" VERBOSE=1
make $(NUMJOBS) -C unix/xserver
touch build-arch-stamp
diff --git a/contrib/packages/deb/ubuntu-jammy/debian/rules b/contrib/packages/deb/ubuntu-jammy/debian/rules
index 1b4fd6f8..33e4523f 100644
--- a/contrib/packages/deb/ubuntu-jammy/debian/rules
+++ b/contrib/packages/deb/ubuntu-jammy/debian/rules
@@ -55,6 +55,12 @@ config-stamp: xorg-source-stamp
# Add here commands to configure the package.
cmake -G"Unix Makefiles" \
-DBUILD_STATIC=off \
+ -DENABLE_NLS=ON \
+ -DENABLE_H264=ON \
+ -DENABLE_GNUTLS=ON \
+ -DENABLE_NETTLE=ON \
+ -DENABLE_SYSTEMD=ON \
+ -DBUILD_VIEWER=ON \
-DCMAKE_INSTALL_PREFIX:PATH=/usr \
-DCMAKE_INSTALL_LIBEXECDIR:PATH=lib/$(DEB_HOST_MULTIARCH) \
-DCMAKE_INSTALL_UNITDIR:PATH=/lib/systemd/system
@@ -126,7 +132,7 @@ build-arch-stamp:
# Add here command to compile/build the package.
# Build first things.
# Build Xvnc
- make $(NUMJOBS) LDFLAGS="-lpng"
+ make $(NUMJOBS) LDFLAGS="-lpng" VERBOSE=1
make $(NUMJOBS) -C unix/xserver
touch build-arch-stamp
diff --git a/contrib/packages/deb/ubuntu-noble/debian/rules b/contrib/packages/deb/ubuntu-noble/debian/rules
index 1b4fd6f8..33e4523f 100644
--- a/contrib/packages/deb/ubuntu-noble/debian/rules
+++ b/contrib/packages/deb/ubuntu-noble/debian/rules
@@ -55,6 +55,12 @@ config-stamp: xorg-source-stamp
# Add here commands to configure the package.
cmake -G"Unix Makefiles" \
-DBUILD_STATIC=off \
+ -DENABLE_NLS=ON \
+ -DENABLE_H264=ON \
+ -DENABLE_GNUTLS=ON \
+ -DENABLE_NETTLE=ON \
+ -DENABLE_SYSTEMD=ON \
+ -DBUILD_VIEWER=ON \
-DCMAKE_INSTALL_PREFIX:PATH=/usr \
-DCMAKE_INSTALL_LIBEXECDIR:PATH=lib/$(DEB_HOST_MULTIARCH) \
-DCMAKE_INSTALL_UNITDIR:PATH=/lib/systemd/system
@@ -126,7 +132,7 @@ build-arch-stamp:
# Add here command to compile/build the package.
# Build first things.
# Build Xvnc
- make $(NUMJOBS) LDFLAGS="-lpng"
+ make $(NUMJOBS) LDFLAGS="-lpng" VERBOSE=1
make $(NUMJOBS) -C unix/xserver
touch build-arch-stamp
diff --git a/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf b/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf
deleted file mode 100644
index 9a69fc7d..00000000
--- a/contrib/packages/rpm/el7/SOURCES/10-libvnc.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file contains configuration of libvnc.so module
-#
-# To get libvnc.so module working, do this:
-# 1. run "vncpasswd" from tigervnc-server package as root user
-# 2. uncomment configuration lines below
-#
-# Please note you can specify any option which Xvnc accepts.
-# Refer to `Xvnc -help` output for detailed list of options.
-
-#Section "Module"
-# Load "vnc"
-#EndSection
-
-#Section "Screen"
-# Identifier "Screen0
-# DefaultDepth 16
-# Option "SecurityTypes" "VncAuth"
-# Option "PasswordFile" "/root/.config/tigervnc/passwd"
-#EndSection
diff --git a/contrib/packages/rpm/el7/SPECS/tigervnc.spec b/contrib/packages/rpm/el7/SPECS/tigervnc.spec
deleted file mode 100644
index ee3baed8..00000000
--- a/contrib/packages/rpm/el7/SPECS/tigervnc.spec
+++ /dev/null
@@ -1,729 +0,0 @@
-#defining macros needed by SELinux
-%global selinuxtype targeted
-%global modulename vncsession
-
-Name: tigervnc
-Version: @VERSION@
-Release: 1%{?snap:.%{snap}}%{?dist}
-Summary: A TigerVNC remote display system
-
-%global _hardened_build 1
-
-License: GPLv2+
-URL: http://www.tigervnc.com
-
-Source0: %{name}-%{version}%{?snap:-%{snap}}.tar.bz2
-Source3: 10-libvnc.conf
-
-BuildRequires: make
-BuildRequires: gcc-c++
-BuildRequires: automake, autoconf, libtool, gettext, gettext-autopoint
-BuildRequires: cmake3, desktop-file-utils
-BuildRequires: libxkbfile-devel, openssl-devel, libpciaccess-devel
-BuildRequires: freetype-devel, libjpeg-turbo-devel, gnutls-devel, pam-devel
-BuildRequires: zlib-devel
-# X11/graphics dependencies
-BuildRequires: xorg-x11-server-source
-BuildRequires: libXext-devel, libX11-devel, libXi-devel, libXfixes-devel
-BuildRequires: libXdamage-devel, libXrandr-devel, libXt-devel, libXdmcp-devel
-BuildRequires: libXinerama-devel, mesa-libGL-devel, libxshmfence-devel
-BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel
-BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel
-BuildRequires: xorg-x11-font-utils
-BuildRequires: libXfont2-devel
-# SELinux
-BuildRequires: libselinux-devel, selinux-policy-devel, systemd
-
-# TigerVNC 1.4.x requires fltk 1.3.3 for keyboard handling support
-# See https://github.com/TigerVNC/tigervnc/issues/8, also bug #1208814
-BuildRequires: fltk-devel >= 1.3.3
-BuildRequires: xorg-x11-server-devel
-
-Requires(post): coreutils
-Requires(postun): coreutils
-
-Requires: hicolor-icon-theme
-Requires: tigervnc-license
-Requires: tigervnc-icons
-
-%description
-Virtual Network Computing (VNC) is a remote display system which
-allows you to view a computing 'desktop' environment not only on the
-machine where it is running, but from anywhere on the Internet and
-from a wide variety of machine architectures. This package contains a
-client which will allow you to connect to other desktops running a VNC
-server.
-
-%package server
-Summary: A TigerVNC server
-Requires: perl-interpreter
-Requires: tigervnc-server-minimal = %{version}-%{release}
-Requires: tigervnc-selinux = %{version}-%{release}
-Requires: xorg-x11-xauth
-Requires: xorg-x11-xinit
-
-%description server
-The VNC system allows you to access the same desktop from a wide
-variety of platforms. This package includes set of utilities
-which make usage of TigerVNC server more user friendly. It also
-contains x0vncserver program which can export your active
-X session.
-
-%package server-minimal
-Summary: A minimal installation of TigerVNC server
-Requires(post): systemd
-Requires(preun): systemd
-Requires(postun): systemd
-Requires(post): systemd
-
-Requires: mesa-dri-drivers, xkeyboard-config, xkbcomp
-Requires: tigervnc-license, dbus-x11
-
-%description server-minimal
-The VNC system allows you to access the same desktop from a wide
-variety of platforms. This package contains minimal installation
-of TigerVNC server, allowing others to access the desktop on your
-machine.
-
-%package server-module
-Summary: TigerVNC module to Xorg
-Requires: xorg-x11-server-Xorg %(xserver-sdk-abi-requires ansic) %(xserver-sdk-abi-requires videodrv)
-Requires: tigervnc-license
-
-%description server-module
-This package contains libvnc.so module to X server, allowing others
-to access the desktop on your machine.
-
-%package license
-Summary: License of TigerVNC suite
-BuildArch: noarch
-
-%description license
-This package contains license of the TigerVNC suite
-
-%package icons
-Summary: Icons for TigerVNC viewer
-BuildArch: noarch
-
-%description icons
-This package contains icons for TigerVNC viewer
-
-%package selinux
-Summary: SELinux module for TigerVNC
-BuildArch: noarch
-BuildRequires: selinux-policy-devel
-Requires: selinux-policy-%{selinuxtype}
-Requires(post): selinux-policy-%{selinuxtype}
-BuildRequires: selinux-policy-devel
-%{?selinux_requires}
-
-%description selinux
-This package provides the SELinux policy module to ensure TigerVNC
-runs properly under an environment with SELinux enabled.
-
-%prep
-%setup -q -n %{name}-%{version}%{?snap:-%{snap}}
-
-# There is no appstream package on CentOS 7, and hence no metainfo.its
-# that msgfmt needs to generate the metainfo XML file
-sed -i 's@add_custom_target(appstream@#\0@' vncviewer/CMakeLists.txt
-sed -i 's@install(.*metainfo.xml@#\0@' vncviewer/CMakeLists.txt
-
-cp -r /usr/share/xorg-x11-server-source/* unix/xserver
-pushd unix/xserver
-for all in `find . -type f -perm -001`; do
- chmod -x "$all"
-done
-xserver_patch="../xserver$(rpm -q --qf '%%{VERSION}' xorg-x11-server-source | awk -F. '{ print $1 $2 }').patch"
-patch -p1 -b --suffix .vnc < "$xserver_patch"
-popd
-
-%build
-%ifarch sparcv9 sparc64 s390 s390x
-export CFLAGS="$RPM_OPT_FLAGS -fPIC"
-%else
-export CFLAGS="$RPM_OPT_FLAGS -fpic"
-%endif
-export CXXFLAGS="$CFLAGS -std=c++11"
-
-%cmake3
-
-%cmake3_build
-
-pushd unix/xserver
-
-autoreconf -fiv
-%configure \
- --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \
- --disable-xwin --disable-xephyr --disable-kdrive --disable-xwayland \
- --with-pic --disable-static \
- --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \
- --with-xkb-output=%{_localstatedir}/lib/xkb \
- --enable-glx --disable-dri --enable-dri2 --enable-dri3 \
- --disable-unit-tests \
- --disable-config-hal \
- --disable-config-udev \
- --without-dtrace \
- --disable-devel-docs \
- --disable-selective-werror
-
-make %{?_smp_mflags}
-popd
-
-# SELinux
-pushd unix/vncserver/selinux
-make
-popd
-
-%install
-%cmake3_install
-
-pushd unix/xserver/hw/vnc
-%make_install
-popd
-
-# Install systemd unit file
-pushd unix/vncserver/selinux
-make install DESTDIR=%{buildroot}
-popd
-
-%find_lang %{name} %{name}.lang
-
-# remove unwanted files
-rm -f %{buildroot}%{_libdir}/xorg/modules/extensions/libvnc.la
-
-mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/
-install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf
-
-%post
-touch -c %{_datadir}/icons/hicolor
-if [ -x %{_bindir}/gtk-update-icon-cache ]; then
- %{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || :
-fi
-
-%postun
-touch -c %{_datadir}/icons/hicolor
-if [ -x %{_bindir}/gtk-update-icon-cache ]; then
- %{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || :
-fi
-
-
-%pre selinux
-%selinux_relabel_pre -s %{selinuxtype}
-
-%post selinux
-%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2
-%selinux_relabel_post -s %{selinuxtype}
-
-%postun selinux
-if [ $1 -eq 0 ]; then
- %selinux_modules_uninstall -s %{selinuxtype} %{modulename}
- %selinux_relabel_post -s %{selinuxtype}
-fi
-
-
-%files -f %{name}.lang
-%doc %{_docdir}/%{name}/README.rst
-%{_bindir}/vncviewer
-%{_datadir}/applications/*
-%{_mandir}/man1/vncviewer.1*
-
-%files server
-%config(noreplace) %{_sysconfdir}/pam.d/tigervnc
-%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-defaults
-%config(noreplace) %{_sysconfdir}/tigervnc/vncserver-config-mandatory
-%config(noreplace) %{_sysconfdir}/tigervnc/vncserver.users
-%{_unitdir}/vncserver@.service
-%{_bindir}/x0vncserver
-%{_sbindir}/vncsession
-%{_libexecdir}/vncserver
-%{_libexecdir}/vncsession-start
-%{_mandir}/man1/x0vncserver.1*
-%{_mandir}/man8/vncserver.8*
-%{_mandir}/man8/vncsession.8*
-%doc %{_docdir}/%{name}/HOWTO.md
-
-%files server-minimal
-%{_bindir}/vncconfig
-%{_bindir}/vncpasswd
-%{_bindir}/Xvnc
-%{_mandir}/man1/Xvnc.1*
-%{_mandir}/man1/vncpasswd.1*
-%{_mandir}/man1/vncconfig.1*
-
-%files server-module
-%{_libdir}/xorg/modules/extensions/libvnc.so
-%config(noreplace) %{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf
-
-%files license
-%doc %{_docdir}/%{name}/LICENCE.TXT
-
-%files icons
-%{_datadir}/icons/hicolor/*/apps/*
-
-%files selinux
-%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.*
-%ghost %verify(not md5 size mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename}
-
-%changelog
-* Fri Aug 19 2022 Pierre Ossman <ossman@cendio.se> 1.12.80-1
-- Synced with current Fedora packaging
-
-* Tue May 18 2021 Jan Grulich <jgrulich@redhat.com> 1.11.0-1
-- SELinux package improvements
-
-* Mon Jul 27 2020 Mark Mielke <mmielke@ciena.com> 1.10.1-1
-- Update build requirements and fix unexpected rpm macro expansion.
-
-* Mon Feb 11 2019 Mark Mielke <mmielke@ciena.com> 1.9.80-5
-- Automatically detect and apply the correct X.org patch.
-
-* Mon Jan 14 2019 Pierre Ossman <ossman@cendio.se> 1.9.80-4
-- Use system FLTK for build
-- Add libXrandr-devel as a dependency so x0vncserver gets resize support.
-
-* Sun Dec 09 2018 Mark Mielke <mmielke@ciena.com> 1.9.80-3
-- Update package dependencies to require version alignment between packages.
-
-* Mon Nov 26 2018 Brian P. Hinz <bphinz@users.sourceforge.net> 1.9.80-2
-- Bumped Xorg version to 1.20
-
-* Sun Jul 22 2018 Brian P. Hinz <bphinz@users.sourceforge.net> 1.9.80-1
-- Updated fltk to latest version
-
-* Thu Dec 24 2015 Brian P. Hinz <bphinz@users.sourceforge.net> 1.6.80-1
-- Adapted from RedHat EL7 Spec
-
-* Wed Sep 02 2015 Jan Grulich <jgrulich@redhat.com> - 1.3.1-3
-- Do not mention that display number is required in the file name
- Resolves: bz#1195266
-
-* Thu Jul 30 2015 Jan Grulich <jgrulich@redhat.com> - 1.3.1-2
-- Resolves: bz#1248422
- CVE-2014-8240 CVE-2014-8241 tigervnc: various flaws
-
-* Wed Apr 15 2015 Jan Grulich <jgrulich@redhat.com> - 1.3.1-1
-- Drop unecessary patches
-- Re-base to 1.3.1 (bug #1199453)
-- Re-build against re-based xserver (bug #1194898)
-- Check the return value from XShmAttach (bug #1072733)
-- Add missing part of xserver114.patch (bug #1140603)
-- Keep pointer in sync (bug #1100661)
-- Make input device class global (bug #1119640)
-- Add IPv6 support (bug #1162722)
-- Set initial mode as prefered (bug #1181287)
-- Do not mention that display number is required in the file name (bug #1195266)
-- Enable Xinerama extension (bug #1199437)
-- Specify full path for runuser command (bug #1208817)
-
-* Tue Sep 23 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.31.20130314svn5065
-- Rebuilt against xorg-x11-server to pick up ppc64le fix (bug #1140424).
-
-* Mon Mar 10 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.30.20130314svn5065
-- Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928).
-
-* Tue Feb 18 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.29.20130314svn5065
-- Previous patch was not applied.
-
-* Mon Feb 10 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.28.20130314svn5065
-- Clearer xstartup file (bug #923655).
-
-* Tue Jan 28 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.27.20130314svn5065
-- Use keyboard input code from tigervnc-1.3.0 (bug #1053536).
-
-* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 1.2.80-0.26.20130314svn5065
-- Mass rebuild 2014-01-24
-
-* Fri Jan 10 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.25.20130314svn5065
-- Fixed viewer crash when cursor has not been set (bug #1051333).
-
-* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 1.2.80-0.24.20130314svn5065
-- Mass rebuild 2013-12-27
-
-* Thu Dec 12 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.23.20130314svn5065
-- Avoid invalid read when ZRLE connection closed (bug #1039926).
-
-* Tue Dec 10 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.22.20130314svn5065
-- Fixed GLX initialisation (bug #1039126).
-
-* Tue Nov 19 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.21.20130314svn5065
-- Better fix for PIDFile problem (bug #1031625).
-
-* Fri Nov 08 2013 Adam Jackson <ajax@redhat.com> 1.2.80-0.20.20130314svn5065
-- Rebuild against xserver 1.15RC1
-
-* Wed Jul 24 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.18.20130314svn5065
-- Avoid PIDFile problems in systemd unit file (bug #983232).
-- Don't use shebang in vncserver script.
-
-* Wed Jul 3 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.18.20130314svn5065
-- Removed systemd_requires macro in order to fix the build.
-
-* Wed Jul 3 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.17.20130314svn5065
-- Synchronise manpages and --help output (bug #980870).
-
-* Mon Jun 17 2013 Adam Jackson <ajax@redhat.com> 1.2.80-0.16.20130314svn5065
-- tigervnc-setcursor-crash.patch: Attempt to paper over a crash in Xvnc when
- setting the cursor.
-
-* Sat Jun 08 2013 Dennis Gilmore <dennis@ausil.us> 1.2.80-0.15.20130314svn5065
-- bump to rebuild and pick up bugfix causing X to crash on ppc and arm
-
-* Thu May 23 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.14.20130314svn5065
-- Use systemd rpm macros (bug #850340). Moved systemd requirements
- from main package to server sub-package.
-- Applied Debian patch to fix busy loop when run from inetd in nowait
- mode (bug #920373).
-- Added dependency on xorg-x11-xinit to server sub-package so that
- default window manager can be found (bug #896284, bug #923655).
-- Fixed bogus changelog date.
-
-* Thu Mar 14 2013 Adam Jackson <ajax@redhat.com> 1.2.80-0.13.20130314svn5065
-- Less RHEL customization
-
-* Thu Mar 14 2013 Adam Tkac <atkac redhat com> - 1.2.80-0.12.20130314svn5065
-- include /etc/X11/xorg.conf.d/10-libvnc.conf sample configuration (#712482)
-- vncserver now honors specified -geometry parameter (#755947)
-
-* Tue Mar 12 2013 Adam Tkac <atkac redhat com> - 1.2.80-0.11.20130307svn5060
-- update to r5060
-- split icons to separate package to avoid multilib issues
-
-* Tue Feb 19 2013 Adam Tkac <atkac redhat com> - 1.2.80-0.10.20130219svn5047
-- update to r5047 (X.Org 1.14 support)
-
-* Fri Feb 15 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.80-0.9.20121126svn5015
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
-
-* Mon Jan 21 2013 Adam Tkac <atkac redhat com> - 1.2.80-0.8.20121126svn5015
-- rebuild due to "jpeg8-ABI" feature drop
-
-* Wed Jan 16 2013 Adam Tkac <atkac redhat com> 1.2.80-0.7.20121126svn5015
-- rebuild
-
-* Tue Dec 04 2012 Adam Tkac <atkac redhat com> 1.2.80-0.6.20121126svn5015
-- rebuild against new fltk
-
-* Mon Nov 26 2012 Adam Tkac <atkac redhat com> 1.2.80-0.5.20121126svn5015
-- update to r5015
-- build with -fpic instead of -fPIC on all archs except s390/sparc
-
-* Wed Nov 7 2012 Peter Robinson <pbrobinson@fedoraproject.org> 1.2.80-0.4.20120905svn4996
-- Build with -fPIC to fix FTBFS on ARM
-
-* Wed Oct 31 2012 Adam Jackson <ajax@redhat.com> 1.2.80-0.3.20120905svn4996
-- tigervnc12-xorg113-glx.patch: Fix to only init glx on the first server
- generation
-
-* Fri Sep 28 2012 Adam Jackson <ajax@redhat.com> 1.2.80-0.2.20120905svn4996
-- tigervnc12-xorg113-glx.patch: Re-enable GLX against xserver 1.13
-
-* Fri Aug 17 2012 Adam Tkac <atkac redhat com> 1.2.80-0.1.20120905svn4996
-- update to 1.2.80
-- remove deprecated patches
- - tigervnc-102434.patch
- - tigervnc-viewer-reparent.patch
- - tigervnc11-java7.patch
-- patches merged
- - tigervnc11-xorg111.patch
- - tigervnc11-xorg112.patch
-
-* Fri Aug 10 2012 Dave Airlie <airlied@redhat.com> 1.1.0-10
-- fix build against newer X server
-
-* Mon Jul 23 2012 Adam Jackson <ajax@redhat.com> 1.1.0-9
-- Build with the Composite extension for feature parity with other X servers
-
-* Sat Jul 21 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.0-8
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
-
-* Thu Jul 19 2012 Dave Airlie <airlied@redhat.com> 1.1.0-7
-- fix building against X.org 1.13
-
-* Wed Apr 04 2012 Adam Jackson <ajax@redhat.com> 1.1.0-6
-- RHEL exclusion for -server-module on ppc* too
-
-* Mon Mar 26 2012 Adam Tkac <atkac redhat com> - 1.1.0-5
-- clean Xvnc's /tmp environment in service file before startup
-- fix building against the latest JAVA 7 and X.Org 1.12
-
-* Sat Jan 14 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.0-4
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
-
-* Tue Nov 22 2011 Adam Tkac <atkac redhat com> - 1.1.0-3
-- don't build X.Org devel docs (#755782)
-- applet: BR generic java-devel instead of java-gcj-devel (#755783)
-- use runuser to start Xvnc in systemd service file (#754259)
-- don't attepmt to restart Xvnc session during update/erase (#753216)
-
-* Fri Nov 11 2011 Adam Tkac <atkac redhat com> - 1.1.0-2
-- libvnc.so: don't use unexported GetMaster function (#744881)
-- remove nasm buildreq
-
-* Mon Sep 12 2011 Adam Tkac <atkac redhat com> - 1.1.0-1
-- update to 1.1.0
-- update the xorg11 patch
-- patches merged
- - tigervnc11-glx.patch
- - tigervnc11-CVE-2011-1775.patch
- - 0001-Use-memmove-instead-of-memcpy-in-fbblt.c-when-memory.patch
-
-* Thu Jul 28 2011 Adam Tkac <atkac redhat com> - 1.0.90-6
-- add systemd service file and remove legacy SysV initscript (#717227)
-
-* Thu May 12 2011 Adam Tkac <atkac redhat com> - 1.0.90-5
-- make Xvnc buildable against X.Org 1.11
-
-* Tue May 10 2011 Adam Tkac <atkac redhat com> - 1.0.90-4
-- viewer can send password without proper validation of X.509 certs
- (CVE-2011-1775)
-
-* Wed Apr 13 2011 Adam Tkac <atkac redhat com> - 1.0.90-3
-- fix wrong usage of memcpy which caused screen artifacts (#652590)
-- don't point to inaccessible link in sysconfig/vncservers (#644975)
-
-* Fri Apr 08 2011 Adam Tkac <atkac redhat com> - 1.0.90-2
-- improve compatibility with vinagre client (#692048)
-
-* Tue Mar 22 2011 Adam Tkac <atkac redhat com> - 1.0.90-1
-- update to 1.0.90
-
-* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.0.90-0.32.20110117svn4237
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
-
-* Mon Jan 17 2011 Adam Tkac <atkac redhat com> 1.0.90-0.31.20110117svn4237
-- fix libvnc.so module loading
-
-* Mon Jan 17 2011 Adam Tkac <atkac redhat com> 1.0.90-0.30.20110117svn4237
-- update to r4237
-- patches merged
- - tigervnc11-optionsdialog.patch
- - tigervnc11-rh607866.patch
-
-* Fri Jan 14 2011 Adam Tkac <atkac redhat com> 1.0.90-0.29.20101208svn4225
-- improve patch for keyboard issues
-
-* Fri Jan 14 2011 Adam Tkac <atkac redhat com> 1.0.90-0.28.20101208svn4225
-- attempt to fix various keyboard-related issues (key repeating etc)
-
-* Fri Jan 07 2011 Adam Tkac <atkac redhat com> 1.0.90-0.27.20101208svn4225
-- render "Ok" and "Cancel" buttons in the options dialog correctly
-
-* Wed Dec 15 2010 Jan Görig <jgorig redhat com> 1.0.90-0.26.20101208svn4225
-- added vncserver lock file (#662784)
-
-* Fri Dec 10 2010 Adam Tkac <atkac redhat com> 1.0.90-0.25.20101208svn4225
-- update to r4225
-- patches merged
- - tigervnc11-rh611677.patch
- - tigervnc11-rh633931.patch
- - tigervnc11-xorg1.10.patch
-- enable VeNCrypt and PAM support
-
-* Mon Dec 06 2010 Adam Tkac <atkac redhat com> 1.0.90-0.24.20100813svn4123
-- rebuild against xserver 1.10.X
-- 0001-Return-Success-from-generate_modkeymap-when-max_keys.patch merged
-
-* Wed Sep 29 2010 jkeating - 1.0.90-0.23.20100813svn4123
-- Rebuilt for gcc bug 634757
-
-* Tue Sep 21 2010 Adam Tkac <atkac redhat com> 1.0.90-0.22.20100420svn4030
-- drop xorg-x11-fonts-misc dependency (#636170)
-
-* Tue Sep 21 2010 Adam Tkac <atkac redhat com> 1.0.90-0.21.20100420svn4030
-- improve patch for #633645 (fix tcsh incompatibilities)
-
-* Thu Sep 16 2010 Adam Tkac <atkac redhat com> 1.0.90-0.20.20100813svn4123
-- press fake modifiers correctly (#633931)
-- supress unneeded debug information emitted from initscript (#633645)
-
-* Wed Aug 25 2010 Adam Tkac <atkac redhat com> 1.0.90-0.19.20100813svn4123
-- separate Xvnc, vncpasswd and vncconfig to -server-minimal subpkg (#626946)
-- move license to separate subpkg and Requires it from main subpkgs
-- Xvnc: handle situations when no modifiers exist well (#611677)
-
-* Fri Aug 13 2010 Adam Tkac <atkac redhat com> 1.0.90-0.18.20100813svn4123
-- update to r4123 (#617973)
-- add perl requires to -server subpkg (#619791)
-
-* Thu Jul 22 2010 Adam Tkac <atkac redhat com> 1.0.90-0.17.20100721svn4113
-- update to r4113
-- patches merged
- - tigervnc11-rh586406.patch
- - tigervnc11-libvnc.patch
- - tigervnc11-rh597172.patch
- - tigervnc11-rh600070.patch
- - tigervnc11-options.patch
-- don't own %%{_datadir}/icons directory (#614301)
-- minor improvements in the .desktop file (#616340)
-- bundled libjpeg configure requires nasm; is executed even if system-wide
- libjpeg is used
-
-* Fri Jul 02 2010 Adam Tkac <atkac redhat com> 1.0.90-0.16.20100420svn4030
-- build against system-wide libjpeg-turbo (#494458)
-- build no longer requires nasm
-
-* Mon Jun 28 2010 Adam Tkac <atkac redhat com> 1.0.90-0.15.20100420svn4030
-- vncserver: accept <+optname> option when specified as the first one
-
-* Thu Jun 24 2010 Adam Tkac <atkac redhat com> 1.0.90-0.14.20100420svn4030
-- fix memory leak in Xvnc input code (#597172)
-- don't crash when receive negative encoding (#600070)
-- explicitly disable udev configuration support
-- add gettext-autopoint to BR
-
-* Mon Jun 14 2010 Adam Tkac <atkac redhat com> 1.0.90-0.13.20100420svn4030
-- update URL about SSH tunneling in the sysconfig file (#601996)
-
-* Fri Jun 11 2010 Adam Tkac <atkac redhat com> 1.0.90-0.12.20100420svn4030
-- use newer gettext
-- autopoint now uses git instead of cvs, adjust BuildRequires appropriately
-
-* Thu May 13 2010 Adam Tkac <atkac redhat com> 1.0.90-0.11.20100420svn4030
-- link libvnc.so "now" to catch "undefined symbol" errors during Xorg startup
-- use always XkbConvertCase instead of XConvertCase (#580159, #586406)
-- don't link libvnc.so against libXi.la, libdix.la and libxkb.la; use symbols
- from Xorg instead
-
-* Thu May 13 2010 Adam Tkac <atkac redhat com> 1.0.90-0.10.20100420svn4030
-- update to r4030 snapshot
-- patches merged to upstream
- - tigervnc11-rh522369.patch
- - tigervnc11-rh551262.patch
- - tigervnc11-r4002.patch
- - tigervnc11-r4014.patch
-
-* Thu Apr 08 2010 Adam Tkac <atkac redhat com> 1.0.90-0.9.20100219svn3993
-- add server-applet subpackage which contains Java vncviewer applet
-- fix Java applet; it didn't work when run from web browser
-- add xorg-x11-xkb-utils to server Requires
-
-* Fri Mar 12 2010 Adam Tkac <atkac redhat com> 1.0.90-0.8.20100219svn3993
-- add French translation to vncviewer.desktop (thanks to Alain Portal)
-
-* Thu Mar 04 2010 Adam Tkac <atkac redhat com> 1.0.90-0.7.20100219svn3993
-- don't crash during pixel format change (#522369, #551262)
-
-* Mon Mar 01 2010 Adam Tkac <atkac redhat com> 1.0.90-0.6.20100219svn3993
-- add mesa-dri-drivers and xkeyboard-config to -server Requires
-- update to r3993 1.0.90 snapshot
- - tigervnc11-noexecstack.patch merged
- - tigervnc11-xorg18.patch merged
- - xserver18.patch is no longer needed
-
-* Wed Jan 27 2010 Jan Gorig <jgorig redhat com> 1.0.90-0.5.20091221svn3929
-- initscript LSB compliance fixes (#523974)
-
-* Fri Jan 22 2010 Adam Tkac <atkac redhat com> 1.0.90-0.4.20091221svn3929
-- mark stack as non-executable in jpeg ASM code
-- add xorg-x11-xauth to Requires
-- add support for X.Org 1.8
-- drop shave sources, they are no longer needed
-
-* Thu Jan 21 2010 Adam Tkac <atkac redhat com> 1.0.90-0.3.20091221svn3929
-- drop tigervnc-xorg25909.patch, it has been merged to X.Org upstream
-
-* Thu Jan 07 2010 Adam Tkac <atkac redhat com> 1.0.90-0.2.20091221svn3929
-- add patch for upstream X.Org issue #25909
-- add libXdmcp-devel to build requires to build Xvnc with XDMCP support (#552322)
-
-* Mon Dec 21 2009 Adam Tkac <atkac redhat com> 1.0.90-0.1.20091221svn3929
-- update to 1.0.90 snapshot
-- patches merged
- - tigervnc10-compat.patch
- - tigervnc10-rh510185.patch
- - tigervnc10-rh524340.patch
- - tigervnc10-rh516274.patch
-
-* Mon Oct 26 2009 Adam Tkac <atkac redhat com> 1.0.0-3
-- create Xvnc keyboard mapping before first keypress (#516274)
-
-* Thu Oct 08 2009 Adam Tkac <atkac redhat com> 1.0.0-2
-- update underlying X source to 1.6.4-0.3.fc11
-- remove bogus '-nohttpd' parameter from /etc/sysconfig/vncservers (#525629)
-- initscript LSB compliance fixes (#523974)
-- improve -LowColorSwitch documentation and handling (#510185)
-- honor dotWhenNoCursor option (and it's changes) every time (#524340)
-
-* Fri Aug 28 2009 Adam Tkac <atkac redhat com> 1.0.0-1
-- update to 1.0.0
-- tigervnc10-rh495457.patch merged to upstream
-
-* Mon Aug 24 2009 Karsten Hopp <karsten@redhat.com> 0.0.91-0.17
-- fix ifnarch s390x for server-module
-
-* Fri Aug 21 2009 Tomas Mraz <tmraz@redhat.com> - 0.0.91-0.16
-- rebuilt with new openssl
-
-* Tue Aug 04 2009 Adam Tkac <atkac redhat com> 0.0.91-0.15
-- make Xvnc compilable
-
-* Sun Jul 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.0.91-0.14.1
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
-
-* Mon Jul 13 2009 Adam Tkac <atkac redhat com> 0.0.91-0.13.1
-- don't write warning when initscript is called with condrestart param (#508367)
-
-* Tue Jun 23 2009 Adam Tkac <atkac redhat com> 0.0.91-0.13
-- temporary use F11 Xserver base to make Xvnc compilable
-- BuildRequires: libXi-devel
-- don't ship tigervnc-server-module on s390/s390x
-
-* Mon Jun 22 2009 Adam Tkac <atkac redhat com> 0.0.91-0.12
-- fix local rendering of cursor (#495457)
-
-* Thu Jun 18 2009 Adam Tkac <atkac redhat com> 0.0.91-0.11
-- update to 0.0.91 (1.0.0 RC1)
-- patches merged
- - tigervnc10-rh499401.patch
- - tigervnc10-rh497592.patch
- - tigervnc10-rh501832.patch
-- after discusion in upstream drop tigervnc-bounds.patch
-- configure flags cleanup
-
-* Thu May 21 2009 Adam Tkac <atkac redhat com> 0.0.90-0.10
-- rebuild against 1.6.1.901 X server (#497835)
-- disable i18n, vncviewer is not UTF-8 compatible (#501832)
-
-* Mon May 18 2009 Adam Tkac <atkac redhat com> 0.0.90-0.9
-- fix vncpasswd crash on long passwords (#499401)
-- start session dbus daemon correctly (#497592)
-
-* Mon May 11 2009 Adam Tkac <atkac redhat com> 0.0.90-0.8.1
-- remove merged tigervnc-manminor.patch
-
-* Tue May 05 2009 Adam Tkac <atkac redhat com> 0.0.90-0.8
-- update to 0.0.90
-
-* Thu Apr 30 2009 Adam Tkac <atkac redhat com> 0.0.90-0.7.20090427svn3789
-- server package now requires xorg-x11-fonts-misc (#498184)
-
-* Mon Apr 27 2009 Adam Tkac <atkac redhat com> 0.0.90-0.6.20090427svn3789
-- update to r3789
- - tigervnc-rh494801.patch merged
-- tigervnc-newfbsize.patch is no longer needed
-- fix problems when vncviewer and Xvnc run on different endianess (#496653)
-- UltraVNC and TightVNC clients work fine again (#496786)
-
-* Wed Apr 08 2009 Adam Tkac <atkac redhat com> 0.0.90-0.5.20090403svn3751
-- workaround broken fontpath handling in vncserver script (#494801)
-
-* Fri Apr 03 2009 Adam Tkac <atkac redhat com> 0.0.90-0.4.20090403svn3751
-- update to r3751
-- patches merged
- - tigervnc-xclients.patch
- - tigervnc-clipboard.patch
- - tigervnc-rh212985.patch
-- basic RandR support in Xvnc (resize of the desktop)
-- use built-in libjpeg (SSE2/MMX accelerated encoding on x86 platform)
-- use Tight encoding by default
-- use TigerVNC icons
-
-* Tue Mar 03 2009 Adam Tkac <atkac redhat com> 0.0.90-0.3.20090303svn3631
-- update to r3631
-
-* Tue Mar 03 2009 Adam Tkac <atkac redhat com> 0.0.90-0.2.20090302svn3621
-- package review related fixes
-
-* Mon Mar 02 2009 Adam Tkac <atkac redhat com> 0.0.90-0.1.20090302svn3621
-- initial package, r3621
diff --git a/contrib/packages/rpm/el8/SPECS/tigervnc.spec b/contrib/packages/rpm/el8/SPECS/tigervnc.spec
index 307e26f6..9fe7563e 100644
--- a/contrib/packages/rpm/el8/SPECS/tigervnc.spec
+++ b/contrib/packages/rpm/el8/SPECS/tigervnc.spec
@@ -33,7 +33,8 @@ BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel
BuildRequires: xorg-x11-font-utils
BuildRequires: libXfont2-devel
# SELinux
-BuildRequires: libselinux-devel, selinux-policy-devel, systemd
+BuildRequires: libselinux-devel, selinux-policy-devel
+BuildRequires: systemd-devel
# TigerVNC 1.4.x requires fltk 1.3.3 for keyboard handling support
# See https://github.com/TigerVNC/tigervnc/issues/8, also bug #1208814
@@ -139,7 +140,13 @@ export CFLAGS="$RPM_OPT_FLAGS -fpic"
%endif
export CXXFLAGS="$CFLAGS -std=c++11"
-%cmake
+%cmake \
+ -DENABLE_NLS=ON \
+ -DENABLE_GNUTLS=ON \
+ -DENABLE_NETTLE=ON \
+ -DENABLE_SELINUX=ON \
+ -DENABLE_SYSTEMD=ON \
+ -DBUILD_VIEWER=ON
%cmake_build
diff --git a/contrib/packages/rpm/el9/SPECS/tigervnc.spec b/contrib/packages/rpm/el9/SPECS/tigervnc.spec
index 5d120bc0..bfab2bf1 100644
--- a/contrib/packages/rpm/el9/SPECS/tigervnc.spec
+++ b/contrib/packages/rpm/el9/SPECS/tigervnc.spec
@@ -32,7 +32,8 @@ BuildRequires: pixman-devel, libdrm-devel, mesa-libgbm-devel
BuildRequires: xorg-x11-util-macros, xorg-x11-xtrans-devel, libXtst-devel
BuildRequires: libXfont2-devel
# SELinux
-BuildRequires: libselinux-devel, selinux-policy-devel, systemd
+BuildRequires: libselinux-devel, selinux-policy-devel
+BuildRequires: systemd-devel
# TigerVNC 1.4.x requires fltk 1.3.3 for keyboard handling support
# See https://github.com/TigerVNC/tigervnc/issues/8, also bug #1208814
@@ -138,7 +139,13 @@ export CFLAGS="$RPM_OPT_FLAGS -fpic"
%endif
export CXXFLAGS="$CFLAGS -std=c++11"
-%cmake
+%cmake \
+ -DENABLE_NLS=ON \
+ -DENABLE_GNUTLS=ON \
+ -DENABLE_NETTLE=ON \
+ -DENABLE_SELINUX=ON \
+ -DENABLE_SYSTEMD=ON \
+ -DBUILD_VIEWER=ON
%cmake_build
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index e833bd38..cf960a92 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10.0)
project(tigervnc-java Java)
if(NOT VERSION)
- set(VERSION 1.14.80)
+ set(VERSION 1.15.80)
endif()
find_package(Java)
diff --git a/java/com/tigervnc/vncviewer/MANIFEST.MF b/java/com/tigervnc/vncviewer/MANIFEST.MF
index 9e282655..5f67f81c 100644
--- a/java/com/tigervnc/vncviewer/MANIFEST.MF
+++ b/java/com/tigervnc/vncviewer/MANIFEST.MF
@@ -1,5 +1,5 @@
Manifest-Version: 1.0
Main-Class: com.tigervnc.vncviewer.VncViewer
-Application-Name: TigerVNC viewer
+Application-Name: TigerVNC
Permissions: all-permissions
Codebase: *
diff --git a/java/com/tigervnc/vncviewer/OptionsDialog.java b/java/com/tigervnc/vncviewer/OptionsDialog.java
index 927fdf21..9c442cbc 100644
--- a/java/com/tigervnc/vncviewer/OptionsDialog.java
+++ b/java/com/tigervnc/vncviewer/OptionsDialog.java
@@ -152,9 +152,11 @@ class OptionsDialog extends Dialog {
/* Misc. */
JCheckBox sharedCheckbox;
- JCheckBox dotWhenNoCursorCheckbox;
+ JCheckBox alwaysCursorCheckbox;
JCheckBox acceptBellCheckbox;
+ JComboBox cursorTypeChoice;
+
/* SSH */
JCheckBox tunnelCheckbox;
JCheckBox viaCheckbox;
@@ -175,7 +177,7 @@ class OptionsDialog extends Dialog {
@SuppressWarnings({"rawtypes","unchecked"})
public OptionsDialog() {
super(true);
- setTitle("VNC viewer options");
+ setTitle("TigerVNC options");
setResizable(false);
getContentPane().setLayout(
@@ -311,6 +313,7 @@ class OptionsDialog extends Dialog {
handleAutoselect();
handleCompression();
handleJpeg();
+ handleAlwaysCursor();
/* Security */
Security security = new Security(SecurityClient.secTypes);
@@ -458,7 +461,9 @@ class OptionsDialog extends Dialog {
/* Misc. */
sharedCheckbox.setSelected(shared.getValue());
- dotWhenNoCursorCheckbox.setSelected(dotWhenNoCursor.getValue());
+ alwaysCursorCheckbox.setSelected(alwaysCursor.getValue());
+ String cursorTypeStr = cursorType.getValueStr();
+ cursorTypeChoice.setSelectedItem(cursorTypeStr);
acceptBellCheckbox.setSelected(acceptBell.getValue());
/* SSH */
@@ -613,8 +618,9 @@ class OptionsDialog extends Dialog {
/* Misc. */
shared.setParam(sharedCheckbox.isSelected());
- dotWhenNoCursor.setParam(dotWhenNoCursorCheckbox.isSelected());
+ alwaysCursor.setParam(alwaysCursorCheckbox.isSelected());
acceptBell.setParam(acceptBellCheckbox.isSelected());
+ cursorType.setParam((String)cursorTypeChoice.getSelectedItem());
/* SSH */
tunnel.setParam(tunnelCheckbox.isSelected());
@@ -1173,31 +1179,54 @@ class OptionsDialog extends Dialog {
MiscPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
sharedCheckbox =
new JCheckBox("Shared (don't disconnect other viewers)");
- dotWhenNoCursorCheckbox = new JCheckBox("Show dot when no cursor");
+ alwaysCursorCheckbox = new JCheckBox("Show local cursor when not provided by server");
+ alwaysCursorCheckbox.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ handleAlwaysCursor();
+ }
+ });
+ JLabel cursorTypeLabel = new JLabel("Cursor type:");
+ String[] cursorTypes = {"Dot", "System"};
+ cursorTypeChoice = new MyJComboBox(cursorTypes);
+ cursorTypeChoice.setPrototypeDisplayValue("System.");
acceptBellCheckbox = new JCheckBox("Beep when requested by the server");
MiscPanel.add(sharedCheckbox,
new GridBagConstraints(0, 0,
- 1, 1,
+ REMAINDER, 1,
LIGHT, LIGHT,
LINE_START, NONE,
new Insets(0, 0, 4, 0),
NONE, NONE));
- MiscPanel.add(dotWhenNoCursorCheckbox,
+ MiscPanel.add(alwaysCursorCheckbox,
new GridBagConstraints(0, 1,
- 1, 1,
+ REMAINDER, 1,
LIGHT, LIGHT,
LINE_START, NONE,
new Insets(0, 0, 4, 0),
NONE, NONE));
- MiscPanel.add(acceptBellCheckbox,
+ MiscPanel.add(cursorTypeLabel,
new GridBagConstraints(0, 2,
1, 1,
LIGHT, LIGHT,
LINE_START, NONE,
new Insets(0, 0, 4, 0),
NONE, NONE));
- MiscPanel.add(Box.createRigidArea(new Dimension(5, 0)),
+ MiscPanel.add(cursorTypeChoice,
+ new GridBagConstraints(1, 2,
+ 1, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 5, 4, 0),
+ NONE, NONE));
+ MiscPanel.add(acceptBellCheckbox,
new GridBagConstraints(0, 3,
+ REMAINDER, 1,
+ LIGHT, LIGHT,
+ LINE_START, NONE,
+ new Insets(0, 0, 4, 0),
+ NONE, NONE));
+ MiscPanel.add(Box.createRigidArea(new Dimension(5, 0)),
+ new GridBagConstraints(0, 4,
REMAINDER, REMAINDER,
HEAVY, HEAVY,
LINE_START, BOTH,
@@ -1633,5 +1662,10 @@ class OptionsDialog extends Dialog {
}
}
+ private void handleAlwaysCursor()
+ {
+ cursorTypeChoice.setEnabled(alwaysCursorCheckbox.isSelected());
+ }
+
static LogWriter vlog = new LogWriter("OptionsDialog");
}
diff --git a/java/com/tigervnc/vncviewer/Parameters.java b/java/com/tigervnc/vncviewer/Parameters.java
index dd2f1c3e..3e14b10e 100644
--- a/java/com/tigervnc/vncviewer/Parameters.java
+++ b/java/com/tigervnc/vncviewer/Parameters.java
@@ -40,9 +40,19 @@ public class Parameters {
public static BoolParameter dotWhenNoCursor
= new BoolParameter("DotWhenNoCursor",
- "Show the dot cursor when the server sends an invisible cursor",
+ "[DEPRECATED] Show the dot cursor when the server sends an invisible cursor",
false);
+ public static BoolParameter alwaysCursor
+ = new BoolParameter("AlwaysCursor",
+ "Show the local cursor when the server sends an invisible cursor",
+ false);
+
+ public static StringParameter cursorType
+ = new StringParameter("CursorType",
+ "Specify which cursor type the local cursor should be. Should be either Dot or System",
+ "Dot");
+
public static BoolParameter sendLocalUsername
= new BoolParameter("SendLocalUsername",
"Send the local username for SecurityTypes "+
@@ -282,7 +292,8 @@ public class Parameters {
CSecurityTLS.X509CA,
CSecurityTLS.X509CRL,
SecurityClient.secTypes,
- dotWhenNoCursor,
+ alwaysCursor,
+ cursorType,
autoSelect,
fullColor,
lowColorLevel,
@@ -315,6 +326,10 @@ public class Parameters {
sshKeyFile,
};
+ static VoidParameter[] readOnlyParameterArray = {
+ dotWhenNoCursor
+ };
+
static LogWriter vlog = new LogWriter("Parameters");
@@ -447,29 +462,35 @@ public class Parameters {
invalidParameterName = false;
} else {
for (int i = 0; i < parameterArray.length; i++) {
- if (parameterArray[i] instanceof StringParameter) {
- if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
+ VoidParameter parameter;
+ if (i < parameterArray.length) {
+ parameter = parameterArray[i];
+ } else {
+ parameter = readOnlyParameterArray[i - parameterArray.length];
+ }
+ if (parameter instanceof StringParameter) {
+ if (line.substring(0,idx).trim().equalsIgnoreCase(parameter.getName())) {
if (value.length() > 256) {
vlog.error(String.format("Failed to read line %d in file %s: %s",
lineNr, filepath, "Invalid format or too large value"));
continue;
}
- ((StringParameter)parameterArray[i]).setParam(value);
+ ((StringParameter)parameter).setParam(value);
invalidParameterName = false;
}
- } else if (parameterArray[i] instanceof IntParameter) {
- if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
- ((IntParameter)parameterArray[i]).setParam(value);
+ } else if (parameter instanceof IntParameter) {
+ if (line.substring(0,idx).trim().equalsIgnoreCase(parameter.getName())) {
+ ((IntParameter)parameter).setParam(value);
invalidParameterName = false;
}
- } else if (parameterArray[i] instanceof BoolParameter) {
- if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
- ((BoolParameter)parameterArray[i]).setParam(value);
+ } else if (parameter instanceof BoolParameter) {
+ if (line.substring(0,idx).trim().equalsIgnoreCase(parameter.getName())) {
+ ((BoolParameter)parameter).setParam(value);
invalidParameterName = false;
}
} else {
vlog.error(String.format("Unknown parameter type for parameter %s",
- parameterArray[i].getName()));
+ parameter.getName()));
}
}
@@ -517,6 +538,10 @@ public class Parameters {
}
}
+ for (int i = 0; i < readOnlyParameterArray.length; i++) {
+ UserPreferences.delete(hKey, readOnlyParameterArray[i].getName());
+ }
+
UserPreferences.save(hKey);
}
@@ -528,28 +553,34 @@ public class Parameters {
if (servername == null)
servername = "";
- for (int i = 0; i < parameterArray.length; i++) {
- if (parameterArray[i] instanceof StringParameter) {
- if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
+ for (int i = 0; i < parameterArray.length + readOnlyParameterArray.length; i++) {
+ VoidParameter parameter;
+ if (i < parameterArray.length) {
+ parameter = parameterArray[i];
+ } else {
+ parameter = readOnlyParameterArray[i - parameterArray.length];
+ }
+ if (parameter instanceof StringParameter) {
+ if (UserPreferences.get(hKey, parameter.getName()) != null) {
String stringValue =
- UserPreferences.get(hKey, parameterArray[i].getName());
- ((StringParameter)parameterArray[i]).setParam(stringValue);
+ UserPreferences.get(hKey, parameter.getName());
+ ((StringParameter)parameter).setParam(stringValue);
}
- } else if (parameterArray[i] instanceof IntParameter) {
- if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
+ } else if (parameter instanceof IntParameter) {
+ if (UserPreferences.get(hKey, parameter.getName()) != null) {
int intValue =
- UserPreferences.getInt(hKey, parameterArray[i].getName());
- ((IntParameter)parameterArray[i]).setParam(intValue);
+ UserPreferences.getInt(hKey, parameter.getName());
+ ((IntParameter)parameter).setParam(intValue);
}
- } else if (parameterArray[i] instanceof BoolParameter) {
- if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
+ } else if (parameter instanceof BoolParameter) {
+ if (UserPreferences.get(hKey, parameter.getName()) != null) {
boolean booleanValue =
- UserPreferences.getBool(hKey, parameterArray[i].getName());
- ((BoolParameter)parameterArray[i]).setParam(booleanValue);
+ UserPreferences.getBool(hKey, parameter.getName());
+ ((BoolParameter)parameter).setParam(booleanValue);
}
} else {
vlog.error(String.format("Unknown parameter type for parameter %s",
- parameterArray[i].getName()));
+ parameter.getName()));
}
}
diff --git a/java/com/tigervnc/vncviewer/README b/java/com/tigervnc/vncviewer/README
index 404b8eb9..4ad198fe 100644
--- a/java/com/tigervnc/vncviewer/README
+++ b/java/com/tigervnc/vncviewer/README
@@ -12,7 +12,7 @@ optimizations, major GUI improvements, and more.
Copyright (C) 2004-2005 Cendio AB
Copyright (C) 2005 Martin Koegler
Copyright (C) 2009 Pierre Ossman for Cendio AB
- Copyright (C) 2009-2024 TigerVNC Team
+ Copyright (C) 2009-2025 TigerVNC team
Copyright (C) 2011-2014 Brian P. Hinz
All rights reserved.
diff --git a/java/com/tigervnc/vncviewer/ServerDialog.java b/java/com/tigervnc/vncviewer/ServerDialog.java
index 01f91db2..9c92698e 100644
--- a/java/com/tigervnc/vncviewer/ServerDialog.java
+++ b/java/com/tigervnc/vncviewer/ServerDialog.java
@@ -47,7 +47,7 @@ class ServerDialog extends Dialog implements Runnable {
super(true);
this.vncServerName = vncServerName;
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
- setTitle("VNC viewer: Connection details");
+ setTitle("TigerVNC");
setResizable(false);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
@@ -258,7 +258,7 @@ class ServerDialog extends Dialog implements Runnable {
JOptionPane op =
new JOptionPane(msg, JOptionPane.QUESTION_MESSAGE,
JOptionPane.OK_CANCEL_OPTION, null, options, options[1]);
- JDialog dlg = op.createDialog(this, "TigerVNC Viewer");
+ JDialog dlg = op.createDialog(this, "TigerVNC");
dlg.setIconImage(VncViewer.frameIcon);
dlg.setAlwaysOnTop(true);
dlg.setVisible(true);
diff --git a/java/com/tigervnc/vncviewer/UserPreferences.java b/java/com/tigervnc/vncviewer/UserPreferences.java
index 544774db..44c62343 100644
--- a/java/com/tigervnc/vncviewer/UserPreferences.java
+++ b/java/com/tigervnc/vncviewer/UserPreferences.java
@@ -144,6 +144,11 @@ public class UserPreferences {
}
}
+ public static void delete(String nName, String key) {
+ Preferences node = root.node(nName);
+ node.remove(key);
+ }
+
static LogWriter vlog = new LogWriter("UserPreferences");
}
diff --git a/java/com/tigervnc/vncviewer/Viewport.java b/java/com/tigervnc/vncviewer/Viewport.java
index c293cb7d..3c6f623e 100644
--- a/java/com/tigervnc/vncviewer/Viewport.java
+++ b/java/com/tigervnc/vncviewer/Viewport.java
@@ -167,8 +167,15 @@ class Viewport extends JPanel implements ActionListener {
for (i = 0; i < width*height; i++)
if (data[i*4 + 3] != 0) break;
- if ((i == width*height) && dotWhenNoCursor.getValue()) {
- vlog.debug("Cursor is empty: Using dot");
+ useSystemCursor = false;
+ if ((i == width*height) && alwaysCursor.getValue()) {
+ String cursorTypeStr = cursorType.getValueStr();
+ if (cursorTypeStr.matches("^System$")) {
+ useSystemCursor = true;
+ } else {
+ vlog.debug("Cursor is empty: Using dot");
+ }
+ // Do this anyway to prevent cursor being null
cursor = new BufferedImage(5, 5, BufferedImage.TYPE_INT_ARGB_PRE);
cursor.setRGB(0, 0, 5, 5, dotcursor_xpm, 0, 5);
cursorHotspot.x = cursorHotspot.y = 3;
@@ -200,8 +207,8 @@ class Viewport extends JPanel implements ActionListener {
Graphics2D g2 = tmp.createGraphics();
g2.drawImage(cursor, 0, 0, cw, ch, 0, 0, width, height, null);
g2.dispose();
- x = (int) Math.min(Math.floor((float) x * (float) cw / (float) width), cw - 1);
- y = (int) Math.min(Math.floor((float) y * (float) ch / (float) height), ch - 1);
+ x = (int) Math.min(Math.floor((float) x * (float) cw / (float) width), Math.max(cw - 1, 0));
+ y = (int) Math.min(Math.floor((float) y * (float) ch / (float) height), Math.max(ch - 1, 0));
cursor = tmp;
}
@@ -216,7 +223,10 @@ class Viewport extends JPanel implements ActionListener {
hotspot = new java.awt.Point(x, y);
softCursor = tk.createCustomCursor(img, hotspot, name);
- setCursor(softCursor);
+ if (useSystemCursor)
+ setCursor(java.awt.Cursor.getDefaultCursor());
+ else
+ setCursor(softCursor);
}
public void resize(int x, int y, int w, int h) {
@@ -637,7 +647,7 @@ class Viewport extends JPanel implements ActionListener {
this, ID.OPTIONS, EnumSet.noneOf(MENU.class));
menu_add(contextMenu, "Connection info...", KeyEvent.VK_I,
this, ID.INFO, EnumSet.noneOf(MENU.class));
- menu_add(contextMenu, "About TigerVNC viewer...", KeyEvent.VK_T,
+ menu_add(contextMenu, "About TigerVNC...", KeyEvent.VK_T,
this, ID.ABOUT, EnumSet.of(MENU.DIVIDER));
menu_add(contextMenu, "Dismiss menu", KeyEvent.VK_M,
@@ -830,6 +840,7 @@ class Viewport extends JPanel implements ActionListener {
float scaleRatioX, scaleRatioY;
static BufferedImage cursor;
+ static boolean useSystemCursor = false;
Point cursorHotspot = new Point();
}
diff --git a/java/com/tigervnc/vncviewer/VncViewer.java b/java/com/tigervnc/vncviewer/VncViewer.java
index 4e4364cb..2a372b98 100644
--- a/java/com/tigervnc/vncviewer/VncViewer.java
+++ b/java/com/tigervnc/vncviewer/VncViewer.java
@@ -63,7 +63,7 @@ public class VncViewer implements Runnable {
public static final String aboutText =
new String("TigerVNC Java viewer v%s (%s)%n"+
"Built on %s at %s%n"+
- "Copyright (C) 1999-2024 TigerVNC Team and many others (see README.rst)%n"+
+ "Copyright (C) 1999-2025 TigerVNC team and many others (see README.rst)%n"+
"See https://www.tigervnc.org for information on TigerVNC.");
public static String version = null;
@@ -212,6 +212,8 @@ public class VncViewer implements Runnable {
// Check if the server name in reality is a configuration file
potentiallyLoadConfigurationFile(vncServerName);
+
+ migrateDeprecatedOptions();
}
public static void usage() {
@@ -359,7 +361,7 @@ public class VncViewer implements Runnable {
JOptionPane op =
new JOptionPane(msg, JOptionPane.INFORMATION_MESSAGE,
JOptionPane.DEFAULT_OPTION, VncViewer.logoIcon, options);
- JDialog dlg = op.createDialog(parent, "About TigerVNC viewer for Java");
+ JDialog dlg = op.createDialog(parent, "About TigerVNC");
dlg.setIconImage(VncViewer.frameIcon);
dlg.setAlwaysOnTop(true);
dlg.setVisible(true);
@@ -378,7 +380,7 @@ public class VncViewer implements Runnable {
void reportException(java.lang.Exception e) {
String title, msg = e.getMessage();
int msgType = JOptionPane.ERROR_MESSAGE;
- title = "TigerVNC viewer : Error";
+ title = "TigerVNC : Error";
e.printStackTrace();
JOptionPane.showMessageDialog(null, msg, title, msgType);
}
@@ -449,6 +451,15 @@ public class VncViewer implements Runnable {
}
}
+ static void migrateDeprecatedOptions() {
+ if (dotWhenNoCursor.getValue()) {
+ vlog.info("DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead");
+
+ alwaysCursor.setParam(true);
+ cursorType.setParam("Dot");
+ }
+ }
+
public static CConn cc;
public static StringParameter config
= new StringParameter("Config",
diff --git a/po/CMakeLists.txt b/po/CMakeLists.txt
index 0be492c8..03fb2632 100644
--- a/po/CMakeLists.txt
+++ b/po/CMakeLists.txt
@@ -23,10 +23,11 @@ if (GETTEXT_XGETTEXT_EXECUTABLE)
"--directory=${PROJECT_SOURCE_DIR}"
"--output=${CMAKE_CURRENT_SOURCE_DIR}/tigervnc.pot"
--default-domain=tigervnc
+ --from-code=UTF-8
--keyword=_
--keyword=p_:1c,2
--keyword=N_
- "--copyright-holder=TigerVNC Team and many others \(see README.rst\)"
+ "--copyright-holder=TigerVNC team and many others \(see README.rst\)"
--msgid-bugs-address=tigervnc-devel@googlegroups.com
--sort-by-file
--add-location
diff --git a/po/bg.po b/po/bg.po
index cca9a632..12df7c94 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -1,14 +1,14 @@
# Bulgarian translation of tigervnc po-file.
-# Copyright (C) 2015, 2017, 2018, 2019. 2021, 2022, 2024 the TigerVNC Team (msgids)
+# Copyright (C) 2015, 2017, 2018, 2019. 2021, 2022, 2024, 2025 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
-# Alexander Shopov <ash@kambanaria.org>, 2015, 2017, 2018, 2019, 2021, 2022, 2024.
+# Alexander Shopov <ash@kambanaria.org>, 2015, 2017, 2018, 2019, 2021, 2022, 2024, 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-21 10:55+0200\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-22 11:46+0100\n"
"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
"Language-Team: Bulgarian <dict@ludost.net>\n"
"Language: bg\n"
@@ -18,17 +18,17 @@ msgstr ""
"X-Bugs: Report translation errors to the Language-Team address.\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Връзка към гнездо „%s“"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Връзка към машина „%s“, порт %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -39,85 +39,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Име на работен плот: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Машина: %.80s, порт: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Размер: %d ✕ %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Формат на пикÑелите: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(Ñтандартното за Ñървъра %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "ЗаÑвено кодиране: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "ПоÑледно ползвано кодиране: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Оценка на ÑкороÑтта на линиÑта: %d kbit/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "ВерÑÐ¸Ñ Ð½Ð° протокола: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Вид ÑигурноÑÑ‚: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Връзката бе прекъÑната от Ñтраната на Ñървъра, преди да Ñе уÑтанови ÑеÑиÑ."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "ÐеуÑпешна идентификациÑ: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"ÐеуÑпешна Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¿Ñ€ÐµÐ´ Ñървъра. Сървърът върна Ñледната причина:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "ÐеуÑпешно задаване на размер на плота чрез SetDesktopSize: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "Ðеправилна палитра SetColourMapEntries от Ñървъра!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "СкороÑÑ‚ %d kbit/s — преминаване към качеÑтво %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "СкороÑÑ‚ %d kbit/s — пълниÑÑ‚ цвÑÑ‚ е включен"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "СкороÑÑ‚ %d kbit/s — пълниÑÑ‚ цвÑÑ‚ е изключен"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Ползва Ñе формат на пикÑелите %s"
@@ -130,21 +146,21 @@ msgstr "Указани Ñа неправилни размери!"
msgid "Reducing window size to fit on current monitor"
msgstr "ÐамалÑване на размера на прозореца, за да Ñе побере на Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "ПреоразмерÑване на екрана за избÑгване на Ñлучайна заÑвка за цÑл екран"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "За контекÑтното меню натиÑнете клавиша „%s“"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "ÐеуÑпешно прихващане на клавиатурата"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "ИзчиÑлено е неправилно разположение на екрана Ñпоред заÑвката за преоразмерÑване!"
@@ -152,251 +168,307 @@ msgstr "ИзчиÑлено е неправилно разположение на
msgid "Invalid state for 3 button emulation"
msgstr "Ðеправилно ÑÑŠÑтоÑние за емулиране на 3 бутона"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "ЛипÑва код за Ñ€Ð°Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÐµÐ½ клавиш 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "ЛипÑва код за Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Ðеправилен код 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "ЛипÑва знак за Ñ€Ð°Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÐµÐ½ клавиш 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "ЛипÑва знак за Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "ÐеуÑпешно обновÑване на ÑÑŠÑтоÑнието на Ñветодиодите на клавиатурата: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "ЛипÑва знак за кода за клавиш %d (в текущото ÑÑŠÑтоÑние)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "ÐеуÑпешно получаване на ÑÑŠÑтоÑнието на Ñветодиодите на клавиатурата: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "ÐеуÑпешно обновÑване на ÑÑŠÑтоÑнието на Ñветодиодите на клавиатурата"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "ÐеуÑпешно получаване на наÑтройките на монитора"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Указани Ñа неправилни наÑтройки за „%s“"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Монитор Ñ Ð¸Ð½Ð´ÐµÐºÑ %d не ÑъщеÑтвува"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Ðеправилен Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° монитор „%s“"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Ðеочакван знак „%c“"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "ÐаÑтройки на TigerVNC"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "ОтмÑна"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "Добре"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "КомпреÑиÑ"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Ðвтоматичен избор"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Предпочитано кодиране"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "ЦвÑÑ‚"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Пълен"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Среден"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Беден"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "СъвÑем беден"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Ðиво на компреÑиÑ:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "ниво (0≡бързо, 9≡най-добро)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Ползване на компреÑÐ¸Ñ JPEG:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "качеÑтво (0≡лошо, 9≡най-добро)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "СигурноÑÑ‚"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Шифриране"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Без"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS + анонимен Ñертификат"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS + Ñертификат X509"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Път към Ñертификата на удоÑÑ‚Ð¾Ð²ÐµÑ€Ð¸Ñ‚ÐµÐ»Ñ Ð¿Ð¾ X509"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Път към файла CPL по X509"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "ИдентификациÑ"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Стандартна за VNC (неÑигурна без шифриране)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Име и парола (неÑигурна без шифриране)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Права̀"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Ð’Ð¸Ð·ÑƒÐ°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ (без вход от мишка и клавиатура)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Мишка"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Ð•Ð¼ÑƒÐ»Ð°Ñ†Ð¸Ñ Ð½Ð° Ñреден бутон на мишката"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Точка, ако нÑма курÑор"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Показване на локален курÑор, когато Ñървърът не предоÑÑ‚Ð°Ð²Ñ Ñ‚Ð°ÐºÑŠÐ²"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Вид курÑор"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Точка"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "СиÑтемен"
+
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Клавиатура"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Изпращане на ÑиÑтемните клавиши директно към Ñървъра (при цÑл екран)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Клавиш за контекÑтното меню"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Буфер за обмен"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Приемане на буфера за обмен от Ñървъра"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Задаване и на оÑÐ½Ð¾Ð²Ð½Ð¸Ñ Ð¸Ð·Ð±Ð¾Ñ€"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Изпращане на буфера за обмен към Ñървъра"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Изпращане на оÑÐ½Ð¾Ð²Ð½Ð¸Ñ Ð¸Ð·Ð±Ð¾Ñ€ като буфер за обмен"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "ВизуализациÑ"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Режим на визуализациÑ"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "В прозорец"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Ðа цÑл екран на Ñ‚ÐµÐºÑƒÑ‰Ð¸Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Ðа цÑл екран на вÑички монитори"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Ðа цÑл екран на Ð¸Ð·Ð±Ñ€Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€/и"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Разни"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Споделена (без прекъÑване на връзката към оÑтаналите визуализатори)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Запитване на повторно Ñвързване при грешка"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "Визуализатор: Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° връзката"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "Сървър за VNC:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "ÐаÑтройки…"
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Зареждане…"
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Запазване като…"
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "ОтноÑно…"
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Свързване"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -407,15 +479,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "ÐаÑтройки на връзка за TigerVNC (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Избор на файл Ñ Ð½Ð°Ñтройки на връзка за TigerVNC"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -426,24 +498,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Запазване на наÑтройките на връзката във файл за TigerVNC"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "Файлът „%s“ вече ÑъщеÑтвува, да Ñе презапише ли"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Ðе"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "ПрезапиÑване"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -454,7 +526,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -465,7 +537,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -476,205 +548,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "ПътÑÑ‚ до папката за ÑÑŠÑтоÑнието не може да бъде получен"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "ПътÑÑ‚ до папката за ÑÑŠÑтоÑнието на VNC не може да бъде получен"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "„%s“ не може да Ñе отвори: %s"
+msgid "Could not open \"%s\""
+msgstr "„%s“ не може да Ñе отвори"
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Ред %d от файл „%s“ не може да Ñе прочете: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Ред %d от файл „%s“ не може да Ñе прочете"
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Прекалено дълъг ред"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Файлът Ñ Ð¿Ð°Ñ€Ð¾Ð»Ð°Ñ‚Ð° не може да Ñе отвори"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð·Ð° VNC"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Тази връзка е Ñигурна"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Тази връзка не е Ñигурна"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Име:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Парола:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Отменена идентификациÑ"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "ÐеуÑпешно обновÑване на ÑÑŠÑтоÑнието на Ñветодиодите на клавиатурата: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "ÐеуÑпешно обновÑване на ÑÑŠÑтоÑнието на Ñветодиодите на клавиатурата: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "ÐеуÑпешно обновÑване на ÑÑŠÑтоÑнието на Ñветодиодите на клавиатурата"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "ÐеуÑпешно получаване на ÑÑŠÑтоÑнието на Ñветодиодите на клавиатурата: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "ЛипÑва код на клавиш при натиÑкането на клавиш"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Запазване на паролата за повторно Ñвързване"
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "ЛипÑва код за Ñ€Ð°Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÐµÐ½ клавиш 0x%02x"
-
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "ЛипÑва код за Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Ðеправилен код 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "ЛипÑва знак за Ñ€Ð°Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÐµÐ½ клавиш 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "ЛипÑва знак за Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "ЛипÑва знак за кода за клавиш 0x%02x (в текущото ÑÑŠÑтоÑние)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "ЛипÑва знак за кода за клавиш %d (в текущото ÑÑŠÑтоÑние)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "&ПрекъÑване на връзка"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&ЦÑл екран"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "&Минимизиране"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "&ПреоразмерÑване на прозореца към ÑеÑиÑта"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "„&Ctrl“"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "„&Alt“"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Изпращане на „%s“"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Изпращане на „Ctrl-Alt-&Del“"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "ОпреÑнÑване на &екрана"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&ÐаÑтройки…"
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "&Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° връзката…"
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "&ОтноÑно TigerVNC…"
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° връзката по VNC"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Прозорецът е региÑтриран за докоÑване, а не за жеÑтове"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "ÐаÑтройките на жеÑтовете не може да Ñе зададат (грешка 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "ÐеуÑпешно получаване на информациÑта за жеÑтове (грешка 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Ðеправилен бутон на мишка: %d — трÑбва да е от 1 до 7, включително."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Ðеподдържан клавиш 0x%x — не може да Ñе генерира Ñъбитие от клавиатурата."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "Ðе може да Ñе получи маÑката за ÑÑŠÐ±Ð¸Ñ‚Ð¸Ñ Ð¿Ð¾ X Input 2 за прозорец 0x%08lx"
@@ -684,7 +698,7 @@ msgstr "Ðе може да Ñе получи маÑката за ÑъбитиÑ
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "Прозорец 0x%08lx нÑма маÑка за ÑÑŠÐ±Ð¸Ñ‚Ð¸Ñ Ð¿Ð¾ X Input 2"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "Прозорец 0x%08lx има поне две маÑки за ÑÑŠÐ±Ð¸Ñ‚Ð¸Ñ Ð¿Ð¾ X Input 2"
@@ -695,7 +709,6 @@ msgid "Failure grabbing device %i"
msgstr "ÐеуÑпешно прихващане на уÑтройÑтво %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "Визуализатор на TigerVNC"
@@ -713,140 +726,141 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC е виÑокоÑкороÑтна верÑÐ¸Ñ Ð½Ð° VNC, коÑто произлиза от RealVNC 4 и X.org. TigerVNC Ñе поÑвÑва като верÑÐ¸Ñ Ð½Ð° TightVNC за разработчици под Unix и Linux, но Ñе Ð¾Ñ‚Ð´ÐµÐ»Ñ Ð¾Ñ‚ родителÑÐºÐ¸Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚ още през 2009, за да може проектът TightVNC да Ñе концентрира върху Windows. TigerVNC поддържа вариант на кодирането Tight, което е уÑкорено чрез ползването на кодера за JPEG „libjpeg-turbo“."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr "Визуализатор на TigerVNC: връзка към CentOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr "Визуализатор на TigerVNC: връзка към MacOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr "Визуализатор на TigerVNC: връзка към Windows"
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "Екипът на TigerVNC"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
-msgstr "Името на параметъра е прекалено дълго"
+msgstr "Името на опциÑта е прекалено дълго"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
-msgstr "СтойноÑтта на параметъра е прекалено голÑма"
+msgstr "СтойноÑтта на опциÑта е прекалено голÑма"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Ðеправилен формат или прекалено голÑма ÑтойноÑÑ‚"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Ключът за региÑтъра не може да Ñе Ñъздаде"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Ключът за региÑтъра не може да Ñе затвори"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "„%s“ не може да Ñе запише: %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Ðепознат вид на параметъра"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "„%s“ не може да Ñе изтрие: %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Ключът за региÑтъра не може да Ñи отвори"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Ð—Ð°Ð¿Ð¸Ñ â„–%d в иÑториÑта на Ñървърите не може да Ñи прочете: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
-msgstr "ÐеуÑпешно прочитане на параметъра „%s“: %s"
+msgstr "ÐеуÑпешно прочитане на опциÑта „%s“: %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "ПътÑÑ‚ до папката за наÑтройките не може да бъде получен"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "ПътÑÑ‚ до папката за наÑтройките на VNC не може да Ñе получи"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
-msgstr "Параметърът не може да Ñи кодира"
+msgstr "ОпциÑта не може да Ñи кодира"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Ðеправилен формат на файла Ñ Ð½Ð°Ñтройки „%s“"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Ðеправилен формат"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
-msgstr "Ðепознат вид на параметъра"
+msgstr "Ðепозната опциÑ"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Получено е Ñъобщение (0x%x) за неподдържан прозорец"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "ПоÑочен е неправилен прозорец 0x%08lx за прихващане на показалеца"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "ФункционалноÑтта за обработка на ÑÑŠÐ±Ð¸Ñ‚Ð¸Ñ Ð´Ð¾ÐºÐ¾Ñване не може да Ñе Ñъздаде: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Ðе може да Ñе закачи Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð·Ð° обработка на ÑÑŠÐ±Ð¸Ñ‚Ð¸Ñ ÐºÑŠÐ¼ прозорец (грешка 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Ðе може да Ñе получат данните за Ñъбитие на X Input"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "Събитие на X Input за неизвеÑтен прозорец"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "Разширението X Input липÑва."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "ЛипÑва верÑÐ¸Ñ 2 или по-нова на разширението X Input."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "ЛипÑва верÑÐ¸Ñ 2.2 или по-нова на разширението X Input. СъбитиÑта жеÑтове не Ñе поддържат."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"Визуализатор на TigerVNC, верÑиÑ: %s\n"
@@ -893,95 +907,174 @@ msgstr "Грешка при Ñтартирането на нов визуалиÐ
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr "Получен е Ñигнал %d. Визуализаторът на TigerVNC ще Ñпре работа."
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "Визуализатор на TigerVNC"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Да"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "ЗатварÑне"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "ОтноÑно"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Скриване"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Спиране"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "УÑлуги"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Скриване на другите"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Показване на вÑички"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Файл"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "Ðова &връзка"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Употреба: %s [ОПЦИЯ…] [ХОСТ][:ÐОМЕР_ÐÐ_ДИСПЛЕЙ]\n"
+" %s [ОПЦИЯ…] [ХОСТ][::ПОРТ]\n"
+" %s [ОПЦИЯ…] [ГÐЕЗДО_ÐÐ_UNIX]\n"
+" %s [ОПЦИЯ…] -listen [ПОРТ]\n"
+" %s [ОПЦИЯ…] [ФÐЙЛ_.tigervnc]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Опции:\n"
+"\n"
+" -display ДИСПЛЕЙ — указва диÑплей на X Ñървър за прозореца на визуализатора\n"
+" -geometry ГЕОМЕТРИЯ — първоначална Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð½Ð° оÑÐ½Ð¾Ð²Ð½Ð¸Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€ÐµÑ† на визуализатора.\n"
+" За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ Ñтраницата от ръководÑтвото.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Опциите Ñе задават Ñ -ОПЦИЯ, а Ñе изключват Ñ -ОПЦИЯ=0\n"
+"Ðко Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ÐµÐ¼Ð° ÑтойноÑÑ‚, Ñ‚Ñ Ð¼Ð¾Ð¶Ðµ да Ñе зададе Ñ -ОПЦИЯ СТОЙÐОСТ\n"
+"Други варианти на изпиÑване Ñа ОПЦИЯ=СТОЙÐОСТ -ОПЦИЯ=СТОЙÐОСТ --ОПЦИЯ=СТОЙÐОСТ\n"
+"Опциите може да Ñе изпиÑват Ñ Ð¼Ð°Ð»ÐºÐ¸ или главни букви, или ÑмеÑено.\n"
+"Опциите Ñа:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "ÐаÑтройката „FullScreenAllMonitors“ е оÑтарÑла, вмеÑто това задайте „FullScreenMode“ да е „all“"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "ÐаÑтройката „DotWhenNoCursor“ е оÑтарÑла: задайте „AlwaysCursor“ да е 1, а „CursorType“ да е „Dot“"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "Папката „~/.vnc“ е оÑтарÑла. Вижте ръководÑтвото „man vncviewer“ кои папки Ñе ползват."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "Папката „%%APPDATA%%\\vnc“ е оÑтарÑла. Ползвайте „%%APPDATA%%\\TigerVNC“."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
+#, c-format
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Папката за наÑтройки на VNC не може да Ñе Ñъздаде „%s“: %s"
+
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Папката за данни на VNC не може да Ñе Ñъздаде"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Папката за данни на VNC не може да Ñе Ñъздаде „%s“: %s"
+
+#: vncviewer/vncviewer.cxx:586
+#, c-format
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Папката за ÑÑŠÑтоÑние на VNC не може да Ñе Ñъздаде „%s“: %s"
+
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "Папката за наÑтройки на VNC не може да Ñе Ñъздаде: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: Ðепозната Ð¾Ð¿Ñ†Ð¸Ñ â€ž%s“\n"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "Папката за данни на VNC не може да Ñе Ñъздаде: %s"
+msgid "See '%s --help' for more information.\n"
+msgstr "За повече Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð²Ð¸Ð¶Ñ‚Ðµ изхода от „%s --help“\n"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:712
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "Папката за ÑÑŠÑтоÑние на VNC не може да Ñе Ñъздаде: %s"
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Допълнителен аргумент „%s“\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "„-listen“ и „-via“ Ñа неÑъвмеÑтими"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Ðе може да Ñе Ñлуша за входÑщи връзки"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Слуша Ñе на порт %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -992,6 +1085,17 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"ÐеуÑпешно уÑтановÑване на шифриран тунел:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "Визуализатор на отдалечени работни меÑта"
diff --git a/po/cs.po b/po/cs.po
index e3dabe80..e149f68c 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -1,14 +1,14 @@
# Czech translation for TigerVNC.
# Copyright (C) 2018 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
-# Petr Pisar <petr.pisar@atlas.cz>, 2018, 2019, 2021, 2022, 2024.
+# Petr Pisar <petr.pisar@atlas.cz>, 2018, 2019, 2021, 2022, 2024, 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-21 20:34+02:00\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-23 21:10+01:00\n"
"Last-Translator: Petr Pisar <petr.pisar@atlas.cz>\n"
"Language-Team: Czech <translation-team-cs@lists.sourceforge.net>\n"
"Language: cs\n"
@@ -17,17 +17,17 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Připojeno na socket %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Připojeno na stroj %s port %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -38,85 +38,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Název plochy: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Stroj: %.80s port: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Velikost: %d×%d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Formát pixelu: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(výchozí serveru %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Požadované kódování: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "Poslední použité kódování: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Odhad rychlosti linky: %d kb/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Verze protokolu: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Způsob zabezpeÄení: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Spojení bylo serverem zahozeno dříve, než mohla být ustanovena relace."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Autentizace selhala: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Autentizace u serveru selhala. Server uvedl tento důvod:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "Požadavek SetDesktopSize selhal: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "Neplatná zpráva SetColourMapEntries od serveru!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "Tok %d kb/S – kvalita se mění na %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "Tok %d kb/s – plný poÄet barev je nyní zapnut"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "Tok %d kb/s – plný poÄet barev je nyní vypnut"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Používá se formát pixelu %s"
@@ -129,21 +145,21 @@ msgstr "Zadána neplatná geometrie!"
msgid "Reducing window size to fit on current monitor"
msgstr "Velikost okna se zmenÅ¡uje, aby se veÅ¡lo na souÄasný monitor"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Upravuje se velikost okna, by se předešlo nechtěnému požadavku na režim celé obrazovky"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "Kontextovou nabídku otevřete stisknutím %s"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Zabrání klávesnice se nezdařilo"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Pro požadavek na zmÄ›nu velikosti bylo vypoÄteno neplatné rozložení obrazovky!"
@@ -151,253 +167,309 @@ msgstr "Pro požadavek na zmÄ›nu velikosti bylo vypoÄteno neplatné rozložení
msgid "Invalid state for 3 button emulation"
msgstr "Neplatný stav 3-tlaÄítkové emulace"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Žádný scan kód pro rozšířenou virtuální klávesu 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Žádný scan kód pro virtuální klávesu 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Neplatný scan kód 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Žádný symbol pro rozšířenou virtuální klávesu 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Žádný symbol pro virtuální klávesu 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Aktualizace stavu diod klávesnice se nezdařila: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Žádný symbol pro kód klávesy %d (v souÄasném stavu)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Získaní stavu diod klávesnice se nezdařilo: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Aktualizace stavu diod klávesnice se nezdařila"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Získání nastavení systémového monitoru selhalo"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Zadáno neplatné nastavení pro %s"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Monitor Äíslo %d neexistuje"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Neplatné Äíslo monitoru „%s“"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "NeÄekaný znak „%c“"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "Volby TigerVNC"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Zrušit"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "OK"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Komprese"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Automaticky vybrat"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Upřednostňované kódování"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Barevnost"
# Attributes for "Color level"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Plná"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Střední"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Nízká"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Velmi nízká"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Uživatelská úroveň komprese"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "úroveň (0 = rychlá, 9 = nejlepší)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Povolit kompresi JPEG:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "kvalita (0 = špatná, 9 = nejlepší)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "ZabezpeÄení"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Šifrování"
# TODO: Conext for gender
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Ne"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS s anonymními certifikáty"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS s certifikáty X509"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Cesta k X509 certifikátu autority"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Cesta k souboru se seznamem odvolaných certifikátů"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Autentizace"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Standardní VNC (bez Å¡ifrování, nezabezpeÄené)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Uživatelské jméno a heslo (bez Å¡ifrování, nezabezpeÄené)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Vstup"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Pouze se dívat (ignoruje myš a klávesnici)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Myš"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Emulovat prostÅ™ední tlaÄítko myÅ¡i"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Zobrazovat puntík, když chybí kurzor"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Zobrazovat místní ukazatel, když sever žádný nedodá"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Druh ukazatele"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Puntík"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "Systémový"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Klávesnice"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Předávat systémové klávesy přímo serveru (režim celé obrazovky)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Klávesa pro vyvolání nabídky"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Schránka"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Přijímat schránku ze serveru"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Rovněž nastavovat primární výběr"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Posílat schránku serveru"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Posílat primární výběr jako schránku"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Zobrazení"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Režim zobrazení"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "V okně"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "PÅ™es celou obrazovku souÄasného monitoru"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Přes celou obrazovku na všech monitorech"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Přes celou obrazovku na vybraných monitorech"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Ostatní"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Sdílené (neodpojit ostatní diváky)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Při chybách spojení se dotázat na nové"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "ProhlížeÄ VNC: Podrobnosti o pÅ™ipojení"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "VNC server:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Volby…"
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "NaÄíst…"
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Uložit jako…"
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "O aplikaci…"
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Připojit"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -408,15 +480,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "Nastavení TigerVNC (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Vybrat konfiguraÄní souboru TigerVNC"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -427,24 +499,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Uložit nastavení TigerVNC do souboru"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s již existuje. Chcete přepsat?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Ne"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Přepsat"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -455,7 +527,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -466,7 +538,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -477,205 +549,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "Cestu ke stavovému adresáři nebylo možné získat"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Cestu ke stavovému adresáři VNC nebylo možné urÄit"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Nebylo možné otevřít „%s“: %s"
+msgid "Could not open \"%s\""
+msgstr "„%s“ nebylo možné otevřít"
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "PÅ™eÄtení řádku %d v souboru %s selhalo: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "PÅ™eÄtení řádku %d v souboru „%s“ selhalo"
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Příliš dlouhý řádek"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Otevření souboru s heslem selhalo"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "Autentizace VNC"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Toto spojení je zabezpeÄené"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Toto spojení není zabezpeÄené"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Jméno:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Heslo:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Autentizace zrušena"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Aktualizace stavu diod klávesnice se nezdařila: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Aktualizace stavu diod klávesnice se nezdařila: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "Aktualizace stavu diod klávesnice se nezdařila"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Získaní stavu diod klávesnice se nezdařilo: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "Při stisku klávesy nebyl zadán žádný kód klávesy"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Žádný scan kód pro rozšířenou virtuální klávesu 0x%02x"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Zapamatovat heslo pro případ obnovení spojení"
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Žádný scan kód pro virtuální klávesu 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Neplatný scan kód 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Žádný symbol pro rozšířenou virtuální klávesu 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Žádný symbol pro virtuální klávesu 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Žádný symbol pro kód klávesy 0x%02x (v souÄasném stavu)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Žádný symbol pro kód klávesy %d (v souÄasném stavu)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "Od&pojit"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "Přes celou o&brazovku"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "Minimali&zovat"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "Přizpůsobit &velikost okna relaci"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Poslat %s"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Poslat Ctrl-Alt-&Del"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "Obnovit ob&razovku"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "V&olby…"
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "Úda&je o spojení…"
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "O prohlížeÄi &TigerVNC…"
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Údaje o spojení VNC"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Okno je registrováno k dotykům namísto ke gestům"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Nastavení gest selhalo (chyba 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Získání údajů o gestech selhalo (chyba 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Neplatné Äíslo tlaÄítka myÅ¡i %d. Musí se jednat o Äíslo mezi 1 a 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Neobsluhovaná klávesa 0x%x – nelze vytvořit událost klávesnice."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "Masku událostí X Input 2 pro okno 0x%08lx nelze získat"
@@ -685,7 +699,7 @@ msgstr "Masku událostí X Input 2 pro okno 0x%08lx nelze získat"
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "Okno 0x%08lx nemá žádnou masku událostí X Input 2"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "Okno 0x%08lx má více než jednu masku událostí X Input 2"
@@ -696,7 +710,6 @@ msgid "Failure grabbing device %i"
msgstr "Zabrání zařízení %i se nezdařilo"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "ProhlížeÄ TigerVNC"
@@ -714,145 +727,146 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC je vysokorychlostní verze VNC založená na kódu RealVNC 4 a X.org. TigerVNC zaÄalo jako úsilí o vývoj nové generace TightVNC pro Unix a Linux, ale na poÄátku roku 2009 se oddÄ›lilo od rodiÄovského projektu, aby se TightVNC mohlo soustÅ™edit na platformu Windows. TigerVNC podporuje variantu kódování Tight, která je znaÄnÄ› urychlena použitím libjpeg-turbo, kodéru a dekodéru formátu JPEG."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr "Spojení prohlížeÄe TigerVNC ke stroji s CentOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr "Spojení prohlížeÄe TigerVNC ke stroji s macOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr "Spojení prohlížeÄe TigerVNC ke stroji s Windows"
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "Tým TigerVNC"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Název parametru %s je příliš dlouhý"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Parametr je příliš dlouhý"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Neplatný formát nebo příliš velká hodnota"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "VytvoÅ™ení klíÄe v registru selhalo"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "UzavÅ™ení klíÄe v registru selhalo"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Uložení „%s“ selhalo: %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Neznámý typ parametru"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Odstranění „%s“ selhalo: %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "OtevÅ™ení klíÄe v registru selhalo"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Položku historie serverů %d se nepodaÅ™ilo pÅ™eÄíst: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "PÅ™eÄtení parametru „%s“ selhalo: %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "Cestu ke konfiguraÄnímu adresáři nebylo možné získat"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Cestu ke konfiguraÄnímu adresáři VNC nebylo možné urÄit"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Parametr nebylo možné zakódovat"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "KonfiguraÄní soubor %s je v neplatném formátu"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Neplatný formát"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Neznámý parametr"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Obdržena zpráva (0x%x) pro neobsluhované okno"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "Pro zabrání ukazatele byl zadáno neplatné okno 0x%08lx"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "Obsluhu dotyků se nepodařilo vytvořit: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "K oknu nebylo možné připojit obsluhu událostí (chyba 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Z události X Input nebylo možné získat data události"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "Událost X Input pro neznámé okno"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "Rozšíření X Input není dostupné."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "Rozšíření X Input 2 (nebo novější) není dostupné."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "Rozšíření X Input 2.2 (nebo novější) není dostupné. Dotyková gesta nebudou podporována."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"ProhlížeÄ TigerVNC v%s\n"
"Sestaven v: %s\n"
-"Copyright © 1999–%d Tým TigerVNC a mnozí další (vizte README.rst)\n"
+"Copyright © 1999–%d tým TigerVNC a mnozí další (vizte README.rst)\n"
"Podrobnosti o TigerVNC naleznete na https://www.tigervnc.org/."
#: vncviewer/vncviewer.cxx:158
@@ -892,95 +906,174 @@ msgstr "Chyba pÅ™i spouÅ¡tÄ›ní prohlížeÄe TigerVNC: %s"
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
-msgstr "Byl pÅ™ijati vnitÅ™ní signál %d. TigerVNC se nyní ukonÄí."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
+msgstr "Byl pÅ™ijat ukonÄovací signál %d. ProhlížeÄ TigerVNC se nyní ukonÄí."
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "ProhlížeÄ TigerVNC"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Ano"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Zavřít"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "O aplikaci"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Skrýt"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "UkonÄit"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Služby"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Skrýt ostatní"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Ukázat všechny"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Soubor"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Nové spojení"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Usage: %s [parametry] [stroj][:Äíslo_displeje]\n"
+" %s [parametry] [stroj][::port]\n"
+" %s [parametry] [unixový_socket]\n"
+" %s [parametry] -listen [port]\n"
+" %s [parametry] [soubor_.tigervnc]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"PÅ™epínaÄe:\n"
+"\n"
+" -display displej − UrÄuje displej X pro okno prohlížeÄe\n"
+" -geometry geometrie − PoÄáteÄní umístÄ›ní hlavního okna prohlížeÄe VNC. Pro\n"
+" podrobnosti nahlédněte to manuálu.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Parametry lze zapnout pomocí -<parametr> a vypnout pomocí -<parametr>=0.\n"
+"Parametry, které mají hodnotu, lze zadat jako -<parametr> <hodnota>.\n"
+"Další možné zápisy jsou <parametr>=<hodnota>, -<parametr>=<hodnota> a\n"
+"--<parametr>=<hodnota>.\n"
+"Názvy parametrů nerozlišují velikost písmen. Parametry jsou:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "Volba FullScreenAllMonitors je zastaralá, místo ní nastavte FullScreenMode na „all“"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor je zastaralý, místo toho nastavte AlwaysCursor na 1 a CursorType na „Dot“"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "Cesta ~/.vnc je zastaralá. Cestu, kam přejít, naleznete popsanou v „man vncviewer“."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "Cesta %%APPDATA%%\\vnc je zastaralá. Prosím, cestu změňte na %%APPDATA%%\\TigerVNC."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "Nebylo možné vytvoÅ™it konfiguraÄní adresář pro VNC: %s"
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Nebylo možné vytvoÅ™it konfiguraÄní adresář pro VNC „%s“: %s"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Nebylo možné urÄit datový adresář pro VNC"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Nebylo možné vytvořit datový adresář pro VNC „%s“: %s"
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "Nebylo možné vytvořit datový adresář pro VNC: %s"
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Nebylo možné vytvořit stavový adresář pro VNC „%s“: %s"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "Nebylo možné vytvořit stavový adresář pro VNC: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: Nerozpoznaný pÅ™epínaÄ â€ž%s\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "Podrobnosti získáte příkazem „%s --help“.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: NadbyteÄný argument „%s“\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Parametry -listen a -via se vzájemnÄ› vyluÄují"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Nelze zaÄít Äekat na příchozí spojení"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Poslouchá se na portu %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -991,10 +1084,38 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Sestavení šifrovaného tunelu se nezdařilo:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "ProhlížeÄ vzdálené plochy"
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Zobrazovat puntík, když chybí kurzor"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "Aktualizace stavu diod klávesnice se nezdařila: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "Při stisku klávesy nebyl zadán žádný kód klávesy"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "Žádný symbol pro kód klávesy 0x%02x (v souÄasném stavu)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "Neznámý typ parametru"
+
#~ msgid "VNC Viewer: Connection Options"
#~ msgstr "ProhlížeÄ VNC: Volby pÅ™ipojení"
diff --git a/po/de.po b/po/de.po
index 2e169852..543da734 100644
--- a/po/de.po
+++ b/po/de.po
@@ -3,13 +3,13 @@
# This file is distributed under the same license as the tigervnc package.
#
# Klaus Franken <Klaus.Franken@StrukturPunkt.de>, 2005.
-# Mario Blättermann <mario.blaettermann@gmail.com>, 2014-2016, 2019, 2021, 2022.
+# Mario Blättermann <mario.blaettermann@gmail.com>, 2014-2016, 2019, 2021-2022, 2025.
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.12.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2022-12-15 16:35+0100\n"
-"PO-Revision-Date: 2022-12-16 15:57+0100\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-21 18:42+0100\n"
"Last-Translator: Mario Blättermann <mario.blaettermann@gmail.com>\n"
"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
"Language: de\n"
@@ -18,14 +18,14 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Lokalize 22.08.3\n"
+"X-Generator: Lokalize 24.12.1\n"
-#: vncviewer/CConn.cxx:103
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Verbunden mit Socket %s"
-#: vncviewer/CConn.cxx:110
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Verbunden mit Rechner %s, Port %d"
@@ -41,112 +41,128 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:159
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Desktop-Name: %.80s"
-#: vncviewer/CConn.cxx:164
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Rechner: %.80s Port: %d"
-#: vncviewer/CConn.cxx:169
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Größe: %d x %d"
-#: vncviewer/CConn.cxx:177
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Pixelformat: %s"
-#: vncviewer/CConn.cxx:184
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(Server-Vorgabe %s)"
-#: vncviewer/CConn.cxx:189
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Angeforderte Zeichenkodierung: %s"
-#: vncviewer/CConn.cxx:194
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "Zuletzt verwendete Zeichenkodierung: %s"
-#: vncviewer/CConn.cxx:199
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Geschätzte Verbindungsgeschwindigkeit: %d kbit/s"
-#: vncviewer/CConn.cxx:204
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Protokollversion: %d.%d"
-#: vncviewer/CConn.cxx:209
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Sicherheitsmethode: %s"
-#: vncviewer/CConn.cxx:270 vncviewer/CConn.cxx:272
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Die Verbindung wurde vom Server abgebrochen, bevor die Sitzung eingerichtet werden konnte."
-#: vncviewer/CConn.cxx:332
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Authentifizierung fehlgeschlagen: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Authentifizierung am Server ist fehlgeschlagen. Vom Server angegebener Grund:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "SetDesktopSize fehlgeschlagen: %d"
-#: vncviewer/CConn.cxx:404
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "Ungültige SetColourMapEntries vom Server!"
-#: vncviewer/CConn.cxx:512
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "Durchsatz %d kbit/s - Qualität wird auf %d geändert"
-#: vncviewer/CConn.cxx:534
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "Durchsatz %d kbit/s - Vollfarbmodus ist jetzt aktiviert"
-#: vncviewer/CConn.cxx:537
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "Durchsatz %d kbit/s - Vollfarbmodus ist jetzt deaktiviert"
-#: vncviewer/CConn.cxx:563
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Pixelformat %s wird verwendet"
-#: vncviewer/DesktopWindow.cxx:145
+#: vncviewer/DesktopWindow.cxx:146
msgid "Invalid geometry specified!"
msgstr "Unzulässige Geometrie wurde angegeben!"
-#: vncviewer/DesktopWindow.cxx:166
+#: vncviewer/DesktopWindow.cxx:167
msgid "Reducing window size to fit on current monitor"
msgstr "Fenstergröße an den aktuellen Bildschirm anpassen"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Fenstergröße anpassen, um zufällige Vollbild-Anforderung zu vermeiden"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "Drücken Sie %s, um das Kontextmenü zu öffnen"
-#: vncviewer/DesktopWindow.cxx:1083 vncviewer/DesktopWindow.cxx:1091
-#: vncviewer/DesktopWindow.cxx:1111
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Fehler beim Erkennen der Tastatur"
-#: vncviewer/DesktopWindow.cxx:1401
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Ungültige Bildschirmanordnung wurde für die Größenänderungsanforderung ermittelt!"
@@ -154,251 +170,307 @@ msgstr "Ungültige Bildschirmanordnung wurde für die Größenänderungsanforder
msgid "Invalid state for 3 button emulation"
msgstr "Unzulässiger Status für 3-Tasten-Emulation"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Kein Scan-Code für erweiterte virtuelle Taste 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Kein Scan-Code für virtuelle Taste 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Ungültiger Scancode 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Kein Symbol für erweiterte virtuelle Taste 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Kein Symbol für virtuelle Taste 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Tastatur-LED-Status konnte nicht aktualisiert werden: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Kein Symbol für Tastencode %d (im aktuellen Zustand)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Tastatur-LED-Status konnte nicht ermittelt werden: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Tastatur-LED-Status konnte nicht aktualisiert werden"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:105
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Konfiguration des Systembildschirms konnte nicht ermittelt werden"
-#: vncviewer/MonitorIndicesParameter.cxx:83
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Unzulässige Konfiguration für %s wurde angegeben"
-#: vncviewer/MonitorIndicesParameter.cxx:91
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Bildschirm-Index %d existiert nicht"
-#: vncviewer/MonitorIndicesParameter.cxx:169
-#: vncviewer/MonitorIndicesParameter.cxx:189
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Unzulässiger Bildschirm-Index »%s«"
-#: vncviewer/MonitorIndicesParameter.cxx:177
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Unerwartetes Zeichen »%c«"
-#: vncviewer/OptionsDialog.cxx:63
-msgid "VNC Viewer: Connection Options"
-msgstr "VNC-Betrachter: Verbindungsoptionen"
+#: vncviewer/OptionsDialog.cxx:64
+msgid "TigerVNC options"
+msgstr "TigerVNC-Optionen"
-#: vncviewer/OptionsDialog.cxx:89 vncviewer/ServerDialog.cxx:108
-#: vncviewer/vncviewer.cxx:417
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Abbrechen"
-#: vncviewer/OptionsDialog.cxx:94 vncviewer/vncviewer.cxx:416
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "OK"
-#: vncviewer/OptionsDialog.cxx:484
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Kompression"
-#: vncviewer/OptionsDialog.cxx:501
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Automatisch auswählen"
-#: vncviewer/OptionsDialog.cxx:516
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Bevorzugte Kodierung"
-#: vncviewer/OptionsDialog.cxx:574
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Farbstufe"
-#: vncviewer/OptionsDialog.cxx:585
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Vollständig"
-#: vncviewer/OptionsDialog.cxx:592
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Mittel"
-#: vncviewer/OptionsDialog.cxx:599
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Niedrig"
-#: vncviewer/OptionsDialog.cxx:606
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Sehr niedrig"
-#: vncviewer/OptionsDialog.cxx:624
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Individuelle Kompressionsstufe:"
-#: vncviewer/OptionsDialog.cxx:630
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "Stufe (0=schnellste, 9=beste)"
-#: vncviewer/OptionsDialog.cxx:637
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "JPEG-Kompression erlauben:"
-#: vncviewer/OptionsDialog.cxx:643
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "Qualität (0=schlechte, 9=beste)"
-#: vncviewer/OptionsDialog.cxx:654
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "Sicherheit"
-#: vncviewer/OptionsDialog.cxx:676
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Verschlüsselung"
-#: vncviewer/OptionsDialog.cxx:687 vncviewer/OptionsDialog.cxx:750
-#: vncviewer/OptionsDialog.cxx:854
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Keine"
-#: vncviewer/OptionsDialog.cxx:694
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS mit anonymen Zertifikaten"
-#: vncviewer/OptionsDialog.cxx:700
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS mit X509-Zertifikaten"
-#: vncviewer/OptionsDialog.cxx:707
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Pfad zum X509-CA-Zertifikat"
-#: vncviewer/OptionsDialog.cxx:714
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Pfad zur X509-CRL-Datei"
-#: vncviewer/OptionsDialog.cxx:739
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Authentifizierung"
-#: vncviewer/OptionsDialog.cxx:756
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Standard-VNC (unsicher ohne Verschlüsselung)"
-#: vncviewer/OptionsDialog.cxx:762
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Benutzername und Passwort (unsicher ohne Verschlüsselung)"
-#: vncviewer/OptionsDialog.cxx:781
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Eingabe"
-#: vncviewer/OptionsDialog.cxx:794
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Nur Ansicht (Maus und Tastatur ignorieren)"
-#: vncviewer/OptionsDialog.cxx:801
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Maus"
-#: vncviewer/OptionsDialog.cxx:815
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Mittlere Maustaste emulieren"
-#: vncviewer/OptionsDialog.cxx:821
-msgid "Show dot when no cursor"
-msgstr "Punkt zeigen, wenn kein Cursor"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Lokalen Cursor anzeigen, wenn der Server keinen bereitstellt"
-#: vncviewer/OptionsDialog.cxx:835
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Cursortyp"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Dot"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "System"
+
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Tastatur"
-#: vncviewer/OptionsDialog.cxx:849
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Systemtasten direkt an den Server übergeben (Vollbild)"
-#: vncviewer/OptionsDialog.cxx:852
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Menü-Taste"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Zwischenablage"
-#: vncviewer/OptionsDialog.cxx:885
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Zwischenablage vom Server akzeptieren"
-#: vncviewer/OptionsDialog.cxx:893
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Primäre Auswahl ebenfalls setzen"
-#: vncviewer/OptionsDialog.cxx:900
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Zwischenablage zum Server senden"
-#: vncviewer/OptionsDialog.cxx:908
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Primäre Auswahl als Zwischenablage senden"
-#: vncviewer/OptionsDialog.cxx:927
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Anzeige"
-#: vncviewer/OptionsDialog.cxx:941
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Anzeigemodus"
-#: vncviewer/OptionsDialog.cxx:956
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "Fenster anpassen"
-#: vncviewer/OptionsDialog.cxx:964
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Vollbild auf dem aktuellen Bildschirm"
-#: vncviewer/OptionsDialog.cxx:972
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Vollbild auf allen Bildschirmen"
-#: vncviewer/OptionsDialog.cxx:980
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Vollbild auf ausgewählte(n) Bildschirm(en)"
-#: vncviewer/OptionsDialog.cxx:1007
-msgid "Misc."
-msgstr "Sonstiges"
+#: vncviewer/OptionsDialog.cxx:1062
+msgid "Miscellaneous"
+msgstr "Verschiedenes"
-#: vncviewer/OptionsDialog.cxx:1015
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Gemeinsamer Zugriff (andere VNC-Viewer nicht trennen)"
-#: vncviewer/OptionsDialog.cxx:1021
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Bei Verbindungsfehlern um erneute Verbindung nachfragen"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "VNC-Betrachter: Verbindungsdetails"
-#: vncviewer/ServerDialog.cxx:65 vncviewer/ServerDialog.cxx:70
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "VNC-Server:"
-#: vncviewer/ServerDialog.cxx:81
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Optionen …"
-#: vncviewer/ServerDialog.cxx:86
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Laden..."
-#: vncviewer/ServerDialog.cxx:91
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Speichern unter …"
-#: vncviewer/ServerDialog.cxx:103
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "Info …"
-#: vncviewer/ServerDialog.cxx:113
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Verbinden"
-#: vncviewer/ServerDialog.cxx:145
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -409,15 +481,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:173 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "TigerVNC-Konfiguration (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:174
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Eine TigerVNC-Konfigurationsdatei wählen"
-#: vncviewer/ServerDialog.cxx:196 vncviewer/vncviewer.cxx:552
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -428,24 +500,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Eine TigerVNC-Konfigurationsdatei speichern"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s existiert bereits. Wollen Sie es überschreiben?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:414
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Nein"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Überschreiben"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -456,7 +528,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -467,7 +539,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -478,202 +550,142 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:387
-#: vncviewer/parameters.cxx:635 vncviewer/parameters.cxx:740
-#: vncviewer/vncviewer.cxx:459
-msgid "Could not obtain the home directory path"
-msgstr "Pfad zum Home-Verzeichnis konnte nicht ermittel werden"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Pfad zum VNC-Statusverzeichnis konnte nicht ermittelt werden"
-#: vncviewer/ServerDialog.cxx:333 vncviewer/ServerDialog.cxx:396
-#: vncviewer/parameters.cxx:646 vncviewer/parameters.cxx:753
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "»%s« konnte nicht geöffnet werden: %s"
+msgid "Could not open \"%s\""
+msgstr "»%s« konnte nicht geöffnet werden"
-#: vncviewer/ServerDialog.cxx:348 vncviewer/ServerDialog.cxx:356
-#: vncviewer/parameters.cxx:767 vncviewer/parameters.cxx:773
-#: vncviewer/parameters.cxx:804 vncviewer/parameters.cxx:833
-#: vncviewer/parameters.cxx:839
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Zeile %d in Datei %s konnte nicht gelesen werden: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Zeile %d in Datei %s konnte nicht gelesen werden"
-#: vncviewer/ServerDialog.cxx:357 vncviewer/parameters.cxx:774
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Zeile ist zu lang"
-#: vncviewer/UserDialog.cxx:98
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Öffnen der Passwortdatei fehlgeschlagen"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "VNC-Autorisierung"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Diese Verbindung ist sicher"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Diese Verbindung ist nicht sicher"
-#: vncviewer/UserDialog.cxx:146
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Benutzername:"
-#: vncviewer/UserDialog.cxx:159
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Passwort:"
-#: vncviewer/UserDialog.cxx:198
-msgid "Authentication cancelled"
-msgstr "Authentifizierung abgebrochen"
-
-#: vncviewer/Viewport.cxx:391
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Tastatur-LED-Status konnte nicht aktualisiert werden: %lu"
-
-#: vncviewer/Viewport.cxx:397 vncviewer/Viewport.cxx:403
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Tastatur-LED-Status konnte nicht aktualisiert werden: %d"
-
-#: vncviewer/Viewport.cxx:433
-msgid "Failed to update keyboard LED state"
-msgstr "Tastatur-LED-Status konnte nicht aktualisiert werden"
-
-#: vncviewer/Viewport.cxx:460 vncviewer/Viewport.cxx:468
-#: vncviewer/Viewport.cxx:485
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Tastatur-LED-Status konnte nicht ermittelt werden: %d"
-
-#: vncviewer/Viewport.cxx:849
-msgid "No key code specified on key press"
-msgstr "Kein Tastencode beim Tastendruck angegeben"
-
-#: vncviewer/Viewport.cxx:1008
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Kein Scan-Code für erweiterte virtuelle Taste 0x%02x"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Passwort für Wiederverbinden merken"
-#: vncviewer/Viewport.cxx:1010
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Kein Scan-Code für virtuelle Taste 0x%02x"
-
-#: vncviewer/Viewport.cxx:1016
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Ungültiger Scancode 0x%02x"
-
-#: vncviewer/Viewport.cxx:1046
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Kein Symbol für erweiterte virtuelle Taste 0x%02x"
-
-#: vncviewer/Viewport.cxx:1048
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Kein Symbol für virtuelle Taste 0x%02x"
-
-#: vncviewer/Viewport.cxx:1154
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Kein Symbol für Tastencode 0x%02x (im aktuellen Zustand)"
-
-#: vncviewer/Viewport.cxx:1187
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Kein Symbol für Tastencode %d (im aktuellen Zustand)"
-
-#: vncviewer/Viewport.cxx:1247
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
-msgid "Dis&connect"
+msgid "Disconn&ect"
msgstr "Verbindung &trennen"
-#: vncviewer/Viewport.cxx:1250
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&Vollbildmodus"
-#: vncviewer/Viewport.cxx:1253
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "M&inimieren"
-#: vncviewer/Viewport.cxx:1255
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "&Fenster an Sitzung anpassen"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Strg"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1269
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "%s senden"
-#: vncviewer/Viewport.cxx:1275
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Strg-Alt-E&ntf senden"
-#: vncviewer/Viewport.cxx:1278
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "Bildschirm &aktualisieren"
-#: vncviewer/Viewport.cxx:1281
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&Optionen …"
-#: vncviewer/Viewport.cxx:1283
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "Verbindungs&informationen …"
-#: vncviewer/Viewport.cxx:1285
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "Info zu &TigerVNC-Betrachter …"
-#: vncviewer/Viewport.cxx:1374
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "VNC-Verbindungsinformation"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Fenster ist für Touch-Bedienung anstelle von Gesten registriert"
-#: vncviewer/Win32TouchHandler.cxx:81
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Gesten-Konfiguration konnte nicht gesetzt werden (Fehler 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:93
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Gesten-Konfiguration konnte nicht ermittelt werden (Fehler 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:358
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Unzulässige Maustaste %d; muss eine Zahl von 1 bis 7 sein."
-#: vncviewer/Win32TouchHandler.cxx:423
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Nicht verarbeitbare Taste 0x%x - Tastaturereignis kann nicht erstellt werden."
@@ -699,7 +711,6 @@ msgid "Failure grabbing device %i"
msgstr "Fehler beim Erkennen des Geräts %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:406 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "TigerVNC-Betrachter"
@@ -717,87 +728,92 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC ist eine Hochgeschwindigkeitsversion von VNC, basierend auf den Codebasen von RealVNC 4 und X.org. TigerVNC begann als Weiterentwicklung von TightVNC auf Unix- und Linux-Plattformen und trennte sich Anfang 2009 von seinem Vorgängerprojekt, so dass sich TightVNC auf Windows-Plattformen konzentrieren konnte. TigerVNC unterstützt eine Variante von Tight Encoding, das durch die Verwendung des JPEG-Codecs »libjpeg-turbo« erheblich beschleunigt wird."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr "TigerVNC-Betrachter-Verbindung zu einem CentOS-Rechner"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr "TigerVNC-Betrachter-Verbindung zu einem macOS-Rechner"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr "TigerVNC-Betrachter-Verbindung zu einem Windows-Rechner"
-#: vncviewer/parameters.cxx:308 vncviewer/parameters.cxx:333
-#: vncviewer/parameters.cxx:350 vncviewer/parameters.cxx:390
-#: vncviewer/parameters.cxx:410
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "Das TigerVNC-Team"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Der Parametername ist zu lang"
-#: vncviewer/parameters.cxx:312 vncviewer/parameters.cxx:317
-#: vncviewer/parameters.cxx:368
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Der Parameter ist zu groß"
-#: vncviewer/parameters.cxx:375 vncviewer/parameters.cxx:696
-#: vncviewer/parameters.cxx:818
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Ungültiges Format oder zu großer Wert"
-#: vncviewer/parameters.cxx:429 vncviewer/parameters.cxx:460
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Registrierungsschlüssel konnte nicht erzeugt werden"
-#: vncviewer/parameters.cxx:448 vncviewer/parameters.cxx:503
-#: vncviewer/parameters.cxx:545 vncviewer/parameters.cxx:612
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Registrierungsschlüssel konnte nicht geschlossen werden"
-#: vncviewer/parameters.cxx:466 vncviewer/parameters.cxx:483
-#: vncviewer/parameters.cxx:654 vncviewer/parameters.cxx:664
-#: vncviewer/parameters.cxx:675
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "»%s« konnte nicht gespeichert werden: %s"
-#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:567
-#: vncviewer/parameters.cxx:677 vncviewer/parameters.cxx:714
-msgid "Unknown parameter type"
-msgstr "Unbekannter Parametertyp"
-
-#: vncviewer/parameters.cxx:496
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "»%s« konnte nicht entfernt werden: %s"
-#: vncviewer/parameters.cxx:518 vncviewer/parameters.cxx:590
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Registrierungsschlüssel konnte nicht geöffnet werden"
-#: vncviewer/parameters.cxx:535
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Eintrag %d in der Server-Chronik konnte nicht gelesen werden: %s"
-#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:601
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Parameter »%s« konnte nicht gelesen werden: %s"
-#: vncviewer/parameters.cxx:655 vncviewer/parameters.cxx:666
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Pfad zum VNC-Konfigurationsverzeichnis konnte nicht ermittelt werden"
+
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Parameter konnte nicht kodiert werden"
-#: vncviewer/parameters.cxx:783
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Format der Konfigurationsdatei %s ist ungültig"
-#: vncviewer/parameters.cxx:805
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Ungültiges Format"
-#: vncviewer/parameters.cxx:840
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Unbekannter Parameter"
@@ -821,32 +837,32 @@ msgstr "Touch-Handler konnte nicht erzeugt werden: %s"
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Ereignishandler konnte nicht an Fenster angehängt werden (Fehler 0x%x)"
-#: vncviewer/touch.cxx:212
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Ereignisdaten für X-Input-Ereignis konnten nicht erhalten werden"
-#: vncviewer/touch.cxx:225
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "X-Input-Ereignis für unbekanntes Fenster"
-#: vncviewer/touch.cxx:251
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "X-Input-Erweiterung ist nicht verfügbar."
-#: vncviewer/touch.cxx:258
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "X-Input 2 (oder neuer) ist nicht verfügbar."
-#: vncviewer/touch.cxx:263
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "X-Input 2.2 (oder neuer) ist nicht verfügbar. Touch-Gesten werden nicht unterstützt."
-#: vncviewer/vncviewer.cxx:107
+#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"TigerVNC-Betrachter Version %s\n"
@@ -854,7 +870,7 @@ msgstr ""
"Copyright (C) 1999-%d TigerVNC-Team und viele andere (siehe README.rst)\n"
"Siehe https://www.tigervnc.org für Informationen zu TigerVNC."
-#: vncviewer/vncviewer.cxx:161
+#: vncviewer/vncviewer.cxx:158
#, c-format
msgid ""
"An unexpected error occurred when communicating with the server:\n"
@@ -865,15 +881,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/vncviewer.cxx:177
+#: vncviewer/vncviewer.cxx:174
msgid "About TigerVNC Viewer"
msgstr "Info zu TigerVNC-Betrachter"
-#: vncviewer/vncviewer.cxx:198
+#: vncviewer/vncviewer.cxx:195
msgid "Internal FLTK error. Exiting."
msgstr "Interner FLTK-Fehler. Abbruch."
-#: vncviewer/vncviewer.cxx:217
+#: vncviewer/vncviewer.cxx:214
#, c-format
msgid ""
"%s\n"
@@ -884,79 +900,183 @@ msgstr ""
"\n"
"Versuchen, die Verbindung erneut aufzubauen?"
-#: vncviewer/vncviewer.cxx:248 vncviewer/vncviewer.cxx:260
+#: vncviewer/vncviewer.cxx:245 vncviewer/vncviewer.cxx:257
#, c-format
msgid "Error starting new TigerVNC Viewer: %s"
msgstr "Fehler beim Starten des neuen TigerVNC-Betrachters: %s"
-#: vncviewer/vncviewer.cxx:269
+#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr "Terminierungssignal %d wurde empfangen. Der TigerVNC-Betrachter wird nun beendet."
-#: vncviewer/vncviewer.cxx:415
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "TigerVNC-Betrachter"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Ja"
-#: vncviewer/vncviewer.cxx:418
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Schließen"
-#: vncviewer/vncviewer.cxx:423
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "Info"
-#: vncviewer/vncviewer.cxx:426
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Verbergen"
-#: vncviewer/vncviewer.cxx:429
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Beenden"
-#: vncviewer/vncviewer.cxx:433
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Dienste"
-#: vncviewer/vncviewer.cxx:434
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Andere verbergen"
-#: vncviewer/vncviewer.cxx:435
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Alle zeigen"
-#: vncviewer/vncviewer.cxx:444
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Datei"
-#: vncviewer/vncviewer.cxx:447
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Neue Verbindung"
-#: vncviewer/vncviewer.cxx:463
+#: vncviewer/vncviewer.cxx:450
#, c-format
-msgid "Could not create VNC home directory: %s"
-msgstr "VNC-Benutzerverzeichnis konnte nicht erstellt werden: %s"
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Aufruf: %s [Parameter] [Host][:Displaynummer]\n"
+" %s [Parameter] [Host][::Port]\n"
+" %s [Parameter] [Unix-Socket]\n"
+" %s [Parameter] -listen [Port]\n"
+" %s [Parameter] [.tigervnc-Datei]\n"
-#: vncviewer/vncviewer.cxx:562
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Optionen:\n"
+"\n"
+" -display X-Display - Gibt das X-Display für das Betrachterfenster an\n"
+" -geometry Geometrie - Anfängliche Position des Hauptfensters des VNC-\n"
+" Betrachters. In der Handbuchseite finden Sie weitere\n"
+" Details.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Parameter können mit -<Parameter> eingeschaltet oder mit -<Parameter>=0\n"
+"ausgeschaltet werden. Parameter, welche einen Wert akzeptieren, können als\n"
+"-<Parameter> <Wert> angegeben werden; außerdem sind die Formen\n"
+"<Parameter>=<Wert>, -<Parameter>=<Wert> oder --<Parameter>=<Wert> möglich.\n"
+"Für die Parameternamen wird Groß-/Kleinschreibung nicht berücksichtigt.\n"
+"Die Parameter sind:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "FullScreenAllMonitors ist veraltet, setzen Sie stattdessen FullScreenMode auf »all«"
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor ist veraltet, setzen Sie stattdessen AlwaysCursor auf 1 und CursorType auf »Dot«"
+
+#: vncviewer/vncviewer.cxx:553
+msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
+msgstr "~/.vnc ist veraltet, bitte rufen Sie »man vncviewer« auf, um Informationen zu den Pfaden zu erhalten, auf die Sie migrieren können."
+
+#: vncviewer/vncviewer.cxx:557
+#, c-format
+msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
+msgstr "%%APPDATA%%\\vnc ist veraltet, bitte wechseln Sie zum %%APPDATA%%\\TigerVNC-Ort."
+
+#: vncviewer/vncviewer.cxx:562
+#, c-format
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "VNC-Konfigurationsverzeichnis »%s« konnte nicht erstellt werden: %s"
+
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Pfad zum VNC-Datenverzeichnis konnte nicht ermittelt werden"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "VNC-Datenverzeichnis »%s« konnte nicht erstellt werden: %s"
+
+#: vncviewer/vncviewer.cxx:586
+#, c-format
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "VNC-Statusverzeichnis »%s« konnte nicht erstellt werden: %s"
+
+#: vncviewer/vncviewer.cxx:703
+#, c-format
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: Nicht erkannte Option »%s«\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "Siehe »%s --help« für weitere Informationen.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Zusätzliches Argument »%s«\n"
+
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:768 vncviewer/vncviewer.cxx:769
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Die Parameter -listen und -via schließen sich gegenseitig aus"
-#: vncviewer/vncviewer.cxx:783
+#: vncviewer/vncviewer.cxx:763
+msgid "Unable to listen for incoming connections"
+msgstr "Warten auf eingehende Verbindungen ist nicht möglich"
+
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Am Port %d wird gelauscht"
-#: vncviewer/vncviewer.cxx:816
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -967,6 +1087,17 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Einrichtung des verschlüsselten Tunnels ist fehlgeschlagen:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "Betrachter für ferne Bildschirme"
diff --git a/po/es.po b/po/es.po
index 2adc2638..98baec70 100644
--- a/po/es.po
+++ b/po/es.po
@@ -1,14 +1,14 @@
# Spanish translation for tigervnc.
-# Copyright (C) 2018, 2022, 2023, 2024 the TigerVNC Team (msgids)
+# Copyright (C) 2018, 2022, 2023, 2024, 2025 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
# Francisco Javier Serrador <fserrador@gmail.com>, 2018.
-# Cristian Othón Martínez Vera <cfuga@cfuga.mx>, 2022, 2023, 2024.
+# Cristian Othón Martínez Vera <cfuga@cfuga.mx>, 2022, 2023, 2024, 2025.
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-20 14:49-0600\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-21 10:33-0600\n"
"Last-Translator: Cristian Othón Martínez Vera <cfuga@cfuga.mx>\n"
"Language-Team: Spanish <es@tp.org.es>\n"
"Language: es\n"
@@ -18,17 +18,17 @@ msgstr ""
"X-Bugs: Report translation errors to the Language-Team address.\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Conectado al zócalo %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Conectado al anfitrión %s puerto %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -39,85 +39,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Nombre del escritorio: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Anfitrión: %.80s puerto: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Tamaño: %d x %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Formato de pixel: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(servidor pred. %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Codificación solicitada: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "Última codificación empleada: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Velocidad de línea estimada: %d kbit/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Versión de protocolo: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Método de seguridad: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "La conexión fue rechazada por el servidor antes de que la sesión se pudiera establecer."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Falló la autenticación: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Falló al autenticar con el servidor. Razón dada por el servidor:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "Error en SetDesktopSize: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "¡SetColourMapEntries inválida del servidor!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "Procesamiento %d kbit/s - cambiado a calidad %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "Procesamiento %d kbit/s - se activa el color total"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "Procesamiento %d kbit/s - se desactiva el color total"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Utilizando formato de pixel %s"
@@ -130,21 +146,21 @@ msgstr "¡Se especificó una geometría inválida!"
msgid "Reducing window size to fit on current monitor"
msgstr "Se reduce el tamaño de ventana para ajustar al monitor actual"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Se ajusta el tamaño de ventana para evitar peticiones accidentales de pantalla completa"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "Pulse %s para abrir el menú contextual"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Error al coger el teclado"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "¡Disposición de pantalla computada inválida para petición de redimensionado!"
@@ -152,251 +168,307 @@ msgstr "¡Disposición de pantalla computada inválida para petición de redimen
msgid "Invalid state for 3 button emulation"
msgstr "Estado inválido para la emulación de 3 botones"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "No hay un código de rastreo para la tecla virtual extendida 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "No hay un código de rastreo para la tecla virtual 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Código de rastreo 0x%02x inválido"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "No hay un símbolo para la tecla virtual extendida 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "No hay un símbolo para la tecla virtual 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Falló al actualizar el estado de LED del teclado: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "No hay un símbolo para el código de tecla %d (en el estado actual)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Falló al obtener el estado de LED del teclado: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Falló al actualizar el estado de LED del teclado"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Falló al obtener la configuración del monitor del sistema"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Se especificó una configuración inválida para %s"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "El índice de monitor %d no existe"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Ãndice de monitor '%s' inválido"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Carácter '%c' inesperado"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "Opciones de TigerVNC"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Cancelar"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "Aceptar"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Compresión"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Autoseleccionar"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Codificación preferida"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Nivel de color"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Total"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Medio"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Bajo"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Muy bajo"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Nivel de compresión personal:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "calidad (0=rápido, 9=mejor)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Permitir compresión JPEG:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "calidad (0=peor, 9=mejor)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "Seguridad"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Cifrado"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Ninguno"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS con certificados anónimos"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS con certificados X509"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Ruta a AC de certificado X509"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Ruta a fichero CRL de X509"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Autenticación"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "VNC común (inseguro sin cifrado)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Usuario y contraseña (inseguro sin cifrado)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Entrada"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Ver solo (ignora ratón y teclado)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Ratón"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Emula el botón medio del ratón"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Muestra punto cuando no hay cursor"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Muestra el cursor local cuando el servidor no lo proporciona"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Tipo de cursor"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Punto"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "Sistema"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Teclado"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Pasa las teclas del sistema directamente al servidor (pantalla completa)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Tecla Menú"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Portapapeles"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Acepta texto desde el portapapeles"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Además establece selección primaria"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Envía portapapel al servidor"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Envía selección primaria como portapapeles"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Despliegue"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Modo de despliegue"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "Ventana"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Pantalla completa en el monitor actual"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Pantalla completa en todos los monitores"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Pantalla completa en el(los) monitor(es) seleccionado(s)"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Misceláneos"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Compartido (no desconecta otras visores)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Pregunta para reconectar después de errores de conexión"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "Visor VNC: Datos de conexión"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "Servidor VNC:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Opciones..."
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Cargar..."
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Guardar como..."
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "Acerca de..."
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Conectar"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -407,15 +479,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "Configuración de TigerVNC (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Selecciona un fichero de configuración TigerVNC"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -426,24 +498,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Guarda la configuración de TigerVNC en el fichero"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s ya existe. ¿Lo quiere sobreescribir?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "No"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Sobreescribir"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -453,7 +525,7 @@ msgstr ""
"No se puede guardar el fichero de configuración especificado:\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -464,7 +536,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -475,205 +547,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "No se puede obtener la ruta del directorio de estado"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "No se puede obtener la ruta del directorio de estado de VNC"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "No se puede abrir \"%s\": %s"
+msgid "Could not open \"%s\""
+msgstr "No se puede abrir \"%s\""
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Falló al leer la línea %d en el fichero %s: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Falló al leer la línea %d en el fichero \"%s\""
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Línea demasiado larga"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Falló al abrir el fichero de contraseña"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "Autenticación VNC"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Esta conexión es segura"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Esta conexión no es segura"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Usuario:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Contraseña:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Autenticación cancelada"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Falló al actualizar el estado de LED del teclado: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Falló al actualizar el estado de LED del teclado: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "Falló al actualizar el estado de LED del teclado"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Falló al obtener el estado de LED del teclado: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "No se especificó un código de tecla al presionar la tecla"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "No hay un código de rastreo para la tecla virtual extendida 0x%02x"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Conserva la contraseña para reconexión"
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "No hay un código de rastreo para la tecla virtual 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Código de rastreo 0x%02x inválido"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "No hay un símbolo para la tecla virtual extendida 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "No hay un símbolo para la tecla virtual 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "No hay un símbolo para el código de tecla 0x%02x (en el estado actual)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "No hay un símbolo para el código de tecla %d (en el estado actual)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "Des&conectar"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&Pantalla completa"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "Minimi&zar"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "Redimensionar &ventana a sesión"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Enviar %s"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Enviar Ctrl+Alt+&Supr"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "&Actualizar pantalla"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&Opciones..."
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "&Info de conexión..."
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "Acerca del visor &TigerVNC..."
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Info de conexión VNC"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "La ventana está registrada para toques en lugar de gestos"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Falló al definir la configuración de gestos (error 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Falló al obtener la información de gestos (error 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Botón de ratón %d inválido, debe ser un número entre 1 y 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Tecla 0x%x sin manejar - no se puede generar un evento de teclado."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "No se puede obtener la máscara de evento X Input 2 para la ventana 0x%08lx"
@@ -683,7 +697,7 @@ msgstr "No se puede obtener la máscara de evento X Input 2 para la ventana 0x%0
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "La ventana 0x%08lx no tiene máscara de evento X Input 2"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "La ventana 0x%08lx tiene más de una máscara de evento X Input 2"
@@ -694,7 +708,6 @@ msgid "Failure grabbing device %i"
msgstr "Error al coger el dispositivo %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "Visor TigerVNC"
@@ -712,140 +725,141 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC es una versión de alta velocidad de VNC basada en las bases de código de RealVNC 4 y X.org. TigerVNC empezó como un esfuerzo de desarrollo de próxima generación para TightVNC en plataformas Unix y Linux, pero se separó de su proyecto padre a inicios del 2009 para que TightVNC se enfocara en plataformas Windows. TigerVNC admite una variante de la codificación Tight que tiene una gran aceleración por el uso del codificador JPEG de libjpeg-turbo."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
-msgstr "Conexión de Visor TigerVNC a una máquina CentOS"
+msgid "TigerVNC viewer connection to a CentOS machine"
+msgstr "Conexión de visor TigerVNC a una máquina CentOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
-msgstr "Conexión de Visor TigerVNC a una máquina macOS"
+msgid "TigerVNC viewer connection to a macOS machine"
+msgstr "Conexión de visor TigerVNC a una máquina macOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
-msgstr "Conexión de Visor TigerVNC a una máquina Windows"
-
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+msgid "TigerVNC viewer connection to a Windows machine"
+msgstr "Conexión de visor TigerVNC a una máquina Windows"
+
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "El equipo TigerVNC"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "El nombre del parámetro es demasiado grande"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "El parámetro es demasiado grande"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Formato inválido o valor demansiado grande"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Falló al crear la llave de registro"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Falló al cerrar la llave de registro"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Falló al guardar \"%s\": %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Parámetro de tipo desconocido"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Falló al borrar \"%s\": %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Falló al abrir la llave de registro"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Falló al leer la entrada de histora del servidor %d: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Falló al leer el parámetro \"%s\": %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "No se puede obtener la ruta del directorio de configuración"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "No se puede obtener la ruta del directorio de configuración de VNC"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "No se puede codificar el parámetro"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "El fichero de configuración %s tiene un formato inválido"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Formato inválido"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Parámetro desconocido"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Se recibió el mensaje (0x%x) de una ventana sin manejar"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "Se especificó la ventana 0x%08lx inválida para sujetar el puntero"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "Falló al crear el manejador de toque: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "No se puede asociar el manejador de eventos a la ventana (error 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Falló al obtener datos de eventos para eventos X Input"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "Evento X Input para una ventana desconocida"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "La extensión X Input no está disponible."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "X Input 2 (o más reciente) no está disponible."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "X Input 2.2 (o más reciente) no está disponible. No se admitirán los gestos de toque."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"Visor de TigerVNC v%s\n"
@@ -890,95 +904,174 @@ msgstr "Error al iniciar un nuevo visor TigerVNC: %s"
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr "Se recibió la señal de terminación %d. El visor TigerVNC terminará ahora."
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "Visor TigerVNC"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Sí"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Cerrar"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "Acerca de"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Ocultar"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Salir"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Servicios"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
-msgstr "Ocultar Otros"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
+msgstr "Ocultar otros"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
-msgstr "Mostrar Todos"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
+msgstr "Mostrar todos"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Archivo"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Nueva conexión"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Uso: %s [parámetros] [anfitrión][:Numpantalla]\n"
+" %s [parámetros] [anfitrión][::puerto]\n"
+" %s [parámetros] [zócalo unix]\n"
+" %s [parámetros] -listen [puerto]\n"
+" %s [parámetros] [fichero .tigervnc]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Opciones:\n"
+"\n"
+" -display Xdisplay - Especifica el despliegue X para la ventana del visor\n"
+" -geometry geometría - Posición inicial de la ventana principal del visor VNC\n"
+" Consulte la página del manual para más detalles.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Los parámetros se pueden activar con -<param> o desactivar con -<param>=0\n"
+"Los parámetros que admiten un valor se pueden especificar como -<param> <valor>\n"
+"Otras formas válidas son <param>=<valor> -<param>=<valor> --<param>=<valor>\n"
+"Los nombres de parámetro no distinguen entre mayúsculas y minúsculas.\n"
+"Los parámetros son:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "FullScreenAllMonitors es obsoleto, en su lugar defina FullScreenMode a 'all'"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor es obsoleto, en su lugar defina AlwaysCursor a 1 y CursorType a 'Dot'"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "~/.vnc es obsoleto, por favor consulte 'man vncviewer' para conocer rutas de migración."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "%%APPDATA%%\\vnc es obsoleto, por favor cambie a la ubicación %%APPDATA%%\\TigerVNC."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "No se puede crear el directorio de inicio VNC: %s"
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "No se puede crear el directorio de inicio VNC \"%s\": %s"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "No se puede crear el directorio de datos VNC"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "No se puede crear el directorio de datos VNC \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "No se puede crear el directorio de datos VNC: %s"
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "No se puede crear el directorio de estado VNC \"%s\": %s"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "No se puede crear el directorio de estado VNC: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: No se reconoce la opción '%s'\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "Vea '%s --help' para más información.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Argumento '%s' extra\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Los parámetros -listen y -via son incompatibles"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "No se pueden escuchar las conexiones entrantes"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Escuchando en el puerto %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -989,9 +1082,37 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Falló al configurar el túnel cifrado:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
-msgstr "Visor de Escritorio Remoto"
+msgid "Remote desktop viewer"
+msgstr "Visor de escritorio eemoto"
+
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Muestra punto cuando no hay cursor"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "Falló al actualizar el estado de LED del teclado: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "No se especificó un código de tecla al presionar la tecla"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "No hay un símbolo para el código de tecla 0x%02x (en el estado actual)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "Parámetro de tipo desconocido"
#~ msgid "VNC Viewer: Connection Options"
#~ msgstr "Visor VNC: Opciones de conexión"
diff --git a/po/fi.po b/po/fi.po
index 938c9282..89438521 100644
--- a/po/fi.po
+++ b/po/fi.po
@@ -6,10 +6,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-22 21:10+0300\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-22 23:21+0200\n"
"Last-Translator: Lauri Nurmi <lanurmi@iki.fi>\n"
"Language-Team: Finnish <translation-team-fi@lists.sourceforge.net>\n"
"Language: fi\n"
@@ -18,19 +18,19 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Generator: Poedit 3.4.4\n"
+"X-Generator: Poedit 3.5\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Yhdistetty sokettiin %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Yhdistetty koneeseen %s porttiin %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -41,85 +41,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Työpöydän nimi: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Kone: %.80s portti: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Koko: %d × %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Pikselimuoto: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(palvelimen oletus %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Pyydetty koodaus: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "Viimeksi käytetty koodaus: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Rivinopeusarvio: %d kilobittiä/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Yhteyskäytäntöversio: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Turvamenetelmä: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Palvelin pudotti yhteyden ennen kuin istuntoa voitiin muodostaa."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Todennus epäonnistui: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Todennus palvelimelle epäonnistui. Palvelimen ilmoittama syy:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "SetDesktopSize epäonnistui: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "Virheellisiä SetColourMapEntries-tietueita palvelimelta!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "Läpisyöttö %d kilobittiä/s - vaihdetaan laaduksi %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "Läpisyöttö %d kilobittiä/s - täysvärit ovat nyt käytössä"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "Läpisyöttö %d kilobittiä/s - täysvärit ovat nyt pois käytöstä"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Käytetään pikselimuotoa %s"
@@ -132,21 +148,21 @@ msgstr "Virheellinen geometria määritelty!"
msgid "Reducing window size to fit on current monitor"
msgstr "Pienennetään ikkunan kokoa nykyiseen näyttöön sovittamiseksi"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Säädetään ikkunakokoa tahattomien kokonäyttöpyyntöjen välttämiseksi"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "%s avaa ponnahdusvalikon"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Häiriö näppäimistöön tarttumisessa"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Virheellinen näyttöasettelu laskettu koonmuuttamispyynnölle!"
@@ -154,252 +170,308 @@ msgstr "Virheellinen näyttöasettelu laskettu koonmuuttamispyynnölle!"
msgid "Invalid state for 3 button emulation"
msgstr "Virheellinen tila kolmen painikkeen jäljittelylle"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Ei toimintakoodia laajennetulle virtuaalinäppäimelle 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Ei toimintakoodia virtuaalinäppäimelle 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Virheellinen toimintakoodi 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Laajennetulle virtuaalinäppäimelle 0x%02x ei ole symbolia"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Virtuaalinäppäimelle 0x%02x ei ole symbolia"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Näppäimistön LED-tilan päivittäminen epäonnistui: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Näppäinkoodille %d ei ole symbolia (nykyisessä tilassa)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Näppäimistön LED-tilan noutaminen epäonnistui: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Näppäimistön LED-tilan päivittäminen epäonnistui"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Järjestelmän näyttökokoonpanon selvittäminen epäonnistui"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "%s:lle määritetty virheellinen arvo"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Näyttöä numero %d ei ole olemassa"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Virheellinen näytön numero â€%sâ€"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Odottamaton merkki â€%câ€"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "TigerVNC-asetukset"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Peru"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "Valmis"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Tiivistys"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Automaattivalinta"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Ensisijainen koodaus"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Väritaso"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Täysi"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Keskilaatu"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Matala"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Hyvin matala"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Oma tiivistystaso:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "laatu (0=nopea, 9=paras)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Salli JPEG-tiivistys:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "laatu (0=heikko, 9=paras)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "Turvallisuus"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Salaus"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Ei mitään"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS anonyymeilla varmenteilla"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS X509-varmenteilla"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Polku X509 CA-varmenteeseen"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Polku X509 CRL-tiedostoon"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Todennus"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Standardi-VNC (turvaton salauksetta)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Käyttäjätunnus ja salasana (turvaton salauksetta)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Syöte"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Vain katselu (hiirtä ja näppäimistöä ei huomioida)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Hiiri"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Jäljittele hiiren keskipainiketta"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Näytä piste kohdistimen puuttuessa"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Näytä paikallinen kohdistin, kun palvelin ei tarjoa kohdistinta"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Kohdistimen tyyppi"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Piste"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "Järjestelmä"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Näppäimistö"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Välitä järjestelmänäppäimet suoraan palvelimelle (kokonäyttö)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Valikkonäppäin"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Leikepöytä"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Hyväksy leikepöytä palvelimelta"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Aseta myös ensisijainen valinta"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Lähetä leikepöytä palvelimelle"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Lähetä ensisijainen valinta leikepöytänä"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Näyttö"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Näyttötila"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "Ikkunoitu"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Kokonäyttö nykyisellä näytöllä"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Kokonäyttö kaikilla näytöillä"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Kokonäyttö valituilla näytöillä"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Sekalaiset"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Jaettu (älä katkaise muiden katselimien yhteyksiä)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Pyydä uudelleenyhdistämään yhteysvirheen sattuessa"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "VNC-katselin: Yhteyden yksityiskohdat"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "VNC-palvelin:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Valinnat..."
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Lataa..."
# Nappi ei skaalaudu tekstin leveyden mukaan.
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Tall. nimellä..."
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "Tietoja..."
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Yhdistä"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -410,15 +482,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "TigerVNC-asetukset (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Valitse TigerVNC-asetustiedosto"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -429,24 +501,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Tallenna TigerVNC-asetukset tiedostoon"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s on jo olemassa. Haluatko korvata sen?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Ei"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Korvaa"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -457,7 +529,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -468,7 +540,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -479,205 +551,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "Tilahakemiston polkua ei saatu tietoon"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "VNC-tilahakemiston polkua ei saatu selvitettyä"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Tiedoston â€%s†avaaminen epäonnistui: %s"
+msgid "Could not open \"%s\""
+msgstr "Tiedoston â€%s†avaaminen epäonnistui"
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Rivin %d lukeminen tiedostosta %s epäonnistui: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Rivin %d lukeminen tiedostosta â€%s†epäonnistui"
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Liian pitkä rivi"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Salasanatiedoston avaaminen epäonnistui"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "VNC-todennus"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Tämä yhteys on turvallinen"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Tämä yhteys ei ole turvallinen"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Käyttäjätunnus:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Salasana:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Todennus peruttu"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Näppäimistön LED-tilan päivittäminen epäonnistui: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Näppäimistön LED-tilan päivittäminen epäonnistui: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "Näppäimistön LED-tilan päivittäminen epäonnistui"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Näppäimistön LED-tilan noutaminen epäonnistui: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "Näppäimenpainalluksella ei tuotettu näppäinkoodia"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Ei toimintakoodia laajennetulle virtuaalinäppäimelle 0x%02x"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Säilytä salasana yhteyden uudelleenmuodostamiseen"
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Ei toimintakoodia virtuaalinäppäimelle 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Virheellinen toimintakoodi 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Laajennetulle virtuaalinäppäimelle 0x%02x ei ole symbolia"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Virtuaalinäppäimelle 0x%02x ei ole symbolia"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Näppäinkoodille 0x%02x ei ole symbolia (nykyisessä tilassa)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Näppäinkoodille %d ei ole symbolia (nykyisessä tilassa)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "Ka&tkaise yhteys"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&Kokonäyttö"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "Pi&enennä"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "&Sovita ikkunan koko istuntoon"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Lähetä %s"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Lähetä Ctrl-Alt-&Del"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "Vi&rkistä näyttö"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&Valinnat..."
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "Yh&teyden tiedot..."
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "Tietoa &TigerVNC:stä..."
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "VNC-yhteyden tiedot"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Ikkuna on rekisteröity kosketuksille eikä eleille"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Eleasetusten asettaminen epäonnistui (virhe 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Eletietojen saaminen epäonnistui (virhe 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Virheellinen hiiren painike %d, ei ole välillä 1 – 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Käsittelemätön näppäin 0x%x - ei voi luoda näppäimistötapahtumaa."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "X Input 2 -tapahtumapeitettä ei saada ikkunalle 0x%08lx"
@@ -687,7 +701,7 @@ msgstr "X Input 2 -tapahtumapeitettä ei saada ikkunalle 0x%08lx"
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "Ikkunalla 0x%08lx ei ole X Input 2 -tapahtumapeitettä"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "Ikkunalla 0x%08lx on useampi X Input 2 -tapahtumapeite"
@@ -698,7 +712,6 @@ msgid "Failure grabbing device %i"
msgstr "Häiriö laitteeseen %i tarttumisessa"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "TigerVNC-katselin"
@@ -716,140 +729,141 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC on RealVNC 4- ja X.org koodikantoihin perustuva nopea versio VNC:stä. TigerVNC aloitettiin uuteen sukupolveen tähtäävänä TightVNC:n kehitystyönä Unix- ja Linux-alustoilla, mutta se erosi emoprojektistaan vuoden 2009 alussa, jotta TightVNC voisi keskittyä Windows-alustoihin. TigerVNC tukee Tight-koodauksen muunnosta, jota libjpeg-turbo-JPEG-koodekin käyttö nopeuttaa huomattavasti."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr "TigerVNC-katselimen yhteys CentOS-koneeseen"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr "TigerVNC-katselimen yhteys macOS-koneeseen"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr "TigerVNC-katselimen yhteys Windows-koneeseen"
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "TigerVNC-ryhmä"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Parametrin nimi on liian suuri"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Parametri on liian suuri"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Virheellinen muoto tai liian suuri arvo"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Rekisteriavaimen luominen epäonnistui"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Rekisteriavaimen sulkeminen epäonnistui"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Tiedoston â€%s†tallentaminen epäonnistui: %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Tuntematon parametrityyppi"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Tiedoston â€%s†poistaminen epäonnistui: %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Rekisteriavaimen avaaminen epäonnistui"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Palvelinhistorian merkinnän %d lukeminen epäonnistui: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Parametrin â€%s†lukeminen epäonnistui: %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "Asetushakemiston polkua ei saatu selvitettyä"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "VNC-setushakemiston polkua ei saatu selvitettyä"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Parametria ei voitu koodata"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Asetustiedosto %s on virheellisessä muodossa"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Virheellinen muoto"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Tuntematon parametri"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Saatiin viesti (0x%x) käsittelemättömälle ikkunalle"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "Virheellinen ikkuna 0x%08lx annettu osoittimeen tarttumiselle"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "Kosketuskäsittelimen luominen epäonnistui: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Tapahtumakäsittelintä ei voitu liittää ikkunaan (virhe 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "X Input -tapahtuman tapahtumatietodon noutaminen epäonnistui"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "X Input -tapahtuma tuntemattomalle ikkunalle"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "X Input -laajennos ei ole saatavilla."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "X Input 2 (tai uudempi) ei ole saatavilla."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "X Input 2.2 (tai uudempi) ei ole saatavilla. Kosketuseleitä ei tueta."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"TigerVNC-katselin v%s\n"
@@ -894,95 +908,173 @@ msgstr "Virhe käynnistettäessä uutta TigerVNC-katselinta: %s"
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr "Päättämissignaali %d on vastaanotettu. TigerVNC-katselin sulkeutuu."
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "TigerVNC-katselin"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Kyllä"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Sulje"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "Tietoja"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Piilota"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Poistu"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Palvelut"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Piilota muut"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Näytä kaikki"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Tiedosto"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Uusi yhteys"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Usage: %s [parametrit] [kone][:näytönNro]\n"
+" %s [parametrit] [kone][::port]\n"
+" %s [parametrit] [unix-soketti]\n"
+" %s [parametrit] -listen [portti]\n"
+" %s [parametrit] [.tigervnc-tiedosto]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Asetukset:\n"
+"\n"
+"-display Xnäyttö - Määrittää katselinikkunan X-näytön\n"
+" -geometry geometria - VNC-katselinohjelman pääikkunan alkusijainti. Katso\n"
+" man-sivulta lisätietoja.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Parametrit asetetaan päälle: -<param> tai pois päältä: -<param>=0\n"
+"Arvon saavat parametrit annetaan: -<param> <arvo>\n"
+"Muita kelvollisia muotoja: <param>=<arvo> -<param>=<arvo> --<param>=<arvo>\n"
+"Kirjainkoolla ei ole merkitystä parametrien nimissä. Parametrit ovat:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "FullScreenAllMonitors on vanhentunut, aseta FullScreenMode-asetukseksi â€all†sen sijaan"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor on vanhentunut, aseta sen sijaan AlwaysCursor-arvoksi 1 ja CursorType-valinnaksi â€Pisteâ€"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "~/.vnc on vanhentunut, katso â€man vncviewer†sisältää lisätietoa korvaavista poluista."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "%%APPDATA%%\\vnc on vanhentunut, vaihda sijainniksi %%APPDATA%%\\TigerVNC."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "VNC-asetushakemiston luominen epäonnistui: %s"
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "VNC-asetushakemiston â€%s†luominen epäonnistui: %s"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "VNC-tietohakemiston polun selvitys epäonnistui"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "VNC-tietohakemiston â€%s†luominen epäonnistui: %s"
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "VNC-tietohakemiston luominen epäonnistui: %s"
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "VNC-tilahakemiston â€%s†luominen epäonnistui: %s"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "VNC-tilahakemiston luominen epäonnistui: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: Tuntematon valitsin â€%sâ€\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "Lisätietoja komennolla â€%s --helpâ€.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Ylimääräinen argumentti â€%sâ€\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Parametrit -listen ja -via ovat yhteensopimattomia"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Saapuvia yhteyksiä ei voi kuunnella"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Kuunnellaan portissa %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -993,10 +1085,38 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Virhe salatun tunnelin muodostamisessa:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "Etätyöpöytäkatselin"
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Näytä piste kohdistimen puuttuessa"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "Näppäimistön LED-tilan päivittäminen epäonnistui: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "Näppäimenpainalluksella ei tuotettu näppäinkoodia"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "Näppäinkoodille 0x%02x ei ole symbolia (nykyisessä tilassa)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "Tuntematon parametrityyppi"
+
#~ msgid "VNC Viewer: Connection Options"
#~ msgstr "VNC-katselin: Yhteysvalinnat"
diff --git a/po/id.po b/po/id.po
index b66a593b..79b58d21 100644
--- a/po/id.po
+++ b/po/id.po
@@ -1,14 +1,14 @@
# Indonesian translation of TigerVNC
# Copyright (C) 2018 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
-# Andika Triwidada <andika@gmail.com>, 2018, 2020-2022, 2024.
+# Andika Triwidada <andika@gmail.com>, 2018, 2020-2022, 2024, 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-21 11:05+0700\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-22 10:47+0700\n"
"Last-Translator: Andika Triwidada <andika@gmail.com>\n"
"Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
"Language: id\n"
@@ -17,19 +17,19 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Generator: Poedit 3.4.4\n"
+"X-Generator: Poedit 3.5\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Terhubung ke soket %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Terhubung ke host %s port %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -40,85 +40,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Nama desktop: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Host: %.80s port: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Ukuran: %d × %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Format piksel: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(server baku %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Pengkodean yang diminta: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "Pengkodean yang terakhir dipakai: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Estimasi kecepatan saluran: %d kbit/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Versi protokol: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Metode keamanan: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Koneksi diputus oleh server sebelum sesi dapat dijalin."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Autentikasi gagal: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Gagal mengautentikasi dengan server. Alasan yang diberikan oleh server:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "SetDesktopSize gagal: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "SetColourMapEntries yang tidak valid dari server!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "Throughput %d kbit/s - mengubah ke kualitas %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "Throughput %d kbit/s - warna penuh sekarang difungsikan"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "Throughput %d kbit/s - warna penuh sekarang dinonaktifkan"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Memakai format piksel %s"
@@ -131,21 +147,21 @@ msgstr "Geometri yang dinyatakan tidak valid!"
msgid "Reducing window size to fit on current monitor"
msgstr "Mengurangi ukuran jendela agar pas di monitor saat ini"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Menyesuaikan ukuran jendela untuk menghindari permintaan layar penuh yang tidak disengaja"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "Tekan %s untuk membuka menu konteks"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Kegagalan dalam mengambil alih papan ketik"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Tata letak layar yang tidak valid dihitung untuk permintaan ubah ukuran!"
@@ -153,251 +169,307 @@ msgstr "Tata letak layar yang tidak valid dihitung untuk permintaan ubah ukuran!
msgid "Invalid state for 3 button emulation"
msgstr "Keadaan yang tidak valid untuk emulasi 3 tombol"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Tidak ada kode pindai untuk tombol virtual yang diperluas 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Tidak ada kode pindai untuk tombol virtual 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Kode pindai tidak valid 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Tidak ada simbol untuk tombol virtual yang diperluas 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Tidak ada simbol untuk tombol virtual 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Gagal memperbarui keadaan LED papan tik: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Tidak ada simbol untuk kode tombol %d (dalam keadaan saat ini)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Gagal mendapatkan keadaan LED papan tik: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Gagal memperbarui keadaan LED papan tik"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Gagal mendapatkan konfigurasi monitor sistem"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Konfigurasi yang tidak valid dinyatakan untuk %s"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Indeks monitor %d tidak ada"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Indeks monitor tidak valid '%s'"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Karakter tak terduga '%c'"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "Opsi TigerVNC"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Batal"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "OK"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Kompresi"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Pilih otomatis"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Pengkodean yang disukai"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Tingkat warna"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Penuh"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Sedang"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Rendah"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Sangat rendah"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Tingkat kompresi ubahan:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "tingkat (0=buruk, 9=terbaik)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Izinkan kompresi JPEG:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "kualitas (0=buruk, 9=terbaik)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "Keamanan"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Enkripsi"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Nihil"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS dengan sertifikat anonim"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS dengan sertifikat X509"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Path ke sertifikat CA X509"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Path ke berkas CRL X509"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Otentikasi"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "VNC standar (tidak aman tanpa enkripsi)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Nama pengguna dan kata sandi (tidak aman tanpa enkripsi)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Masukan"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Hanya melihat (mengabaikan tetikus dan papan ketik)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Tetikus"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Emulasikan tombol tengah tetikus"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Tampilkan titik saat tidak ada kursor"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Tampilkan kursor lokal ketika tidak disediakan oleh server"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Tipe kursor"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Titik"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "Sistem"
+
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Papan Tik"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Lewatkan tombol-tombol sistem secara langsung ke server (layar penuh)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Tombol menu"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Papan Klip"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Terima papan klip dari server"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Juga atur pemilihan primer"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Kirim papan klip ke server"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Kirim pilihan primer sebagai papan klip"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Tampilan"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Mode tampilan"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "Berjendela"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Layar penuh pada monitor saat ini"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Layar penuh di semua monitor"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Layar penuh pada monitor yang dipilih"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Rupa-rupa"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Bersama (jangan putuskan pemirsa lain)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Minta untuk menyambungkan kembali saat kesalahan koneksi"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
-msgstr "Penampil VNC: Rincian Sambungan"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
+msgstr "Penampil VNC: Rincian sambungan"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "Server VNC:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Opsi..."
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Muat..."
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
-msgstr "Simpan Sebagai..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
+msgstr "Simpan sebagai..."
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "Tentang..."
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Sambung"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -408,15 +480,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "Konfigurasi TigerVNC (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Pilih berkas konfigurasi TigerVNC"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -427,24 +499,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Simpan konfigurasi TigerVNC ke berkas"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s sudah ada. Apakah Anda ingin menimpa?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Tidak"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Timpa"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -455,7 +527,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -466,7 +538,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -477,205 +549,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "Tidak bisa mendapatkan path direktori keadaan"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Tidak bisa menentukan path direktori keadaan VNC"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Tak bisa membuka %s: %s"
+msgid "Could not open \"%s\""
+msgstr "Tak bisa membuka \"%s\""
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Gagal membaca baris %d dalam berkas %s: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Gagal membaca baris %d dalam berkas \"%s\""
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Baris terlalu panjang"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Membuka berkas kata sandi gagal"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "Otentikasi VNC"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Sambungan ini aman"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Sambungan ini tidak aman"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Nama Pengguna:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Kata Sandi:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Autentikasi dibatalkan"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Gagal memperbarui keadaan LED papan tik: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Gagal memperbarui keadaan LED papan tik: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "Gagal memperbarui keadaan LED papan tik"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Gagal mendapatkan keadaan LED papan tik: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "Tidak ada kode tombol yang dinyatakan saat penekanan tombol"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Simpan sandi untuk penyambungan ulang"
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Tidak ada kode pindai untuk tombol virtual yang diperluas 0x%02x"
-
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Tidak ada kode pindai untuk tombol virtual 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Kode pindai tidak valid 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Tidak ada simbol untuk tombol virtual yang diperluas 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Tidak ada simbol untuk tombol virtual 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Tidak ada simbol untuk kode tombol 0x%02x (dalam keadaan saat ini)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Tidak ada simbol untuk kode tombol %d (dalam keadaan saat ini)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "Putuskan &Sambungan"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "Layar &Penuh"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "Mi&nimalkan"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "Ubah ukuran &jendela ke sesi"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Kirim %s"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Kirim Ctrl-Alt-&Del"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "Sega&rkan layar"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&Opsi..."
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "&Info koneksi..."
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "Tentang penampil &TigerVNC..."
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Informasi sambungan VNC"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Jendela terdaftar untuk sentuhan, bukan gestur"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Gagal mengatur konfigurasi gestur (galat 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Gagal mendapatkan informasi gestur (error 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Tombol tetikus yang tidak valid %d, harus angka antara 1 dan 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Tombol 0x%x yang tidak ditangani - tidak dapat menghasilkan kejadian papan ketik."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "Tidak bisa mendapatkan mask kejadian X Input 2 untuk jendela 0x%08lx"
@@ -685,7 +699,7 @@ msgstr "Tidak bisa mendapatkan mask kejadian X Input 2 untuk jendela 0x%08lx"
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "Jendela 0x%08lx tidak memiliki mask kejadian X Input 2"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "Window 0x%08lx memiliki lebih dari satu mask kejadian X Input 2"
@@ -696,7 +710,6 @@ msgid "Failure grabbing device %i"
msgstr "Kegagalan saat meng-grab perangkat %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "Penampil TigerVNC"
@@ -714,144 +727,145 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC adalah versi VNC berkecepatan tinggi berdasarkan basis kode RealVNC 4 dan X.org. TigerVNC dimulai sebagai upaya pengembangan generasi berikutnya untuk TightVNC pada platform Unix dan Linux, tetapi terpisah dari proyek induknya pada awal 2009 sehingga TightVNC dapat fokus pada platform Windows. TigerVNC mendukung varian Pengodean ketat yang sangat dipercepat dengan penggunaan kodek JPEG libjpeg-turbo."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
-msgstr "Koneksi Penampil TigerVNC ke mesin CentOS"
+msgid "TigerVNC viewer connection to a CentOS machine"
+msgstr "Koneksi penampil TigerVNC ke mesin CentOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
-msgstr "Koneksi Penampil TigerVNC ke mesin macOS"
+msgid "TigerVNC viewer connection to a macOS machine"
+msgstr "Koneksi penampil TigerVNC ke mesin macOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
-msgstr "Koneksi Penampil TigerVNC ke mesin Windows"
-
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+msgid "TigerVNC viewer connection to a Windows machine"
+msgstr "Koneksi penampil TigerVNC ke mesin Windows"
+
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "Tim TigerVNC"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Nama parameter terlalu besar"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Parameter terlalu besar"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Format tidak valid atau nilai terlalu besar"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Gagal membuat kunci registry"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Gagal menutup kunci registry"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Gagal menyimpan \"%s\": %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Tipe parameter tidak dikenal"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Gagal menghapus \"%s\": %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Gagal membuka kunci registry"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Gagal membaca entri riwayat server %d: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Gagal membaca parameter \"%s\": %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "Tidak bisa mendapatkan path direktori konfig"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Tidak bisa menentukan path direktori konfig VNC"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Tak bisa meng-enkode parameter"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Berkas konfigurasi %s berada dalam format yang tidak valid"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Format tidak valid"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Parameter tidak dikenal"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Mendapat pesan (0x%x) untuk jendela yang tidak tertangani"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "Jendela tidak valid 0x%08lx ditentukan untuk pengambilan penunjuk"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "Gagal membuat penangan sentuh: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Tak bisa melampirkan penangan kejadian ke jendela (galat 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Gagal mendapatkan data kejadian untuk kejadian X Input"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "Kejadian X Input untuk jendela yang tidak diketahui"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "Ekstensi X Input tidak tersedia."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "X Input 2 (atau yang lebih baru) tidak tersedia."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "X Input 2.2 (atau yang lebih baru) tidak tersedia. Gestur sentuh tidak akan didukung."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"Penampil TigerVNC v%s\n"
-"Dibangun di atas: %s\n"
+"Dibangun pada: %s\n"
"Hak Cipta (C) 1999-%d Tim TigerVNC dan banyak lainnya (lihat README.rst)\n"
"Lihat https://www.tigervnc.org untuk informasi tentang TigerVNC."
@@ -892,95 +906,173 @@ msgstr "Kesalahan saat memulai Penampil TigerVNC baru: %s"
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr "Sinyal pengakhiran %d telah diterima. Penampil TigerVNC sekarang akan keluar."
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "Penampil TigerVNC"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Ya"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Tutup"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "Tentang"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Sembunyikan"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Keluar"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Layanan"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
-msgstr "Sembunyikan Lainnya"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
+msgstr "Sembunyikan lainnya"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
-msgstr "Tampilkan Semua"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
+msgstr "Tampilkan semua"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Berkas"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "Ko&neksi Baru"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Cara pakai: %s [parameter] [host][:displayNum]\n"
+" %s [parameter] [host][::port]\n"
+" %s [parameter] [unix socket]\n"
+" %s [parameter] -listen [port]\n"
+" %s [parameter] [.tigervnc file]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Opsi:\n"
+"\n"
+" -display Xdisplay - Menyatakan display X bagi jendela penampil\n"
+" -geometry geometri - Posisi awal dari jendela penampil VNC utama. Lihat\n"
+" halaman man untuk rincian.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Parameter dapat dinyalakan dengan -<param> atau dimatikan dengan -<param>=0\n"
+"Parameter yang menerima nilai dapat dinyatakan sebagai -<param> <value>\n"
+"Bentuk valid lain adalah <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Nama parameter tidak peka huruf besar kecil. Parameternya adalah:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "FullScreenAllMonitors sudah usang, atur FullScreenMode ke 'all' sebagai gantinya"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor usang, tata AlwaysCursor ke 1 dan CursorType ke 'Dot' sebagai pengganti"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "~/.vnc usang, harap baca 'man vncviewer' untuk migrasi ke path mana."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "%%APPDATA%%\\vnc usang, harap beralih ke lokasi %%APPDATA%%\\TigerVNC."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
+#, c-format
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Tidak bisa membuat direktori konfig VNC \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Tidak bisa menentukan path direktori data VNC"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Tidak bisa membuat direktori data VNC \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:586
+#, c-format
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Tidak bisa membuat direktori keadaan VNC \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "Tidak bisa membuat direktori konfig VNC: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: Opsi tidak dikenal '%s'\n"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "Tidak bisa membuat direktori data VNC: %s"
+msgid "See '%s --help' for more information.\n"
+msgstr "Lihat '%s --help' untuk informasi lebih lanjut.\n"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:712
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "Tidak bisa membuat direktori keadaan VNC: %s"
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Argumen ekstra '%s'\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Parameter -listen dan -via tidak kompatibel"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Tidak bisa mendengarkan koneksi masuk"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Mendengarkan pada port %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -991,6 +1083,17 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Kegagalan menyiapkan tunnel terenkripsi:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
-msgstr "Penampil Desktop Jarak Jauh"
+msgid "Remote desktop viewer"
+msgstr "Penampil desktop jarak jauh"
diff --git a/po/ka.po b/po/ka.po
index df94ae12..26afa019 100644
--- a/po/ka.po
+++ b/po/ka.po
@@ -1,30 +1,30 @@
-# SOME DESCRIPTIVE TITLE.
+# Georgian translation for tigervnc
# Copyright (C) 2022 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
-# Temuri Doghonadze <temuri.doghonadze@gmail.com>, 2022
+# Temuri Doghonadze <temuri.doghonadze@gmail.com>, 2022-2025
#
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.11.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2021-09-08 09:19+0200\n"
-"PO-Revision-Date: 2022-04-18 06:01+0200\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-22 05:48+0100\n"
"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n"
"Language-Team: Georgian <(nothing)>\n"
"Language: ka\n"
-"X-Bugs: Report translation errors to the Language-Team address.\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 3.0.1\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 3.5\n"
-#: vncviewer/CConn.cxx:103
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "მიერთებრსáƒáƒ™áƒ”ტთáƒáƒœ %s"
-#: vncviewer/CConn.cxx:110
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "მიერთებულირჰáƒáƒ¡áƒ¢áƒ—áƒáƒœ %s პáƒáƒ áƒ¢áƒ˜ %d"
@@ -40,123 +40,128 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:159
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "სáƒáƒ›áƒ£áƒ¨áƒáƒ მáƒáƒ’იდის სáƒáƒ®áƒ”ლი: %.80s"
-#: vncviewer/CConn.cxx:164
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "პáƒáƒ¡áƒ¢áƒ˜: %.80s პáƒáƒ áƒ¢áƒ˜: %d"
-#: vncviewer/CConn.cxx:169
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "ზáƒáƒ›áƒ: %d x %d"
-#: vncviewer/CConn.cxx:177
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "პიქსელის ფáƒáƒ áƒ›áƒáƒ¢áƒ˜: %s"
-#: vncviewer/CConn.cxx:184
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(სერვერის ნáƒáƒ’ულისხმები %s)"
-#: vncviewer/CConn.cxx:189
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "მáƒáƒ—ხáƒáƒ•ნილი კáƒáƒ“ირებáƒ: %s"
-#: vncviewer/CConn.cxx:194
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "ბáƒáƒšáƒáƒ¡ გáƒáƒ›áƒáƒ§áƒ”ნებული კáƒáƒ“ირებáƒ: %s"
-#: vncviewer/CConn.cxx:199
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "კáƒáƒ•შირის დáƒáƒáƒ®áƒšáƒáƒ”ბითი სიჩქáƒáƒ áƒ”: %d kbit/s"
-#: vncviewer/CConn.cxx:204
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "პრáƒáƒ¢áƒáƒ™áƒáƒšáƒ˜áƒ¡ ვერსიáƒ: %d.%d"
-#: vncviewer/CConn.cxx:209
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის მეთáƒáƒ“ი: %s"
-#: vncviewer/CConn.cxx:271 vncviewer/CConn.cxx:273
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "კáƒáƒ•შირი გáƒáƒ˜áƒ—იშრსერვერის მიერ სáƒáƒœáƒáƒ› სესირდáƒáƒ“გებáƒáƒ“áƒ."
-#: vncviewer/CConn.cxx:280 vncviewer/Viewport.cxx:575
-#: vncviewer/Viewport.cxx:673 vncviewer/Viewport.cxx:776
-#: vncviewer/Viewport.cxx:791 vncviewer/Viewport.cxx:802
-#: vncviewer/Viewport.cxx:830 vncviewer/Viewport.cxx:901
-#: vncviewer/Viewport.cxx:937
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "áƒáƒ•თენტიკáƒáƒªáƒ˜áƒ˜áƒ¡ შეცდáƒáƒ›áƒ: %s"
+
+#: vncviewer/CConn.cxx:263
#, c-format
msgid ""
-"An unexpected error occurred when communicating with the server:\n"
+"Failed to authenticate with the server. Reason given by the server:\n"
"\n"
"%s"
msgstr ""
-"გáƒáƒ£áƒ—ვáƒáƒšáƒ˜áƒ¡áƒ¬áƒ˜áƒœáƒ”ბელი შეცდáƒáƒ›áƒ სერვერთáƒáƒœ დáƒáƒ™áƒáƒ•შირებისáƒáƒ¡:\n"
+"სერვერთáƒáƒœ áƒáƒ•თენტიკáƒáƒªáƒ˜áƒ ჩáƒáƒ•áƒáƒ áƒ“áƒ. სერვერის მიერ მáƒáƒ¬áƒáƒ“ებული მიზეზიáƒ:\n"
"\n"
"%s"
-#: vncviewer/CConn.cxx:333
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "SetDesktopSize-ის შეცდáƒáƒ›áƒ: %d"
-#: vncviewer/CConn.cxx:405
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ SetColourMapEntries სერვერიდáƒáƒœ!"
-#: vncviewer/CConn.cxx:513
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "გáƒáƒ›áƒ¢áƒáƒ áƒáƒ‘რ%d კბიტ/წმ - ხáƒáƒ áƒ˜áƒ¡áƒ®áƒ˜ შეიცვლებáƒ: %d"
-#: vncviewer/CConn.cxx:535
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "გáƒáƒ›áƒ¢áƒáƒ áƒáƒ‘რ%d კბიტ/წმ - ფერთრსრული გáƒáƒ›áƒ ჩáƒáƒ áƒ—ულიáƒ"
-#: vncviewer/CConn.cxx:538
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "გáƒáƒ›áƒ¢áƒáƒ áƒáƒ‘რ%d კბიტ/წმ - ფერთრსრული გáƒáƒ›áƒ გáƒáƒ›áƒáƒ áƒ—ულიáƒ"
-#: vncviewer/CConn.cxx:564
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "პიქსელის ფáƒáƒ áƒ›áƒáƒ¢áƒ˜: %s"
-#: vncviewer/DesktopWindow.cxx:143
+#: vncviewer/DesktopWindow.cxx:146
msgid "Invalid geometry specified!"
msgstr "მითითებული გეáƒáƒ›áƒ”ტრირáƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ!"
-#: vncviewer/DesktopWindow.cxx:616
-msgid "Adjusting window size to avoid accidental full screen request"
-msgstr "ეკრáƒáƒœáƒ˜áƒ¡ ზáƒáƒ›áƒ˜áƒ¡ მáƒáƒ áƒ’ებრშემთხვევით მთელ ეკრáƒáƒœáƒ–ე გáƒáƒ¨áƒšáƒ˜áƒ¡ თáƒáƒ•იდáƒáƒœ áƒáƒ¡áƒáƒ áƒ˜áƒ“ებლáƒáƒ“"
+#: vncviewer/DesktopWindow.cxx:167
+msgid "Reducing window size to fit on current monitor"
+msgstr "ფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡ ზáƒáƒ›áƒ˜áƒ¡ შეცვლრმიმდინáƒáƒ áƒ” ეკრáƒáƒœáƒ–ე დáƒáƒ¡áƒáƒ¢áƒ”ვáƒáƒ“"
+
+#: vncviewer/DesktopWindow.cxx:646
+msgid "Adjusting window size to avoid accidental full-screen request"
+msgstr "ეკრáƒáƒœáƒ˜áƒ¡ ზáƒáƒ›áƒ˜áƒ¡ მáƒáƒ áƒ’ებრშემთხვევით სრულ ეკრáƒáƒœáƒ–ე გáƒáƒ¨áƒšáƒ˜áƒ¡ თáƒáƒ•იდáƒáƒœ áƒáƒ¡áƒáƒ áƒ˜áƒ“ებლáƒáƒ“"
-#: vncviewer/DesktopWindow.cxx:667
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "კáƒáƒœáƒ¢áƒ”ქსტური მენიუს გáƒáƒ¡áƒáƒ®áƒ¡áƒœáƒ”ლáƒáƒ“ დáƒáƒáƒ¬áƒ”ქით: %s"
-#: vncviewer/DesktopWindow.cxx:1030 vncviewer/DesktopWindow.cxx:1038
-#: vncviewer/DesktopWindow.cxx:1058
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ ჩáƒáƒ­áƒ”რის შეცდáƒáƒ›áƒ"
-#: vncviewer/DesktopWindow.cxx:1352
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "ზáƒáƒ›áƒ˜áƒ¡ შესáƒáƒªáƒ•ლელáƒáƒ“ გáƒáƒ›áƒáƒ—ვლილი ფáƒáƒœáƒ¯áƒ áƒ”ბის გáƒáƒœáƒšáƒáƒ’ებრáƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ!"
@@ -164,27 +169,56 @@ msgstr "ზáƒáƒ›áƒ˜áƒ¡ შესáƒáƒªáƒ•ლელáƒáƒ“ გáƒáƒ›áƒáƒ—ვლá
msgid "Invalid state for 3 button emulation"
msgstr "áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘რ3 ღილáƒáƒ™áƒ˜áƒ¡ ემულáƒáƒªáƒ˜áƒ˜áƒ¡áƒ—ვის"
-#: vncviewer/MonitorArrangement.cxx:403
-msgid "Failed to get monitor name because X11 RandR could not be found"
-msgstr "მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒ¡ სáƒáƒ®áƒ”ლის მიღებრშეუძლებელირX11 Randr-ის áƒáƒ áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ის გáƒáƒ›áƒ"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბული ვირტუáƒáƒšáƒ£áƒ áƒ˜ ღილáƒáƒ™áƒ˜áƒ¡áƒ—ვის სკáƒáƒœáƒ˜áƒ áƒ”ბის კáƒáƒ“ი áƒáƒ  áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს: 0x%02x"
-#: vncviewer/MonitorArrangement.cxx:409
-#: vncviewer/MonitorIndicesParameter.cxx:47
-#: vncviewer/MonitorIndicesParameter.cxx:100
-msgid "Failed to get system monitor configuration"
-msgstr "სისტემური მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღებრშეუძლებელიáƒ"
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "სკáƒáƒœáƒ˜áƒ áƒ”ბის კáƒáƒ“ი ვირტუáƒáƒšáƒ£áƒ áƒ˜ ღილáƒáƒ™áƒ˜áƒ¡áƒ—ვის áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს: 0x%02x"
-#: vncviewer/MonitorArrangement.cxx:417
+#: vncviewer/KeyboardWin32.cxx:250
#, c-format
-msgid "Failed to get information about CRTC %d"
-msgstr "CRTC %d-ის შესáƒáƒ®áƒ”ბ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღებრშეუძლებელიáƒ"
+msgid "Invalid scan code 0x%02x"
+msgstr "სკáƒáƒœáƒ˜áƒ áƒ”ბის áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ კáƒáƒ“ი: 0x%02x"
-#: vncviewer/MonitorArrangement.cxx:430
+#: vncviewer/KeyboardWin32.cxx:262
#, c-format
-msgid "Failed to get information about output %d for CRTC %d"
-msgstr "CRTC %d-ის %d გáƒáƒ›áƒáƒ¢áƒáƒœáƒ˜áƒ¡ შესáƒáƒ®áƒ”ბ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღებრშეუძლებელიáƒ"
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბული ვირტუáƒáƒšáƒ£áƒ áƒ˜ ღილáƒáƒ™áƒ˜áƒ¡ სიმბáƒáƒšáƒ ნáƒáƒžáƒáƒ•ნი áƒáƒ áƒáƒ:0x%02x"
-#: vncviewer/MonitorIndicesParameter.cxx:78
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "ვირტუáƒáƒšáƒ£áƒ áƒ˜ ღილáƒáƒ™áƒ˜áƒ¡ სიმბáƒáƒšáƒ ნáƒáƒžáƒáƒ•ნი áƒáƒ áƒáƒ: 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ LED-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის გáƒáƒœáƒáƒ®áƒšáƒ”ბის შეცდáƒáƒ›áƒ: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "ღილáƒáƒ™áƒ˜áƒ¡ კáƒáƒ“ისთვის %d (მიმდინáƒáƒ áƒ” მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘áƒáƒ¨áƒ˜) სიმბáƒáƒšáƒ áƒáƒ¦áƒ›áƒáƒ©áƒ”ნილი áƒáƒ áƒáƒ"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ LED-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის მიღების შეცდáƒáƒ›áƒ: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ LED-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის გáƒáƒœáƒáƒ®áƒšáƒ”ბის შეცდáƒáƒ›áƒ"
+
+#: vncviewer/MonitorIndicesParameter.cxx:52
+#: vncviewer/MonitorIndicesParameter.cxx:100
+msgid "Failed to get system monitor configuration"
+msgstr "სისტემური მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღებრშეუძლებელიáƒ"
+
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "%s-ის მითითებული კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ"
@@ -194,228 +228,248 @@ msgstr "%s-ის მითითებული კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªá
msgid "Monitor index %d does not exist"
msgstr "ეკრáƒáƒœáƒ˜áƒ¡ ინდექსი %d áƒáƒ  áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს"
-#: vncviewer/MonitorIndicesParameter.cxx:164
-#: vncviewer/MonitorIndicesParameter.cxx:184
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "ეკრáƒáƒœáƒ˜áƒ¡ áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ ინდექსი: '%s'"
-#: vncviewer/MonitorIndicesParameter.cxx:172
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "მáƒáƒ£áƒšáƒáƒ“ნელი სიმბáƒáƒšáƒ '%c'"
-#: vncviewer/OptionsDialog.cxx:58
-msgid "VNC Viewer: Connection Options"
-msgstr "VNC თვáƒáƒšáƒ˜áƒ”რებáƒ: შეერთების დეტáƒáƒšáƒ”ბი"
+#: vncviewer/OptionsDialog.cxx:64
+msgid "TigerVNC options"
+msgstr "TigerVNC-ის მáƒáƒ áƒ’ებáƒ"
-#: vncviewer/OptionsDialog.cxx:84 vncviewer/ServerDialog.cxx:109
-#: vncviewer/vncviewer.cxx:418
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ"
-#: vncviewer/OptionsDialog.cxx:89 vncviewer/vncviewer.cxx:417
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "დიáƒáƒ®"
-#: vncviewer/OptionsDialog.cxx:447
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "შეკუმშვáƒ"
-#: vncviewer/OptionsDialog.cxx:463
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "áƒáƒ•ტáƒáƒ›áƒáƒ¢áƒ£áƒ áƒ˜ áƒáƒ áƒ©áƒ”ვáƒ"
-#: vncviewer/OptionsDialog.cxx:475
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "სáƒáƒ¡áƒ£áƒ áƒ•ელი კáƒáƒ“ირებ"
-#: vncviewer/OptionsDialog.cxx:523
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "ფერის დáƒáƒœáƒ”"
-#: vncviewer/OptionsDialog.cxx:534
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "მთლიáƒáƒœáƒ˜"
-#: vncviewer/OptionsDialog.cxx:541
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "სáƒáƒ¨áƒ£áƒáƒšáƒ"
-#: vncviewer/OptionsDialog.cxx:548
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "დáƒáƒ‘áƒáƒšáƒ˜"
-#: vncviewer/OptionsDialog.cxx:555
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "ძáƒáƒšáƒ˜áƒáƒœ დáƒáƒ‘áƒáƒšáƒ˜"
-#: vncviewer/OptionsDialog.cxx:572
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "შეკუმშვის დáƒáƒœáƒ˜áƒ¡ ხელით მითითებáƒ:"
-#: vncviewer/OptionsDialog.cxx:578
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "დáƒáƒœáƒ” (0=სწრáƒáƒ¤áƒ˜, 9=სáƒáƒ£áƒ™áƒ”თესáƒ)"
-#: vncviewer/OptionsDialog.cxx:585
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "JPEG შეკუმშვის ჩáƒáƒ áƒ—ვáƒ:"
-#: vncviewer/OptionsDialog.cxx:591
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "ხáƒáƒ áƒ˜áƒ¡áƒ®áƒ˜ (0=ცუდი, 9=სáƒáƒ£áƒ™áƒ”თესáƒ)"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბáƒ"
-#: vncviewer/OptionsDialog.cxx:617
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "დáƒáƒ¨áƒ˜áƒ¤áƒ áƒ•áƒ"
-#: vncviewer/OptionsDialog.cxx:628 vncviewer/OptionsDialog.cxx:681
-#: vncviewer/OptionsDialog.cxx:767
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "áƒáƒ áƒáƒ¤áƒ”რი"
-#: vncviewer/OptionsDialog.cxx:634
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS áƒáƒœáƒáƒœáƒ˜áƒ›áƒ£áƒ áƒ˜ სერტიფიკáƒáƒ¢áƒ”ბით"
-#: vncviewer/OptionsDialog.cxx:640
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS X509 სერტიფიკáƒáƒ¢áƒ”ბით"
-#: vncviewer/OptionsDialog.cxx:647
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "X509 CA სერტიფიკáƒáƒ¢áƒ˜áƒ¡ ბილიკი"
-#: vncviewer/OptionsDialog.cxx:654
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "X509 CRL ფáƒáƒ˜áƒšáƒ˜áƒ¡ ბილიკი"
-#: vncviewer/OptionsDialog.cxx:670
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "áƒáƒ•თენტიფიკáƒáƒªáƒ˜áƒ"
-#: vncviewer/OptionsDialog.cxx:687
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "VNC-ის სტáƒáƒœáƒ“áƒáƒ áƒ¢áƒ˜ (დáƒáƒ£áƒªáƒ•ელი, დáƒáƒ¨áƒ˜áƒ¤áƒ•რის გáƒáƒ áƒ”შე)"
-#: vncviewer/OptionsDialog.cxx:693
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბელი დრპáƒáƒ áƒáƒšáƒ˜ (დáƒáƒ£áƒªáƒ•ელი, დáƒáƒ¨áƒ˜áƒ¤áƒ•რის გáƒáƒ áƒ”შე)"
-#: vncviewer/OptionsDialog.cxx:712
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "შეყვáƒáƒœáƒ"
-#: vncviewer/OptionsDialog.cxx:720
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "მხáƒáƒšáƒáƒ“ ნáƒáƒ®áƒ•რ(თáƒáƒ’უნáƒáƒ¡ დრკლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ იგნáƒáƒ áƒ˜áƒ áƒ”ბáƒ)"
-#: vncviewer/OptionsDialog.cxx:726
+#: vncviewer/OptionsDialog.cxx:842
+msgid "Mouse"
+msgstr "თáƒáƒ’უნáƒ"
+
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "თáƒáƒ’უნáƒáƒ¡ შურღილიკის ემულáƒáƒªáƒ˜áƒ"
-#: vncviewer/OptionsDialog.cxx:732
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "ლáƒáƒ™áƒáƒšáƒ£áƒ áƒ˜ კურსáƒáƒ áƒ˜áƒ¡ ჩვენებáƒ, რáƒáƒªáƒ ის მáƒáƒ¬áƒáƒ“ებული áƒáƒ áƒáƒ სერვერის მიერ"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "კურსáƒáƒ áƒ˜áƒ¡ ტიპი"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "წერტილი"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "სისტემáƒ"
+
+#: vncviewer/OptionsDialog.cxx:888
+msgid "Keyboard"
+msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ"
+
+#: vncviewer/OptionsDialog.cxx:900
+msgid "Pass system keys directly to server (full screen)"
+msgstr "სისტემური ღილáƒáƒ™áƒ”ბის პირდáƒáƒžáƒ˜áƒ  სერვერზე გáƒáƒ’ზáƒáƒ•ნრ(სრულ ეკრáƒáƒœáƒ–ე)"
+
+#: vncviewer/OptionsDialog.cxx:903
+msgid "Menu key"
+msgstr "მენიუს ღილáƒáƒ™áƒ˜"
+
+#: vncviewer/OptionsDialog.cxx:926
+msgid "Clipboard"
+msgstr "გáƒáƒªáƒ•ლის ბუფერი"
+
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "სერვერიდáƒáƒœ გáƒáƒªáƒ•ლის ბუფერის მიღებáƒ"
-#: vncviewer/OptionsDialog.cxx:740
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "ძირითáƒáƒ“ი áƒáƒ áƒ©áƒ”ვáƒáƒœáƒ˜áƒ¡ დáƒáƒ§áƒ”ნებáƒ"
-#: vncviewer/OptionsDialog.cxx:747
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "გáƒáƒªáƒ•ლის ბáƒáƒ¤áƒ”რის სერვერზე გáƒáƒ’ზáƒáƒ•ნáƒ"
-#: vncviewer/OptionsDialog.cxx:755
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "ძირითáƒáƒ“ი áƒáƒ áƒ©áƒ”ვáƒáƒœáƒ˜áƒ¡ გáƒáƒªáƒ•ლის ბუფერით გáƒáƒ’ზáƒáƒ•ნáƒ"
-#: vncviewer/OptionsDialog.cxx:762
-msgid "Pass system keys directly to server (full screen)"
-msgstr "სისტემური ღილáƒáƒ™áƒ”ბის პირდáƒáƒžáƒ˜áƒ  სერვერზე გáƒáƒ’ზáƒáƒ•ნრ(სრულ ეკრáƒáƒœáƒ–ე)"
+#: vncviewer/OptionsDialog.cxx:982
+msgid "Display"
+msgstr "ჩვენებáƒ"
-#: vncviewer/OptionsDialog.cxx:765
-msgid "Menu key"
-msgstr "მენიუს ღილáƒáƒ™áƒ˜"
-
-#: vncviewer/OptionsDialog.cxx:782
-msgid "Screen"
-msgstr "ეკრáƒáƒœáƒ˜"
+#: vncviewer/OptionsDialog.cxx:996
+msgid "Display mode"
+msgstr "ჩვენების რეჟიმი"
-#: vncviewer/OptionsDialog.cxx:790
-msgid "Resize remote session on connect"
-msgstr "შეერთებისáƒáƒ¡ დáƒáƒ¨áƒáƒ áƒ”ბული ეკრáƒáƒœáƒ˜áƒ¡ ზáƒáƒ›áƒ˜áƒ¡ შეცვლáƒ"
+#: vncviewer/OptionsDialog.cxx:1009
+msgid "Windowed"
+msgstr "ფáƒáƒœáƒ¯áƒáƒ áƒáƒ¨áƒ˜"
-#: vncviewer/OptionsDialog.cxx:803
-msgid "Resize remote session to the local window"
-msgstr "დáƒáƒ¨áƒáƒ áƒ”ბული ეკრáƒáƒœáƒ˜áƒ¡ áƒáƒ“გილáƒáƒ‘რივ ფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡ ზáƒáƒ›áƒáƒ›áƒ“ე შეცვლáƒ"
+#: vncviewer/OptionsDialog.cxx:1017
+msgid "Full screen on current monitor"
+msgstr "სრულ ეკრáƒáƒœáƒ–ე მიმდინáƒáƒ áƒ” მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ–ე"
-#: vncviewer/OptionsDialog.cxx:809
-msgid "Enable full-screen"
-msgstr "სრული ეკრáƒáƒœáƒ˜áƒ¡ ჩáƒáƒ áƒ—ვáƒ"
+#: vncviewer/OptionsDialog.cxx:1025
+msgid "Full screen on all monitors"
+msgstr "სრულ ეკრáƒáƒœáƒ–ე ყველრმáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ–ე"
-#: vncviewer/OptionsDialog.cxx:825
-msgid "Use current monitor"
-msgstr "მიმდინáƒáƒ áƒ” ეკრáƒáƒœáƒ˜áƒ¡ გáƒáƒ›áƒáƒ§áƒ”ნებáƒ"
+#: vncviewer/OptionsDialog.cxx:1033
+msgid "Full screen on selected monitor(s)"
+msgstr "სრულ ეკრáƒáƒœáƒ–ე მáƒáƒœáƒ˜áƒ¨áƒœáƒ£áƒš მáƒáƒœáƒ˜áƒ¢áƒáƒ (ებ)-ზე"
-#: vncviewer/OptionsDialog.cxx:833
-msgid "Use all monitors"
-msgstr "ყველრეკრáƒáƒœáƒ˜áƒ¡ გáƒáƒ›áƒáƒ§áƒ”ნებáƒ"
+#: vncviewer/OptionsDialog.cxx:1062
+msgid "Miscellaneous"
+msgstr "სხვáƒáƒ“áƒáƒ¡áƒ®áƒ•áƒ"
-#: vncviewer/OptionsDialog.cxx:841
-msgid "Use selected monitor(s)"
-msgstr "მáƒáƒœáƒ˜áƒ¨áƒœáƒ£áƒšáƒ˜ ეკრáƒáƒœ(ებ)-ის გáƒáƒ›áƒáƒ§áƒ”ნებáƒ"
-
-#: vncviewer/OptionsDialog.cxx:867
-msgid "Misc."
-msgstr "სხვ."
-
-#: vncviewer/OptionsDialog.cxx:875
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "გáƒáƒ–იáƒáƒ áƒ”ბული (სხვრმáƒáƒ§áƒ£áƒ áƒ”ბლები áƒáƒ  გáƒáƒ›áƒáƒ˜áƒ§áƒ áƒ”ბიáƒáƒœ)"
-#: vncviewer/OptionsDialog.cxx:881
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "კáƒáƒ•შირის დáƒáƒ™áƒáƒ áƒ’ვისáƒáƒ¡ თáƒáƒ•იდáƒáƒœ შეერთების შესáƒáƒ®áƒ”ბ კითხვáƒ"
-#: vncviewer/OptionsDialog.cxx:887
-msgid "Show dot when no cursor"
-msgstr "კურსáƒáƒ áƒ˜áƒ¡ áƒáƒ áƒ¥áƒáƒœáƒ˜áƒ¡ შემთხვევáƒáƒ¨áƒ˜ წერტილის ჩვენებáƒ"
-
-#: vncviewer/ServerDialog.cxx:57
-msgid "VNC Viewer: Connection Details"
-msgstr "VNC თვáƒáƒšáƒ˜áƒ”რებáƒ: შეერთების დეტáƒáƒšáƒ”ბი"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
+msgstr "VNC-ის დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რებáƒ: კáƒáƒ•შირის დეტáƒáƒšáƒ”ბი"
-#: vncviewer/ServerDialog.cxx:64 vncviewer/ServerDialog.cxx:69
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "VNC სერვერი:"
-#: vncviewer/ServerDialog.cxx:82
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "პáƒáƒ áƒáƒ›áƒ”ტრები..."
-#: vncviewer/ServerDialog.cxx:87
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "ჩáƒáƒ¢áƒ•ირთვáƒ..."
-#: vncviewer/ServerDialog.cxx:92
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "შენáƒáƒ®áƒ•áƒ, რáƒáƒ’áƒáƒ áƒª..."
-#: vncviewer/ServerDialog.cxx:104
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "შესáƒáƒ®áƒ”ბ..."
-#: vncviewer/ServerDialog.cxx:114
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "დáƒáƒ™áƒáƒ•შირებáƒ"
-#: vncviewer/ServerDialog.cxx:140
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -426,15 +480,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:164 vncviewer/ServerDialog.cxx:200
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "TigerVNC-ის კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:165
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "áƒáƒ˜áƒ áƒ©áƒ˜áƒ”თ TigerVNC-ის კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ ფáƒáƒ˜áƒšáƒ˜"
-#: vncviewer/ServerDialog.cxx:186 vncviewer/vncviewer.cxx:553
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -445,24 +499,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:201
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "TigerVNC-ის კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ ფáƒáƒ˜áƒšáƒ˜áƒ¡ შენáƒáƒ®áƒ•áƒ"
-#: vncviewer/ServerDialog.cxx:226
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "'%s' უკვე áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს. გნებáƒáƒ•თ გáƒáƒ“áƒáƒáƒ¬áƒ”რáƒáƒ—?"
-#: vncviewer/ServerDialog.cxx:227 vncviewer/vncviewer.cxx:415
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "áƒáƒ áƒ"
-#: vncviewer/ServerDialog.cxx:227
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "თáƒáƒ•ზე გáƒáƒ“áƒáƒ¬áƒ”რáƒ"
-#: vncviewer/ServerDialog.cxx:243
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -473,7 +527,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:277
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -484,7 +538,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -495,205 +549,145 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:305 vncviewer/ServerDialog.cxx:368
-#: vncviewer/parameters.cxx:628 vncviewer/parameters.cxx:733
-#: vncviewer/vncviewer.cxx:460
-msgid "Could not obtain the home directory path"
-msgstr "სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ის ბილიკის მიღების შეცდáƒáƒ›áƒ"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "VNC-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ის ბილიკის დáƒáƒ“გენრშეუძლებელიáƒ"
-#: vncviewer/ServerDialog.cxx:318 vncviewer/ServerDialog.cxx:377
-#: vncviewer/parameters.cxx:639 vncviewer/parameters.cxx:746
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "\"%s\"-ის გáƒáƒ®áƒ¡áƒœáƒ˜áƒ¡ შეცდáƒáƒ›áƒ: %s"
+msgid "Could not open \"%s\""
+msgstr "\"%s\"-ის გáƒáƒ®áƒ¡áƒœáƒ˜áƒ¡ შეცდáƒáƒ›áƒ"
-#: vncviewer/ServerDialog.cxx:333 vncviewer/ServerDialog.cxx:339
-#: vncviewer/parameters.cxx:760 vncviewer/parameters.cxx:766
-#: vncviewer/parameters.cxx:797 vncviewer/parameters.cxx:826
-#: vncviewer/parameters.cxx:832
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "%d-ე ხáƒáƒ–ის წáƒáƒ™áƒ˜áƒ—ხვრფáƒáƒ˜áƒšáƒ¨áƒ˜ \"%s\" შეუძლებელიáƒ: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "შეუძლებელირ%d-ე ხáƒáƒ–ის წáƒáƒ™áƒ˜áƒ—ხვრფáƒáƒ˜áƒšáƒ¨áƒ˜ \"%s\""
-#: vncviewer/ServerDialog.cxx:340 vncviewer/parameters.cxx:767
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "ხáƒáƒ–ი ძáƒáƒšáƒ˜áƒáƒœ გრძელიáƒ"
-#: vncviewer/UserDialog.cxx:98
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "ფáƒáƒ˜áƒšáƒ˜áƒ¡ გáƒáƒ®áƒ¡áƒœáƒ˜áƒ¡ შეცდáƒáƒ›áƒ"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "VNC áƒáƒ•თენტიფიკáƒáƒªáƒ˜áƒ"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "შეერთებრდáƒáƒªáƒ£áƒšáƒ˜áƒ"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "შეერთებრდáƒáƒ£áƒªáƒ•ელიáƒ"
-#: vncviewer/UserDialog.cxx:146
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბელი:"
-#: vncviewer/UserDialog.cxx:159
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "პáƒáƒ áƒáƒšáƒ˜:"
-#: vncviewer/UserDialog.cxx:198
-msgid "Authentication cancelled"
-msgstr "áƒáƒ•თენტიკáƒáƒªáƒ˜áƒ გáƒáƒ£áƒ¥áƒ›áƒ“áƒ"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ LED-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის გáƒáƒœáƒáƒ®áƒšáƒ”ბის შეცდáƒáƒ›áƒ: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ LED-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის გáƒáƒœáƒáƒ®áƒšáƒ”ბის შეცდáƒáƒ›áƒ: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ LED-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის გáƒáƒœáƒáƒ®áƒšáƒ”ბის შეცდáƒáƒ›áƒ"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ LED-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის მიღების შეცდáƒáƒ›áƒ: %d"
-
-#: vncviewer/Viewport.cxx:854
-msgid "No key code specified on key press"
-msgstr "ღილáƒáƒ™áƒ˜áƒ¡ დáƒáƒ¬áƒáƒšáƒ˜áƒ¡ კáƒáƒ“ი მითითებული áƒáƒ áƒáƒ"
-
-#: vncviewer/Viewport.cxx:1017
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბული ვირტუáƒáƒšáƒ£áƒ áƒ˜ ღილáƒáƒ™áƒ˜áƒ¡áƒ—ვის სკáƒáƒœáƒ˜áƒ áƒ”ბის კáƒáƒ“ი áƒáƒ  áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს: 0x%02x"
-
-#: vncviewer/Viewport.cxx:1019
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "სკáƒáƒœáƒ˜áƒ áƒ”ბის კáƒáƒ“ი ვირტუáƒáƒšáƒ£áƒ áƒ˜ ღილáƒáƒ™áƒ˜áƒ¡áƒ—ვის áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს: 0x%02x"
-
-#: vncviewer/Viewport.cxx:1025
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "სკáƒáƒœáƒ˜áƒ áƒ”ბის áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ კáƒáƒ“ი: 0x%02x"
-
-#: vncviewer/Viewport.cxx:1055
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბული ვირტუáƒáƒšáƒ£áƒ áƒ˜ ღილáƒáƒ™áƒ˜áƒ¡ სიმბáƒáƒšáƒ ნáƒáƒžáƒáƒ•ნი áƒáƒ áƒáƒ:0x%02x"
-
-#: vncviewer/Viewport.cxx:1057
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "ვირტუáƒáƒšáƒ£áƒ áƒ˜ ღილáƒáƒ™áƒ˜áƒ¡ სიმბáƒáƒšáƒ ნáƒáƒžáƒáƒ•ნი áƒáƒ áƒáƒ: 0x%02x"
-
-#: vncviewer/Viewport.cxx:1157
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:1190
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr ""
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "პáƒáƒ áƒáƒšáƒ˜áƒ¡ შენáƒáƒ®áƒ•რთáƒáƒ•იდáƒáƒœ დáƒáƒ¡áƒáƒ™áƒáƒ•შირებლáƒáƒ“"
-#: vncviewer/Viewport.cxx:1250
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
-msgid "Dis&connect"
+msgid "Disconn&ect"
msgstr "&გáƒáƒ—იშვáƒ"
-#: vncviewer/Viewport.cxx:1253
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&მთელს ეკრáƒáƒœáƒ–ე"
-#: vncviewer/Viewport.cxx:1256
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "&მინიმიზáƒáƒªáƒ˜áƒ"
-#: vncviewer/Viewport.cxx:1258
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "&ფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡ ზáƒáƒ›áƒ˜áƒ¡ სესიის ზáƒáƒ›áƒáƒ›áƒ“ე შეცვლáƒ"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1266
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1272
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "%s-ის გáƒáƒ’ზáƒáƒ•ნáƒ"
-#: vncviewer/Viewport.cxx:1278
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Ctrl-Alt-&Del-ის გáƒáƒ’ზáƒáƒ•ნáƒ"
-#: vncviewer/Viewport.cxx:1281
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "&ეკრáƒáƒœáƒ˜áƒ¡ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ"
-#: vncviewer/Viewport.cxx:1284
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&მáƒáƒ áƒ’ებáƒ..."
-#: vncviewer/Viewport.cxx:1286
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "&შეერთების ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ..."
-#: vncviewer/Viewport.cxx:1288
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "&TigerVNC-ის კლიენტის შესáƒáƒ®áƒ”ბ..."
-#: vncviewer/Viewport.cxx:1377
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "VNC-ის შეერთების ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
-msgstr ""
+msgstr "ფáƒáƒœáƒ¯áƒáƒ áƒ რეგისტრირებულირშესáƒáƒ®áƒ”ბáƒáƒ“, ჟესტების მáƒáƒ’იერ"
-#: vncviewer/Win32TouchHandler.cxx:81
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
-msgstr ""
+msgstr "ჟესტის კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ მიღებრჩáƒáƒ•áƒáƒ áƒ“რ(შეცდáƒáƒ›áƒ 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:93
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
-msgstr ""
+msgstr "ჟესტის ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღებრჩáƒáƒ•áƒáƒ áƒ“რ(შეცდáƒáƒ›áƒ 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:358
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
-msgstr ""
+msgstr "áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ თáƒáƒ’უნáƒáƒ¡ ღილáƒáƒ™áƒ˜ %d. უნდრიყáƒáƒ¡ რიცხვი შუáƒáƒšáƒ”დიდáƒáƒœ 1-7."
-#: vncviewer/Win32TouchHandler.cxx:423
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
-msgstr ""
+msgstr "უცნáƒáƒ‘ი ღილáƒáƒ™áƒ˜ 0x%x - კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ მáƒáƒ•ლენის გენერáƒáƒªáƒ˜áƒ შეუძლებელიáƒ."
#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
@@ -715,71 +709,110 @@ msgstr ""
msgid "Failure grabbing device %i"
msgstr "მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის ჩáƒáƒ­áƒ”რის შეცდáƒáƒ›áƒ: %i"
-#: vncviewer/parameters.cxx:301 vncviewer/parameters.cxx:326
-#: vncviewer/parameters.cxx:343 vncviewer/parameters.cxx:383
-#: vncviewer/parameters.cxx:403
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
+msgid "TigerVNC Viewer"
+msgstr "TigerVNC-ის კლიენტი"
+
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:14
+#: vncviewer/vncviewer.desktop.in.in:5
+msgid "Connect to VNC server and display remote desktop"
+msgstr ""
+
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:17
+msgid "Virtual Network Computing (VNC) is a remote display system that allows you to view and interact with a virtual desktop environment running on another computer on the network. Using VNC, you can run graphical applications on a remote machine and send only the display from these applications to your local device. This package contains a client which will enable you to connect to other desktops running a VNC server. VNC is platform-independent and supports various operating systems and architectures as both servers and clients."
+msgstr ""
+
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:23
+msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org code bases. TigerVNC started as a next-generation development effort for TightVNC on Unix and Linux platforms, but it split from its parent project in early 2009 so that TightVNC could focus on Windows platforms. TigerVNC supports a variant of Tight encoding that is greatly accelerated by the use of the libjpeg-turbo JPEG codec."
+msgstr ""
+
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
+msgid "TigerVNC viewer connection to a CentOS machine"
+msgstr "TigerVNC-ის დáƒáƒ›áƒ—ვáƒáƒšáƒ˜áƒ”რებლის კáƒáƒ•შირი CentOS-ის მáƒáƒœáƒ¥áƒáƒœáƒáƒ¡áƒ—áƒáƒœ"
+
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
+msgid "TigerVNC viewer connection to a macOS machine"
+msgstr "TigerVNC-ის დáƒáƒ›áƒ—ვáƒáƒšáƒ˜áƒ”რებლის კáƒáƒ•შირი macOS-ის მáƒáƒœáƒ¥áƒáƒœáƒáƒ¡áƒ—áƒáƒœ"
+
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
+msgid "TigerVNC viewer connection to a Windows machine"
+msgstr "TigerVNC-ის დáƒáƒ›áƒ—ვáƒáƒšáƒ˜áƒ”რებლის კáƒáƒ•შირი Windows-ის მáƒáƒœáƒ¥áƒáƒœáƒáƒ¡áƒ—áƒáƒœ"
+
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "TigerVNC-ის გუნდი"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "პáƒáƒ áƒáƒ›áƒ”ტრის სáƒáƒ®áƒ”ლი ძáƒáƒšáƒ˜áƒáƒœ დიდიáƒ"
-#: vncviewer/parameters.cxx:305 vncviewer/parameters.cxx:310
-#: vncviewer/parameters.cxx:361
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "პáƒáƒ áƒáƒ›áƒ”ტრი ძáƒáƒšáƒ˜áƒáƒœ დიდიáƒ"
-#: vncviewer/parameters.cxx:368 vncviewer/parameters.cxx:689
-#: vncviewer/parameters.cxx:811
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ ფáƒáƒ áƒ›áƒáƒ¢áƒ˜ áƒáƒœ ძáƒáƒšáƒ˜áƒáƒœ დიდი მნიშვნელáƒáƒ‘áƒ"
-#: vncviewer/parameters.cxx:422 vncviewer/parameters.cxx:453
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "რეესრის გáƒáƒ¡áƒáƒ¦áƒ”ბის შექმნის შეცდáƒáƒ›áƒ"
-#: vncviewer/parameters.cxx:441 vncviewer/parameters.cxx:496
-#: vncviewer/parameters.cxx:538 vncviewer/parameters.cxx:605
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "რეესტრის გáƒáƒ¡áƒáƒ¦áƒ”ბის დáƒáƒ®áƒ£áƒ áƒ•ის შეცდáƒáƒ›áƒ"
-#: vncviewer/parameters.cxx:459 vncviewer/parameters.cxx:476
-#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:647
-#: vncviewer/parameters.cxx:657 vncviewer/parameters.cxx:668
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "\"%s'-ის შენáƒáƒ®áƒ•ის შეცდáƒáƒ›áƒ: %s"
-#: vncviewer/parameters.cxx:472 vncviewer/parameters.cxx:560
-#: vncviewer/parameters.cxx:670 vncviewer/parameters.cxx:707
-msgid "Unknown parameter type"
-msgstr "პáƒáƒ áƒáƒ›áƒ”ტრის უცნáƒáƒ‘ ტიპი"
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
+#, c-format
+msgid "Failed to remove \"%s\": %s"
+msgstr "\"%s\"-ის წáƒáƒ¨áƒšáƒ˜áƒ¡ შეცდáƒáƒ›áƒ: %s"
-#: vncviewer/parameters.cxx:511 vncviewer/parameters.cxx:583
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "რეესტრის გáƒáƒ¡áƒáƒ¦áƒ”ბის გáƒáƒ®áƒ¡áƒœáƒ˜áƒ¡ შეცდáƒáƒ›áƒ"
-#: vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "სერვერის ისტáƒáƒ áƒ˜áƒ˜áƒ¡ ჩáƒáƒœáƒáƒ¬áƒ”რის (%d) წáƒáƒ™áƒ˜áƒ—ხვრშეუძლებელიáƒ: %s"
-#: vncviewer/parameters.cxx:564 vncviewer/parameters.cxx:594
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "\"%s\"-ის წáƒáƒ™áƒ˜áƒ—ხვის შეცდáƒáƒ›áƒ: %s"
-#: vncviewer/parameters.cxx:648 vncviewer/parameters.cxx:659
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "VNC-ის კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ის ბილიკის დáƒáƒ“გენრშეუძლებელიáƒ"
+
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "პáƒáƒ áƒáƒ›áƒ”ტრის კáƒáƒ“ირების შეცდáƒáƒ›áƒ"
-#: vncviewer/parameters.cxx:776
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ ფáƒáƒ áƒ›áƒáƒ¢áƒ˜ ფáƒáƒ˜áƒšáƒ˜áƒ¡áƒ—ვის : %s"
-#: vncviewer/parameters.cxx:798
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ ფáƒáƒ áƒ›áƒáƒ¢áƒ˜"
-#: vncviewer/parameters.cxx:833
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "უცნáƒáƒ‘ი პáƒáƒ áƒáƒ›áƒ”ტრი"
@@ -796,51 +829,62 @@ msgstr ""
#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
-msgstr ""
+msgstr "ვერ შევქმენი შეხების დáƒáƒ›áƒ›áƒ£áƒ¨áƒáƒ•ებელი: %s"
#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr ""
-#: vncviewer/touch.cxx:212
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
-msgstr ""
+msgstr "ჩáƒáƒ•áƒáƒ áƒ“რმáƒáƒ•ლენის მáƒáƒœáƒáƒªáƒ”მების მიღებრX-ის შეყვáƒáƒœáƒ˜áƒ¡ მáƒáƒ•ლენისთვის"
-#: vncviewer/touch.cxx:225
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "X Input-ის მáƒáƒ•ლენრუცნáƒáƒ‘ი ფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡áƒ—ვის"
-#: vncviewer/touch.cxx:251
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "X Input-ის გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბრმიუწვდáƒáƒ›áƒ”ლიáƒ."
-#: vncviewer/touch.cxx:258
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "X Input 2 (áƒáƒœ უფრრáƒáƒ®áƒáƒšáƒ˜) მიუწვდáƒáƒ›áƒ”ლიáƒ."
-#: vncviewer/touch.cxx:263
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "X Input 2.2 (áƒáƒœ უფრრáƒáƒ®áƒáƒšáƒ˜) მიუწვდáƒáƒ›áƒ”ლიáƒ. შეხების ჟესტები მხáƒáƒ áƒ“áƒáƒ£áƒ­áƒ”რელიáƒ."
-#: vncviewer/vncviewer.cxx:106
+#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer %d-bit v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
-#: vncviewer/vncviewer.cxx:172
+#: vncviewer/vncviewer.cxx:158
+#, c-format
+msgid ""
+"An unexpected error occurred when communicating with the server:\n"
+"\n"
+"%s"
+msgstr ""
+"გáƒáƒ£áƒ—ვáƒáƒšáƒ˜áƒ¡áƒ¬áƒ˜áƒœáƒ”ბელი შეცდáƒáƒ›áƒ სერვერთáƒáƒœ დáƒáƒ™áƒáƒ•შირებისáƒáƒ¡:\n"
+"\n"
+"%s"
+
+#: vncviewer/vncviewer.cxx:174
msgid "About TigerVNC Viewer"
msgstr "TigerVNC-ის კლიენტის შესáƒáƒ®áƒ”ბ"
-#: vncviewer/vncviewer.cxx:193
+#: vncviewer/vncviewer.cxx:195
msgid "Internal FLTK error. Exiting."
msgstr "FLTK-ის შიდრშეცდáƒáƒ›áƒ. პრáƒáƒ’რáƒáƒ›áƒ áƒáƒ¡áƒ áƒ£áƒšáƒ”ბს მუშáƒáƒáƒ‘áƒáƒ¡."
-#: vncviewer/vncviewer.cxx:212
+#: vncviewer/vncviewer.cxx:214
#, c-format
msgid ""
"%s\n"
@@ -851,83 +895,162 @@ msgstr ""
"\n"
"ვცáƒáƒ“რთáƒáƒ•იდáƒáƒœ დáƒáƒ™áƒáƒ•შირებáƒ?"
-#: vncviewer/vncviewer.cxx:243 vncviewer/vncviewer.cxx:255
+#: vncviewer/vncviewer.cxx:245 vncviewer/vncviewer.cxx:257
#, c-format
msgid "Error starting new TigerVNC Viewer: %s"
msgstr "TigerVNC-ის áƒáƒ®áƒáƒšáƒ˜ დáƒáƒ›áƒ—ვáƒáƒšáƒ˜áƒ”რებლის გáƒáƒ¨áƒ•ების შეცდáƒáƒ›áƒ: %s"
-#: vncviewer/vncviewer.cxx:264
+#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr ""
-#: vncviewer/vncviewer.cxx:407 vncviewer/vncviewer.desktop.in.in:3
-msgid "TigerVNC Viewer"
-msgstr "TigerVNC-ის კლიენტი"
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "TigerVNC-ის დáƒáƒ›áƒ—ვáƒáƒšáƒ˜áƒ”რებელი"
-#: vncviewer/vncviewer.cxx:416
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "დიáƒáƒ®"
-#: vncviewer/vncviewer.cxx:419
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "დáƒáƒ®áƒ£áƒ áƒ•áƒ"
-#: vncviewer/vncviewer.cxx:424
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "შესáƒáƒ®áƒ”ბ"
-#: vncviewer/vncviewer.cxx:427
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "დáƒáƒ›áƒáƒšáƒ•áƒ"
-#: vncviewer/vncviewer.cxx:430
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "გáƒáƒ¡áƒ•ლáƒ"
-#: vncviewer/vncviewer.cxx:434
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "სერვისები"
-#: vncviewer/vncviewer.cxx:435
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "სხვების დáƒáƒ›áƒáƒšáƒ•áƒ"
-#: vncviewer/vncviewer.cxx:436
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "ყველáƒáƒ¡ ჩვენებáƒ"
-#: vncviewer/vncviewer.cxx:445
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&ფáƒáƒ˜áƒšáƒ˜"
-#: vncviewer/vncviewer.cxx:448
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&áƒáƒ®áƒáƒšáƒ˜ შეერთებáƒ"
-#: vncviewer/vncviewer.cxx:464
+#: vncviewer/vncviewer.cxx:450
#, c-format
-msgid "Could not create VNC home directory: %s."
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
msgstr ""
-#: vncviewer/vncviewer.cxx:563
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr ""
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:553
+msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:557
+#, c-format
+msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
+msgstr "%%APPDATA%%\\vnc მáƒáƒ«áƒ•ელებულიáƒ. გáƒáƒ“áƒáƒ”რთეთ მდებáƒáƒ áƒ”áƒáƒ‘áƒáƒ–ე %%APPDATA%%\\TigerVNC."
+
+#: vncviewer/vncviewer.cxx:562
+#, c-format
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "ვერ შევქმენი VNC-ის კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ე \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "VNC-ის მáƒáƒœáƒáƒªáƒ”მების სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ის ბილიკის დáƒáƒ“გენრშეუძლებელიáƒ"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "ვერ შევქმენი VNC-ის მáƒáƒœáƒáƒªáƒ”მების სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ე \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:586
+#, c-format
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "VNC-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის სáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ის \"%s\" შექმნრშეუძლებელიáƒ: %s"
+
+#: vncviewer/vncviewer.cxx:703
+#, c-format
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: უცნáƒáƒ‘ი პáƒáƒ áƒáƒ›áƒ”ტრი '%s'\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "მეტი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡áƒ—ვის იხილეთ '%s --help'.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: დáƒáƒ›áƒáƒ¢áƒ”ბითი áƒáƒ áƒ’უმენტი '%s'\n"
+
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:769 vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
-msgstr ""
+msgstr "პáƒáƒ áƒáƒ›áƒ”ტრები -listen დრ-via თáƒáƒ•სებáƒáƒ“ი áƒáƒ áƒáƒ"
+
+#: vncviewer/vncviewer.cxx:763
+msgid "Unable to listen for incoming connections"
+msgstr "შემáƒáƒ›áƒáƒ•áƒáƒšáƒ˜ კáƒáƒ•შირებისთვის მáƒáƒ¡áƒ›áƒ”ნრშეუძლებელიáƒ"
-#: vncviewer/vncviewer.cxx:784
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "ვუსმენ პáƒáƒ áƒ¢áƒ–ე %d"
-#: vncviewer/vncviewer.cxx:817
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -938,10 +1061,56 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"შეცდáƒáƒ›áƒ დáƒáƒ¨áƒ˜áƒ¤áƒ áƒ£áƒšáƒ˜ გვირáƒáƒ‘ის მáƒáƒ áƒ’ებისáƒáƒ¡:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
-msgstr "დáƒáƒ¨áƒáƒ áƒ”ბული სáƒáƒ›áƒ£áƒ¨áƒáƒ მáƒáƒ’იდის სერვერის კლიენტი"
+msgid "Remote desktop viewer"
+msgstr "დáƒáƒ¨áƒáƒ áƒ”ბული სáƒáƒ›áƒ£áƒ¨áƒáƒ მáƒáƒ’იდის კლიენტი"
-#: vncviewer/vncviewer.desktop.in.in:5
-msgid "Connect to VNC server and display remote desktop"
-msgstr ""
+#~ msgid "Failed to get monitor name because X11 RandR could not be found"
+#~ msgstr "მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒ¡ სáƒáƒ®áƒ”ლის მიღებრშეუძლებელირX11 Randr-ის áƒáƒ áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ის გáƒáƒ›áƒ"
+
+#, c-format
+#~ msgid "Failed to get information about CRTC %d"
+#~ msgstr "CRTC %d-ის შესáƒáƒ®áƒ”ბ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღებრშეუძლებელიáƒ"
+
+#, c-format
+#~ msgid "Failed to get information about output %d for CRTC %d"
+#~ msgstr "CRTC %d-ის %d გáƒáƒ›áƒáƒ¢áƒáƒœáƒ˜áƒ¡ შესáƒáƒ®áƒ”ბ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღებრშეუძლებელიáƒ"
+
+#~ msgid "Screen"
+#~ msgstr "ეკრáƒáƒœáƒ˜"
+
+#~ msgid "Resize remote session on connect"
+#~ msgstr "შეერთებისáƒáƒ¡ დáƒáƒ¨áƒáƒ áƒ”ბული ეკრáƒáƒœáƒ˜áƒ¡ ზáƒáƒ›áƒ˜áƒ¡ შეცვლáƒ"
+
+#~ msgid "Resize remote session to the local window"
+#~ msgstr "დáƒáƒ¨áƒáƒ áƒ”ბული ეკრáƒáƒœáƒ˜áƒ¡ áƒáƒ“გილáƒáƒ‘რივ ფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡ ზáƒáƒ›áƒáƒ›áƒ“ე შეცვლáƒ"
+
+#~ msgid "Enable full-screen"
+#~ msgstr "სრული ეკრáƒáƒœáƒ˜áƒ¡ ჩáƒáƒ áƒ—ვáƒ"
+
+#~ msgid "Misc."
+#~ msgstr "სხვ."
+
+#~ msgid "Show dot when no cursor"
+#~ msgstr "კურსáƒáƒ áƒ˜áƒ¡ áƒáƒ áƒ¥áƒáƒœáƒ˜áƒ¡ შემთხვევáƒáƒ¨áƒ˜ წერტილის ჩვენებáƒ"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "კლáƒáƒ•იáƒáƒ¢áƒ£áƒ áƒ˜áƒ¡ LED-ის მდგáƒáƒ›áƒáƒ áƒ”áƒáƒ‘ის გáƒáƒœáƒáƒ®áƒšáƒ”ბის შეცდáƒáƒ›áƒ: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "ღილáƒáƒ™áƒ˜áƒ¡ დáƒáƒ¬áƒáƒšáƒ˜áƒ¡ კáƒáƒ“ი მითითებული áƒáƒ áƒáƒ"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "პáƒáƒ áƒáƒ›áƒ”ტრის უცნáƒáƒ‘ ტიპი"
diff --git a/po/ro.po b/po/ro.po
index 50c764d2..448dce49 100644
--- a/po/ro.po
+++ b/po/ro.po
@@ -1,22 +1,24 @@
+# Romanian translation for tigervnc.
# Mesajele în limba română pentru pachetul tigervnc.
-# Copyright © 2022, 2024 the TigerVNC Team (msgids)
+# Copyright © 2022, 2024, 2025 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
-# Copyright © 2022, 2024 TigerVNC Team and many others (see README.rst).
+# Copyright © 2022, 2024, 2025 TigerVNC Team and many others (see README.rst).
#
-# Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>, 2022, 2024.
+# Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>, 2022 - 2025.
#
# Cronologia traducerii fiÈ™ierului „tigervncâ€:
-# Traducerea inițială, făcută de R-GC, pentru versiunea tigervnc 1.11.90.
+# Traducerea inițială, făcută de R-GC, pentru versiunea tigervnc 1.11.90, mai-2022.
# Actualizare a traducerii pentru versiunea 1.12.90, făcută de R-GC, dec-2022.
# Actualizare a traducerii pentru versiunea 1.13.90, făcută de R-GC, iun-2024.
+# Actualizare a traducerii pentru versiunea 1.14.90, făcută de R-GC, ian-2025.
# Actualizare a traducerii pentru versiunea Y, făcută de X, Z(anul).
#
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-21 01:03+0200\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-21 18:32+0100\n"
"Last-Translator: Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>\n"
"Language-Team: Romanian <translation-team-ro@lists.sourceforge.net>\n"
"Language: ro\n"
@@ -25,19 +27,19 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n==0 || (n!=1 && n%100>=1 && n%100<=19) ? 1 : 2);\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Generator: Poedit 3.4.3\n"
+"X-Generator: Poedit 3.5\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Conectat la soclul %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Conectat la gazda %s portul %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -78,37 +80,37 @@ msgstr ""
# È™i nici bineînÈ›eles „corespondentulâ€
# românesc de, Remote Desktop =
# Desktop la distanță
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Numele biroului: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Gazdă: %.80s port: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Dimensiune: %d x %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Format pixel: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(server implicit %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Codificarea solicitată: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "Ultima codificare utilizată: %s"
@@ -119,31 +121,47 @@ msgstr "Ultima codificare utilizată: %s"
# linieiâ€(legăturii/circuitului/firului)â€
# ===
# Ok, sugestie aplicată
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Viteza estimată a conexiunii: %d kbit/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Versiunea protocolului: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Metoda de securitate: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Conexiunea a fost întreruptă de server înainte ca sesiunea să poată fi stabilită."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Autentificarea a eșuat: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Autentificarea cu serverul a eșuat. Motivul dat de server:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "Funcția SetDesktopSize() a eșuat: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "Valoare SetColourMapEntries nevalidă de la server!"
@@ -161,22 +179,22 @@ msgstr "Valoare SetColourMapEntries nevalidă de la server!"
# // If the bandwidth drops below 256 Kbps, we switch to palette mode.
# //
# Note: The system here is fairly arbitrary and should be replaced with something more intelligent at the server end.â€
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "Lățimea de bandă este de %d kbit/s - se trece la calitatea %d de JPEG"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "Lățimea de bandă este de %d kbit/s - nivelul de profunditate al culorii → «deplin», este acum activat acum"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "Lățimea de bandă este de %d kbit/s - nivelul de profunditate al culorii → «deplin», este dezactivat acum"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Se utilizează formatul de pixel %s"
@@ -189,21 +207,21 @@ msgstr "Geometria specificată nu este validă!"
msgid "Reducing window size to fit on current monitor"
msgstr "Se reduce dimensiunea ferestrei pentru a se potrivi pe monitorul actual"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Se ajustează dimensiunea ferestrei pentru a evita solicitarea accidentală a ecranului complet"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "Apăsați %s pentru a deschide meniul contextual"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Eroare la preluarea tastaturii"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Aspect nevalid al ecranului calculat pentru cererea de redimensionare!"
@@ -211,211 +229,267 @@ msgstr "Aspect nevalid al ecranului calculat pentru cererea de redimensionare!"
msgid "Invalid state for 3 button emulation"
msgstr "Stare nevalidă pentru emularea cu trei butoane"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Niciun cod de scanare pentru tasta virtuală extinsă 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Niciun cod de scanare pentru tasta virtuală 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Cod de scanare nevalid 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Niciun simbol pentru tasta virtuală extinsă 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Niciun simbol pentru tasta virtuală 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Nu s-a putut actualiza starea LED-ului tastaturii: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Niciun simbol pentru codul tastei %d (în starea curentă)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Nu s-a putut obține starea LED-ului tastaturii: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Nu s-a putut actualiza starea LED-ului tastaturii"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Nu s-a putut obține configurația monitorului sistemului"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Configurație nevalidă specificată pentru %s"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Indexul de monitor %d nu există"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Index de monitor nevalid „%sâ€"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Caracter neaÈ™teptat „%câ€"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "Opțiuni TigerVNC"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Anulare"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "Ok"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Comprimare"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Selectare automată"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Codificarea preferată"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Nivelul de profunditate al culorii"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Deplin"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Mediu"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Scăzut"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Foarte scăzut"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Nivel de comprimare personalizat:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "nivel (0 = rapid, 9 = cel mai bun)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Permite comprimarea JPEG:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "calitate (0 = redusă, 9 = cea mai bună)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "Securitate"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Criptare"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Niciuna"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS cu certificate anonime"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS cu certificate X509"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Ruta către certificatul CA X509"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Ruta către fișierul CRL X509"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Autentificare"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "VNC standard (nesigur fără criptare)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Nume de utilizator și parolă (nesigure fără criptare)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Intrare"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Numai vizualizare (se ignoră mouse-ul și tastatura)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Mouse"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Emulează butonul din mijloc al mouse-ului"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Afișează un punct când nu există cursor al mouse-ului"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Afișează cursorul local atunci când nu este furnizat de server"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Tipul cursorului"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Punct „Dotâ€"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "Sistem"
+
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Tastatură"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Pasează tastele sistemului direct către server (ecran complet)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Tasta de meniu"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Clipboard"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Acceptă clipboard-ul de pe server"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Stabilește, de asemenea, selecția principală"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Trimite clipboard-ul la server"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Trimite selecția principală ca clipboard"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Afișare"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Modul de afișare"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "În fereastră"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Ecran complet pe monitorul actual"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Ecran complet pe toate monitoare"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Ecran complet pe monitorul(ele) selectat(e)"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Diverse"
@@ -424,43 +498,43 @@ msgstr "Diverse"
# „→ lipseÈ™te închiderea parantezeiâ€
# ===
# corectare făcută
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
-msgstr "Partajat (nu deconectează alte vizualizatoare)"
+msgstr "Partajat (nu deconectează alte vizoare)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Solicită reconectarea în cazul erorilor de conectare"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
-msgstr "Vizualizator VNC: Detalii de conectare"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
+msgstr "Vizor VNC: Detalii de conectare"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "Serverul VNC:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Opțiuni..."
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Încărcare..."
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Salvează ca..."
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "Despre..."
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Conectare"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -471,15 +545,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "Configurația TigerVNC (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Selectați un fișier de configurare TigerVNC"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -490,24 +564,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Salvați configurația TigerVNC în fișier"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s există deja. Doriți să-l suprascrieți?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Nu"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Suprascrie"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -518,7 +592,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -529,7 +603,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -540,205 +614,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "Nu s-a putut obține ruta directorului de stare"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Nu s-a putut determina ruta directorului de stare al VNC"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Nu s-a putut deschide „%sâ€: %s"
+msgid "Could not open \"%s\""
+msgstr "Nu s-a putut deschide „%sâ€"
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Nu s-a putut citi linia %d din fișierul %s: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Nu s-a putut citi linia %d din fiÈ™ierul „%sâ€"
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Linia este prea lungă"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Deschiderea fișierului cu parole a eșuat"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "Autentificare VNC"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Această conexiune este sigură"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Această conexiune nu este sigură"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Numele utilizatorului:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Parola:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Autentificarea a fost anulată"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Nu s-a putut actualiza starea LED-ului tastaturii: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Nu s-a putut actualiza starea LED-ului tastaturii: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "Nu s-a putut actualiza starea LED-ului tastaturii"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Nu s-a putut obține starea LED-ului tastaturii: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "Nu a fost specificat niciun cod de tastă la apăsarea tastei"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Niciun cod de scanare pentru tasta virtuală extinsă 0x%02x"
-
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Niciun cod de scanare pentru tasta virtuală 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Cod de scanare nevalid 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Niciun simbol pentru tasta virtuală extinsă 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Niciun simbol pentru tasta virtuală 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Niciun simbol pentru codul tastei 0x%02x (în starea curentă)"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Păstrează parola pentru reconectare"
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Niciun simbol pentru codul tastei %d (în starea curentă)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "Deco&nectare"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&Ecran complet"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "Minimi&zare"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "Redimensionează &fereastra conform sesiunii"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Trimite %s"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Trimite Ctrl-Alt-&Del"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "&Reîmprospătează ecranul"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&Opțiuni..."
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "&Informații despre conexiune..."
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
-msgstr "Despre vizualizatorul &TigerVNC..."
+msgstr "Despre vizorul &TigerVNC..."
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Informații despre conexiunea VNC"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Fereastra este înregistrată pentru atingere în loc de gesturi"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Nu s-a putut definii configurația gesturilor (eroare 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Nu s-au putut obține informații despre gesturi (eroare 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Butonul mouse-ului %d nu este valid, trebuie să fie un număr între 1 și 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Tasta 0x%x necunoscută - nu se poate genera un eveniment de la tastatură."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "Nu se poate obține masca de eveniment X Input 2 pentru fereastra 0x%08lx"
@@ -748,7 +764,7 @@ msgstr "Nu se poate obține masca de eveniment X Input 2 pentru fereastra 0x%08l
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "Fereastra 0x%08lx nu are mască de eveniment X Input 2"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "Fereastra 0x%08lx are mai mult de o mască de eveniment X Input 2"
@@ -759,9 +775,8 @@ msgid "Failure grabbing device %i"
msgstr "Eroare la preluarea dispozitivului %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
-msgstr "Vizualizator TigerVNC"
+msgstr "Vizor TigerVNC"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:14
#: vncviewer/vncviewer.desktop.in.in:5
@@ -777,131 +792,132 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC este o versiune de mare viteză a VNC bazată pe bazele codurilor RealVNC 4 și X.org. TigerVNC a început ca un efort de dezvoltare de ultimă generație pentru TightVNC pe platformele Unix și Linux, dar s-a despărțit de proiectul său părinte la începutul anului 2009, astfel încât TightVNC să se poată concentra pe platformele Windows. TigerVNC acceptă o variantă de codificare Tight care este mult accelerată prin utilizarea codec-ului JPEG libjpeg-turbo."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
-msgstr "Conexiune a vizualizatorului TigerVNC la o mașină «GNU/Linux»"
+msgid "TigerVNC viewer connection to a CentOS machine"
+msgstr "Conexiune a vizorului TigerVNC la o mașină «GNU/Linux»"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
-msgstr "Conexiune a vizualizatorului TigerVNC la o mașină «macOS»"
+msgid "TigerVNC viewer connection to a macOS machine"
+msgstr "Conexiune a vizorului TigerVNC la o mașină «macOS»"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
-msgstr "Conexiune a vizualizatorului TigerVNC la o mașină «Windows»"
-
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+msgid "TigerVNC viewer connection to a Windows machine"
+msgstr "Conexiune a vizorului TigerVNC la o mașină «Windows»"
+
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "Echipa TigerVNC"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Numele parametrului este prea lung"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Parametrul este prea lung"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Format nevalid sau valoare prea mare"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Nu s-a putut crea cheia de registru"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Nu s-a putut închide cheia de registru"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Nu s-a putut salva „%sâ€: %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Tip de parametru necunoscut"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Nu s-a putut elimina „%sâ€: %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Nu s-a putut deschide cheia de registru"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Nu s-a putut citi intrarea din istoricul serverului %d: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Nu s-a putut citi parametrul „%sâ€: %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "Nu s-a putut obține ruta directorului de configurare"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Nu s-a putut determina ruta directorului de configurare al VNC"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Nu s-a putut codifica parametrul"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Fișierul de configurare %s este într-un format nevalid"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Format nevalid"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Parametru necunoscut"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "S-a primit mesajul (0x%x) pentru o fereastră negestionată"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "Fereastra 0x%08lx nevalidă a fost specificată pentru preluarea indicatorului mouse-ului"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "Nu s-a putut crea gestionarul de atingere: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Nu s-a putut atașa gestionarul de evenimente la fereastră (eroare 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Nu s-au putut obține datele despre eveniment pentru evenimentul X Input"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "Eveniment X Input pentru o fereastră necunoscută"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "Extensia X Input nu este disponibilă."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "X Input 2 (sau mai nouă) nu este disponibilă."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "X Input 2 (sau mai nouă) nu este disponibilă. Gesturile tactile nu vor fi acceptate."
@@ -919,12 +935,12 @@ msgstr "X Input 2 (sau mai nouă) nu este disponibilă. Gesturile tactile nu vor
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
-"Vizualizator TigerVNC versiunea %s\n"
+"Vizor TigerVNC versiunea %s\n"
"Construit pe: %s\n"
"Drepturi de autor © 1999-%d Echipa TigerVNC și mulți alții (vedeți fișierul README.rst)\n"
"Consultați https://www.tigervnc.org pentru informații despre TigerVNC."
@@ -942,7 +958,7 @@ msgstr ""
#: vncviewer/vncviewer.cxx:174
msgid "About TigerVNC Viewer"
-msgstr "Despre vizualizatorul TigerVNC"
+msgstr "Despre vizorul TigerVNC"
#: vncviewer/vncviewer.cxx:195
msgid "Internal FLTK error. Exiting."
@@ -962,99 +978,177 @@ msgstr ""
#: vncviewer/vncviewer.cxx:245 vncviewer/vncviewer.cxx:257
#, c-format
msgid "Error starting new TigerVNC Viewer: %s"
-msgstr "Eroare la pornirea noului vizualizator TigerVNC: %s"
+msgstr "Eroare la pornirea noului vizor TigerVNC: %s"
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
-msgstr "Semnalul de terminare %d a fost primit. Vizualizatorul TigerVNC se va închide acum."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
+msgstr "Semnalul de terminare %d a fost primit. Vizorul TigerVNC se va închide acum."
+
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "Vizor TigerVNC"
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Da"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "ÃŽnchide"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "Despre"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Ascunde"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Ieșire"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Servicii"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Ascunde pe celelalte"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Afișează pe toate"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&FiÅŸier"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "Conexiune &nouă"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Utilizare: %s [parametri] [gazda][:Număr-ecran]\n"
+" %s [parametri] [gazda][::port]\n"
+" %s [parametri] [soclu unix]\n"
+" %s [parametri] -listen [port]\n"
+" %s [parametri] [fișier .tigervnc]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Opțiuni:\n"
+"\n"
+" -display afișajulX - Specifică afișajul X pentru fereastra vizorului\n"
+" -geometry geometria - Poziția inițială a ferestrei principale a vizorului VNC.\n"
+" Consultați pagina de manual pentru detalii.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Parametrii pot fi activați cu -<param> sau dezactivați cu -<param>=0\n"
+"Parametrii care iau o valoare pot fi specificați ca -<param> <valoare>\n"
+"Alte forme valide sunt <param>=<valoare> -<param>=<valoare> --<param>=<valoare>\n"
+"Numele parametrilor nu sunt sensibile la majuscule. Parametrii sunt:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
-msgstr "FullScreenAllMonitors este învechit, setaÈ›i în schimb FullScreenMode la „allâ€"
+msgstr "FullScreenAllMonitors este învechit, stabiliÈ›i în schimb FullScreenMode la „allâ€"
+
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor este depreciat, stabiliți AlwaysCursor la 1 și CursorType la „Dot†în schimb"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "~/.vnc este depreciat, vă rugăm să consultați «man vncviewer» pentru căile de migrare."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "%%APPDATA%%\\vnc este depreciat, vă rugăm să treceți la locația %%APPDATA%%\\TigerVNC."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "Nu s-a putut crea directorul de configurare VNC: %s"
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Nu s-a putut crea directorul de configurare al VNC „%sâ€: %s"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Nu s-a putut determina ruta directorului de date al VNC"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Nu s-a putut crea directorul de date al VNC „%sâ€: %s"
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "Nu s-a putut crea directorul de date VNC: %s"
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Nu s-a putut crea directorul de stare al VNC „%sâ€: %s"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "Nu s-a putut crea directorul de stare VNC: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: opÈ›iune nerecunoscută „%sâ€\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "Consultați «%s --help» pentru mai multe informații.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Argument extra „%sâ€\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Parametrii „-listen†și „-via†sunt incompatibili"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Nu se poate asculta pentru conexiunile primite"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Se ascultă pe portul %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -1065,9 +1159,37 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Eșec la configurarea tunelului criptat\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
-msgstr "Vizualizator pentru birou la distanță"
+msgid "Remote desktop viewer"
+msgstr "Vizor pentru birou la distanță"
+
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Afișează un punct când nu există cursor al mouse-ului"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "Nu s-a putut actualiza starea LED-ului tastaturii: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "Nu a fost specificat niciun cod de tastă la apăsarea tastei"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "Niciun simbol pentru codul tastei 0x%02x (în starea curentă)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "Tip de parametru necunoscut"
#~ msgid "VNC Viewer: Connection Options"
#~ msgstr "Vizualizator VNC: Opțiuni de conectare"
diff --git a/po/ru.po b/po/ru.po
index c57d3acc..7dd1cc0f 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -4,13 +4,13 @@
# PuppyRus linux team <www.puppyrus.org>.
# Constantin Kaplinsky <const@tightvnc.com>, 2011.
# Pavel Maryanov <acid@jack.kiev.ua>, 2016.
-# Yuri Kozlov <yuray@komyakino.ru>, 2016, 2017, 2018, 2019, 2021, 2023.
+# Yuri Kozlov <yuray@komyakino.ru>, 2016, 2017, 2018, 2019, 2021, 2023, 2025.
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.12.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2022-12-15 16:35+0100\n"
-"PO-Revision-Date: 2023-10-20 18:09+0300\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-03-26 21:38+0300\n"
"Last-Translator: Yuri Kozlov <yuray@komyakino.ru>\n"
"Language-Team: Russian <gnu@d07.ru>\n"
"Language: ru_UA\n"
@@ -19,14 +19,14 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-"X-Generator: Lokalize 22.12.3\n"
+"X-Generator: Lokalize 24.12.0\n"
-#: vncviewer/CConn.cxx:103
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Подключён к Ñокету %s"
-#: vncviewer/CConn.cxx:110
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Подключён к компьютеру %s, порт %d"
@@ -42,112 +42,128 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:159
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Ð˜Ð¼Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð°: %.80s"
-#: vncviewer/CConn.cxx:164
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Компьютер: %.80s порт: %d"
-#: vncviewer/CConn.cxx:169
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Размер: %d x %d"
-#: vncviewer/CConn.cxx:177
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Формат пикÑелей: %s"
-#: vncviewer/CConn.cxx:184
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(Ñервер по умолчанию %s)"
-#: vncviewer/CConn.cxx:189
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Запрошено кодирование: %s"
-#: vncviewer/CConn.cxx:194
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "ИÑпользуетÑÑ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ðµ: %s"
-#: vncviewer/CConn.cxx:199
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "СкороÑть ÑоединениÑ: %d кбит/Ñ"
-#: vncviewer/CConn.cxx:204
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "ВерÑÐ¸Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ð°: %d.%d"
-#: vncviewer/CConn.cxx:209
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Метод защиты: %s"
-#: vncviewer/CConn.cxx:270 vncviewer/CConn.cxx:272
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Соединение прервано Ñервером до уÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÑеанÑа."
-#: vncviewer/CConn.cxx:332
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Ошибка аутентификации: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Ошибка аутентификации на Ñервере. Причина, Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð½Ð°Ñ Ð¾Ñ‚ Ñервера:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "Ошибка SetDesktopSize: %d"
-#: vncviewer/CConn.cxx:404
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "С Ñервера получен недопуÑтимый SetColourMapEntries"
-#: vncviewer/CConn.cxx:512
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "ПропуÑÐºÐ½Ð°Ñ ÑпоÑобноÑть %d кбит/Ñ. УÑтановлено качеÑтво %d"
-#: vncviewer/CConn.cxx:534
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "ПропуÑÐºÐ½Ð°Ñ ÑпоÑобноÑть %d кбит/Ñ â€” включено полноцветное отображение"
-#: vncviewer/CConn.cxx:537
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "ПропуÑÐºÐ½Ð°Ñ ÑпоÑобноÑть %d кбит/Ñ â€” полноцветное отображение выключено"
-#: vncviewer/CConn.cxx:563
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "ИÑпользуетÑÑ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ пикÑелей %s"
-#: vncviewer/DesktopWindow.cxx:145
+#: vncviewer/DesktopWindow.cxx:146
msgid "Invalid geometry specified!"
msgstr "Указан недопуÑтимый размер Ñкрана."
-#: vncviewer/DesktopWindow.cxx:166
+#: vncviewer/DesktopWindow.cxx:167
msgid "Reducing window size to fit on current monitor"
msgstr "УменьшаетÑÑ Ñ€Ð°Ð·Ð¼ÐµÑ€ окна, чтобы помеÑтитьÑÑ Ð² текущем мониторе"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "ПодгонÑетÑÑ Ñ€Ð°Ð·Ð¼ÐµÑ€ окна, чтобы избегать Ñлучайных запроÑов Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð² полный Ñкран"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "Ðажмите %s, чтобы открыть контекÑтное меню"
-#: vncviewer/DesktopWindow.cxx:1083 vncviewer/DesktopWindow.cxx:1091
-#: vncviewer/DesktopWindow.cxx:1111
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Ðе удалоÑÑŒ перехватить клавиатуру"
-#: vncviewer/DesktopWindow.cxx:1401
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Ð”Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа на изменение размера раÑÑчитан недопуÑтимый макет Ñкрана."
@@ -155,251 +171,307 @@ msgstr "Ð”Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа на изменение размера раÑÑчÐ
msgid "Invalid state for 3 button emulation"
msgstr "Ðекорректное ÑоÑтоÑние Ð´Ð»Ñ ÑмулÑÑ†Ð¸Ñ Ñредней кнопки"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Ðет Ñкан-кода Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ виртуальной клавиши 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Ðет Ñкан-кода Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð¹ клавиши 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Ðекорректный Ñкан-код 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Ðет Ñимвола Ð´Ð»Ñ Ñ€Ð°Ñширенной виртуальной клавиши 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Ðет Ñимвола Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð¹ клавиши 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Ðе удалоÑÑŒ обновить ÑоÑтоÑние LED клавиатуры: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Ðет Ñимвола Ð´Ð»Ñ ÐºÐ¾Ð´Ð° клавиши %d (в текущем ÑоÑтоÑнии)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Ðе удалоÑÑŒ получить ÑоÑтоÑние LED клавиатуры: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Ðе удалоÑÑŒ обновить ÑоÑтоÑние LED клавиатуры"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:105
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Ðе удалоÑÑŒ получить наÑтройки ÑиÑтемного монитора"
-#: vncviewer/MonitorIndicesParameter.cxx:83
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Задано недопуÑтимое значение Ð´Ð»Ñ %s"
-#: vncviewer/MonitorIndicesParameter.cxx:91
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Монитор Ñ Ð¸Ð½Ð´ÐµÐºÑом %d не ÑущеÑтвует"
-#: vncviewer/MonitorIndicesParameter.cxx:169
-#: vncviewer/MonitorIndicesParameter.cxx:189
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Ðекорректный Ð¸Ð½Ð´ÐµÐºÑ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð° «%s»"
-#: vncviewer/MonitorIndicesParameter.cxx:177
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Ðеожиданный Ñимвол «%c»"
-#: vncviewer/OptionsDialog.cxx:63
-msgid "VNC Viewer: Connection Options"
-msgstr "VNC Viewer: параметры ÑоединениÑ"
+#: vncviewer/OptionsDialog.cxx:64
+msgid "TigerVNC options"
+msgstr "Параметры TigerVNC"
-#: vncviewer/OptionsDialog.cxx:89 vncviewer/ServerDialog.cxx:108
-#: vncviewer/vncviewer.cxx:417
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Отмена"
-#: vncviewer/OptionsDialog.cxx:94 vncviewer/vncviewer.cxx:416
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "ОК"
-#: vncviewer/OptionsDialog.cxx:484
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Сжатие"
-#: vncviewer/OptionsDialog.cxx:501
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "ÐвтоматичеÑкий выбор"
-#: vncviewer/OptionsDialog.cxx:516
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Вид кодированиÑ"
-#: vncviewer/OptionsDialog.cxx:574
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Глубина цвета"
-#: vncviewer/OptionsDialog.cxx:585
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "ПолнаÑ"
-#: vncviewer/OptionsDialog.cxx:592
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "СреднÑÑ"
-#: vncviewer/OptionsDialog.cxx:599
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "ÐизкаÑ"
-#: vncviewer/OptionsDialog.cxx:606
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Очень низкаÑ"
-#: vncviewer/OptionsDialog.cxx:624
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Уровень ÑжатиÑ:"
-#: vncviewer/OptionsDialog.cxx:630
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "уровень (0=быÑтрое, 9=лучшее)"
-#: vncviewer/OptionsDialog.cxx:637
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Разрешить Ñжатие JPEG:"
-#: vncviewer/OptionsDialog.cxx:643
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "качеÑтво (0=наихудшее, 9=наилучшее)"
-#: vncviewer/OptionsDialog.cxx:654
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "БезопаÑноÑть"
-#: vncviewer/OptionsDialog.cxx:676
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Шифрование"
-#: vncviewer/OptionsDialog.cxx:687 vncviewer/OptionsDialog.cxx:750
-#: vncviewer/OptionsDialog.cxx:854
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Ðет"
-#: vncviewer/OptionsDialog.cxx:694
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS Ñ Ð°Ð½Ð¾Ð½Ð¸Ð¼Ð½Ñ‹Ð¼Ð¸ Ñертификатами"
-#: vncviewer/OptionsDialog.cxx:700
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS Ñ Ñертификатами X509"
-#: vncviewer/OptionsDialog.cxx:707
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Путь к Ñертификату X509 CA"
-#: vncviewer/OptionsDialog.cxx:714
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Путь к файлу X509 CRL"
-#: vncviewer/OptionsDialog.cxx:739
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "ÐвторизациÑ"
-#: vncviewer/OptionsDialog.cxx:756
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Стандартный VNC (без защиты и шифрованиÑ)"
-#: vncviewer/OptionsDialog.cxx:762
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸ пароль (без защиты и шифрованиÑ)"
-#: vncviewer/OptionsDialog.cxx:781
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Ввод"
-#: vncviewer/OptionsDialog.cxx:794
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Только проÑмотр (не перехватывать мышь и клавиатуру)"
-#: vncviewer/OptionsDialog.cxx:801
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Мышь"
-#: vncviewer/OptionsDialog.cxx:815
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Эмулировать Ñреднюю кнопку мыши"
-#: vncviewer/OptionsDialog.cxx:821
-msgid "Show dot when no cursor"
-msgstr "Показывать точку при отÑутÑтвии курÑора"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Показывать локальный курÑор, когда он не предоÑтавлÑетÑÑ Ñервером"
-#: vncviewer/OptionsDialog.cxx:835
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Тип курÑора"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Dot"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "System"
+
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Клавиатура"
-#: vncviewer/OptionsDialog.cxx:849
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "ОтправлÑть ÑÐ¾Ñ‡ÐµÑ‚Ð°Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ (Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð³Ð¾ Ñкрана)"
-#: vncviewer/OptionsDialog.cxx:852
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Вызов меню:"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Буфер обмена"
-#: vncviewer/OptionsDialog.cxx:885
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Принимать буфер обмена Ñ Ñервера"
-#: vncviewer/OptionsDialog.cxx:893
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Также принимать мышиный буфер"
-#: vncviewer/OptionsDialog.cxx:900
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "ОтправлÑть буфер обмена на Ñервер"
-#: vncviewer/OptionsDialog.cxx:908
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "ОтправлÑть мышиный буфер туда же, куда и буфер обмена"
-#: vncviewer/OptionsDialog.cxx:927
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Экран"
-#: vncviewer/OptionsDialog.cxx:941
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Режим Ñкрана"
-#: vncviewer/OptionsDialog.cxx:956
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "Оконный режим"
-#: vncviewer/OptionsDialog.cxx:964
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "ПолноÑкранный режим на текущем мониторе"
-#: vncviewer/OptionsDialog.cxx:972
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "ПолноÑкранный режим на вÑех мониторах"
-#: vncviewer/OptionsDialog.cxx:980
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "ПолноÑкранный режим на выбранных мониторах"
-#: vncviewer/OptionsDialog.cxx:1007
-msgid "Misc."
+#: vncviewer/OptionsDialog.cxx:1062
+msgid "Miscellaneous"
msgstr "Разное"
-#: vncviewer/OptionsDialog.cxx:1015
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "СовмеÑÑ‚Ð½Ð°Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð° (не отключать других клиентов)"
-#: vncviewer/OptionsDialog.cxx:1021
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Запрашивать о переподключении при ошибках ÑоединениÑ"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
-msgstr "VNC Viewer: Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ Ñоединении"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
+msgstr "VNC viewer: Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ Ñоединении"
-#: vncviewer/ServerDialog.cxx:65 vncviewer/ServerDialog.cxx:70
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "Сервер VNC:"
-#: vncviewer/ServerDialog.cxx:81
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Параметры"
-#: vncviewer/ServerDialog.cxx:86
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Загрузить"
-#: vncviewer/ServerDialog.cxx:91
-msgid "Save As..."
-msgstr "Сохранить"
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
+msgstr "Сохранить как…"
-#: vncviewer/ServerDialog.cxx:103
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "О программе"
-#: vncviewer/ServerDialog.cxx:113
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Войти"
-#: vncviewer/ServerDialog.cxx:145
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -410,15 +482,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:173 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "ÐаÑтройки TigerVNC (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:174
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Выбрать файл наÑтроек TigerVNC"
-#: vncviewer/ServerDialog.cxx:196 vncviewer/vncviewer.cxx:552
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -429,24 +501,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Сохранить наÑтройки TigerVNC в файл"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "Файл «%s» уже ÑущеÑтвует, перезапиÑать?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:414
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Ðет"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "ПерезапиÑать"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -457,7 +529,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -468,7 +540,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -479,202 +551,142 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:387
-#: vncviewer/parameters.cxx:635 vncviewer/parameters.cxx:740
-#: vncviewer/vncviewer.cxx:459
-msgid "Could not obtain the home directory path"
-msgstr "Ðевозможно получить путь к домашнему каталогу"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Ðевозможно определить путь к каталогу ÑоÑтоÑÐ½Ð¸Ñ VNC"
-#: vncviewer/ServerDialog.cxx:333 vncviewer/ServerDialog.cxx:396
-#: vncviewer/parameters.cxx:646 vncviewer/parameters.cxx:753
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Ðевозможно открыть «%s»: %s"
+msgid "Could not open \"%s\""
+msgstr "Ðевозможно открыть «%s»"
-#: vncviewer/ServerDialog.cxx:348 vncviewer/ServerDialog.cxx:356
-#: vncviewer/parameters.cxx:767 vncviewer/parameters.cxx:773
-#: vncviewer/parameters.cxx:804 vncviewer/parameters.cxx:833
-#: vncviewer/parameters.cxx:839
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Ðе удалоÑÑŒ прочитать Ñтроку %d из файла %s: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Ðе удалоÑÑŒ прочитать Ñтроку %d из файла «%s»"
-#: vncviewer/ServerDialog.cxx:357 vncviewer/parameters.cxx:774
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Строка Ñлишком длиннаÑ"
-#: vncviewer/UserDialog.cxx:98
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Ðе удалоÑÑŒ открыть файл Ñ Ð¿Ð°Ñ€Ð¾Ð»ÐµÐ¼"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ VNC"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Это Ñоединение защищено"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Это Ñоединение не защищено"
-#: vncviewer/UserDialog.cxx:146
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ:"
-#: vncviewer/UserDialog.cxx:159
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Пароль:"
-#: vncviewer/UserDialog.cxx:198
-msgid "Authentication cancelled"
-msgstr "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¾Ñ‚Ð¼ÐµÐ½ÐµÐ½Ð°"
-
-#: vncviewer/Viewport.cxx:391
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Ðе удалоÑÑŒ обновить ÑоÑтоÑние LED клавиатуры: %lu"
-
-#: vncviewer/Viewport.cxx:397 vncviewer/Viewport.cxx:403
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Ðе удалоÑÑŒ обновить ÑоÑтоÑние LED клавиатуры: %d"
-
-#: vncviewer/Viewport.cxx:433
-msgid "Failed to update keyboard LED state"
-msgstr "Ðе удалоÑÑŒ обновить ÑоÑтоÑние LED клавиатуры"
-
-#: vncviewer/Viewport.cxx:460 vncviewer/Viewport.cxx:468
-#: vncviewer/Viewport.cxx:485
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Ðе удалоÑÑŒ получить ÑоÑтоÑние LED клавиатуры: %d"
-
-#: vncviewer/Viewport.cxx:849
-msgid "No key code specified on key press"
-msgstr "Ðе задан код клавиши при нажатии"
-
-#: vncviewer/Viewport.cxx:1008
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Ðет Ñкан-кода Ð´Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ виртуальной клавиши 0x%02x"
-
-#: vncviewer/Viewport.cxx:1010
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Ðет Ñкан-кода Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð¹ клавиши 0x%02x"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Сохранить пароль Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ"
-#: vncviewer/Viewport.cxx:1016
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Ðекорректный Ñкан-код 0x%02x"
-
-#: vncviewer/Viewport.cxx:1046
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Ðет Ñимвола Ð´Ð»Ñ Ñ€Ð°Ñширенной виртуальной клавиши 0x%02x"
-
-#: vncviewer/Viewport.cxx:1048
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Ðет Ñимвола Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð¹ клавиши 0x%02x"
-
-#: vncviewer/Viewport.cxx:1154
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Ðет Ñимвола Ð´Ð»Ñ ÐºÐ¾Ð´Ð° клавиши 0x%02x (в текущем ÑоÑтоÑнии)"
-
-#: vncviewer/Viewport.cxx:1187
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Ðет Ñимвола Ð´Ð»Ñ ÐºÐ¾Ð´Ð° клавиши %d (в текущем ÑоÑтоÑнии)"
-
-#: vncviewer/Viewport.cxx:1247
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
-msgid "Dis&connect"
+msgid "Disconn&ect"
msgstr "От&ключитьÑÑ"
-#: vncviewer/Viewport.cxx:1250
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "Полный &Ñкран"
-#: vncviewer/Viewport.cxx:1253
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "&Свернуть"
-#: vncviewer/Viewport.cxx:1255
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "Изменить &размер окна"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1269
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Отправить %s"
-#: vncviewer/Viewport.cxx:1275
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Отправить Ctrl-Alt-&Del"
-#: vncviewer/Viewport.cxx:1278
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "&Обновить Ñкран"
-#: vncviewer/Viewport.cxx:1281
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&Параметры…"
-#: vncviewer/Viewport.cxx:1283
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "Сведен&Ð¸Ñ Ð¾ Ñоединении…"
-#: vncviewer/Viewport.cxx:1285
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "О &TigerVNC…"
-#: vncviewer/Viewport.cxx:1374
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ Ñоединении VNC"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Ð”Ð»Ñ Ð¾ÐºÐ½Ð° зарегиÑтрировано управление прикоÑновениÑми, а не жеÑтами"
-#: vncviewer/Win32TouchHandler.cxx:81
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Ðе удалоÑÑŒ задать параметры жеÑтов (ошибка 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:93
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Ðе удалоÑÑŒ получить информацию о жеÑтах (ошибка 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:358
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "ÐÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° мыши %d: должно быть чиÑло от 1 до 7."
-#: vncviewer/Win32TouchHandler.cxx:423
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "ÐÐµÐ¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚Ð°Ð½Ð½Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° 0x%x: невозможно Ñгенерировать Ñобытие клавиатуры."
@@ -700,7 +712,6 @@ msgid "Failure grabbing device %i"
msgstr "Ðе удалоÑÑŒ перехватить уÑтройÑтво %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:406 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "TigerVNC Viewer"
@@ -718,87 +729,92 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC — выÑокоÑкороÑÑ‚Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ VNC, в оÑнове лежит код RealVNC 4 и X.org. TigerVNC начиналаÑÑŒ как разработка Ñледующего Ð¿Ð¾ÐºÐ¾Ð»ÐµÐ½Ð¸Ñ TightVNC Ð´Ð»Ñ Ð¿Ð»Ð°Ñ‚Ñ„Ð¾Ñ€Ð¼ Unix и Linux, но отделилаÑÑŒ от родительÑкого проекта в начале 2009 года Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы TightVNC Ñмогла ÑфокуÑироватьÑÑ Ð½Ð° платформе Windows. TigerVNC поддерживает вариант ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Tight, который был значительно уÑкорен Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ кодека libjpeg-turbo JPEG."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
-msgstr "Подключение TigerVNC Viewer к машине CentOS"
+msgid "TigerVNC viewer connection to a CentOS machine"
+msgstr "Подключение TigerVNC viewer к машине CentOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
-msgstr "Подключение TigerVNC Viewer к машине macOS"
+msgid "TigerVNC viewer connection to a macOS machine"
+msgstr "Подключение TigerVNC viewer к машине macOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
-msgstr "Подключение TigerVNC Viewer к машине Windows"
-
-#: vncviewer/parameters.cxx:308 vncviewer/parameters.cxx:333
-#: vncviewer/parameters.cxx:350 vncviewer/parameters.cxx:390
-#: vncviewer/parameters.cxx:410
+msgid "TigerVNC viewer connection to a Windows machine"
+msgstr "Подключение TigerVNC viewer к машине Windows"
+
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "Команда TigerVNC"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Ðазвание параметра Ñлишком длинное"
-#: vncviewer/parameters.cxx:312 vncviewer/parameters.cxx:317
-#: vncviewer/parameters.cxx:368
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Параметр Ñлишком длинный"
-#: vncviewer/parameters.cxx:375 vncviewer/parameters.cxx:696
-#: vncviewer/parameters.cxx:818
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "ÐедопуÑтимый формат или Ñлишком большое значение"
-#: vncviewer/parameters.cxx:429 vncviewer/parameters.cxx:460
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Ðе удалоÑÑŒ Ñоздать ключ рееÑтра"
-#: vncviewer/parameters.cxx:448 vncviewer/parameters.cxx:503
-#: vncviewer/parameters.cxx:545 vncviewer/parameters.cxx:612
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Ðе удалоÑÑŒ закрыть ключ рееÑтра"
-#: vncviewer/parameters.cxx:466 vncviewer/parameters.cxx:483
-#: vncviewer/parameters.cxx:654 vncviewer/parameters.cxx:664
-#: vncviewer/parameters.cxx:675
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Ðе удалоÑÑŒ Ñохранить «%s»: %s"
-#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:567
-#: vncviewer/parameters.cxx:677 vncviewer/parameters.cxx:714
-msgid "Unknown parameter type"
-msgstr "ÐеизвеÑтный тип Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°"
-
-#: vncviewer/parameters.cxx:496
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Ðе удалоÑÑŒ удалить «%s»: %s"
-#: vncviewer/parameters.cxx:518 vncviewer/parameters.cxx:590
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Ðе удалоÑÑŒ открыть ключ рееÑтра"
-#: vncviewer/parameters.cxx:535
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Ðе удалоÑÑŒ прочитать Ñлемент иÑтории Ñервера %d: %s"
-#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:601
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Ðе удалоÑÑŒ прочитать параметр «%s»: %s"
-#: vncviewer/parameters.cxx:655 vncviewer/parameters.cxx:666
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Ðевозможно определить путь к каталогу наÑтроек VNC"
+
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Ðе удалоÑÑŒ закодировать параметр"
-#: vncviewer/parameters.cxx:783
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "ÐедопуÑтимый формат файла конфигурации %s"
-#: vncviewer/parameters.cxx:805
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "ÐедопуÑтимый формат"
-#: vncviewer/parameters.cxx:840
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "ÐеизвеÑтный параметр"
@@ -822,40 +838,40 @@ msgstr "Ðе удалоÑÑŒ Ñоздать обработчик прикоÑно
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Ðевозможно прикрепить обработчик Ñобытий к окну (ошибка 0x%x)"
-#: vncviewer/touch.cxx:212
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Ðе удалоÑÑŒ получить данные о Ñобытии Ð´Ð»Ñ ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ X Input"
-#: vncviewer/touch.cxx:225
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "Событие X Input Ð´Ð»Ñ Ð½ÐµÐ¸Ð·Ð²ÐµÑтного окна"
-#: vncviewer/touch.cxx:251
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "РаÑширение X Input недоÑтупно."
-#: vncviewer/touch.cxx:258
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "РаÑширение X Input 2 (или новее) недоÑтупно."
-#: vncviewer/touch.cxx:263
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "РаÑширение X Input 2.2 (или новее) недоÑтупно. ПрикоÑÐ½Ð¾Ð²ÐµÐ½Ð¸Ñ Ð¶ÐµÑтов не будут поддерживатьÑÑ."
-#: vncviewer/vncviewer.cxx:107
+#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Сборка от: %s\n"
-"Copyright (C) 1999-%d, TigerVNC Team и многие другие (Ñм. README.rst)\n"
+"Copyright (C) 1999-%d, команда TigerVNC и многие другие (Ñм. README.rst)\n"
"Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ TigerVNC на Ñайте https://www.tigervnc.org"
-#: vncviewer/vncviewer.cxx:161
+#: vncviewer/vncviewer.cxx:158
#, c-format
msgid ""
"An unexpected error occurred when communicating with the server:\n"
@@ -866,15 +882,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/vncviewer.cxx:177
+#: vncviewer/vncviewer.cxx:174
msgid "About TigerVNC Viewer"
msgstr "О TigerVNC viewer"
-#: vncviewer/vncviewer.cxx:198
+#: vncviewer/vncviewer.cxx:195
msgid "Internal FLTK error. Exiting."
msgstr "ВнутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ° FLTK. Выход."
-#: vncviewer/vncviewer.cxx:217
+#: vncviewer/vncviewer.cxx:214
#, c-format
msgid ""
"%s\n"
@@ -885,79 +901,182 @@ msgstr ""
"\n"
"ПопытатьÑÑ Ð¿ÐµÑ€ÐµÐ¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ?"
-#: vncviewer/vncviewer.cxx:248 vncviewer/vncviewer.cxx:260
+#: vncviewer/vncviewer.cxx:245 vncviewer/vncviewer.cxx:257
#, c-format
msgid "Error starting new TigerVNC Viewer: %s"
msgstr "Ðе удалоÑÑŒ запуÑтить новый TigerVNC Viewer: %s"
-#: vncviewer/vncviewer.cxx:269
+#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
-msgstr "Получен Ñигнал Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ %d. TigerVNC Viewer будет закрыт."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
+msgstr "Получен Ñигнал Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ %d. TigerVNC viewer будет закрыт."
-#: vncviewer/vncviewer.cxx:415
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "TigerVNC viewer"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Да"
-#: vncviewer/vncviewer.cxx:418
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Закрыть"
-#: vncviewer/vncviewer.cxx:423
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "О программе"
-#: vncviewer/vncviewer.cxx:426
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Скрыть"
-#: vncviewer/vncviewer.cxx:429
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Выход"
-#: vncviewer/vncviewer.cxx:433
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Службы"
-#: vncviewer/vncviewer.cxx:434
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Скрыть прочее"
-#: vncviewer/vncviewer.cxx:435
-msgid "Show All"
-msgstr "Показать вÑе"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
+msgstr "Показать вÑÑ‘"
-#: vncviewer/vncviewer.cxx:444
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Файл"
-#: vncviewer/vncviewer.cxx:447
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Ðовое Ñоединение"
-#: vncviewer/vncviewer.cxx:463
+#: vncviewer/vncviewer.cxx:450
#, c-format
-msgid "Could not create VNC home directory: %s"
-msgstr "Ðе удалоÑÑŒ Ñоздать домашний каталог VNC: %s"
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"ИÑпользование: %s [параметры] [узел][:номерДиÑплеиÑ]\n"
+" %s [параметры] [узел][::порт]\n"
+" %s [параметры] [Ñокет unix]\n"
+" %s [параметры] -listen [порт]\n"
+" %s [параметры] [файл .tigervnc]\n"
-#: vncviewer/vncviewer.cxx:562
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Параметры:\n"
+"\n"
+" -display Xdisplay - Задать X-диÑплей Ð´Ð»Ñ Ð¾ÐºÐ½Ð° программы\n"
+" -geometry Ð³ÐµÐ¾Ð¼ÐµÑ‚Ñ€Ð¸Ñ - Ðачальное положение оÑновного окна VNC.\n"
+" ПодробноÑти в Ñправочной Ñтранице.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Параметры включаютÑÑ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸ÐµÐ¼ в виде -<параметр> или \n"
+"отключаютÑÑ Ð² виде -<параметр>=0\n"
+"Параметры Ñо значениÑми можно задавать в виде -<параметр> <значение>\n"
+"Также допуÑкаетÑÑ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ <параметр>=<значение> -<параметр>=<значение>\n"
+"--<параметр>=<значение>\n"
+"Имена параметров не чувÑтвительны к региÑтру. Возможные параметры:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "FullScreenAllMonitors уÑтарел, задайте FullScreenMode Ñо значением «all»"
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor уÑтарел, вмеÑто него иÑпользуйте AlwaysCursor равным 1 и CursorType равным «Dot»"
+
+#: vncviewer/vncviewer.cxx:553
+msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
+msgstr "Каталог ~/.vnc уÑтарел, по «man vncviewer» можно найти информацию об изменениÑÑ… в путÑÑ…."
+
+#: vncviewer/vncviewer.cxx:557
+#, c-format
+msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
+msgstr "%%APPDATA%%\\vnc уÑтарел, иÑпользуйте %%APPDATA%%\\TigerVNC."
+
+#: vncviewer/vncviewer.cxx:562
+#, c-format
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Ðевозможно Ñоздать каталог наÑтроек VNC «%s»: %s"
+
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Ðевозможно определить путь к каталогу данных VNC"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Ðевозможно Ñоздать каталог данных VNC «%s»: %s"
+
+#: vncviewer/vncviewer.cxx:586
+#, c-format
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Ðевозможно Ñоздать каталог ÑоÑтоÑÐ½Ð¸Ñ VNC «%s»: %s"
+
+#: vncviewer/vncviewer.cxx:703
+#, c-format
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: ÐераÑпознанный параметр «%s»\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "По команде «%s --help» можно получить дополнительную информацию.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Лишний аргумент «%s»\n"
+
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:768 vncviewer/vncviewer.cxx:769
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Параметры -listen и -via неÑовмеÑтимы"
-#: vncviewer/vncviewer.cxx:783
+#: vncviewer/vncviewer.cxx:763
+msgid "Unable to listen for incoming connections"
+msgstr "Ðевозможно проÑлушивать входÑщие ÑоединениÑ"
+
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "ПроÑлушиваетÑÑ Ð¿Ð¾Ñ€Ñ‚ %d"
-#: vncviewer/vncviewer.cxx:816
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -968,10 +1087,44 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Ошибка при Ñоздании шифрованного туннелÑ:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "ПроÑмотр удалённых рабочих Ñтолов"
+#~ msgid "VNC Viewer: Connection Options"
+#~ msgstr "VNC Viewer: параметры ÑоединениÑ"
+
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Показывать точку при отÑутÑтвии курÑора"
+
+#~ msgid "Misc."
+#~ msgstr "Разное"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "Ðе удалоÑÑŒ обновить ÑоÑтоÑние LED клавиатуры: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "Ðе задан код клавиши при нажатии"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "Ðет Ñимвола Ð´Ð»Ñ ÐºÐ¾Ð´Ð° клавиши 0x%02x (в текущем ÑоÑтоÑнии)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "ÐеизвеÑтный тип Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°"
+
#~ msgid "Failed to get monitor name because X11 RandR could not be found"
#~ msgstr "Ðе удалоÑÑŒ получить Ð¸Ð¼Ñ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð°, так как не найден X11 RandR"
diff --git a/po/sk.po b/po/sk.po
index 480d9061..d0bdf58d 100644
--- a/po/sk.po
+++ b/po/sk.po
@@ -1,15 +1,15 @@
# Slovak translation of TigerVNC
-# Copyright (C) 2024 the TigerVNC Team (msgids)
+# Copyright (C) 2025 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
# Jozef Riha <jose1711@gmail.com>, 2008.
-# Marián Haburaj <hajkomajko5@gmail.com>, 2024.
+# Marián Haburaj <hajkomajko5@gmail.com>, 2024, 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-25 11:04+0200\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-23 14:21+0100\n"
"Last-Translator: Marián Haburaj <hajkomajko5@gmail.com>\n"
"Language-Team: Slovak <sk-i18n@lists.linux.sk>\n"
"Language: sk\n"
@@ -17,19 +17,19 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Generator: Poedit 3.4.3\n"
+"X-Generator: Poedit 3.5\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Pripojené na socket %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Pripojené na stroj %s port %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -40,85 +40,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Názov plochy: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Stroj: %.80s port: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Veľkosť: %d x %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Formát pixelu: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(predvolené serveru %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Požadované kódovanie: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "Naposledy použité kódovanie: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Predpokladaná rýchlosť linky: %d kbit/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Verzia protokolu: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Metóda zabezpeÄenia: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Spojenie bolo prerušené serverom skôr, než mohla byť nadviazaná relácia."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Autentifikácia zlyhala: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Autentifikácia so serverom zlyhala. Dôvod poskytnutý serverom:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "Požiadavka SetDesktopSize zlyhala: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "Neplatná správa SetColourMapEntries od serveru!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "Dátový tok %d kbit/s - mením na kvalitu %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "Dátový tok %d kbit/s - plné farby sú teraz zapnuté"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "Dátový tok %d kbit/s - plné farby sú teraz vypnuté"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Používaný formát pixelu %s"
@@ -131,21 +147,21 @@ msgstr "Zadaná neplatná geometria!"
msgid "Reducing window size to fit on current monitor"
msgstr "ZmenÅ¡ovanie veľkosti okna, aby sa zmestilo na súÄasný monitor"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Upravovanie veľkosti okna na vyhnutie sa náhodným požiadavkám na celú obrazovku"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "StlaÄ %s na otvorenie kontextovej ponuky"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Chyba pri preberaní klávesnice"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "VypoÄítané neplatné rozloženie obrazovky pre požiadavku na zmenu veľkosti!"
@@ -153,251 +169,307 @@ msgstr "VypoÄítané neplatné rozloženie obrazovky pre požiadavku na zmenu v
msgid "Invalid state for 3 button emulation"
msgstr "Neplatný stav pre 3-tlaÄidlovú emuláciu"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Žiaden scan kód pre rozšírený virtuálny kláves 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Žiaden scan kód pre virtuálny kláves 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Neplatný scan kód 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Žiaden symbol pre rozšírený virtuálny kláves 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Žiaden symbol pre virtuálny kláves 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Zlyhalo aktualizovanie stavu diód na klávesnici: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Žiaden symbol pre kód klávesy %d (v súÄasnom stave)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Zlyhalo získanie stavu diód na klávesnici: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Zlyhalo aktualizovanie stavu diód na klávesnici"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Nepodarilo sa získať nastavenie monitora systému"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Zadané neplatné nastavenie pre %s"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Monitor s Äíslom %d neexistuje"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Neplatné Äíslo monitoru \"%s\""
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "NeoÄakávaný znak \"%c\""
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "Nastavenia TigerVNC"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Zrušiť"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "OK"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Kompresia"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Automatický výber"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Uprednostňované kódovanie"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Farebnosť"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Plná"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Stredná"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Malá"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Veľmi malá"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Vlastný stupeň kompresie:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "úroveň (0=rýchla, 9=najlepšia)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Povoliť kompresiu JPEG:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "kvalita (0=nízka, 9=najlepšia)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "BezpeÄnosÅ¥"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Å ifrovanie"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Žiadne"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS s anonymnými certifikátmi"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS s X509 certifikátmi"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Cesta k X509 certifikátu autority"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Cesta k X509 súboru so zoznamom zneplatnených certifikátov"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Autentifikácia"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Å tandardné VNC (nezabezpeÄené bez Å¡ifrovania)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Používateľské meno a heslo (nezabezpeÄené bez Å¡ifrovania)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Vstup"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Iba prezerať (ignorovať myš a klávesnicu)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Myš"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "EmulovaÅ¥ stredné tlaÄidlo myÅ¡i"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Zobraziť bodku, ak kurzor nie je zobrazený"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "ZobraziÅ¥ lokálny kurzor, keÄ nie je poskytovaný serverom"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Typ kurzoru"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Bodka"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "Systémový"
+
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Klávesnica"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Podávať systémové klávesy priamo na server (celá obrazovka)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Kláves pre zobrazenie ponuky"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Schránka"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Akceptovať schránku zo servera"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Tiež nastaviť hlavný výber"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Posielať schránku serveru"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Poslať hlavný výber ako schránku"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Zobrazenie"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Režim zobrazenia"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "V okne"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Celá obrazovka na tomto monitore"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Celá obrazovka na všetkých monitoroch"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Celá obrazovka na zvolených monitoroch"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Rôzne"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Zdieľané (neodpojiť iných klientov)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Spýtať sa na opätovné pripojenie pri chybe v spojení"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "PriehliadaÄ VNC: Detaily o pripojení"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "VNC server:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Voľby..."
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "NaÄítaÅ¥..."
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Uložiť ako..."
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "O programe..."
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Pripojiť"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -408,15 +480,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "Nastavenie TigerVNC (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Zvoliť súbor s nastaveniami TigerVNC"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -427,24 +499,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Uložiť nastavenie TigerVNC do súboru"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s už existuje. Chceš ho prepísať?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Nie"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Prepísať"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -455,7 +527,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -466,7 +538,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -477,205 +549,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "Nemožno získať cestu k adresáru stavu"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Nemožno urÄiÅ¥ cestu k adresáru stavu VNC"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Nedá sa otvoriť \"%s\": %s"
+msgid "Could not open \"%s\""
+msgstr "Nedá sa otvoriť \"%s\""
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Nedá sa preÄítaÅ¥ riadok %d v súbore %s: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Nedá sa preÄítaÅ¥ riadok %d v súbore \"%s\""
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Príliš dlhý riadok"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Zlyhalo otváranie súboru s heslami"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "VNC autorizácia"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Toto spojenie je zabezpeÄené"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Toto spojenie nie je zabezpeÄené"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Meno používateľa:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Heslo:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Autentifikácia zrušená"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Zlyhalo aktualizovanie stavu diód na klávesnici: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Zlyhalo aktualizovanie stavu diód na klávesnici: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "Zlyhalo aktualizovanie stavu diód na klávesnici"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Zlyhalo získanie stavu diód na klávesnici: %d"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Ponechať heslo pre opätovné pripojenie"
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "Pri stlaÄení klávesa nebol zadaný žiaden kód klávesu"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Žiaden scan kód pre rozšírený virtuálny kláves 0x%02x"
-
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Žiaden scan kód pre virtuálny kláves 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Neplatný scan kód 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Žiaden symbol pre rozšírený virtuálny kláves 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Žiaden symbol pre virtuálny kláves 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Žiaden symbol pre kód klávesy 0x%02x (v súÄasnom stave)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Žiaden symbol pre kód klávesy %d (v súÄasnom stave)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "O&dpojiť"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&Režim celej obrazovky"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "Minimali&zovať"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "Prispôsobiť &veľkosť okna relácii"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Poslať %s"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Poslať Ctrl-Alt-&Del"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "Obnoviť ob&razovku"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "V&oľby..."
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "&Informácie o pripojení..."
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "O prehliadaÄi &TigerVNC..."
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Informácie o VNC pripojení"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Okno je registrované na dotyk namiesto ku gestám"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Zlyhalo nastavenie pre gestá (chyba 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Zlyhalo získanie informácií o gestách (chyba 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Neplatné Äíslo tlaÄidla myÅ¡i %d, musí to byÅ¥ Äíslo medzi 1 a 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Neriadený kláves 0x%x - nedá sa vytvoriť udalosť klávesnice."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "Maska udalosti X Input 2 pre okno 0x%08lx sa nedá naÄítaÅ¥"
@@ -685,7 +699,7 @@ msgstr "Maska udalosti X Input 2 pre okno 0x%08lx sa nedá naÄítaÅ¥"
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "Okno 0x%08lx nemá masku udalosti X Input 2"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "Okno 0x%08lx má viac než jednu masku udalosti X Input 2"
@@ -696,7 +710,6 @@ msgid "Failure grabbing device %i"
msgstr "Chyba pri preberaní zariadenia %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "PrehliadaÄ TigerVNC"
@@ -714,145 +727,146 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC je vysokorýchlostná verzia VNC založená na kóde RealVNC 4 a X.org. TigerVNC sa zaÄala ako snaha o vývoj novej generácie TightVNC pre Unix a Linux, ale oddelilo sa od rodiÄovského projektu na zaÄiatku roka 2009, a tak sa TigerVNC mohlo sústrediÅ¥ na platformu Windows. TigerVNC podporuje variant Tight kódovania, ktorý je znaÄne zrýchlený použitím JPEG kodeku libjpeg-turbo."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr "Pripojenie prehliadaÄa TigerVNC k stroju s CentOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr "Pripojenie prehliadaÄa TigerVNC k stroju s macOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr "Pripojenie prehliadaÄa TigerVNC k stroju s Windows"
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "TigerVNC tím"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Názov parametru je veľmi dlhý"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Parameter je veľmi dlhý"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Neplatný formát alebo veľmi veľká hodnota"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Zlyhalo vytvorenie kľúÄa v registry"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Zlyhalo zatvorenie kľúÄa v registry"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Zlyhalo uloženie \"%s\": %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Neznámy typ parametra"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Zlyhalo vymazanie \"%s\": %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Zlyhalo otvorenie kľúÄa v registry"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Zlyhalo preÄítanie záznamu histórie servera %d: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Zlyhalo preÄítanie parametra \"%s\": %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "Nedá sa získať cesta k adresáru s nastaveniami"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Nedá sa urÄiÅ¥ cesta k adresáru s nastaveniami VNC"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Nedá sa zakódovať parameter"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Súbor s nastaveniami %s je v neplatnom formáte"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Neplatný formát"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Neznámy parameter"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Prijatá správa (0x%x) pre neobsluhované okno"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "Neplatné okno 0x%08lx nastavené pre zabranie ukazovateľa"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "Zlyhalo vytvorenie obsluhy dotyku: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Nedá sa pripojiť obsluha udalostí k oknu (chyba 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Nepodarilo sa získať dáta udalostí pre udalosť X Input"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "Udalosť X Input pre neznáme okno"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "Rozšírenie X Input je nedostupné."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "X Input 2 (alebo novšie) nie je dostupné."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "X Input 2 (alebo novšie) nie je dostupné. Dotykové gestá nebudú podporované."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"PrehliadaÄ TigerVNC v%s\n"
"Postavený na: %s\n"
-"Copyright (C) 1999-%d Tím TigerVNC a mnohí Äalší (pozri README.txt)\n"
+"Copyright (C) 1999-%d Tím TigerVNC a mnohí Äalší (pozri README.rst)\n"
"Pre informácie o TigerVNC navštívte https://www.tigervnc.org."
#: vncviewer/vncviewer.cxx:158
@@ -892,95 +906,173 @@ msgstr "Chyba pri spustení prehliadaÄa TigerVNC: %s"
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr "Vnútorný signál na ukonÄenie %d bol prijatý. PrehliadaÄ TigerVNC sa teraz ukonÄí."
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "PrehliadaÄ TigerVNC"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Ãno"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Zatvoriť"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "O programe"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Skryť"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Odísť"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Služby"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Skryť ostatné"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Zobraziť všetky"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Súbor"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Nové pripojenie"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Použitie: %s [parametre] [hostiteľ][:ÄísloDispleja]\n"
+" %s[parametre] [hostiteľ][::port]\n"
+" %s[parametre] [unix socket]\n"
+" %s[parametre] -listen [port]\n"
+" %s[parametre] [.tigervnc súbor]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Možnosti:\n"
+"\n"
+" -display Xdisplay - Å pecifikuje X displej pre okno prehliadaÄa\n"
+" -geometry geometry - PoÄiatoÄná poloha hlavného okna prehliadaÄa VNC. Pozri\n"
+" stránku man pre detaily.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Parametre môžu byť zapnuté s -<param> alebo vypnuté s -<param>=0\n"
+"Parametre, ktoré vyžadujú hodnotu môžu byť zadané ako -<param> <value>\n"
+"Ostatné správne formáty sú <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Názvy parametrov nie sú citlivé na veľkosť písmen. Parametre sú:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "FullScreenAllMonitors je zastaralé, nastavte FullScreenMode na \"all\" radšej"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor je zastaralé, nastav hodnotu AlwaysCursos na 1 a CursorType na 'Dot' namiesto toho"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "~/.vnc je zastaralé, prosím poraÄte sa s \"man vncviewer\" pre možnosti, ktoré možno použiÅ¥."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "%%APPDATA%%\\vnc je zastaralé, prosím prejdite na %%APPDATA%%\\TigerVNC prieÄinok."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
+#, c-format
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Nedá sa vytvoriť VNC adresár s nastaveniami: \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Nedá sa urÄiÅ¥ cesta k VNC adresáru pre údaje"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Nedá sa vytvoriť VNC adresár pre údaje: \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:586
+#, c-format
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Nedá sa vytvoriť VNC adresár pre stavy: \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "Nedá sa vytvoriť VNC adresár s nastaveniami: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: Nerozpoznané nastavenie '%s'\n"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "Nedá sa vytvoriť VNC adresár pre údaje: %s"
+msgid "See '%s --help' for more information.\n"
+msgstr "Pozri '%s --help' pre viac informácií.\n"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:712
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "Nedá sa vytvoriť VNC adresár pre stavy: %s"
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: DodatoÄný argument '%s'\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Parametre -listen a -via sa navzájom vyluÄujú"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Nedajú sa zachytávať prichádzajúce spojenia"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "NaÄúva sa na porte %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -991,10 +1083,36 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Zlyhalo nastavovanie šifrovaného tunela:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "PrehliadaÄ vzdialenej plochy"
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Zobraziť bodku, ak kurzor nie je zobrazený"
+
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "Zlyhalo aktualizovanie stavu diód na klávesnici: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "Pri stlaÄení klávesa nebol zadaný žiaden kód klávesu"
+
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "Žiaden symbol pre kód klávesy 0x%02x (v súÄasnom stave)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "Neznámy typ parametra"
+
#~ msgid "Alt"
#~ msgstr "Alt"
diff --git a/po/sr.po b/po/sr.po
index fceaa6f3..ccef6737 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -1,14 +1,14 @@
# Serbian translation for tigervnc.
# Copyright © 2020 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
-# МироÑлав Ðиколић <miroslavnikolic@rocketmail.com>, 2016-2024.
+# МироÑлав Ðиколић <miroslavnikolic@rocketmail.com>, 2016-2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc-1.13.90\n"
+"Project-Id-Version: tigervnc-1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-12-15 19:41+0100\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-05-18 09:05+0200\n"
"Last-Translator: МироÑлав Ðиколић <miroslavnikolic@rocketmail.com>\n"
"Language-Team: Serbian <(nothing)>\n"
"Language: sr\n"
@@ -19,17 +19,17 @@ msgstr ""
"X-Bugs: Report translation errors to the Language-Team address.\n"
"X-Generator: Poedit 3.5\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Повезан на прикључницу „%s“"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Повезан Ñа домаћином „%s“ прикључник %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -40,85 +40,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Ðазив радне површи: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Домаћин: %.80s прикључник: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Величина: %d x %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Формат пикÑела: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(оÑновно на Ñерверу %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Затражено кодирање: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "ПоÑледње коришћено кодирање: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Процењена брзина линије: %d kbit/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Издања протокола: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Метода безбедноÑти: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Сервер је одбацио везу пре него ли је ÑеÑија могла да Ñе уÑпоÑтави."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Потврђивање идентитета није уÑпело: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"ÐиÑам уÑпео да потврдим идентитет Ñа Ñервером. Разлог који је дао Ñервер:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "ÐеуÑпело подешавање величине радне површи: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "ÐеиÑправни уноÑи подешавања мапе боје Ñа Ñервера!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "ПропуÑноÑÑ‚ је %d kbit/s — мењам на квалитет %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "ПропуÑноÑÑ‚ је %d kbit/s — пуна боја је Ñада омогућена"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "ПропуÑноÑÑ‚ је %d kbit/s — пуна боја је Ñада онемогућена"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "КориÑтим формат пикÑела %s"
@@ -131,21 +147,21 @@ msgstr "Ðаведена је неиÑправна геометрија!"
msgid "Reducing window size to fit on current monitor"
msgstr "Смањујем величину прозора да Ñтане на текући монитор"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Прилагођавам величину прозора да би Ñе избегли Ñлучајни захтеви за целим екраном"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "ПритиÑните „%s“ да отворите приручни изборник"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "ÐеуÑпех хватања таÑтатуре"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Прорачунат је неодговарајући раÑпоред екрана за захтев промене величине!"
@@ -153,251 +169,307 @@ msgstr "Прорачунат је неодговарајући раÑпоред
msgid "Invalid state for 3 button emulation"
msgstr "ÐеиÑправно Ñтање за опонашање 3 дугмета"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Ðема шифре прегледа за проширени виртуелни кључ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Ðема шифре прегледа за виртуелни кључ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "ÐеиÑправан код Ñкенирања 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Ðема Ñимбола за проширени виртуелни кључ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Ðема Ñимбола за виртуелни кључ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "ÐиÑам уÑпео да оÑвежим Ñтање диоде таÑтатуре: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Ðема Ñимбола за шифру кључа %d (у текућем Ñтању)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "ÐиÑам уÑпео да добавим Ñтање диоде таÑтатуре: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "ÐиÑам уÑпео да оÑвежим Ñтање диоде таÑтатуре"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "ÐиÑам уÑпео да добавим подешавање монитора ÑиÑтема"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "ÐеиÑправно подешавање је наведено за „%s“"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Ð˜Ð½Ð´ÐµÐºÑ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð° %d не поÑтоји"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "ÐеиÑправан Ð¸Ð½Ð´ÐµÐºÑ Ð¼Ð¾Ð½Ð¸Ñ‚Ð¾Ñ€Ð° „%s“"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Ðеочекивани знак „%c“"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "Опције ТигарВÐЦ-а"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Откажи"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "У реду"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Сажимање"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Сам изабери"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Жељено кодирање"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Ðиво боје"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Пуна"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Средња"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Слаба"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Врло Ñлаба"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Произвољни ниво Ñажимања:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "ниво (0=брзо, 9=најбоље)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Дозволи ЈПЕГ Ñажимање:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "квалитет (0=лош, 9=најбољи)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "БезбедноÑÑ‚"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Шифровање"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Ðишта"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "ТЛС Ñа анонимним уверењима"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "ТЛС Ñа X509 уверењима"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Путања до X509 уверења"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Путања до X509 ЦРЛ датотеке"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Потврђивање идентитета"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Стандардни Ð’ÐЦ (неÑигурно без шифровања)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "КориÑник и лозинка (неÑигурно без шифровања)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Улаз"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Само преглед (занемари миша и таÑтатуру)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Миш"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Опонашај Ñредње дугме миша"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Прикажи тачку када нема курзора"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Прикажи локални курзор када га Ñервер не доÑтави"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Ð’Ñ€Ñта курзора"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Тачка"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "СиÑтем"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "ТаÑтатура"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "ПроÑледи ÑиÑтемÑке кључеве директно на Ñервер (пун екран)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "ТаÑтер изборника"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "ОÑтава"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Прихвати оÑтаву Ñа Ñервера"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Такође поÑтави први избор"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Пошаљи оÑтаву на Ñервер"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Пошаљи први избор као оÑтаву"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Приказ"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Режим приказа"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "Упрозорен"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Цео екран на текућем монитору"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Цео екран на Ñвим мониторима"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Цео екран на изабраном монитору"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Разно"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Дељено (не прекидај везу другим прегледачима)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Питај за поновно повезивање при грешкама везе"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "Ð’ÐЦ прегледач: ПојединоÑти повезивања"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "Ð’ÐЦ Ñервер:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "МогућноÑти..."
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Учитавам..."
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Сачувај као..."
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "О програму..."
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Повежи Ñе"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -408,15 +480,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "Подешавање ТиграВÐЦ (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Изаберите датотеку подешавања ТиграВÐЦ"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -427,24 +499,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Сачувајте подешавање ТиграВÐЦ у датотеку"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "„%s“ већ поÑтоји. Желите ли да је препишете?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Ðе"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Препиши"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -455,7 +527,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -466,7 +538,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -477,205 +549,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "Ðе могу да набавим путању директоријума Ñтања"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Ðе могу да одредим путању фаÑцикле Ð’ÐЦ Ñтања"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Ðе могу да отворим „%s“: %s"
+msgid "Could not open \"%s\""
+msgstr "Ðе могу да отворим „%s“"
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "ÐиÑам уÑпео да прочитам %d. ред у датотеци „%s“: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "ÐиÑам уÑпео да прочитам %d. ред у датотеци „%s“"
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Ред је предуг"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Отварање датотеке лозинке није уÑпело"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "Потврђивање идентитета Ð’ÐЦ-а"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Ова веза је безбедна"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Ова веза није безбедна"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "КориÑник:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Лозинка:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Потврђивање идентитета је отказано"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "ÐиÑам уÑпео да оÑвежим Ñтање диоде таÑтатуре: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "ÐиÑам уÑпео да оÑвежим Ñтање диоде таÑтатуре: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "ÐиÑам уÑпео да оÑвежим Ñтање диоде таÑтатуре"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "ÐиÑам уÑпео да добавим Ñтање диоде таÑтатуре: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "Ðије наведен код таÑтера на притиÑак иÑтог"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Ðема шифре прегледа за проширени виртуелни кључ 0x%02x"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Задржи лозинку за поновно повезивање"
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Ðема шифре прегледа за виртуелни кључ 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "ÐеиÑправан код Ñкенирања 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Ðема Ñимбола за проширени виртуелни кључ 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Ðема Ñимбола за виртуелни кључ 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Ðема Ñимбола за шифру кључа 0x%02x (у текућем Ñтању)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Ðема Ñимбола за шифру кључа %d (у текућем Ñтању)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "Пре&кини везу"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&Пун екран"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "&Умањи"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "&Величина прозора на ÑеÑију"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ктрл"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Ðлт"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Пошаљи „%s“"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Пошаљи Ктрл-Ðлт-&Дел"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "&ОÑвежи екран"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&МогућноÑти..."
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "Подаци о &вези..."
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "О &програму..."
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Подаци о Ð’ÐЦ вези"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Прозор је региÑтрован за додир умеÑто покрета"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "ÐиÑам уÑпео да поÑтавим подешавање покрета (грешка 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "ÐиÑам уÑпео да добавим информације покрета (грешка 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "ÐеиÑправно дугме миша %d, мора бити број између 1 и 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Ðеобрадиви таÑтер 0x%x – не могу да Ñтворим догађај таÑтатуре."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "Ðе могу да добавим маÑку „X Input 2“ догађаја за прозор 0x%08lx"
@@ -685,7 +699,7 @@ msgstr "Ðе могу да добавим маÑку „X Input 2“ догађÐ
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "Прозор 0x%08lx нема маÑку „X Input 2“ догађаја"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "Прозор 0x%08lx има више од једне маÑке „X Input 2“ догађаја"
@@ -696,7 +710,6 @@ msgid "Failure grabbing device %i"
msgstr "ÐеуÑпех хватања уређаја %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "Прегледач ТигарВÐЦ"
@@ -714,145 +727,146 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "ТигарВÐЦ великобрзинÑко издање Ð’ÐЦ-а заÑновано на оÑновама „RealVNC“-у 4 и „X.org“ кода. ТигарВÐЦ је започео као развојно залагање Ñледеће генерације за „TightVNC“ на ÐˆÑƒÐ½Ð¸ÐºÑ Ð¸ Ð›Ð¸Ð½ÑƒÐºÑ Ð¿Ð»Ð°Ñ‚Ñ„Ð¾Ñ€Ð¼Ð°Ð¼Ð°, али Ñе издваја из Ñвог родитељÑког пројекта у раним 2009 тако да Ñе „TightVNC“ може фокуÑирати на Виндоуз платформама. ТигарВÐЦ подржава варијанту „Tight“ кодирања тако да је поприлично убрзан коришћењем „libjpeg-turbo“ ЈПЕГ кодека."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr "Веза ТигарВÐЦ прегледача Ñа CentOS рачунаром"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr "Веза ТигарВÐЦ прегледача Ñа macOS рачунаром"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr "Веза ТигарВÐЦ прегледача Ñа Виндоуз рачунаром"
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "Тим ТигарВÐЦ-а"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Ðазив параметра је превелик"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Параметар је превелик"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "ÐеиÑправан Ð·Ð°Ð¿Ð¸Ñ Ð¸Ð»Ð¸ предуга вредноÑÑ‚"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "ÐиÑам уÑпео да направим кључ региÑтра"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "ÐиÑам уÑпео да затворим кључ региÑтра"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "ÐиÑам уÑпео да Ñачувам „%s“: %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Ðепозната врÑта параметра"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "ÐиÑам уÑпео да уклоним „%s“: %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "ÐиÑам уÑпео да отворим кључ региÑтра"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "ÐиÑам уÑпео да прочитам ÑƒÐ½Ð¾Ñ Ð¸Ñторијата Ñервера %d: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "ÐиÑам уÑпео да прочитам параметар „%s“: %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "Ðе могу да набавим путању директоријума подешавања"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Ðе могу да одредим путању фаÑцикле Ð’ÐЦ подешавања"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Ðе могу да кодирам параметар"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Датотека подешавања „%s“ је у неиÑправном запиÑу"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "ÐеиÑправан запиÑ"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Ðепознат параметар"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Добих поруку (0x%x) за неруковани прозор"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "ÐеиÑправан прозор 0x%08lx је наведен за хватање показивача"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "ÐиÑам уÑпео да Ñтворим руковаоца додира: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Ðе могу да приложим руковаоца догађајем прозору (грешка 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "ÐиÑам уÑпео да добавим податке догађаја за „X Input“ догађај"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "„X Input“ догађај за непознати прозор"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "„X Input“ проширење није доÑтупно."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "„X Input 2“ (или новије) није доÑтупно."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "„X Input 2“ (или новије) није доÑтупно. Покрети додира неће бити подржани."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"Прегледач ТигарВÐЦ и%s\n"
"Изграђен: %s\n"
-"ÐуторÑка права © 1999-%d Тим Тигра Ð’ÐЦ-а и многи други (видите „README.rst“)\n"
+"ÐуторÑка права © 1999-%d Тим ТигарВÐЦ-а и многи други (видите „README.rst“)\n"
"ПоÑетите „https://www.tigervnc.org“ да Ñазнате више о програму."
#: vncviewer/vncviewer.cxx:158
@@ -892,95 +906,173 @@ msgstr "Грешка покретања новог примерка програ
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr "Примљен је Ñигнал за окончавање %d. Програм ће Ñада изаћи."
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "Прегледач ТигарВÐЦ"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Да"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Затвори"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "О програму"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Сакриј"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Изађи"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "УÑлуге"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Сакриј оÑтале"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Прикажи Ñве"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Датотека"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Ðова веза"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Коришћење: %s [parametri] [domaćin][:displayNum]\n"
+" %s [parametri] [domaćin][::port]\n"
+" %s [parametri] [prikljuÄnica linuksa]\n"
+" %s [parametri] -listen [prikquÄnik]\n"
+" %s [parametri] [.tigervnc datteka]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Опције:\n"
+"\n"
+" -display Xdisplay – Ðаводи X приказ за прозор прегледача\n"
+" -geometry geometry – почетни почожај главног прозора VNC прегледача. Вифите\n"
+" Ñтраницу упутÑтва за више о томе.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Параметри Ñе могу укључити Ñа „-<param>“ или иÑкључити Ñа „-<param>=0“\n"
+"Параметри који имају вредноÑÑ‚ Ñе могу навеÑти као „-<param> <vrednost>“\n"
+"Други иÑправни облици Ñу „<param>=<vrednost> -<param>=<vrednost> --<param>=<vrednost>“\n"
+"Ðазиви параметара ниÑу оÑетљиви на величину Ñлова. Параметри Ñу:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "„FullScreenAllMonitors“ је заÑтарело, поÑтавите „FullScreenMode“ на „all“"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "„DotWhenNoCursor“ је заÑтарело, поÑтавите „AlwaysCursor“ на 1 и „CursorType“ на „Dot“ (тачка)"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "„~/.vnc“ је заÑтарело, погледајте „man vncviewer“ за путање за преÑељење."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "„%%APPDATA%%\\vnc“ је заÑтарело, пређите на „%%APPDATA%%\\TigerVNC“."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "Ðе могу да направим фаÑциклу подешавања Ð’ÐЦ-а: %s"
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Ðе могу да направим фаÑциклу подешавања Ð’ÐЦ-а „%s“: %s"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Ðе могу да одредим путању фаÑцикле Ð’ÐЦ података"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Ðе могу да направим фаÑциклу података Ð’ÐЦ-а „%s“: %s"
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "Ðе могу да направим фаÑциклу података Ð’ÐЦ-а: %s"
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Ðе могу да направим фаÑциклу Ñтања Ð’ÐЦ-а „%s“: %s"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "Ðе могу да направим фаÑциклу Ñтања Ð’ÐЦ-а: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: Ðепозната опција „%s“\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "Видите „%s --help“ за више информација.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Додатни аргумент „%s“\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Параметри „-listen“ и „-via“ ниÑу ÑаглаÑни"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Ðе могу да оÑлушкујем долазне везе"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "ОÑлушкујем на прикључнику %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -991,10 +1083,38 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"ÐеуÑпех поÑтављања шифрованог тунела:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "Прегледач удаљених радних површи"
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Прикажи тачку када нема курзора"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "ÐиÑам уÑпео да оÑвежим Ñтање диоде таÑтатуре: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "Ðије наведен код таÑтера на притиÑак иÑтог"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "Ðема Ñимбола за шифру кључа 0x%02x (у текућем Ñтању)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "Ðепозната врÑта параметра"
+
#~ msgid "VNC Viewer: Connection Options"
#~ msgstr "Ð’ÐЦ прегледач: МогућноÑти повезивања"
diff --git a/po/sv.po b/po/sv.po
index 285716c0..a6b721ee 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -4,15 +4,15 @@
#
# Peter Ã…strand <astrand@cendio.se>, 2011.
# Göran Uddeborg <goeran@uddeborg.se>, 2015, 2016, 2017, 2018, 2019, 2021, 2022.
-# Luna Jernberg <droidbittin@gmail.com>, 2022, 2024.
+# Luna Jernberg <droidbittin@gmail.com>, 2022, 2024, 2025.
#
# $Revision: 1.25 $
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-23 08:49+0200\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-22 07:43+0100\n"
"Last-Translator: Luna Jernberg <droidbittin@gmail.com>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@@ -21,19 +21,19 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Generator: Poedit 3.4.2\n"
+"X-Generator: Poedit 3.5\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "Ansluten till uttaget %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "Ansluten till värden %s port %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -44,85 +44,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Skrivbordsnamn: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Värd: %.80s port: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Storlek: %d x %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Pixelformat: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(serverstandard %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Begärd kodning: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "Senast använd kodning: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Uppskattad hastighet på förbindelsen: %d kbit/s"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "Protokollversion: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Säkerhetsmetod: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "Anslutningen släpptes av servern innan sessionen kunde etableras."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Autentisering misslyckades: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Misslyckades med autentisering med servern. Anledning från servern:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "SetDesktopSize misslyckades: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "Ogiltig SetColourMapEntries från server!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "Bandbredd %d kbit/s - byter till kvalitet %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "Bandbredd %d kbit/s – fullfärg är nu aktiverat"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "Bandbredd %d kbit/s – fullfärg är nu avaktiverat"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "Använder pixelformat %s"
@@ -135,21 +151,21 @@ msgstr "Ogiltig geometri angiven!"
msgid "Reducing window size to fit on current monitor"
msgstr "Reducerar fönsterstorleken till att passa på den aktuella bildskärmen"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Justerar fönsterstorleken för att undvika fullskärm av misstag"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "Tryck %s för att öppna sammanhangsmenyn"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Misslyckades med att fånga tangentbordet"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Ogiltig skärmlayout beräknad för storleksförändrings-begäran!"
@@ -157,251 +173,307 @@ msgstr "Ogiltig skärmlayout beräknad för storleksförändrings-begäran!"
msgid "Invalid state for 3 button emulation"
msgstr "Felaktigt tillstånd för 3-knappsemulering"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Ingen scancode för utökad virtuell tangent 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Ingen scancode för virtuell tangent 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Felaktig skanningskod 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Ingen symbol för utökad virtuell tangent 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Ingen symbol för virtuell tangent 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Misslyckades att uppdatera tillståndet för tangentbords-LED: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Ingen symbol för tangentkod %d (i nuvarande tillstånd)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Misslyckades att hämta tillståndet för tangentbords-LED: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Misslyckades att uppdatera tillståndet för tangentbords-LED"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Misslyckades att hämta systemets bildskärmskonfiguration"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Ogiltig konfiguration angiven för %s"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Bildskärmsindex %d finns inte"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Felaktigt skärmindex â€%sâ€"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Oväntat tecken â€%câ€"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
-msgstr "TigerVNC-alternativ"
+msgid "TigerVNC options"
+msgstr "TigerVNC alternativ"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "Avbryt"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "Ok"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "Kompression"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Automatiskt val"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Föredragen kodning"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Färgnivå"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Fullständig"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Medium"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "LÃ¥g"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Mycket låg"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Anpassad komprimeringsnivå:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "kvalitet (0=snabb, 9=bäst)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Tillåt JPEG-komprimering:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "kvalitet (0=dålig, 9=bäst)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "Säkerhet"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "Kryptering"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Ingen"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS med anonyma certifikat"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS med X509-certifikat"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "Sökväg till CA-certifikat för X509"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "Sökväg till CRL-fil för X509"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "Autentisering"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Standard-VNC (osäkert utan kryptering)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Användarnamn och lösenord (osäkert utan kryptering)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "Inmatning"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Endast visning (ignorera mus och tangentbord)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Mus"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Emulera mittenknapp på musen"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Visa punkt när muspekare saknas"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Visa den lokala markören när den inte tillhandahålls av servern"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Markörtyp"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Punkt"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "System"
+
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Tangentbord"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Skicka systemtangenter direkt till servern (fullskärm)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Menytangent"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Urklipp"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Acceptera urklipp från server"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Sätt även primär markering"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "Skicka urklipp till server"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "Skicka primär markering som urklipp"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "Display"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Visningsläge"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "Fönster"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Helskärm på nuvarande bildskärm"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Helskärm på alla bildskärmar"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Helskärm på valda bildskärmar"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Diverse"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Delad (koppla ej från andra visare)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Be att få återansluta vid anslutningsfel"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
-msgstr "VNC-visare: Anslutningsdetaljer"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
+msgstr "VNC visare: Anslutningsdetaljer"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "VNC-server:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Inställningar..."
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Öppna..."
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Spara som..."
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "Om..."
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "Anslut"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -412,15 +484,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "TigerVNC-konfiguration (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Välj en TigerVNC-konfigurationsfil"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -431,24 +503,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Spara TigerVNC-konfigurationen i en fil"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s finns redan. Vill du skriva över den?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "Nej"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "Skriv över"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -459,7 +531,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -470,7 +542,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -481,205 +553,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "Det gick inte att hämta tillståndskatalogens sökväg"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Kunde inte bestämma VNC-tillståndskatalogsökväg"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Kunde inte öppna â€%sâ€: %s"
+msgid "Could not open \"%s\""
+msgstr "Kunde inte öppna \"%s\""
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Misslyckades med att läsa rad %d i fil %s: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Misslyckades med att läsa rad %d i fil \"%s\""
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Raden är för lång"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Öppning av lösenordsfilen misslyckades"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "VNC-autentisering"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Denna anslutning är säker"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Denna anslutning är inte säker"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "Användarnamn:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Lösenord:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Autentisering avbruten"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Misslyckades att uppdatera tillståndet för tangentbords-LED: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Misslyckades att uppdatera tillståndet för tangentbords-LED: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "Misslyckades att uppdatera tillståndet för tangentbords-LED"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Misslyckades att hämta tillståndet för tangentbords-LED: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "Ingen tangentkod angiven vid tangenttryckning"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Ingen scancode för utökad virtuell tangent 0x%02x"
-
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Ingen scancode för virtuell tangent 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Felaktig skanningskod 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Ingen symbol för utökad virtuell tangent 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Ingen symbol för virtuell tangent 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Ingen symbol för tangentkod 0x%02x (i nuvarande tillstånd)"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Behåll lösenordet för att återansluta"
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Ingen symbol för tangentkod %d (i nuvarande tillstånd)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "Koppla &ifrån"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&Fullskärm"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "M&inimera"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "Anpassa &fönster till session"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "Skicka %s"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Skicka Ctrl-Alt-&Del"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "&Uppdatera skärm"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "&Inställningar..."
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "&Information om anslutningen..."
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "Om &TigerVNC-visaren..."
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "VNC anslutningsinformation"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Fönstret har registrerats för beröring istället för gester"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Misslyckades med att sätta gestkonfigurationen (fel 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Misslyckades att få gestinformation (fel 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Felaktig musknapp %d, måste vara ett nummer mellan 1 och 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Ej hanterad tangent 0x%x — kan inte generera en tangentbordshändelse."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "Kan inte få X inmatning 2 händelsemask för fönster 0x%08lx"
@@ -689,7 +703,7 @@ msgstr "Kan inte få X inmatning 2 händelsemask för fönster 0x%08lx"
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "Fönster 0x%08lx har ingen X inmatning 2 händelsemask"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "Fönster 0x%08lx har mer än en X inmatning 2 händelsemask"
@@ -700,7 +714,6 @@ msgid "Failure grabbing device %i"
msgstr "Misslyckades med att fånga enhet %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "VNC-visare"
@@ -718,143 +731,144 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC är en höghastighetsversion av VNC baserat på kodbaserna RealVNC 4 och X.org. TigerVNC startades som ett arbete att utveckla nästa generation av TightVNC på Unix- och Linuxplattformar, men delades av från sitt föräldraprojekt i början av 2009 så att TightVNC kunde fokusera på plattformen Windows. TigerVNC stödjer en variant av Tight-kodning som är kraftigt accelererad genom användning av JPEG-omkodaren från libjpeg-turbo."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
-msgstr "TigerVNC-visares anslutning till en CentOS-maskin"
+msgid "TigerVNC viewer connection to a CentOS machine"
+msgstr "TigerVNC-visningsanslutning till en CentOS-maskin"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
-msgstr "TigerVNC-visares anslutning till en macOS-maskin"
+msgid "TigerVNC viewer connection to a macOS machine"
+msgstr "TigerVNC-visningsanslutning till en MacOS-maskin"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
-msgstr "TigerVNC-visares anslutning till en Windows-maskin"
-
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+msgid "TigerVNC viewer connection to a Windows machine"
+msgstr "TigerVNC-visningsanslutning till en Windows-maskin"
+
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "TigerVNC-teamet"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Namnet på parametern är för stort"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Parametern är för stor"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Ogiltigt format eller för stort värde"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Misslyckades med att skapa registernyckel"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Misslyckades med att stänga registernyckel"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Misslyckades att spara â€%sâ€: %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Okänd parametertyp"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Misslyckades att ta bort â€%sâ€: %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Misslyckades med att öppna registernyckel"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Misslyckades med att läsa serverhistorikpost %d: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Misslyckades med att läsa parametern â€%sâ€: %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "Det gick inte att hämta sökvägen till konfigurationskatalogen"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Kunde inte bestämma VNC-konfigurationskatalogsökvägen"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Kunde inte koda parametern"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Konfigurationsfilen %s har ogiltigt format"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Ogiltigt format"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Okänd parameter"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Fick ett meddelande (0x%x) för ett ej hanterat fönster"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "Felaktigt fönster 0x%08lx angivet för pekargrepp"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "Misslyckades med att skapa en beröringshanterare: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Kunde inte koppla en händelsehanterare till fönstret (fel 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Misslyckades att få händelsedata för en X inmatningshändelse"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "X inmatningshändelse för ett okänt fönster"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "X inmatningsutökning är inte tillgänglig."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "X inmatning 2 (eller nyare) är inte tillgänglig."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "X inmatning 2.2 (eller nyare) är inte tillgänglig. Beröringsgester kommer inte stödjas."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC visare v%s\n"
"Byggd på: %s\n"
"Copyright © 1999-%d TigerVNC-teamet och många andra (se README.rst)\n"
"Se https://www.tigervnc.org för information om TigerVNC."
@@ -896,95 +910,173 @@ msgstr "Fel vid start av ny TigerVNC-visare: %s"
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
-msgstr "Termineringssignal %d har mottagits. TigerVNC-visaren kommer nu att avslutas."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
+msgstr "Termineringssignal %d har tagits emot. TigerVNC visaren kommer nu att avslutas."
+
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "TigerVNC-visare"
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Ja"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Stäng"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "Om"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Göm"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Avsluta"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Tjänster"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Göm andra"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Visa alla"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Arkiv"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Ny anslutning"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"Användning: %s [parametrar] [värd][:displayNum]\n"
+" %s [parametrar] [värd][::port]\n"
+" %s [parametrar] [unix-uttag]\n"
+" %s [parametrar] -listen [port]\n"
+" %s [parametrar] [.tigervnc fil]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Alternativ:\n"
+"\n"
+" -display Xdisplay - Specificerar X-skärm för visningsfönstret\n"
+" -geometry geometry - Initial position för huvudfönstret för VNC-visning. Se\n"
+" manualsidan för detaljer.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Parametrar kan slås på med-<param> eller av med -<param>=0\n"
+"Parametrar som tar ett värde kan specificeras som-<param> <value>\n"
+"Andra giltiga former är <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameternamn är skiftlägesokänsliga. Parametrarna är:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "FullScreenAllMonitors är förÃ¥ldrat, sätt FullScreenMode till â€all†istället"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor är utfasad, ställ in AlwaysCursor till 1 och CursorType till \"Dot\" istället"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "~/.vnc är utfasad, vänligen konsultera 'man vncviewer' för sökvägar att migrera till."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "%%APPDATA%%\\vnc är utfasad, vänligen byt till %%APPDATA%%\\TigerVNC-platsen."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "Kunde inte skapa en VNC-konfigurationskatalog: %s"
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Kunde inte skapa en VNC-konfigurationskatalog: \"%s\": %s"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Kunde inte fastställa sökvägen till VNC-datakatalogen"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Kunde inte skapa en VNC-datakatalog: \"%s\": %s"
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "Kunde inte skapa en VNC-datakatalog: %s"
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Kunde inte skapa VNC-tillståndskatalog: \"%s\": %s"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "Kunde inte skapa VNC-tillståndskatalog: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: Okänt alternativ '%s'\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "Se '%s --help' för mer information.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: Extra argument '%s'\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Parametrar -listen och -via är inkompatibla"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Misslyckades att lyssna efter inkommande anslutningar"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Lyssnar på port %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -995,10 +1087,38 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Misslyckades med att konfigurera krypterad tunnel:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "Fjärrskrivbordsvisare"
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Visa punkt när muspekare saknas"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "Misslyckades att uppdatera tillståndet för tangentbords-LED: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "Ingen tangentkod angiven vid tangenttryckning"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "Ingen symbol för tangentkod 0x%02x (i nuvarande tillstånd)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "Okänd parametertyp"
+
#~ msgid "VNC Viewer: Connection Options"
#~ msgstr "VNC-visare: Anslutningsalternativ"
diff --git a/po/tigervnc.pot b/po/tigervnc.pot
index 9485b928..be5bd730 100644
--- a/po/tigervnc.pot
+++ b/po/tigervnc.pot
@@ -1,5 +1,5 @@
# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR TigerVNC Team and many others (see README.rst)
+# Copyright (C) YEAR TigerVNC team and many others (see README.rst)
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,17 +17,17 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr ""
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr ""
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -35,87 +35,100 @@ msgid ""
"%s"
msgstr ""
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr ""
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr ""
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr ""
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr ""
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr ""
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr ""
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr ""
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr ""
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr ""
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr ""
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid ""
"The connection was dropped by the server before the session could be "
"established."
msgstr ""
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr ""
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr ""
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr ""
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr ""
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr ""
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr ""
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr ""
@@ -128,21 +141,21 @@ msgstr ""
msgid "Reducing window size to fit on current monitor"
msgstr ""
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr ""
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr ""
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr ""
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr ""
@@ -150,251 +163,307 @@ msgstr ""
msgid "Invalid state for 3 button emulation"
msgstr ""
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr ""
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr ""
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr ""
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr ""
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr ""
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr ""
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr ""
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr ""
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr ""
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr ""
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr ""
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr ""
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr ""
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr ""
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr ""
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr ""
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr ""
+
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr ""
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr ""
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr ""
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr ""
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr ""
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr ""
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr ""
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr ""
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr ""
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -402,15 +471,15 @@ msgid ""
"%s"
msgstr ""
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr ""
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr ""
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -418,24 +487,24 @@ msgid ""
"%s"
msgstr ""
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr ""
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr ""
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr ""
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr ""
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -443,7 +512,7 @@ msgid ""
"%s"
msgstr ""
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -451,7 +520,7 @@ msgid ""
"%s"
msgstr ""
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -459,205 +528,147 @@ msgid ""
"%s"
msgstr ""
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
msgstr ""
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
+msgid "Could not open \"%s\""
msgstr ""
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
+msgid "Failed to read line %d in file \"%s\""
msgstr ""
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr ""
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr ""
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr ""
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr ""
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr ""
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr ""
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr ""
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
msgstr ""
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr ""
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr ""
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr ""
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr ""
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr ""
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr ""
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr ""
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr ""
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr ""
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr ""
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr ""
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr ""
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr ""
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr ""
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr ""
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr ""
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr ""
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr ""
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr ""
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr ""
@@ -667,7 +678,7 @@ msgstr ""
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr ""
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr ""
@@ -678,7 +689,6 @@ msgid "Failure grabbing device %i"
msgstr ""
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr ""
@@ -710,131 +720,132 @@ msgid ""
msgstr ""
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr ""
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr ""
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr ""
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr ""
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr ""
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr ""
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr ""
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr ""
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr ""
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr ""
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr ""
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr ""
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr ""
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr ""
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr ""
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
msgstr ""
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr ""
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr ""
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr ""
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr ""
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr ""
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr ""
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr ""
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr ""
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr ""
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr ""
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr ""
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr ""
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid ""
"X Input 2.2 (or newer) is not available. Touch gestures will not be "
"supported."
@@ -843,9 +854,9 @@ msgstr ""
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
@@ -880,99 +891,162 @@ msgstr ""
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr ""
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr ""
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr ""
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr ""
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr ""
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr ""
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr ""
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr ""
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr ""
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr ""
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr ""
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See "
+"the\n"
+" man page for details.\n"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:527
msgid ""
"FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr ""
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid ""
+"DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' "
+"instead"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:553
msgid ""
"~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr ""
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid ""
"%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC "
"location."
msgstr ""
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
+#, c-format
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC config directory: %s"
+msgid "Could not create VNC state directory \"%s\": %s"
msgstr ""
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC data directory: %s"
+msgid "%s: Unrecognized option '%s'\n"
msgstr ""
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
#, c-format
-msgid "Could not create VNC state directory: %s"
+msgid "See '%s --help' for more information.\n"
+msgstr ""
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
msgstr ""
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr ""
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr ""
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr ""
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -980,6 +1054,14 @@ msgid ""
"%s"
msgstr ""
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr ""
diff --git a/po/uk.po b/po/uk.po
index a063f036..06fb0fd6 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -2,13 +2,13 @@
# Copyright (C) 2014 the TigerVNC Team (msgids)
# This file is distributed under the same license as the tigervnc package.
#
-# Yuri Chornoivan <yurchor@ukr.net>, 2014, 2015, 2016, 2017, 2018, 2019, 2021, 2022, 2024.
+# Yuri Chornoivan <yurchor@ukr.net>, 2014, 2015, 2016, 2017, 2018, 2019, 2021, 2022, 2024, 2025.
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-06-20 19:02+0300\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-01-21 19:30+0200\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
"Language: uk\n"
@@ -19,17 +19,17 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Lokalize 23.04.3\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "З’єднано з Ñокетом %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "З’єднано з вузлом %s, порт %d"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -40,85 +40,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "Ðазва робочої Ñтанції: %.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "Вузол: %.80s порт: %d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "Розмір: %d x %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "Формат у пікÑелÑÑ…: %s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(типовий Ð´Ð»Ñ Ñервера %s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "Запит щодо кодуваннÑ: %s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "ОÑтаннє викориÑтане кодуваннÑ: %s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "Оцінка швидкоÑті лінії: %d кбіт/Ñ"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "ВерÑÑ–Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ: %d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "Метод захиÑту: %s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð±ÑƒÐ»Ð¾ розірвано Ñервером до того, Ñк виникла можливіÑть розпочати ÑеанÑ."
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "Ð Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ðµ пройдено: %s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ð¹Ñ‚Ð¸ Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð° Ñервері. Причина, Ñку вказано Ñервером:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "Помилка SetDesktopSize: %d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ SetColourMapEntries від Ñервера!"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "ПропуÑкна здатніÑть %d кбіт/Ñ â€” змінюємо ÑкіÑть на %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "ПропуÑкна здатніÑть %d кбіт/Ñ â€” увімкнено повноцінні кольори"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "ПропуÑкна здатніÑть %d кбіт/Ñ â€” вимкнено повноцінні кольори"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "ВикориÑтовуємо формат у пікÑелÑÑ… %s"
@@ -131,21 +147,21 @@ msgstr "Вказано некоректні геометричні парамеÑ
msgid "Reducing window size to fit on current monitor"
msgstr "Зменшуємо розмір вікна, щоб уміÑтити його на поточному моніторі"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "Коригувати розміри вікна, щоб уникнути випадкового запиту щодо переходу у повноекранний режим"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "ÐатиÑніть %s, щоб відкрити контекÑтне меню"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "Помилка під Ñ‡Ð°Ñ Ñпроби перехопити клавіатуру"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "Результати обчиÑÐ»ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–ÐºÐ½Ð° Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ щодо зміни розмірів Ñ” некоректними!"
@@ -153,251 +169,307 @@ msgstr "Результати обчиÑÐ»ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–Ð
msgid "Invalid state for 3 button emulation"
msgstr "Ðекоректний Ñтан Ð´Ð»Ñ ÐµÐ¼ÑƒÐ»Ñції 3 кнопок"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "Ðемає коду ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ñ— клавіші Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "Ðемає коду ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ñ— клавіші 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "Ðекоректний код ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "Ðемає Ñимволу Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ñ— клавіші Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "Ðемає Ñимволу Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ñ— клавіші 0x%02x"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ Ñтан лампочки клавіатури: %lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "Ðемає Ñимволу Ð´Ð»Ñ ÐºÐ»Ð°Ð²Ñ–ÑˆÑ– з кодом %d (у поточному Ñтані)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ Ñтан лампочки клавіатури: %d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ Ñтан лампочки клавіатури"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð° з боку ÑиÑтеми"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "Вказано некоректні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ %s"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "Монітора із індекÑом %d не Ñ–Ñнує"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
msgstr "Ðекоректний Ñ–Ð½Ð´ÐµÐºÑ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð°, «%s»"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
msgstr "Ðеочікуваний Ñимвол «%c»"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "Параметри TigerVNC"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "СкаÑувати"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "Гаразд"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "СтиÑканнÑ"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "Ðвтовибір"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "Бажане кодуваннÑ"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "Рівень Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ð»ÑŒÐ¾Ñ€Ñƒ"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "Повний"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "Середній"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "Ðизький"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "Дуже низький"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "Ðетиповий рівень ÑтиÑканнÑ:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "рівень (0=швидко, 9=найкраще)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "Дозволити ÑтиÑÐºÐ°Ð½Ð½Ñ JPEG:"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "ÑкіÑть (0=найгірша, 9=найкраща)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "ЗахиÑÑ‚"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "ШифруваннÑ"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "Ðемає"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "TLS із анонімними Ñертифікатами"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "TLS з Ñертифікатами X509"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "ШлÑÑ… до Ñертифіката CA X509"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "ШлÑÑ… до файла CRL X509"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "РозпізнаваннÑ"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "Стандартний VNC (без захиÑту Ñ– шифруваннÑ)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "Ð†Ð¼â€™Ñ ÐºÐ¾Ñ€Ð¸Ñтувача Ñ– пароль (без захиÑту Ñ– шифруваннÑ)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "ВведеннÑ"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "Лише переглÑд (ігнорувати Ñигнали від миші Ñ– клавіатури)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "Миша"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "Емулювати Ñередню кнопку миші"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "Показувати крапку, Ñкщо немає курÑора"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "Показувати локальний курÑор, Ñкщо його не надано Ñервером"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "Тип курÑора"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "Крапка"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "СиÑтемний"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "Клавіатура"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "Передавати натиÑÐºÐ°Ð½Ð½Ñ ÑиÑтемних клавіш безпоÑередньо до Ñервера (повноекранний режим)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "Клавіша меню"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "Буфер обміну"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "Приймати вміÑÑ‚ буфера з Ñервера"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "Також вÑтановити оÑновне позначене"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "ÐадіÑлати вміÑÑ‚ буфера обміну до Ñервера"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "ÐадіÑлати оÑновне позначене Ñк буфер обміну"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "ДиÑплей"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "Режим показу"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "У вікні"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "Повноекранний режим на поточному моніторі"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "Повноекранний режимі на уÑÑ–Ñ… моніторах"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "Повноекранний режим на позначених моніторах"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "Інше"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "Спільний (не від’єднувати інші заÑоби переглÑду)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "Питати про повторне з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸ помилка з'єднаннÑ"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "ЗаÑіб переглÑду VNC: подробиці з’єднаннÑ"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "Сервер VNC:"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "Параметри…"
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "Завантажити…"
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
msgstr "Зберегти Ñк…"
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "Про програму…"
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "З'єднатиÑÑ"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -408,15 +480,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ TigerVNC (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "Виберіть файл налаштувань TigerVNC"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -427,24 +499,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "Зберегти Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ TigerVNC до файла"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s вже Ñ–Ñнує. ПерезапиÑати?"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "ÐÑ–"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "ПерезапиÑати"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -455,7 +527,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -466,7 +538,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -477,205 +549,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ шлÑÑ… до каталогу Ñтану"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ каталог Ñтану VNC"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ «%s»: %s"
+msgid "Could not open \"%s\""
+msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ «%s»"
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ Ñ€Ñдок %d у файлі %s: %s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ Ñ€Ñдок %d у файлі «%s»"
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "Занадто довгий Ñ€Ñдок"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "Спроба Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ„Ð°Ð¹Ð»Ð° паролів зазнала невдачі"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "Ð Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ VNC"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "Це з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ” безпечним"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "Це з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð½Ðµ Ñ” безпечним"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "КориÑтувач:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "Пароль:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "Ð Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ ÑкаÑовано"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ Ñтан лампочки клавіатури: %lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ Ñтан лампочки клавіатури: %d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ Ñтан лампочки клавіатури"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ Ñтан лампочки клавіатури: %d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "Ðе вказано коду клавіші при натиÑканні"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "Ðемає коду ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ñ— клавіші Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 0x%02x"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "Зберігати пароль Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ð³Ð¾ з'єднаннÑ"
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "Ðемає коду ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ñ— клавіші 0x%02x"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "Ðекоректний код ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ 0x%02x"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "Ðемає Ñимволу Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ñ— клавіші Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ 0x%02x"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "Ðемає Ñимволу Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ñ— клавіші 0x%02x"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "Ðемає Ñимволу Ð´Ð»Ñ ÐºÐ»Ð°Ð²Ñ–ÑˆÑ– з кодом 0x%02x (у поточному Ñтані)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "Ðемає Ñимволу Ð´Ð»Ñ ÐºÐ»Ð°Ð²Ñ–ÑˆÑ– з кодом %d (у поточному Ñтані)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "Від'єд&натиÑÑ"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "&Ðа веÑÑŒ екран"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "М&інімізувати"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "Змінити &розміри вікна відповідно до ÑеанÑу"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "ÐадіÑлати %s"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "Ðа&діÑлати Ctrl-Alt-Del"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "&Оновити вміÑÑ‚ екрана"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "П&араметри…"
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "Дані щодо з’&єднаннÑ…"
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "Про &заÑіб переглÑду TigerVNC…"
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "Дані щодо Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ VNC"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "Вікно зареєÑтровано Ð´Ð»Ñ ÑенÑорних дій, а не Ð´Ð»Ñ Ð¶ÐµÑтів"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "Ðе вдалоÑÑ Ð²Ñтановити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¶ÐµÑтів (помилка 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ відомоÑті щодо жеÑтів (помилка 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "Ðекоректна кнопка миші, %d, номер кнопки має бути чиÑлом від 1 до 7."
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "Ðепридатна до обробки клавіша 0x%x — не вдалоÑÑ Ñтворити подію клавіатури."
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ маÑку події X Input 2 Ð´Ð»Ñ Ð²Ñ–ÐºÐ½Ð° 0x%08lx"
@@ -685,7 +699,7 @@ msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ маÑку події X Input 2 дÐ
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "У вікна 0x%08lx немає маÑки подій X Input 2"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "У вікна 0x%08lx Ñ” декілька маÑок подій X Input 2"
@@ -696,7 +710,6 @@ msgid "Failure grabbing device %i"
msgstr "Помилка під Ñ‡Ð°Ñ Ñпроби захопити приÑтрій %i"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "ЗаÑіб переглÑду TigerVNC"
@@ -714,140 +727,141 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC — виÑокошвидкіÑна верÑÑ–Ñ VNC на оÑнові програмного коду RealVNC 4 та X.org. Роботу над TigerVNC було розпочато у межах побудови наÑтупного Ð¿Ð¾ÐºÐ¾Ð»Ñ–Ð½Ð½Ñ Ð´Ð»Ñ TightVNC на платформах Unix та Linux, але програма відокремилаÑÑ Ð²Ñ–Ð´ батьківÑького проєкту на початку 2009 року, коли проєкт TightVNC зоÑередивÑÑ Ð½Ð° платформах Windows. У TigerVNC передбачено підтримку варіанта ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Tight, Ñкий значно пришвидшено викориÑтаннÑм кодека JPEG libjpeg-turbo."
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ ÐŸÐµÑ€ÐµÐ³Ð»Ñдача TigerVNC зі комп'ютером, де працює CentOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ ÐŸÐµÑ€ÐµÐ³Ð»Ñдача TigerVNC із комп'ютером, де працює macOS"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ ÐŸÐµÑ€ÐµÐ³Ð»Ñдача TigerVNC із комп'ютером, де працює Windows"
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "Команда TigerVNC"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "Ðазва параметра Ñ” надто довгою"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "Параметр є надто великим"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "Ðекоректне Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ надто велике значеннÑ"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "Ðе вдалоÑÑ Ñтворити ключ реєÑтру"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "Ðе вдалоÑÑ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸ ключ реєÑтру"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ «%s»: %s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "Ðевідомий тип параметра"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð»ÑƒÑ‡Ð¸Ñ‚Ð¸ «%s»: %s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ ключ реєÑтру"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ Ð·Ð°Ð¿Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ñƒ Ñервера %d: %s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ параметр «%s»: %s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ шлÑÑ… до каталогу налаштувань"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ шлÑÑ… до каталогу налаштувань VNC"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "Ðе вдалоÑÑ Ð·Ð°ÐºÐ¾Ð´ÑƒÐ²Ð°Ñ‚Ð¸ параметр"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "Файл налаштувань %s збережено у некоректному форматі"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "Ðекоректне форматуваннÑ"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "Ðевідомий параметр"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "Отримано Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ (0x%x) Ð´Ð»Ñ Ð²Ñ–ÐºÐ½Ð°, обробка Ñкого не здійÑнюєтьÑÑ"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "Ð”Ð»Ñ Ð·Ð°Ñ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ Ð²ÐºÐ°Ð·Ñ–Ð²Ð½Ð¸ÐºÐ° вказано некоректне вікно 0x%08lx"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "Ðе вдалоÑÑ Ñтворити обробник ÑенÑорних даних: %s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚Ð¸ обробник подій до вікна (помилка 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ дані події Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ–Ñ— X Input"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "ÐŸÐ¾Ð´Ñ–Ñ X Input Ð´Ð»Ñ Ð½ÐµÐ²Ñ–Ð´Ð¾Ð¼Ð¾Ð³Ð¾ вікна"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "Ð Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ X Input Ñ” недоÑтупним."
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "Ðемає доÑтупу до X Input 2 (або новішої верÑÑ–Ñ—)."
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "Ðемає доÑтупу до X Input 2.2 (або новішої верÑÑ–Ñ—). Ви не зможете ÑкориÑтатиÑÑ Ð¿Ñ–Ð´Ñ‚Ñ€Ð¸Ð¼ÐºÐ¾ÑŽ ÑенÑорних жеÑтів."
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"ЗаÑіб переглÑду TigerVNC, v%s\n"
@@ -892,95 +906,173 @@ msgstr "Помилка під Ñ‡Ð°Ñ Ñпроби запуÑку нового з
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
msgstr "Отримано Ñигнал Ð¿ÐµÑ€ÐµÑ€Ð¸Ð²Ð°Ð½Ð½Ñ %d. Зараз заÑіб переглÑду TigerVNC завершить роботу."
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "ЗаÑіб переглÑду TigerVNC"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "Так"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "Закрити"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "Про програму"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "Сховати"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "Вийти"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "Служби"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "Сховати решту"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "Показати вÑÑ–"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "&Файл"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "&Створити з'єднаннÑ"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"КориÑтуваннÑ: %s [параметри] [вузол][:номерДиÑплеÑ]\n"
+" %s [параметри] [вузол][::порт]\n"
+" %s [параметри] [Ñокет unix]\n"
+" %s [параметри] -listen [порт]\n"
+" %s [параметри] [файл .tigervnc]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"Параметри:\n"
+"\n"
+" -display диÑплейX - визначити диÑплей X Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ вікна переглÑдача\n"
+" -geometry Ð³ÐµÐ¾Ð¼ÐµÑ‚Ñ€Ñ–Ñ - початкова Ð¿Ð¾Ð·Ð¸Ñ†Ñ–Ñ Ð³Ð¾Ð»Ð¾Ð²Ð½Ð¾Ð³Ð¾ вікна переглÑдача VNC.\n"
+" Див. Ñторінку man, щоб дізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ.\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"Параметри можна увімкнути за допомогою -<парам> або вимкнути за допомогою -<парам>=0\n"
+"Параметри, Ñкі приймають Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¼Ð¾Ð¶Ð½Ð° вказати у формі -<парам> <значеннÑ>\n"
+"Інші коректні форми — <парам>=<значеннÑ> -<парам>=<значеннÑ> --<парам>=<значеннÑ>\n"
+"Ðазви параметрів Ñлід вказувати з врахуваннÑм регіÑтру Ñимволів. Параметри:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "FullScreenAllMonitors вважаєтьÑÑ Ð·Ð°Ñтарілим, заміÑть нього Ñлід вÑтановити Ð´Ð»Ñ FullScreenMode Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«all»"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor з заÑтарілим, натоміÑть вÑтановіть Ð´Ð»Ñ AlwaysCursor Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ 1, а Ð´Ð»Ñ CursorType Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ 'Dot'"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "~/.vnc вважаєтьÑÑ Ð·Ð°Ñтарілим, будь лаÑка, ознайомтеÑÑ Ñ–Ð· «man vncviewer», щоб дізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про перенеÑÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ…."
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "%%APPDATA%%\\vnc вважаєтьÑÑ Ð·Ð°Ñтарілим, будь лаÑка, переходьте на %%APPDATA%%\\TigerVNC."
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "Ðе вдалоÑÑ Ñтворити каталог налаштувань VNC: %s"
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "Ðе вдалоÑÑ Ñтворити каталог налаштувань VNC «%s»: %s"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ шлÑÑ… до каталогу даних VNC"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "Ðе вдалоÑÑ Ñтворити каталог даних VNC «%s»: %s"
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "Ðе вдалоÑÑ Ñтворити каталог даних VNC: %s"
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "Ðе вдалоÑÑ Ñтворити каталог Ñтану VNC «%s»: %s"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "Ðе вдалоÑÑ Ñтворити каталог Ñтану VNC: %s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s: невідомий параметр «%s»\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "Див. «%s --help», щоб дізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ.\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s: зайвий аргумент «%s»\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "Параметри -listen Ñ– -via Ñ” неÑуміÑними"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð·Ð° вхідними з'єднаннÑми"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "Очікуємо на дані на порту %d"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -991,10 +1083,38 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"Ðе вдалоÑÑ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ñ‚Ð¸ зашифрований тунель:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "ЗаÑіб переглÑду віддаленої Ñтільниці"
+#~ msgid "Show dot when no cursor"
+#~ msgstr "Показувати крапку, Ñкщо немає курÑора"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ Ñтан лампочки клавіатури: %d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "Ðе вказано коду клавіші при натиÑканні"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "Ðемає Ñимволу Ð´Ð»Ñ ÐºÐ»Ð°Ð²Ñ–ÑˆÑ– з кодом 0x%02x (у поточному Ñтані)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "Ðевідомий тип параметра"
+
#~ msgid "VNC Viewer: Connection Options"
#~ msgstr "ЗаÑіб переглÑду VNC: параметри з’єднаннÑ"
diff --git a/po/zh_TW.po b/po/zh_TW.po
index 749d5007..f46799a1 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -5,10 +5,10 @@
# pan93412 <pan93412@gmail.com>, 2019.
msgid ""
msgstr ""
-"Project-Id-Version: tigervnc 1.13.90\n"
+"Project-Id-Version: tigervnc 1.14.90\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2024-06-20 15:01+0200\n"
-"PO-Revision-Date: 2024-11-30 13:57+0800\n"
+"POT-Creation-Date: 2025-01-14 16:15+0100\n"
+"PO-Revision-Date: 2025-02-02 00:23+0800\n"
"Last-Translator: Yi-Jyun Pan <pan93412@gmail.com>\n"
"Language-Team: Chinese (traditional) <zh-l10n@lists.slat.org>\n"
"Language: zh_TW\n"
@@ -19,17 +19,17 @@ msgstr ""
"X-Bugs: Report translation errors to the Language-Team address.\n"
"X-Generator: Poedit 3.5\n"
-#: vncviewer/CConn.cxx:99
+#: vncviewer/CConn.cxx:102
#, c-format
msgid "Connected to socket %s"
msgstr "已連線到 socket %s"
-#: vncviewer/CConn.cxx:106
+#: vncviewer/CConn.cxx:109
#, c-format
msgid "Connected to host %s port %d"
msgstr "已連線到主機ä½å€ %s (連線埠 %d)"
-#: vncviewer/CConn.cxx:111
+#: vncviewer/CConn.cxx:114
#, c-format
msgid ""
"Failed to connect to \"%s\":\n"
@@ -40,85 +40,101 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/CConn.cxx:155
+#: vncviewer/CConn.cxx:151
#, c-format
msgid "Desktop name: %.80s"
msgstr "桌é¢å稱:%.80s"
-#: vncviewer/CConn.cxx:160
+#: vncviewer/CConn.cxx:154
#, c-format
msgid "Host: %.80s port: %d"
msgstr "主機å稱:%.80s 連線埠:%d"
-#: vncviewer/CConn.cxx:165
+#: vncviewer/CConn.cxx:158
#, c-format
msgid "Size: %d x %d"
msgstr "大å°ï¼š%d x %d"
-#: vncviewer/CConn.cxx:173
+#: vncviewer/CConn.cxx:165
#, c-format
msgid "Pixel format: %s"
msgstr "åƒç´ æ ¼å¼ï¼š%s"
-#: vncviewer/CConn.cxx:180
+#: vncviewer/CConn.cxx:170
#, c-format
msgid "(server default %s)"
msgstr "(伺æœå™¨é è¨­å€¼ï¼š%s)"
-#: vncviewer/CConn.cxx:185
+#: vncviewer/CConn.cxx:173
#, c-format
msgid "Requested encoding: %s"
msgstr "請求的編碼方å¼ï¼š%s"
-#: vncviewer/CConn.cxx:190
+#: vncviewer/CConn.cxx:177
#, c-format
msgid "Last used encoding: %s"
msgstr "上次使用的編碼方å¼ï¼š%s"
-#: vncviewer/CConn.cxx:195
+#: vncviewer/CConn.cxx:181
#, c-format
msgid "Line speed estimate: %d kbit/s"
msgstr "估計線速:%d kbit/秒"
-#: vncviewer/CConn.cxx:200
+#: vncviewer/CConn.cxx:185
#, c-format
msgid "Protocol version: %d.%d"
msgstr "å”定版本:%d.%d"
-#: vncviewer/CConn.cxx:205
+#: vncviewer/CConn.cxx:189
#, c-format
msgid "Security method: %s"
msgstr "安全性方法:%s"
-#: vncviewer/CConn.cxx:266 vncviewer/CConn.cxx:268
+#: vncviewer/CConn.cxx:250 vncviewer/CConn.cxx:252
msgid "The connection was dropped by the server before the session could be established."
msgstr "在工作階段能夠建立å‰ï¼Œé€£ç·šå°±è¢«ä¼ºæœå™¨ä¸Ÿæ£„。"
-#: vncviewer/CConn.cxx:326
+#: vncviewer/CConn.cxx:262
+#, c-format
+msgid "Authentication failed: %s"
+msgstr "èªè­‰å¤±æ•—:%s"
+
+#: vncviewer/CConn.cxx:263
+#, c-format
+msgid ""
+"Failed to authenticate with the server. Reason given by the server:\n"
+"\n"
+"%s"
+msgstr ""
+"無法通éŽä¼ºæœå™¨èªè­‰ã€‚伺æœå™¨æä¾›çš„原因:\n"
+"\n"
+"%s"
+
+#: vncviewer/CConn.cxx:335
#, c-format
msgid "SetDesktopSize failed: %d"
msgstr "執行 SetDesktopSize 失敗:%d"
-#: vncviewer/CConn.cxx:399
+#: vncviewer/CConn.cxx:408
msgid "Invalid SetColourMapEntries from server!"
msgstr "伺æœå™¨å‚³ä¾†ç„¡æ•ˆçš„ SetColourMapEntriesï¼"
-#: vncviewer/CConn.cxx:507
+#: vncviewer/CConn.cxx:516
#, c-format
msgid "Throughput %d kbit/s - changing to quality %d"
msgstr "輸é€é‡ %d kbit/ç§’ - å°‡å“質等級變更至 %d"
-#: vncviewer/CConn.cxx:529
+#: vncviewer/CConn.cxx:538
#, c-format
msgid "Throughput %d kbit/s - full color is now enabled"
msgstr "輸é€é‡ %d kbit/ç§’ - 全彩模å¼ç¾å·²å•Ÿç”¨"
-#: vncviewer/CConn.cxx:532
+#: vncviewer/CConn.cxx:541
#, c-format
msgid "Throughput %d kbit/s - full color is now disabled"
msgstr "輸é€é‡ %d kbit/ç§’ - 全彩模å¼ç¾å·²åœç”¨"
-#: vncviewer/CConn.cxx:558
+#: vncviewer/CConn.cxx:567
#, c-format
msgid "Using pixel format %s"
msgstr "使用åƒç´ æ ¼å¼ %s"
@@ -131,21 +147,21 @@ msgstr "指定了無效的幾何大å°ï¼"
msgid "Reducing window size to fit on current monitor"
msgstr "縮å°è¦–窗大å°ï¼Œä½¿ä¹‹èƒ½å®Œå…¨ç½®æ–¼ç›®å‰é¡¯ç¤ºå™¨ä¸­"
-#: vncviewer/DesktopWindow.cxx:648
+#: vncviewer/DesktopWindow.cxx:646
msgid "Adjusting window size to avoid accidental full-screen request"
msgstr "調整視窗大å°ï¼Œé¿å…產生æ„外的全螢幕請求"
-#: vncviewer/DesktopWindow.cxx:696
+#: vncviewer/DesktopWindow.cxx:694
#, c-format
msgid "Press %s to open the context menu"
msgstr "按下 %s éµé–‹å•Ÿå…§å®¹é¸å–®"
-#: vncviewer/DesktopWindow.cxx:1097 vncviewer/DesktopWindow.cxx:1105
-#: vncviewer/DesktopWindow.cxx:1125
+#: vncviewer/DesktopWindow.cxx:1094 vncviewer/DesktopWindow.cxx:1102
+#: vncviewer/DesktopWindow.cxx:1122
msgid "Failure grabbing keyboard"
msgstr "æ“·å–éµç›¤å¤±æ•—"
-#: vncviewer/DesktopWindow.cxx:1415
+#: vncviewer/DesktopWindow.cxx:1411
msgid "Invalid screen layout computed for resize request!"
msgstr "為縮放請求計算的螢幕版é¢é…置無效ï¼"
@@ -153,251 +169,307 @@ msgstr "為縮放請求計算的螢幕版é¢é…置無效ï¼"
msgid "Invalid state for 3 button emulation"
msgstr "無效的 3 按鈕模擬狀態"
+#: vncviewer/KeyboardWin32.cxx:242
+#, c-format
+msgid "No scan code for extended virtual key 0x%02x"
+msgstr "æ²’æœ‰å°æ‡‰åˆ°å»¶ä¼¸è™›æ“¬ä»£ç¢¼ 0x%02x 的掃æç¢¼"
+
+#: vncviewer/KeyboardWin32.cxx:244
+#, c-format
+msgid "No scan code for virtual key 0x%02x"
+msgstr "æ²’æœ‰å°æ‡‰åˆ°è™›æ“¬æŒ‰éµ 0x%02x 的掃æç¢¼"
+
+#: vncviewer/KeyboardWin32.cxx:250
+#, c-format
+msgid "Invalid scan code 0x%02x"
+msgstr "掃æç¢¼ 0x%02x 無效"
+
+#: vncviewer/KeyboardWin32.cxx:262
+#, c-format
+msgid "No symbol for extended virtual key 0x%02x"
+msgstr "æ²’æœ‰å°æ‡‰åˆ°å»¶ä¼¸è™›æ“¬ä»£ç¢¼ 0x%02x 的符號"
+
+#: vncviewer/KeyboardWin32.cxx:264
+#, c-format
+msgid "No symbol for virtual key 0x%02x"
+msgstr "æ²’æœ‰å°æ‡‰åˆ°è™›æ“¬æŒ‰éµ 0x%02x 的符號"
+
+#: vncviewer/KeyboardWin32.cxx:423
+#, c-format
+msgid "Failed to update keyboard LED state: %lu"
+msgstr "æ›´æ–°éµç›¤ LED 狀態失敗:%lu"
+
+#: vncviewer/KeyboardX11.cxx:104
+#, c-format
+msgid "No symbol for key code %d (in the current state)"
+msgstr "æ²’æœ‰å°æ‡‰åˆ°æŒ‰éµä»£ç¢¼ %d 的符號 (ç›®å‰ç‹€æ…‹)"
+
+#: vncviewer/KeyboardX11.cxx:129
+#, c-format
+msgid "Failed to get keyboard LED state: %d"
+msgstr "å–å¾—éµç›¤ LED 狀態失敗:%d"
+
+#: vncviewer/KeyboardX11.cxx:174
+msgid "Failed to update keyboard LED state"
+msgstr "æ›´æ–°éµç›¤ LED 狀態失敗"
+
#: vncviewer/MonitorIndicesParameter.cxx:52
-#: vncviewer/MonitorIndicesParameter.cxx:102
+#: vncviewer/MonitorIndicesParameter.cxx:100
msgid "Failed to get system monitor configuration"
msgstr "無法å–得系統顯示器設定"
-#: vncviewer/MonitorIndicesParameter.cxx:80
+#: vncviewer/MonitorIndicesParameter.cxx:79
#, c-format
msgid "Invalid configuration specified for %s"
msgstr "為 %s 指定之組態無效"
-#: vncviewer/MonitorIndicesParameter.cxx:88
+#: vncviewer/MonitorIndicesParameter.cxx:86
#, c-format
msgid "Monitor index %d does not exist"
msgstr "沒有索引編號是 %d 的顯示器"
-#: vncviewer/MonitorIndicesParameter.cxx:166
-#: vncviewer/MonitorIndicesParameter.cxx:186
+#: vncviewer/MonitorIndicesParameter.cxx:162
+#: vncviewer/MonitorIndicesParameter.cxx:182
#, c-format
msgid "Invalid monitor index '%s'"
-msgstr "顯示器索引編號 ‘%s’ 無效"
+msgstr "顯示器索引編號「%sã€ç„¡æ•ˆ"
-#: vncviewer/MonitorIndicesParameter.cxx:174
+#: vncviewer/MonitorIndicesParameter.cxx:170
#, c-format
msgid "Unexpected character '%c'"
-msgstr "é‡åˆ°éžé æœŸå­—å…ƒ ‘%c’"
+msgstr "é‡åˆ°éžé æœŸå­—元「%cã€"
#: vncviewer/OptionsDialog.cxx:64
-msgid "TigerVNC Options"
+msgid "TigerVNC options"
msgstr "TigerVNC é¸é …"
-#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:102
-#: vncviewer/vncviewer.cxx:395
+#: vncviewer/OptionsDialog.cxx:97 vncviewer/ServerDialog.cxx:107
+#: vncviewer/vncviewer.cxx:397
msgid "Cancel"
msgstr "å–æ¶ˆ"
-#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:394
+#: vncviewer/OptionsDialog.cxx:102 vncviewer/vncviewer.cxx:396
msgid "OK"
msgstr "確èª"
-#: vncviewer/OptionsDialog.cxx:502
+#: vncviewer/OptionsDialog.cxx:514
msgid "Compression"
msgstr "壓縮模å¼"
-#: vncviewer/OptionsDialog.cxx:518
+#: vncviewer/OptionsDialog.cxx:530
msgid "Auto select"
msgstr "è‡ªå‹•é¸æ“‡"
-#: vncviewer/OptionsDialog.cxx:529
+#: vncviewer/OptionsDialog.cxx:541
msgid "Preferred encoding"
msgstr "å好編碼方å¼"
-#: vncviewer/OptionsDialog.cxx:590
+#: vncviewer/OptionsDialog.cxx:602
msgid "Color level"
msgstr "色彩等級"
-#: vncviewer/OptionsDialog.cxx:602
+#: vncviewer/OptionsDialog.cxx:614
msgid "Full"
msgstr "完整"
-#: vncviewer/OptionsDialog.cxx:609
+#: vncviewer/OptionsDialog.cxx:621
msgid "Medium"
msgstr "中é‡"
-#: vncviewer/OptionsDialog.cxx:616
+#: vncviewer/OptionsDialog.cxx:628
msgid "Low"
msgstr "å°‘é‡"
-#: vncviewer/OptionsDialog.cxx:623
+#: vncviewer/OptionsDialog.cxx:635
msgid "Very low"
msgstr "極少"
-#: vncviewer/OptionsDialog.cxx:645
+#: vncviewer/OptionsDialog.cxx:657
msgid "Custom compression level:"
msgstr "自訂壓縮等級:"
-#: vncviewer/OptionsDialog.cxx:652
+#: vncviewer/OptionsDialog.cxx:664
msgid "level (0=fast, 9=best)"
msgstr "級別 (0=速度最快ã€9=å“質最好)"
-#: vncviewer/OptionsDialog.cxx:659
+#: vncviewer/OptionsDialog.cxx:671
msgid "Allow JPEG compression:"
msgstr "å…許 JPEG 壓縮方å¼ï¼š"
-#: vncviewer/OptionsDialog.cxx:666
+#: vncviewer/OptionsDialog.cxx:678
msgid "quality (0=poor, 9=best)"
msgstr "å“質 (0=最低ã€9=最好)"
-#: vncviewer/OptionsDialog.cxx:677
+#: vncviewer/OptionsDialog.cxx:689
msgid "Security"
msgstr "安全性"
-#: vncviewer/OptionsDialog.cxx:691
+#: vncviewer/OptionsDialog.cxx:703
msgid "Encryption"
msgstr "加密方å¼"
-#: vncviewer/OptionsDialog.cxx:703 vncviewer/OptionsDialog.cxx:770
-#: vncviewer/OptionsDialog.cxx:876
+#: vncviewer/OptionsDialog.cxx:715 vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:905
msgid "None"
msgstr "ç„¡"
-#: vncviewer/OptionsDialog.cxx:710
+#: vncviewer/OptionsDialog.cxx:722
msgid "TLS with anonymous certificates"
msgstr "ä½¿ç”¨åŒ¿åæ†‘證的 TLS"
-#: vncviewer/OptionsDialog.cxx:716
+#: vncviewer/OptionsDialog.cxx:728
msgid "TLS with X509 certificates"
msgstr "使用 X509 憑證的 TLS"
-#: vncviewer/OptionsDialog.cxx:723
+#: vncviewer/OptionsDialog.cxx:735
msgid "Path to X509 CA certificate"
msgstr "X509 CA 憑證ä½ç½®"
-#: vncviewer/OptionsDialog.cxx:730
+#: vncviewer/OptionsDialog.cxx:742
msgid "Path to X509 CRL file"
msgstr "X509 CRL 檔案ä½ç½®"
-#: vncviewer/OptionsDialog.cxx:758
+#: vncviewer/OptionsDialog.cxx:770
msgid "Authentication"
msgstr "èªè­‰æ–¹å¼"
-#: vncviewer/OptionsDialog.cxx:776
+#: vncviewer/OptionsDialog.cxx:788
msgid "Standard VNC (insecure without encryption)"
msgstr "標準 VNC èªè­‰æ–¹å¼ (若未開啟加密功能則ä¸å®‰å…¨)"
-#: vncviewer/OptionsDialog.cxx:782
+#: vncviewer/OptionsDialog.cxx:794
msgid "Username and password (insecure without encryption)"
msgstr "使用者與密碼èªè­‰æ–¹å¼ (若未開啟加密功能則ä¸å®‰å…¨)"
-#: vncviewer/OptionsDialog.cxx:805
+#: vncviewer/OptionsDialog.cxx:822
msgid "Input"
msgstr "輸入"
-#: vncviewer/OptionsDialog.cxx:818
+#: vncviewer/OptionsDialog.cxx:835
msgid "View only (ignore mouse and keyboard)"
msgstr "åƒ…ä¾›æª¢è¦–æ¨¡å¼ (忽略滑鼠與éµç›¤å‹•作)"
-#: vncviewer/OptionsDialog.cxx:825
+#: vncviewer/OptionsDialog.cxx:842
msgid "Mouse"
msgstr "滑鼠"
-#: vncviewer/OptionsDialog.cxx:837
+#: vncviewer/OptionsDialog.cxx:854
msgid "Emulate middle mouse button"
msgstr "模擬滑鼠中éµ"
-#: vncviewer/OptionsDialog.cxx:843
-msgid "Show dot when no cursor"
-msgstr "若無游標則改顯示一個點"
+#: vncviewer/OptionsDialog.cxx:860
+msgid "Show local cursor when not provided by server"
+msgstr "如果伺æœå™¨æ²’有æä¾›æ¸¸æ¨™ï¼Œå‰‡é¡¯ç¤ºæœ¬æ©Ÿæ¸¸æ¨™"
+
+#: vncviewer/OptionsDialog.cxx:865
+msgid "Cursor type"
+msgstr "游標類型"
+
+#: vncviewer/OptionsDialog.cxx:867
+msgid "Dot"
+msgstr "點狀"
+
+#: vncviewer/OptionsDialog.cxx:868
+msgid "System"
+msgstr "系統"
-#: vncviewer/OptionsDialog.cxx:859
+#: vncviewer/OptionsDialog.cxx:888
msgid "Keyboard"
msgstr "éµç›¤"
-#: vncviewer/OptionsDialog.cxx:871
+#: vncviewer/OptionsDialog.cxx:900
msgid "Pass system keys directly to server (full screen)"
msgstr "直接將系統éµå‚³è‡³ä¼ºæœå™¨ (全螢幕模å¼)"
-#: vncviewer/OptionsDialog.cxx:874
+#: vncviewer/OptionsDialog.cxx:903
msgid "Menu key"
msgstr "é¸å–®éµ"
-#: vncviewer/OptionsDialog.cxx:895
+#: vncviewer/OptionsDialog.cxx:926
msgid "Clipboard"
msgstr "剪貼æ¿"
-#: vncviewer/OptionsDialog.cxx:907
+#: vncviewer/OptionsDialog.cxx:938
msgid "Accept clipboard from server"
msgstr "接å—來自伺æœå™¨çš„剪貼簿內容"
-#: vncviewer/OptionsDialog.cxx:915
+#: vncviewer/OptionsDialog.cxx:946
msgid "Also set primary selection"
msgstr "亦設定主è¦é¸å€"
-#: vncviewer/OptionsDialog.cxx:922
+#: vncviewer/OptionsDialog.cxx:953
msgid "Send clipboard to server"
msgstr "將剪貼簿內容傳至伺æœå™¨"
-#: vncviewer/OptionsDialog.cxx:930
+#: vncviewer/OptionsDialog.cxx:961
msgid "Send primary selection as clipboard"
msgstr "將主è¦é¸å–å€å¡Šä½œç‚ºå‰ªè²¼ç°¿å…§å®¹å‚³é€"
-#: vncviewer/OptionsDialog.cxx:951
+#: vncviewer/OptionsDialog.cxx:982
msgid "Display"
msgstr "顯示"
-#: vncviewer/OptionsDialog.cxx:965
+#: vncviewer/OptionsDialog.cxx:996
msgid "Display mode"
msgstr "顯示模å¼"
-#: vncviewer/OptionsDialog.cxx:978
+#: vncviewer/OptionsDialog.cxx:1009
msgid "Windowed"
msgstr "視窗模å¼"
-#: vncviewer/OptionsDialog.cxx:986
+#: vncviewer/OptionsDialog.cxx:1017
msgid "Full screen on current monitor"
msgstr "在目å‰é¡¯ç¤ºå™¨å…¨èž¢å¹•"
-#: vncviewer/OptionsDialog.cxx:994
+#: vncviewer/OptionsDialog.cxx:1025
msgid "Full screen on all monitors"
msgstr "在所有顯示器全螢幕"
-#: vncviewer/OptionsDialog.cxx:1002
+#: vncviewer/OptionsDialog.cxx:1033
msgid "Full screen on selected monitor(s)"
msgstr "在é¸å–顯示器全螢幕"
-#: vncviewer/OptionsDialog.cxx:1031
+#: vncviewer/OptionsDialog.cxx:1062
msgid "Miscellaneous"
msgstr "雜項設定"
-#: vncviewer/OptionsDialog.cxx:1039
+#: vncviewer/OptionsDialog.cxx:1070
msgid "Shared (don't disconnect other viewers)"
msgstr "共用連線 (䏿–·é–‹å…¶ä»–檢視器的連線)"
-#: vncviewer/OptionsDialog.cxx:1045
+#: vncviewer/OptionsDialog.cxx:1076
msgid "Ask to reconnect on connection errors"
msgstr "è©¢å•æ˜¯å¦è¦åœ¨é€£æŽ¥ç™¼ç”ŸéŒ¯èª¤æ™‚釿–°é€£ç·š"
-#: vncviewer/ServerDialog.cxx:58
-msgid "VNC Viewer: Connection Details"
+#: vncviewer/ServerDialog.cxx:63
+msgid "VNC viewer: Connection details"
msgstr "VNC 檢視器:連線詳細資訊"
-#: vncviewer/ServerDialog.cxx:68
+#: vncviewer/ServerDialog.cxx:73
msgid "VNC server:"
msgstr "VNC 伺æœå™¨ï¼š"
-#: vncviewer/ServerDialog.cxx:75
+#: vncviewer/ServerDialog.cxx:80
msgid "Options..."
msgstr "é¸é ……"
-#: vncviewer/ServerDialog.cxx:79
+#: vncviewer/ServerDialog.cxx:84
msgid "Load..."
msgstr "載入…"
-#: vncviewer/ServerDialog.cxx:83
-msgid "Save As..."
-msgstr "å¦å­˜æ–°æª”…"
+#: vncviewer/ServerDialog.cxx:88
+msgid "Save as..."
+msgstr "å¦å­˜æ–°æª”..."
-#: vncviewer/ServerDialog.cxx:97
+#: vncviewer/ServerDialog.cxx:102
msgid "About..."
msgstr "關於…"
-#: vncviewer/ServerDialog.cxx:106
+#: vncviewer/ServerDialog.cxx:111
msgid "Connect"
msgstr "連線"
-#: vncviewer/ServerDialog.cxx:143
+#: vncviewer/ServerDialog.cxx:147
#, c-format
msgid ""
"Unable to load the server history:\n"
@@ -408,15 +480,15 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:172 vncviewer/ServerDialog.cxx:212
+#: vncviewer/ServerDialog.cxx:176 vncviewer/ServerDialog.cxx:216
msgid "TigerVNC configuration (*.tigervnc)"
msgstr "TigerVNC 組態設定 (*.tigervnc)"
-#: vncviewer/ServerDialog.cxx:173
+#: vncviewer/ServerDialog.cxx:177
msgid "Select a TigerVNC configuration file"
msgstr "è«‹é¸å– TigerVNC 組態設定檔"
-#: vncviewer/ServerDialog.cxx:195 vncviewer/vncviewer.cxx:515
+#: vncviewer/ServerDialog.cxx:199 vncviewer/vncviewer.cxx:517
#, c-format
msgid ""
"Unable to load the specified configuration file:\n"
@@ -427,24 +499,24 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:213
+#: vncviewer/ServerDialog.cxx:217
msgid "Save the TigerVNC configuration to file"
msgstr "將 TigerVNC 組態設定儲存為檔案"
-#: vncviewer/ServerDialog.cxx:239
+#: vncviewer/ServerDialog.cxx:243
#, c-format
msgid "%s already exists. Do you want to overwrite?"
msgstr "%s 已存在,是å¦è¦†å¯«ï¼Ÿ"
-#: vncviewer/ServerDialog.cxx:240 vncviewer/vncviewer.cxx:392
+#: vncviewer/ServerDialog.cxx:244 vncviewer/vncviewer.cxx:394
msgid "No"
msgstr "å¦"
-#: vncviewer/ServerDialog.cxx:240
+#: vncviewer/ServerDialog.cxx:244
msgid "Overwrite"
msgstr "覆寫"
-#: vncviewer/ServerDialog.cxx:256
+#: vncviewer/ServerDialog.cxx:260
#, c-format
msgid ""
"Unable to save the specified configuration file:\n"
@@ -455,7 +527,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:290
+#: vncviewer/ServerDialog.cxx:294
#, c-format
msgid ""
"Unable to save the default configuration:\n"
@@ -466,7 +538,7 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:303
+#: vncviewer/ServerDialog.cxx:306
#, c-format
msgid ""
"Unable to save the server history:\n"
@@ -477,205 +549,147 @@ msgstr ""
"\n"
"%s"
-#: vncviewer/ServerDialog.cxx:320 vncviewer/ServerDialog.cxx:386
-msgid "Could not obtain the state directory path"
-msgstr "無法å–得狀態目錄路徑"
+#: vncviewer/ServerDialog.cxx:351 vncviewer/ServerDialog.cxx:429
+#: vncviewer/vncviewer.cxx:580
+msgid "Could not determine VNC state directory path"
+msgstr "無法決定 VNC 狀態目錄的路徑"
-#: vncviewer/ServerDialog.cxx:332 vncviewer/ServerDialog.cxx:394
-#: vncviewer/parameters.cxx:644 vncviewer/parameters.cxx:750
+#: vncviewer/ServerDialog.cxx:363 vncviewer/ServerDialog.cxx:437
+#: vncviewer/parameters.cxx:671 vncviewer/parameters.cxx:752
#, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "無法開啟「%sã€ï¼š%s"
+msgid "Could not open \"%s\""
+msgstr "無法開啟「%sã€"
-#: vncviewer/ServerDialog.cxx:347 vncviewer/ServerDialog.cxx:355
-#: vncviewer/parameters.cxx:764 vncviewer/parameters.cxx:770
-#: vncviewer/parameters.cxx:801 vncviewer/parameters.cxx:830
-#: vncviewer/parameters.cxx:836
+#: vncviewer/ServerDialog.cxx:378 vncviewer/ServerDialog.cxx:387
+#: vncviewer/parameters.cxx:766 vncviewer/parameters.cxx:773
+#: vncviewer/parameters.cxx:807 vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:844
#, c-format
-msgid "Failed to read line %d in file %s: %s"
-msgstr "è®€å–æª”案 %2$s 中第 %1$d 行失敗:%3$s"
+msgid "Failed to read line %d in file \"%s\""
+msgstr "無法讀å–「%2$sã€æª”案的第 %1$d 列"
-#: vncviewer/ServerDialog.cxx:356 vncviewer/parameters.cxx:771
+#: vncviewer/ServerDialog.cxx:390 vncviewer/parameters.cxx:776
msgid "Line too long"
msgstr "行字數éŽé•·"
-#: vncviewer/UserDialog.cxx:99
+#: vncviewer/UserDialog.cxx:123
msgid "Opening password file failed"
msgstr "開啟密碼檔失敗"
-#: vncviewer/UserDialog.cxx:118
+#: vncviewer/UserDialog.cxx:143
msgid "VNC authentication"
msgstr "VNC èªè­‰"
-#: vncviewer/UserDialog.cxx:125
+#: vncviewer/UserDialog.cxx:150
msgid "This connection is secure"
msgstr "此連線階段安全"
-#: vncviewer/UserDialog.cxx:129
+#: vncviewer/UserDialog.cxx:154
msgid "This connection is not secure"
msgstr "此連線階段ä¸å®‰å…¨"
-#: vncviewer/UserDialog.cxx:151
+#: vncviewer/UserDialog.cxx:176
msgid "Username:"
msgstr "使用者å稱:"
-#: vncviewer/UserDialog.cxx:164
+#: vncviewer/UserDialog.cxx:189
msgid "Password:"
msgstr "密碼:"
-#: vncviewer/UserDialog.cxx:207
-msgid "Authentication cancelled"
-msgstr "已喿¶ˆèªè­‰ç¨‹åº"
-
-#: vncviewer/Viewport.cxx:390
-#, c-format
-msgid "Failed to update keyboard LED state: %lu"
-msgstr "æ›´æ–°éµç›¤ LED 狀態失敗:%lu"
-
-#: vncviewer/Viewport.cxx:396 vncviewer/Viewport.cxx:402
-#, c-format
-msgid "Failed to update keyboard LED state: %d"
-msgstr "æ›´æ–°éµç›¤ LED 狀態失敗:%d"
-
-#: vncviewer/Viewport.cxx:432
-msgid "Failed to update keyboard LED state"
-msgstr "æ›´æ–°éµç›¤ LED 狀態失敗"
-
-#: vncviewer/Viewport.cxx:459 vncviewer/Viewport.cxx:467
-#: vncviewer/Viewport.cxx:484
-#, c-format
-msgid "Failed to get keyboard LED state: %d"
-msgstr "å–å¾—éµç›¤ LED 狀態失敗:%d"
-
-#: vncviewer/Viewport.cxx:839
-msgid "No key code specified on key press"
-msgstr "沒有指定按下按éµäº‹ä»¶çš„æŒ‰éµä»£ç¢¼"
-
-#: vncviewer/Viewport.cxx:990
-#, c-format
-msgid "No scan code for extended virtual key 0x%02x"
-msgstr "æ²’æœ‰å°æ‡‰åˆ°å»¶ä¼¸è™›æ“¬ä»£ç¢¼ 0x%02x 的掃æç¢¼"
+#: vncviewer/UserDialog.cxx:197
+msgid "Keep password for reconnect"
+msgstr "ç•™å­˜å¯†ç¢¼ä¾›é‡æ–°é€£ç·šä½¿ç”¨"
-#: vncviewer/Viewport.cxx:992
-#, c-format
-msgid "No scan code for virtual key 0x%02x"
-msgstr "æ²’æœ‰å°æ‡‰åˆ°è™›æ“¬æŒ‰éµ 0x%02x 的掃æç¢¼"
-
-#: vncviewer/Viewport.cxx:998
-#, c-format
-msgid "Invalid scan code 0x%02x"
-msgstr "掃æç¢¼ 0x%02x 無效"
-
-#: vncviewer/Viewport.cxx:1028
-#, c-format
-msgid "No symbol for extended virtual key 0x%02x"
-msgstr "æ²’æœ‰å°æ‡‰åˆ°å»¶ä¼¸è™›æ“¬ä»£ç¢¼ 0x%02x 的符號"
-
-#: vncviewer/Viewport.cxx:1030
-#, c-format
-msgid "No symbol for virtual key 0x%02x"
-msgstr "æ²’æœ‰å°æ‡‰åˆ°è™›æ“¬æŒ‰éµ 0x%02x 的符號"
-
-#: vncviewer/Viewport.cxx:1136
-#, c-format
-msgid "No symbol for key code 0x%02x (in the current state)"
-msgstr "æ²’æœ‰å°æ‡‰åˆ°æŒ‰éµä»£ç¢¼ 0x%02x 的符號 (ç›®å‰ç‹€æ…‹)"
-
-#: vncviewer/Viewport.cxx:1169
-#, c-format
-msgid "No symbol for key code %d (in the current state)"
-msgstr "æ²’æœ‰å°æ‡‰åˆ°æŒ‰éµä»£ç¢¼ %d 的符號 (ç›®å‰ç‹€æ…‹)"
-
-#: vncviewer/Viewport.cxx:1229
+#: vncviewer/Viewport.cxx:695
msgctxt "ContextMenu|"
msgid "Disconn&ect"
msgstr "中斷連線(&E)"
-#: vncviewer/Viewport.cxx:1232
+#: vncviewer/Viewport.cxx:698
msgctxt "ContextMenu|"
msgid "&Full screen"
msgstr "全螢幕(&F)"
-#: vncviewer/Viewport.cxx:1235
+#: vncviewer/Viewport.cxx:701
msgctxt "ContextMenu|"
msgid "Minimi&ze"
msgstr "最å°åŒ–(&Z)"
-#: vncviewer/Viewport.cxx:1237
+#: vncviewer/Viewport.cxx:703
msgctxt "ContextMenu|"
msgid "Resize &window to session"
msgstr "將視窗縮放至與連線階段åŒå¤§å°(&W)"
-#: vncviewer/Viewport.cxx:1242
+#: vncviewer/Viewport.cxx:708
msgctxt "ContextMenu|"
msgid "&Ctrl"
msgstr "&Ctrl"
-#: vncviewer/Viewport.cxx:1245
+#: vncviewer/Viewport.cxx:711
msgctxt "ContextMenu|"
msgid "&Alt"
msgstr "&Alt"
-#: vncviewer/Viewport.cxx:1251
+#: vncviewer/Viewport.cxx:717
#, c-format
msgctxt "ContextMenu|"
msgid "Send %s"
msgstr "å‚³é€ %s éµ"
-#: vncviewer/Viewport.cxx:1257
+#: vncviewer/Viewport.cxx:724
msgctxt "ContextMenu|"
msgid "Send Ctrl-Alt-&Del"
msgstr "å‚³é€ Ctrl-Alt-&Del éµ"
-#: vncviewer/Viewport.cxx:1260
+#: vncviewer/Viewport.cxx:727
msgctxt "ContextMenu|"
msgid "&Refresh screen"
msgstr "釿–°æ•´ç†èž¢å¹•(&R)"
-#: vncviewer/Viewport.cxx:1263
+#: vncviewer/Viewport.cxx:730
msgctxt "ContextMenu|"
msgid "&Options..."
msgstr "é¸é …(&O)…"
-#: vncviewer/Viewport.cxx:1265
+#: vncviewer/Viewport.cxx:732
msgctxt "ContextMenu|"
msgid "Connection &info..."
msgstr "連線資訊(&I)…"
-#: vncviewer/Viewport.cxx:1267
+#: vncviewer/Viewport.cxx:734
msgctxt "ContextMenu|"
msgid "About &TigerVNC viewer..."
msgstr "關於 TigerVNC 檢視器(&T)…"
-#: vncviewer/Viewport.cxx:1356
+#: vncviewer/Viewport.cxx:830
msgid "VNC connection info"
msgstr "VNC 連線資訊"
-#: vncviewer/Win32TouchHandler.cxx:47
+#: vncviewer/Win32TouchHandler.cxx:48
msgid "Window is registered for touch instead of gestures"
msgstr "è¦–çª—å·²è¢«è¨»å†Šç”¨ä¾†æŽ¥æ”¶è§¸æŽ§ï¼ˆè€Œéžæ‰‹å‹¢ï¼‰æ“作"
-#: vncviewer/Win32TouchHandler.cxx:82
+#: vncviewer/Win32TouchHandler.cxx:83
#, c-format
msgid "Failed to set gesture configuration (error 0x%x)"
msgstr "無法設定手勢設定(錯誤 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:94
+#: vncviewer/Win32TouchHandler.cxx:95
#, c-format
msgid "Failed to get gesture information (error 0x%x)"
msgstr "無法å–得手勢資訊(錯誤 0x%x)"
-#: vncviewer/Win32TouchHandler.cxx:359
+#: vncviewer/Win32TouchHandler.cxx:360
#, c-format
msgid "Invalid mouse button %d, must be a number between 1 and 7."
msgstr "無效的滑鼠按éµç·¨è™Ÿ %d,必須是介於 1 到 7 之間的數字。"
-#: vncviewer/Win32TouchHandler.cxx:424
+#: vncviewer/Win32TouchHandler.cxx:425
#, c-format
msgid "Unhandled key 0x%x - can't generate keyboard event."
msgstr "æœªæŽ¥ç®¡çš„æŒ‰éµ 0x%x - 無法產生éµç›¤äº‹ä»¶ã€‚"
-#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:108
+#: vncviewer/XInputTouchHandler.cxx:102 vncviewer/touch.cxx:107
#, c-format
msgid "Unable to get X Input 2 event mask for window 0x%08lx"
msgstr "無法å–得視窗 0x%08lx çš„ X Input 2 事件é®ç½©"
@@ -685,7 +699,7 @@ msgstr "無法å–得視窗 0x%08lx çš„ X Input 2 事件é®ç½©"
msgid "Window 0x%08lx has no X Input 2 event mask"
msgstr "視窗 0x%08lx 沒有 X Input 2 事件é®ç½©"
-#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:115
+#: vncviewer/XInputTouchHandler.cxx:112 vncviewer/touch.cxx:114
#, c-format
msgid "Window 0x%08lx has more than one X Input 2 event mask"
msgstr "視窗 0x%08lx 有超éŽä¸€å€‹ X Input 2 事件é®ç½©"
@@ -696,7 +710,6 @@ msgid "Failure grabbing device %i"
msgstr "æ“·å–è£ç½® %i 失敗"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:13
-#: vncviewer/vncviewer.cxx:389 vncviewer/vncviewer.desktop.in.in:3
msgid "TigerVNC Viewer"
msgstr "TigerVNC 檢視器"
@@ -714,140 +727,141 @@ msgid "TigerVNC is a high-speed version of VNC based on the RealVNC 4 and X.org
msgstr "TigerVNC 是以 RealVNC 4 å’Œ X.org 程å¼ç¢¼ç‚ºåŸºç¤Žæ‰“造的 VNC 高速版本。TigerVNC 原先是 TightVNC 在 Unix å’Œ Linux å¹³å°ä¸Šçš„ä¸‹ä¸€ä»£é–‹ç™¼æˆæžœï¼Œä½†åœ¨ 2009 å¹´åˆå¾žåŽŸæœ¬çš„å°ˆæ¡ˆä¸­åˆ†é›¢ï¼Œè®“ TigerVNC 得以專注在 Windows å¹³å°ä¸Šã€‚TigerVNC æ”¯æ´ Tight 編碼的變體版本,é€éŽ libjpeg-turbo JPEG 編解碼器,使其速度ç²å¾—相當大的æå‡ã€‚"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:33
-msgid "TigerVNC Viewer connection to a CentOS machine"
+msgid "TigerVNC viewer connection to a CentOS machine"
msgstr "連線至 CentOS 機器的 TigerVNC 檢視器"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:37
-msgid "TigerVNC Viewer connection to a macOS machine"
+msgid "TigerVNC viewer connection to a macOS machine"
msgstr "連線至 macOS 機器的 TigerVNC 檢視器"
#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:41
-msgid "TigerVNC Viewer connection to a Windows machine"
+msgid "TigerVNC viewer connection to a Windows machine"
msgstr "連線至 Windows 機器的 TigerVNC 檢視器"
-#: vncviewer/parameters.cxx:307 vncviewer/parameters.cxx:332
-#: vncviewer/parameters.cxx:349 vncviewer/parameters.cxx:389
-#: vncviewer/parameters.cxx:409
+#. developer_name tag deprecated with Appstream 1.0
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:46
+#: vncviewer/org.tigervnc.vncviewer.metainfo.xml.in:48
+msgid "The TigerVNC team"
+msgstr "TigerVNC 團隊"
+
+#: vncviewer/parameters.cxx:319 vncviewer/parameters.cxx:344
+#: vncviewer/parameters.cxx:361 vncviewer/parameters.cxx:401
+#: vncviewer/parameters.cxx:421
msgid "The name of the parameter is too large"
msgstr "åƒæ•¸å稱éŽé•·"
-#: vncviewer/parameters.cxx:311 vncviewer/parameters.cxx:316
-#: vncviewer/parameters.cxx:367
+#: vncviewer/parameters.cxx:323 vncviewer/parameters.cxx:328
+#: vncviewer/parameters.cxx:379
msgid "The parameter is too large"
msgstr "åƒæ•¸éŽé•·"
-#: vncviewer/parameters.cxx:374 vncviewer/parameters.cxx:694
-#: vncviewer/parameters.cxx:815
+#: vncviewer/parameters.cxx:386 vncviewer/parameters.cxx:712
+#: vncviewer/parameters.cxx:822
msgid "Invalid format or too large value"
msgstr "æ ¼å¼ç„¡æ•ˆæˆ–數值éŽå¤§"
-#: vncviewer/parameters.cxx:428 vncviewer/parameters.cxx:459
+#: vncviewer/parameters.cxx:440 vncviewer/parameters.cxx:473
msgid "Failed to create registry key"
msgstr "無法建立登錄機碼"
-#: vncviewer/parameters.cxx:447 vncviewer/parameters.cxx:502
-#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:611
+#: vncviewer/parameters.cxx:461 vncviewer/parameters.cxx:528
+#: vncviewer/parameters.cxx:571 vncviewer/parameters.cxx:638
msgid "Failed to close registry key"
msgstr "無法關閉登錄機碼"
-#: vncviewer/parameters.cxx:465 vncviewer/parameters.cxx:482
-#: vncviewer/parameters.cxx:652 vncviewer/parameters.cxx:662
-#: vncviewer/parameters.cxx:673
+#: vncviewer/parameters.cxx:479 vncviewer/parameters.cxx:506
+#: vncviewer/parameters.cxx:680 vncviewer/parameters.cxx:692
#, c-format
msgid "Failed to save \"%s\": %s"
msgstr "無法儲存「%sã€ï¼š%s"
-#: vncviewer/parameters.cxx:478 vncviewer/parameters.cxx:566
-#: vncviewer/parameters.cxx:675 vncviewer/parameters.cxx:712
-msgid "Unknown parameter type"
-msgstr "åƒæ•¸é¡žåž‹æœªçŸ¥"
-
-#: vncviewer/parameters.cxx:495
+#: vncviewer/parameters.cxx:489 vncviewer/parameters.cxx:520
#, c-format
msgid "Failed to remove \"%s\": %s"
msgstr "無法移除「%sã€ï¼š%s"
-#: vncviewer/parameters.cxx:517 vncviewer/parameters.cxx:589
+#: vncviewer/parameters.cxx:544 vncviewer/parameters.cxx:616
msgid "Failed to open registry key"
msgstr "無法開啟登錄機碼"
-#: vncviewer/parameters.cxx:534
+#: vncviewer/parameters.cxx:561
#, c-format
msgid "Failed to read server history entry %d: %s"
msgstr "無法讀å–伺æœå™¨æ­·å²è¨˜éŒ„的第 %d æ¢é …目:%s"
-#: vncviewer/parameters.cxx:570 vncviewer/parameters.cxx:600
+#: vncviewer/parameters.cxx:597 vncviewer/parameters.cxx:627
#, c-format
msgid "Failed to read parameter \"%s\": %s"
msgstr "無法讀å–「%sã€åƒæ•¸ï¼š%s"
-#: vncviewer/parameters.cxx:634 vncviewer/parameters.cxx:738
-msgid "Could not obtain the config directory path"
-msgstr "無法å–得組態目錄路徑"
+#: vncviewer/parameters.cxx:661 vncviewer/parameters.cxx:740
+#: vncviewer/vncviewer.cxx:546
+msgid "Could not determine VNC config directory path"
+msgstr "無法決定 VNC 組態目錄的路徑"
-#: vncviewer/parameters.cxx:653 vncviewer/parameters.cxx:664
+#: vncviewer/parameters.cxx:682 vncviewer/parameters.cxx:694
msgid "Could not encode parameter"
msgstr "無法å°åƒæ•¸é€²è¡Œç·¨ç¢¼"
-#: vncviewer/parameters.cxx:780
+#: vncviewer/parameters.cxx:785
#, c-format
msgid "Configuration file %s is in an invalid format"
msgstr "組態檔案 %s æ ¼å¼ç„¡æ•ˆ"
-#: vncviewer/parameters.cxx:802
+#: vncviewer/parameters.cxx:809
msgid "Invalid format"
msgstr "æ ¼å¼ç„¡æ•ˆ"
-#: vncviewer/parameters.cxx:837
+#: vncviewer/parameters.cxx:846
msgid "Unknown parameter"
msgstr "æœªçŸ¥åƒæ•¸"
-#: vncviewer/touch.cxx:76
+#: vncviewer/touch.cxx:75
#, c-format
msgid "Got message (0x%x) for an unhandled window"
msgstr "æ”¶åˆ°å°æœªè™•ç†è¦–çª—çš„è¨Šæ¯ (0x%x)"
-#: vncviewer/touch.cxx:139 vncviewer/touch.cxx:161
+#: vncviewer/touch.cxx:138 vncviewer/touch.cxx:160
#, c-format
msgid "Invalid window 0x%08lx specified for pointer grab"
msgstr "æŒ‡å®šè¦æ“·å–指標的視窗 0x%08lx 無效"
-#: vncviewer/touch.cxx:184 vncviewer/touch.cxx:185
+#: vncviewer/touch.cxx:183 vncviewer/touch.cxx:184
#, c-format
msgid "Failed to create touch handler: %s"
msgstr "無法建立觸控處ç†å¸¸å¼ï¼š%s"
-#: vncviewer/touch.cxx:189
+#: vncviewer/touch.cxx:188
#, c-format
msgid "Couldn't attach event handler to window (error 0x%x)"
msgstr "無法將事件處ç†å¸¸å¼é€£æŽ¥åˆ°è¦–窗上(錯誤 0x%x)"
-#: vncviewer/touch.cxx:216
+#: vncviewer/touch.cxx:215
msgid "Failed to get event data for X Input event"
msgstr "無法å–å¾— X Input 事件資料"
-#: vncviewer/touch.cxx:229
+#: vncviewer/touch.cxx:228
msgid "X Input event for unknown window"
msgstr "未知視窗的 X Input 事件"
-#: vncviewer/touch.cxx:255
+#: vncviewer/touch.cxx:254
msgid "X Input extension not available."
msgstr "䏿”¯æ´ X Input 擴充方法。"
-#: vncviewer/touch.cxx:262
+#: vncviewer/touch.cxx:261
msgid "X Input 2 (or newer) is not available."
msgstr "䏿”¯æ´ X Input 2(或新版)。"
-#: vncviewer/touch.cxx:267
+#: vncviewer/touch.cxx:266
msgid "X Input 2.2 (or newer) is not available. Touch gestures will not be supported."
msgstr "䏿”¯æ´ X Input 2.2ï¼ˆæˆ–æ–°ç‰ˆï¼‰ã€‚å°‡ä¸æ”¯æ´è§¸æŽ§æ‰‹å‹¢ã€‚"
#: vncviewer/vncviewer.cxx:104
#, c-format
msgid ""
-"TigerVNC Viewer v%s\n"
+"TigerVNC viewer v%s\n"
"Built on: %s\n"
-"Copyright (C) 1999-%d TigerVNC Team and many others (see README.rst)\n"
+"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."
msgstr ""
"TigerVNC 檢視器 v%s\n"
@@ -892,95 +906,173 @@ msgstr "啟動新的 TigerVNC 檢視器時發生錯誤:%s"
#: vncviewer/vncviewer.cxx:266
#, c-format
-msgid "Termination signal %d has been received. TigerVNC Viewer will now exit."
-msgstr "接收到終端器信號 %d。TigerVNC 檢視器ç¾å°‡é€€å‡ºã€‚"
+msgid "Termination signal %d has been received. TigerVNC viewer will now exit."
+msgstr "接收到終止信號 %d。TigerVNC 檢視器ç¾å°‡çµæŸã€‚"
-#: vncviewer/vncviewer.cxx:393
+#: vncviewer/vncviewer.cxx:391 vncviewer/vncviewer.desktop.in.in:3
+msgid "TigerVNC viewer"
+msgstr "TigerVNC 檢視器"
+
+#: vncviewer/vncviewer.cxx:395
msgid "Yes"
msgstr "確èª"
-#: vncviewer/vncviewer.cxx:396
+#: vncviewer/vncviewer.cxx:398
msgid "Close"
msgstr "關閉"
-#: vncviewer/vncviewer.cxx:401
+#: vncviewer/vncviewer.cxx:403
msgid "About"
msgstr "關於"
-#: vncviewer/vncviewer.cxx:404
+#: vncviewer/vncviewer.cxx:406
msgid "Hide"
msgstr "éš±è—"
-#: vncviewer/vncviewer.cxx:407
+#: vncviewer/vncviewer.cxx:409
msgid "Quit"
msgstr "關閉"
-#: vncviewer/vncviewer.cxx:411
+#: vncviewer/vncviewer.cxx:413
msgid "Services"
msgstr "æœå‹™"
-#: vncviewer/vncviewer.cxx:412
-msgid "Hide Others"
+#: vncviewer/vncviewer.cxx:414
+msgid "Hide others"
msgstr "éš±è—å…¶ä»–"
-#: vncviewer/vncviewer.cxx:413
-msgid "Show All"
+#: vncviewer/vncviewer.cxx:415
+msgid "Show all"
msgstr "全部顯示"
-#: vncviewer/vncviewer.cxx:422
+#: vncviewer/vncviewer.cxx:424
msgctxt "SysMenu|"
msgid "&File"
msgstr "檔案(&F)"
-#: vncviewer/vncviewer.cxx:425
+#: vncviewer/vncviewer.cxx:427
msgctxt "SysMenu|File|"
msgid "&New Connection"
msgstr "建立新連線(&N)"
-#: vncviewer/vncviewer.cxx:525
+#: vncviewer/vncviewer.cxx:450
+#, c-format
+msgid ""
+"\n"
+"Usage: %s [parameters] [host][:displayNum]\n"
+" %s [parameters] [host][::port]\n"
+" %s [parameters] [unix socket]\n"
+" %s [parameters] -listen [port]\n"
+" %s [parameters] [.tigervnc file]\n"
+msgstr ""
+"\n"
+"用法:%s [åƒæ•¸] [主機][:顯示器編號]\n"
+" %s [åƒæ•¸] [主機][::通訊埠]\n"
+" %s [åƒæ•¸] [unix 通訊端]\n"
+" %s [åƒæ•¸] -listen [通訊埠]\n"
+" %s [åƒæ•¸] [.tigervnc 檔案]\n"
+
+#: vncviewer/vncviewer.cxx:465
+#, c-format
+msgid ""
+"\n"
+"Options:\n"
+"\n"
+" -display Xdisplay - Specifies the X display for the viewer window\n"
+" -geometry geometry - Initial position of the main VNC viewer window. See the\n"
+" man page for details.\n"
+msgstr ""
+"\n"
+"é¸é …:\n"
+"\n"
+" -display Xdisplay - 指定檢視器視窗的 X 顯示器\n"
+" -geometry geometry - 設定 VNC 檢視器主視窗的åˆå§‹ä½ç½®ã€‚\n"
+" 詳細資訊請åƒé–± man é é¢ã€‚\n"
+
+#: vncviewer/vncviewer.cxx:472
+#, c-format
+msgid ""
+"\n"
+"Parameters can be turned on with -<param> or off with -<param>=0\n"
+"Parameters which take a value can be specified as -<param> <value>\n"
+"Other valid forms are <param>=<value> -<param>=<value> --<param>=<value>\n"
+"Parameter names are case-insensitive. The parameters are:\n"
+"\n"
+msgstr ""
+"\n"
+"åƒæ•¸å¯ç”¨ -<param> 開啟,或用 -<param>=0 關閉\n"
+"éœ€è¦æŒ‡å®šæ•¸å€¼çš„åƒæ•¸å¯ä½¿ç”¨ -<param> <value> 的格å¼\n"
+"其他有效格å¼åŒ…括 <param>=<value> -<param>=<value> —<param>=<value>\n"
+"åƒæ•¸å稱ä¸åˆ†å¤§å°å¯«ã€‚å¯ç”¨çš„åƒæ•¸å¦‚下:\n"
+"\n"
+
+#: vncviewer/vncviewer.cxx:527
msgid "FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead"
msgstr "已棄用 FullScreenAllMonitors,請改設定 FullScreenMode 為 'all'"
-#: vncviewer/vncviewer.cxx:721
+#: vncviewer/vncviewer.cxx:532
+msgid "DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"
+msgstr "DotWhenNoCursor é¸é …å·²ç¶“éŽæ™‚,請改將 AlwaysCursor 設為 1,然後將 CursorType 設為「Dotã€ï¼ˆé»žç‹€ï¼‰"
+
+#: vncviewer/vncviewer.cxx:553
msgid "~/.vnc is deprecated, please consult 'man vncviewer' for paths to migrate to."
msgstr "~/.vnc 已廢棄,請查閱「man vncviewerã€äº†è§£å¯ä»¥é·ç§»åˆ°çš„路徑。"
-#: vncviewer/vncviewer.cxx:725
+#: vncviewer/vncviewer.cxx:557
#, c-format
msgid "%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."
msgstr "%%APPDATA%%\\vnc 已廢棄,請改到 %%APPDATA%%\\TigerVNC ä½ç½®ã€‚"
-#: vncviewer/vncviewer.cxx:730
+#: vncviewer/vncviewer.cxx:562
#, c-format
-msgid "Could not create VNC config directory: %s"
-msgstr "無法建立 VNC 組態目錄:%s"
+msgid "Could not create VNC config directory \"%s\": %s"
+msgstr "無法建立 VNC 組態目錄「%sã€ï¼š%s"
-#: vncviewer/vncviewer.cxx:735
+#: vncviewer/vncviewer.cxx:568
+msgid "Could not determine VNC data directory path"
+msgstr "無法決定 VNC 資料目錄的路徑"
+
+#: vncviewer/vncviewer.cxx:574
+#, c-format
+msgid "Could not create VNC data directory \"%s\": %s"
+msgstr "無法建立 VNC 資料目錄「%sã€ï¼š%s"
+
+#: vncviewer/vncviewer.cxx:586
#, c-format
-msgid "Could not create VNC data directory: %s"
-msgstr "無法建立 VNC 資料目錄:%s"
+msgid "Could not create VNC state directory \"%s\": %s"
+msgstr "無法建立 VNC 狀態目錄「%sã€ï¼š%s"
-#: vncviewer/vncviewer.cxx:740
+#: vncviewer/vncviewer.cxx:703
#, c-format
-msgid "Could not create VNC state directory: %s"
-msgstr "無法建立 VNC 狀態目錄:%s"
+msgid "%s: Unrecognized option '%s'\n"
+msgstr "%s:ä¸èªè­˜é¸é …「%sã€\n"
+
+#: vncviewer/vncviewer.cxx:705 vncviewer/vncviewer.cxx:713
+#, c-format
+msgid "See '%s --help' for more information.\n"
+msgstr "åƒé–±ã€Œ%s --helpã€æ·±å…¥äº†è§£ã€‚\n"
+
+#: vncviewer/vncviewer.cxx:712
+#, c-format
+msgid "%s: Extra argument '%s'\n"
+msgstr "%s:發ç¾å¤šé¤˜å¼•數「%sã€\n"
#. TRANSLATORS: "Parameters" are command line arguments, or settings
#. from a file or the Windows registry.
-#: vncviewer/vncviewer.cxx:755 vncviewer/vncviewer.cxx:756
+#: vncviewer/vncviewer.cxx:748 vncviewer/vncviewer.cxx:749
msgid "Parameters -listen and -via are incompatible"
msgstr "-listen 與 -via åƒæ•¸ä¸ç›¸å®¹"
-#: vncviewer/vncviewer.cxx:770
+#: vncviewer/vncviewer.cxx:763
msgid "Unable to listen for incoming connections"
msgstr "無法監è½é€£å…¥é€£ç·š"
-#: vncviewer/vncviewer.cxx:772
+#: vncviewer/vncviewer.cxx:765
#, c-format
msgid "Listening on port %d"
msgstr "正於 %d 連線埠監è½"
-#: vncviewer/vncviewer.cxx:805
+#: vncviewer/vncviewer.cxx:794
#, c-format
msgid ""
"Failure waiting for incoming VNC connection:\n"
@@ -991,10 +1083,38 @@ msgstr ""
"\n"
"%s"
+#: vncviewer/vncviewer.cxx:815
+#, c-format
+msgid ""
+"Failure setting up encrypted tunnel:\n"
+"\n"
+"%s"
+msgstr ""
+"無法設定加密隧é“:\n"
+"\n"
+"%s"
+
#: vncviewer/vncviewer.desktop.in.in:4
-msgid "Remote Desktop Viewer"
+msgid "Remote desktop viewer"
msgstr "é ç«¯æ¡Œé¢æª¢è¦–器"
+#~ msgid "Show dot when no cursor"
+#~ msgstr "若無游標則改顯示一個點"
+
+#, c-format
+#~ msgid "Failed to update keyboard LED state: %d"
+#~ msgstr "æ›´æ–°éµç›¤ LED 狀態失敗:%d"
+
+#~ msgid "No key code specified on key press"
+#~ msgstr "沒有指定按下按éµäº‹ä»¶çš„æŒ‰éµä»£ç¢¼"
+
+#, c-format
+#~ msgid "No symbol for key code 0x%02x (in the current state)"
+#~ msgstr "æ²’æœ‰å°æ‡‰åˆ°æŒ‰éµä»£ç¢¼ 0x%02x 的符號 (ç›®å‰ç‹€æ…‹)"
+
+#~ msgid "Unknown parameter type"
+#~ msgstr "åƒæ•¸é¡žåž‹æœªçŸ¥"
+
#~ msgid "VNC Viewer: Connection Options"
#~ msgstr "VNC 檢視器:連線設定"
diff --git a/release/CMakeLists.txt b/release/CMakeLists.txt
index 6cb14de0..02491a2b 100644
--- a/release/CMakeLists.txt
+++ b/release/CMakeLists.txt
@@ -15,18 +15,18 @@ endif()
configure_file(tigervnc.iss.in tigervnc.iss)
-add_custom_target(installer
- iscc -o. ${INST_DEFS} -F${CMAKE_PROJECT_NAME}${INST_SUFFIX}-${VERSION} tigervnc.iss
- DEPENDS vncviewer
- SOURCES ${CMAKE_CURRENT_BINARY_DIR}/tigervnc.iss)
+add_custom_command(OUTPUT ${CMAKE_PROJECT_NAME}${INST_SUFFIX}-${VERSION}.exe
+ COMMAND iscc -o. ${INST_DEFS} -F${CMAKE_PROJECT_NAME}${INST_SUFFIX}-${VERSION} tigervnc.iss
+ DEPENDS vncviewer tigervnc.iss)
+add_custom_target(installer DEPENDS ${CMAKE_PROJECT_NAME}${INST_SUFFIX}-${VERSION}.exe)
if(BUILD_WINVNC)
configure_file(winvnc.iss.in winvnc.iss)
- add_custom_target(winvnc_installer
- iscc -o. ${INST_DEFS} -F${CMAKE_PROJECT_NAME}${INST_SUFFIX}-winvnc-${VERSION} winvnc.iss
- DEPENDS winvnc4 wm_hooks vncconfig
- SOURCES ${CMAKE_CURRENT_BINARY_DIR}/winvnc.iss)
+ add_custom_command(OUTPUT ${CMAKE_PROJECT_NAME}${INST_SUFFIX}-winvnc-${VERSION}.exe
+ COMMAND iscc -o. ${INST_DEFS} -F${CMAKE_PROJECT_NAME}${INST_SUFFIX}-winvnc-${VERSION} winvnc.iss
+ DEPENDS winvnc4 wm_hooks vncconfig winvnc.iss)
+ add_custom_target(winvnc_installer DEPENDS ${CMAKE_PROJECT_NAME}${INST_SUFFIX}-winvnc-${VERSION}.exe)
endif()
endif() # WIN32
@@ -41,9 +41,10 @@ if(APPLE)
configure_file(makemacapp.in makemacapp)
configure_file(Info.plist.in Info.plist)
-add_custom_target(dmg sh makemacapp
- DEPENDS vncviewer
- SOURCES makemacapp)
+add_custom_command(OUTPUT TigerVNC-${VERSION}.dmg
+ COMMAND sh makemacapp
+ DEPENDS vncviewer makemacapp Info.plist)
+add_custom_target(dmg DEPENDS TigerVNC-${VERSION}.dmg)
endif() # APPLE
@@ -56,16 +57,16 @@ if(UNIX)
configure_file(maketarball.in maketarball)
-set(TARBALL_DEPENDS vncviewer vncpasswd vncconfig)
if(BUILD_JAVA)
- set(TARBALL_DEPENDS ${TARBALL_DEPENDS} java)
+ set(TARBALL_JAVA_DEPENDENCY java)
endif()
-add_custom_target(tarball bash maketarball
- DEPENDS ${TARBALL_DEPENDS})
+set(PACKAGE_FILE ${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}-${VERSION}.tar.gz)
+add_custom_command(OUTPUT ${PACKAGE_FILE}
+ COMMAND bash maketarball
+ DEPENDS maketarball vncviewer vncpasswd vncconfig ${TARBALL_JAVA_DEPENDENCY})
-add_custom_target(servertarball bash maketarball server
- DEPENDS ${TARBALL_DEPENDS})
+add_custom_target(tarball DEPENDS ${PACKAGE_FILE})
endif() #UNIX
diff --git a/release/Info.plist.in b/release/Info.plist.in
index c7505dd1..9be17e5e 100644
--- a/release/Info.plist.in
+++ b/release/Info.plist.in
@@ -5,13 +5,13 @@
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
- <string>TigerVNC viewer</string>
+ <string>TigerVNC</string>
<key>CFBundleExecutable</key>
- <string>TigerVNC viewer</string>
+ <string>vncviewer</string>
<key>NSHighResolutionCapable</key>
<false/>
<key>CFBundleGetInfoString</key>
- <string>@VERSION@, Copyright © 1998-2024 [many holders]</string>
+ <string>@VERSION@, Copyright (C) 1999-2025 TigerVNC team and many others (see README.rst)</string>
<key>CFBundleIconFile</key>
<string>tigervnc.icns</string>
<key>CFBundleIdentifier</key>
@@ -19,9 +19,9 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
- <string>TigerVNC viewer @VERSION@</string>
+ <string>TigerVNC @VERSION@</string>
<key>CFBundleName</key>
- <string>TigerVNC viewer</string>
+ <string>TigerVNC</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@@ -31,6 +31,6 @@
<key>LSRequiresCarbon</key>
<true/>
<key>NSHumanReadableCopyright</key>
- <string>Copyright © 1998-2024 [many holders]</string>
+ <string>Copyright (C) 1999-2025 TigerVNC team and many others (see README.rst)</string>
</dict>
</plist>
diff --git a/release/makemacapp.in b/release/makemacapp.in
index 0827715c..43441b8b 100644
--- a/release/makemacapp.in
+++ b/release/makemacapp.in
@@ -29,25 +29,23 @@ BUILD=@BUILD@
SRCDIR=@CMAKE_SOURCE_DIR@
BINDIR=@CMAKE_BINARY_DIR@
-cd $BINDIR
-
if [ -f $PACKAGE_NAME.dmg ]; then
rm -f $PACKAGE_NAME.dmg
fi
umask 022
TMPDIR=`mktemp -d /tmp/$PACKAGE_NAME-build.XXXXXX`
-APPROOT="$TMPDIR/dmg/TigerVNC viewer $VERSION.app"
+APPROOT="$TMPDIR/dmg/TigerVNC.app"
mkdir -p "$APPROOT/Contents/MacOS"
mkdir -p "$APPROOT/Contents/Resources"
-install -m 755 vncviewer/vncviewer "$APPROOT/Contents/MacOS/TigerVNC viewer"
+install -m 755 $BINDIR/vncviewer/vncviewer "$APPROOT/Contents/MacOS/"
install -m 644 $SRCDIR/media/icons/tigervnc.icns "$APPROOT/Contents/Resources/"
-install -m 644 release/Info.plist "$APPROOT/Contents/"
+install -m 644 $BINDIR/release/Info.plist "$APPROOT/Contents/"
for lang in `cat "$SRCDIR/po/LINGUAS"`; do
mkdir -p "$APPROOT/Contents/Resources/locale/$lang/LC_MESSAGES"
- install -m 644 po/$lang.mo \
+ install -m 644 $BINDIR/po/$lang.mo \
"$APPROOT/Contents/Resources/locale/$lang/LC_MESSAGES/tigervnc.mo"
done
diff --git a/release/maketarball.in b/release/maketarball.in
index 56618934..108de92c 100644
--- a/release/maketarball.in
+++ b/release/maketarball.in
@@ -28,13 +28,6 @@ if [[ $CFLAGS = *-m32* ]]; then
CPU=i686
fi
PACKAGE_FILE=$PACKAGE_NAME-$OS-$CPU-$VERSION.tar.gz
-SERVER=0
-
-if [ $# -gt 0 ]; then
- if [ "$1" = "server" ]; then
- SERVER=1
- fi
-fi
cd $BINDIR
@@ -47,13 +40,6 @@ mkdir -p $OUTDIR/bin
mkdir -p $OUTDIR/man/man1
make DESTDIR=$TMPDIR/inst install
-if [ $SERVER = 1 ]; then
- install -m 755 ./xorg.build/bin/Xvnc $OUTDIR/bin/
- install -m 644 ./xorg.build/man/man1/Xvnc.1 $OUTDIR/man/man1/Xvnc.1
- install -m 644 ./xorg.build/man/man1/Xserver.1 $OUTDIR/man/man1/Xserver.1
- mkdir -p $OUTDIR/lib/dri/
- install -m 755 ./xorg.build/lib/dri/swrast_dri.so $OUTDIR/lib/dri/
-fi
pushd $TMPDIR/inst
tar cfz ../$PACKAGE_FILE .
diff --git a/release/tigervnc.iss.in b/release/tigervnc.iss.in
index de4ee317..519d232f 100644
--- a/release/tigervnc.iss.in
+++ b/release/tigervnc.iss.in
@@ -5,7 +5,7 @@ ArchitecturesInstallIn64BitMode=x64
AppName=TigerVNC
AppVerName=TigerVNC @VERSION@ (@BUILD@)
AppVersion=@VERSION@
-AppPublisher=TigerVNC project
+AppPublisher=TigerVNC team
AppPublisherURL=https://tigervnc.org
DefaultDirName={pf}\TigerVNC
DefaultGroupName=TigerVNC
@@ -25,8 +25,8 @@ Source: "@CMAKE_SOURCE_DIR@\LICENCE.TXT"; DestDir: "{app}"; Flags: ignoreversion
#for {LINGUAS = FileOpen("@CMAKE_SOURCE_DIR@\po\LINGUAS"); !FileEof(LINGUAS); ""} AddLanguage
[Icons]
-Name: "{group}\TigerVNC Viewer"; FileName: "{app}\vncviewer.exe";
-Name: "{group}\Listening TigerVNC Viewer"; FileName: "{app}\vncviewer.exe"; Parameters: "-listen";
+Name: "{group}\TigerVNC"; FileName: "{app}\vncviewer.exe";
+Name: "{group}\Listening TigerVNC"; FileName: "{app}\vncviewer.exe"; Parameters: "-listen";
Name: "{group}\License"; FileName: "write.exe"; Parameters: "LICENCE.TXT"; WorkingDir: "{app}"; Flags: "useapppaths"
Name: "{group}\Read Me"; FileName: "write.exe"; Parameters: "README.rst"; WorkingDir: "{app}"; Flags: "useapppaths"
diff --git a/release/winvnc.iss.in b/release/winvnc.iss.in
index 773aa175..2b002983 100644
--- a/release/winvnc.iss.in
+++ b/release/winvnc.iss.in
@@ -5,7 +5,7 @@ ArchitecturesInstallIn64BitMode=x64
AppName=TigerVNC server
AppVerName=TigerVNC server v@VERSION@ (@BUILD@)
AppVersion=@VERSION@
-AppPublisher=TigerVNC project
+AppPublisher=TigerVNC team
AppPublisherURL=https://tigervnc.org
DefaultDirName={pf}\TigerVNC server
DefaultGroupName=TigerVNC server
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3d0d4390..5e5f7902 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -6,4 +6,6 @@ endif()
add_subdirectory(perf)
# Unit tests
-add_subdirectory(unit)
+if(GTest_FOUND)
+ add_subdirectory(unit)
+endif()
diff --git a/tests/perf/CMakeLists.txt b/tests/perf/CMakeLists.txt
index 13061b9b..54a1ad89 100644
--- a/tests/perf/CMakeLists.txt
+++ b/tests/perf/CMakeLists.txt
@@ -6,10 +6,10 @@ add_executable(convperf convperf.cxx)
target_link_libraries(convperf test_util rfb)
add_executable(decperf decperf.cxx)
-target_link_libraries(decperf test_util rfb)
+target_link_libraries(decperf test_util rdr rfb)
add_executable(encperf encperf.cxx)
-target_link_libraries(encperf test_util rfb)
+target_link_libraries(encperf test_util core rdr rfb)
if (BUILD_VIEWER)
add_executable(fbperf
@@ -27,8 +27,8 @@ if (BUILD_VIEWER)
target_sources(fbperf PRIVATE ${CMAKE_SOURCE_DIR}/vncviewer/Surface_X11.cxx)
endif()
target_include_directories(fbperf SYSTEM PUBLIC ${FLTK_INCLUDE_DIR})
- target_include_directories(fbperf SYSTEM PUBLIC ${GETTEXT_INCLUDE_DIR})
- target_link_libraries(fbperf test_util rfb ${FLTK_LIBRARIES} ${GETTEXT_LIBRARIES})
+ target_include_directories(fbperf SYSTEM PUBLIC ${Intl_INCLUDE_DIR})
+ target_link_libraries(fbperf test_util core rfb ${FLTK_LIBRARIES} ${Intl_LIBRARIES})
if(WIN32)
target_link_libraries(fbperf msimg32)
endif()
diff --git a/tests/perf/decperf.cxx b/tests/perf/decperf.cxx
index 46f42fa2..2c7efa3b 100644
--- a/tests/perf/decperf.cxx
+++ b/tests/perf/decperf.cxx
@@ -33,7 +33,6 @@
#include <math.h>
#include <sys/time.h>
-#include <rdr/Exception.h>
#include <rdr/FileInStream.h>
#include <rdr/OutStream.h>
@@ -68,8 +67,6 @@ public:
~CConn();
void initDone() override;
- void setCursor(int, int, const rfb::Point&, const uint8_t*) override;
- void setCursorPos(const rfb::Point&) override;
void framebufferUpdateStart() override;
void framebufferUpdateEnd() override;
void setColourMapEntries(int, int, uint16_t*) override;
@@ -141,14 +138,6 @@ void CConn::initDone()
server.height()));
}
-void CConn::setCursor(int, int, const rfb::Point&, const uint8_t*)
-{
-}
-
-void CConn::setCursorPos(const rfb::Point&)
-{
-}
-
void CConn::framebufferUpdateStart()
{
CConnection::framebufferUpdateStart();
diff --git a/tests/perf/encperf.cxx b/tests/perf/encperf.cxx
index d761bbed..0da54603 100644
--- a/tests/perf/encperf.cxx
+++ b/tests/perf/encperf.cxx
@@ -37,34 +37,32 @@
#include <math.h>
#include <sys/time.h>
-#include <rdr/Exception.h>
+#include <core/Configuration.h>
+
#include <rdr/OutStream.h>
#include <rdr/FileInStream.h>
#include <rfb/AccessRights.h>
-
#include <rfb/PixelFormat.h>
-
#include <rfb/CConnection.h>
#include <rfb/CMsgReader.h>
#include <rfb/CMsgWriter.h>
#include <rfb/UpdateTracker.h>
-
#include <rfb/EncodeManager.h>
#include <rfb/SConnection.h>
#include <rfb/SMsgWriter.h>
#include "util.h"
-static rfb::IntParameter width("width", "Frame buffer width", 0);
-static rfb::IntParameter height("height", "Frame buffer height", 0);
-static rfb::IntParameter count("count", "Number of benchmark iterations", 9);
+static core::IntParameter width("width", "Frame buffer width", 0);
+static core::IntParameter height("height", "Frame buffer height", 0);
+static core::IntParameter count("count", "Number of benchmark iterations", 9);
-static rfb::StringParameter format("format", "Pixel format (e.g. bgr888)", "");
+static core::StringParameter format("format", "Pixel format (e.g. bgr888)", "");
-static rfb::BoolParameter translate("translate",
- "Translate 8-bit and 16-bit datasets into 24-bit",
- true);
+static core::BoolParameter translate("translate",
+ "Translate 8-bit and 16-bit datasets into 24-bit",
+ true);
// The frame buffer (and output) is always this format
static const rfb::PixelFormat fbPF(32, 24, false, true, 255, 255, 255, 0, 8, 16);
@@ -100,11 +98,9 @@ public:
void initDone() override {};
void resizeFramebuffer() override;
- void setCursor(int, int, const rfb::Point&, const uint8_t*) override;
- void setCursorPos(const rfb::Point&) override;
void framebufferUpdateStart() override;
void framebufferUpdateEnd() override;
- bool dataRect(const rfb::Rect&, int) override;
+ bool dataRect(const core::Rect&, int) override;
void setColourMapEntries(int, int, uint16_t*) override;
void bell() override;
void serverCutText(const char*) override;
@@ -143,6 +139,10 @@ public:
void setDesktopSize(int fb_width, int fb_height,
const rfb::ScreenSet& layout) override;
+ void keyEvent(uint32_t keysym, uint32_t keycode, bool down) override;
+ void pointerEvent(const core::Point& pos,
+ uint16_t buttonMask) override;
+
protected:
DummyOutStream *out;
Manager *manager;
@@ -196,7 +196,7 @@ CConn::CConn(const char *filename)
sc = new SConn();
sc->client.setPF((bool)translate ? fbPF : pf);
- sc->setEncodings(sizeof(encodings) / sizeof(*encodings), encodings);
+ ((rfb::SMsgHandler*)sc)->setEncodings(sizeof(encodings) / sizeof(*encodings), encodings);
}
CConn::~CConn()
@@ -221,14 +221,6 @@ void CConn::resizeFramebuffer()
setFramebuffer(pb);
}
-void CConn::setCursor(int, int, const rfb::Point&, const uint8_t*)
-{
-}
-
-void CConn::setCursorPos(const rfb::Point&)
-{
-}
-
void CConn::framebufferUpdateStart()
{
CConnection::framebufferUpdateStart();
@@ -241,7 +233,7 @@ void CConn::framebufferUpdateEnd()
{
rfb::UpdateInfo ui;
rfb::PixelBuffer* pb = getFramebuffer();
- rfb::Region clip(pb->getRect());
+ core::Region clip(pb->getRect());
CConnection::framebufferUpdateEnd();
@@ -258,13 +250,13 @@ void CConn::framebufferUpdateEnd()
encodeTime += getCpuCounter();
}
-bool CConn::dataRect(const rfb::Rect &r, int encoding)
+bool CConn::dataRect(const core::Rect& r, int encoding)
{
if (!CConnection::dataRect(r, encoding))
return false;
if (encoding != rfb::encodingCopyRect) // FIXME
- updates.add_changed(rfb::Region(r));
+ updates.add_changed(r);
return true;
}
@@ -351,6 +343,14 @@ void SConn::setDesktopSize(int, int, const rfb::ScreenSet&)
{
}
+void SConn::keyEvent(uint32_t, uint32_t, bool)
+{
+}
+
+void SConn::pointerEvent(const core::Point&, uint16_t)
+{
+}
+
struct stats
{
double decodeTime;
@@ -421,7 +421,7 @@ static void usage(const char *argv0)
{
fprintf(stderr, "Syntax: %s [options] <rfb file>\n", argv0);
fprintf(stderr, "Options:\n");
- rfb::Configuration::listParams(79, 14);
+ core::Configuration::listParams(79, 14);
exit(1);
}
@@ -433,18 +433,16 @@ int main(int argc, char **argv)
fn = nullptr;
for (i = 1; i < argc; i++) {
- if (rfb::Configuration::setParam(argv[i]))
+ int ret;
+
+ ret = core::Configuration::handleParamArg(argc, argv, i);
+ if (ret > 0) {
+ i += ret;
continue;
+ }
- if (argv[i][0] == '-') {
- if (i + 1 < argc) {
- if (rfb::Configuration::setParam(&argv[i][1], argv[i + 1])) {
- i++;
- continue;
- }
- }
+ if (argv[i][0] == '-')
usage(argv[0]);
- }
if (fn != nullptr)
usage(argv[0]);
diff --git a/tests/perf/fbperf.cxx b/tests/perf/fbperf.cxx
index e4d0febf..1a5b5ba7 100644
--- a/tests/perf/fbperf.cxx
+++ b/tests/perf/fbperf.cxx
@@ -28,8 +28,8 @@
#include <FL/fl_draw.H>
#include <FL/x.H>
-#include <rdr/Exception.h>
-#include <rfb/util.h>
+#include <core/string.h>
+#include <core/time.h>
#include "../vncviewer/PlatformPixelBuffer.h"
@@ -155,7 +155,7 @@ void TestWindow::flush()
void TestWindow::update()
{
- rfb::Rect r;
+ core::Rect r;
startTimeCounter();
@@ -194,7 +194,7 @@ void TestWindow::timer(void* data)
void PartialTestWindow::changefb()
{
- rfb::Rect r;
+ core::Rect r;
uint32_t pixel;
r = fb->getRect();
@@ -300,7 +300,7 @@ static void dosubtest(TestWindow* win, int width, int height,
win->start(width, height);
gettimeofday(&start, nullptr);
- while (rfb::msSince(&start) < 3000)
+ while (core::msSince(&start) < 3000)
Fl::wait();
win->stop();
@@ -370,7 +370,7 @@ static void dotest(TestWindow* win)
fprintf(stderr, "Rendering delay: %g ms/frame\n", delay * 1000.0);
fprintf(stderr, "Rendering rate: %s\n",
(rate == 0.0) ? "N/A pixels/s" :
- rfb::siPrefix(1.0 / rate, "pixels/s").c_str());
+ core::siPrefix(1.0 / rate, "pixels/s").c_str());
fprintf(stderr, "Maximum FPS: %g fps @ 1920x1080\n",
1.0 / (delay + rate * 1920 * 1080));
}
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index 8e223052..1e40a645 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -1,24 +1,50 @@
+include(GoogleTest)
+
+# Google Test requires a new C++ standard
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
+
+enable_testing()
+
include_directories(${CMAKE_SOURCE_DIR}/common)
include_directories(${CMAKE_SOURCE_DIR}/vncviewer)
+add_executable(configargs configargs.cxx)
+target_link_libraries(configargs rfb GTest::gtest_main)
+gtest_discover_tests(configargs)
+
add_executable(conv conv.cxx)
-target_link_libraries(conv rfb)
+target_link_libraries(conv rfb GTest::gtest_main)
+gtest_discover_tests(conv)
add_executable(convertlf convertlf.cxx)
-target_link_libraries(convertlf rfb)
+target_link_libraries(convertlf core GTest::gtest_main)
+gtest_discover_tests(convertlf)
add_executable(gesturehandler gesturehandler.cxx ../../vncviewer/GestureHandler.cxx)
-target_link_libraries(gesturehandler rfb)
+target_link_libraries(gesturehandler core GTest::gtest_main)
+gtest_discover_tests(gesturehandler)
add_executable(hostport hostport.cxx)
-target_link_libraries(hostport rfb)
+target_link_libraries(hostport network GTest::gtest_main)
+gtest_discover_tests(hostport)
+
+add_executable(parameters parameters.cxx)
+target_link_libraries(parameters core GTest::gtest_main)
+gtest_discover_tests(parameters)
add_executable(pixelformat pixelformat.cxx)
-target_link_libraries(pixelformat rfb)
+target_link_libraries(pixelformat rfb GTest::gtest_main)
+gtest_discover_tests(pixelformat)
+
+add_executable(shortcuthandler shortcuthandler.cxx ../../vncviewer/ShortcutHandler.cxx)
+target_link_libraries(shortcuthandler core ${Intl_LIBRARIES} GTest::gtest_main)
+gtest_discover_tests(shortcuthandler)
add_executable(unicode unicode.cxx)
-target_link_libraries(unicode rfb)
+target_link_libraries(unicode core GTest::gtest_main)
+gtest_discover_tests(unicode)
add_executable(emulatemb emulatemb.cxx ../../vncviewer/EmulateMB.cxx)
-target_include_directories(emulatemb SYSTEM PUBLIC ${GETTEXT_INCLUDE_DIR})
-target_link_libraries(emulatemb rfb ${GETTEXT_LIBRARIES})
+target_include_directories(emulatemb SYSTEM PUBLIC ${Intl_INCLUDE_DIR})
+target_link_libraries(emulatemb core ${Intl_LIBRARIES} GTest::gtest_main)
+gtest_discover_tests(emulatemb)
diff --git a/tests/unit/configargs.cxx b/tests/unit/configargs.cxx
new file mode 100644
index 00000000..2d3406f3
--- /dev/null
+++ b/tests/unit/configargs.cxx
@@ -0,0 +1,325 @@
+/* Copyright 2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtest/gtest.h>
+
+#include <core/Configuration.h>
+
+static core::BoolParameter boolparam("boolparam", "", false);
+static core::IntParameter intparam("intparam", "", 0);
+static core::StringParameter strparam("strparam", "", "");
+
+TEST(ConfigArgs, args)
+{
+ int ret;
+ std::vector<const char*> argv;
+
+ boolparam.setParam(true);
+ intparam.setParam(1);
+ strparam.setParam("test");
+
+ // Just program name
+ argv = {"prog" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 0);
+ EXPECT_EQ(ret, 0);
+ EXPECT_EQ(boolparam, true);
+ EXPECT_EQ(intparam, 1);
+ EXPECT_STREQ(strparam, "test");
+
+ // A bunch of standard arguments
+ argv = {"prog", "arg1", "arg2", "arg3" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 2);
+ EXPECT_EQ(ret, 0);
+ EXPECT_EQ(boolparam, true);
+ EXPECT_EQ(intparam, 1);
+ EXPECT_STREQ(strparam, "test");
+
+ // A parameter without any dash
+ argv = {"prog", "strparam", "intparam" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 0);
+ EXPECT_EQ(boolparam, true);
+ EXPECT_EQ(intparam, 1);
+ EXPECT_STREQ(strparam, "test");
+}
+
+TEST(ConfigArgs, noDash)
+{
+ int ret;
+ std::vector<const char*> argv;
+
+ boolparam.setParam(true);
+ intparam.setParam(1);
+ strparam.setParam("test");
+
+ // int argument
+ argv = {"prog", "intparam=12", "34"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(intparam, 12);
+
+ // string argument
+ argv = {"prog", "strparam=foo", "bar" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_STREQ(strparam, "foo");
+
+ // empty string argument
+ argv = {"prog", "strparam=", "bar" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_STREQ(strparam, "");
+
+ // Bad parameter
+ argv = {"prog", "fooparam=123"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 0);
+}
+
+TEST(ConfigArgs, singleDash)
+{
+ int ret;
+ std::vector<const char*> argv;
+
+ boolparam.setParam(true);
+ intparam.setParam(1);
+ strparam.setParam("test");
+
+ // int argument
+ argv = {"prog", "-intparam", "12", "34"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 2);
+ EXPECT_EQ(intparam, 12);
+
+ // int argument with equals
+ argv = {"prog", "-intparam=12", "34"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(intparam, 12);
+
+ // string argument
+ argv = {"prog", "-strparam", "foo", "bar" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 2);
+ EXPECT_STREQ(strparam, "foo");
+
+ // string argument with equals
+ argv = {"prog", "-strparam=foo", "bar" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_STREQ(strparam, "foo");
+
+ // empty string argument with equals
+ argv = {"prog", "-strparam=", "bar" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_STREQ(strparam, "");
+
+ // Missing argument
+ intparam.setParam(1);
+ argv = {"prog", "-intparam"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 0);
+ EXPECT_EQ(intparam, 1);
+
+ // Bad parameter
+ argv = {"prog", "-fooparam", "123"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 0);
+
+ // Bad parameter with equals
+ argv = {"prog", "-fooparam=123"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 0);
+}
+
+TEST(ConfigArgs, doubleDash)
+{
+ int ret;
+ std::vector<const char*> argv;
+
+ boolparam.setParam(true);
+ intparam.setParam(1);
+ strparam.setParam("test");
+
+ // int argument
+ argv = {"prog", "--intparam", "12", "34"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 2);
+ EXPECT_EQ(intparam, 12);
+
+ // int argument with equals
+ argv = {"prog", "--intparam=12", "34"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(intparam, 12);
+
+ // string argument
+ argv = {"prog", "--strparam", "foo", "bar" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 2);
+ EXPECT_STREQ(strparam, "foo");
+
+ // string argument with equals
+ argv = {"prog", "--strparam=foo", "bar" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_STREQ(strparam, "foo");
+
+ // empty string argument with equals
+ argv = {"prog", "--strparam=", "bar" };
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_STREQ(strparam, "");
+
+ // Missing argument
+ intparam.setParam(1);
+ argv = {"prog", "--intparam"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 0);
+ EXPECT_EQ(intparam, 1);
+
+ // Bad parameter
+ argv = {"prog", "--fooparam", "123"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 0);
+
+ // Bad parameter with equals
+ argv = {"prog", "--fooparam=123"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 0);
+}
+
+TEST(ConfigArgs, bool)
+{
+ int ret;
+ std::vector<const char*> argv;
+
+ // solo bool (single)
+ boolparam.setParam(false);
+ argv = {"prog", "-boolparam"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(boolparam, true);
+
+ // solo bool (double)
+ boolparam.setParam(false);
+ argv = {"prog", "--boolparam"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(boolparam, true);
+
+ // bool argument (single)
+ boolparam.setParam(true);
+ argv = {"prog", "-boolparam", "off", "on"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 2);
+ EXPECT_EQ(boolparam, false);
+
+ // bool argument (double)
+ boolparam.setParam(true);
+ argv = {"prog", "--boolparam", "off", "on"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 2);
+ EXPECT_EQ(boolparam, false);
+
+ // bool argument equals (single)
+ boolparam.setParam(true);
+ argv = {"prog", "-boolparam=off", "on"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(boolparam, false);
+
+ // bool argument equals (double)
+ boolparam.setParam(true);
+ argv = {"prog", "--boolparam=off", "on"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(boolparam, false);
+
+ // empty bool argument equals (single)
+ boolparam.setParam(true);
+ argv = {"prog", "-boolparam=", "on"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(boolparam, true);
+
+ // empty bool argument equals (double)
+ boolparam.setParam(true);
+ argv = {"prog", "--boolparam=", "on"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(boolparam, true);
+
+ // bool bad argument (single)
+ boolparam.setParam(false);
+ argv = {"prog", "-boolparam", "foo", "off"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(boolparam, true);
+
+ // bool bad argument (double)
+ boolparam.setParam(false);
+ argv = {"prog", "--boolparam", "foo", "off"};
+ ret = core::Configuration::handleParamArg(argv.size(),
+ (char**)argv.data(), 1);
+ EXPECT_EQ(ret, 1);
+ EXPECT_EQ(boolparam, true);
+}
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tests/unit/conv.cxx b/tests/unit/conv.cxx
index 2f15cb55..e4959299 100644
--- a/tests/unit/conv.cxx
+++ b/tests/unit/conv.cxx
@@ -1,4 +1,4 @@
-/* Copyright 2013-2014 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2013-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,10 +20,12 @@
#include <config.h>
#endif
-#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
+#include <list>
+
+#include <gtest/gtest.h>
+
#include <rfb/PixelFormat.h>
static const uint8_t pixelRed = 0xf1;
@@ -61,7 +63,7 @@ void makePixel(const rfb::PixelFormat &pf,
pf.bufferFromPixel(buffer, p);
}
-bool verifyPixel(const rfb::PixelFormat &dstpf,
+void verifyPixel(const rfb::PixelFormat &dstpf,
const rfb::PixelFormat &srcpf,
const uint8_t *buffer)
{
@@ -89,14 +91,23 @@ bool verifyPixel(const rfb::PixelFormat &dstpf,
ge = (1 << (8 - min(dstpf.greenBits, srcpf.greenBits))) - 1;
be = (1 << (8 - min(dstpf.blueBits, srcpf.blueBits))) - 1;
- if (abs(r - pixelRed) > re)
- return false;
- if (abs(g - pixelGreen) > ge)
- return false;
- if (abs(b - pixelBlue) > be)
- return false;
+ EXPECT_NEAR(r, pixelRed, re);
+ EXPECT_NEAR(g, pixelGreen, ge);
+ EXPECT_NEAR(b, pixelBlue, be);
+}
- return true;
+}
+
+typedef std::pair<rfb::PixelFormat, rfb::PixelFormat> TestPair;
+typedef testing::TestWithParam<TestPair> Conv;
+
+namespace rfb {
+
+static std::ostream& operator<<(std::ostream& os, const PixelFormat& pf)
+{
+ char b[256];
+ pf.print(b, sizeof(b));
+ return os << b;
}
}
@@ -104,12 +115,14 @@ bool verifyPixel(const rfb::PixelFormat &dstpf,
using rfb::makePixel;
using rfb::verifyPixel;
-static bool testPixel(const rfb::PixelFormat &dstpf,
- const rfb::PixelFormat &srcpf)
+TEST_P(Conv, pixelFromPixel)
{
rfb::Pixel p;
uint8_t buffer[4];
+ const rfb::PixelFormat &srcpf = GetParam().first;
+ const rfb::PixelFormat &dstpf = GetParam().second;
+
makePixel(srcpf, buffer);
p = srcpf.pixelFromBuffer(buffer);
@@ -117,18 +130,17 @@ static bool testPixel(const rfb::PixelFormat &dstpf,
memset(buffer, 0, sizeof(buffer));
dstpf.bufferFromPixel(buffer, p);
- if (!verifyPixel(dstpf, srcpf, buffer))
- return false;
-
- return true;
+ verifyPixel(dstpf, srcpf, buffer);
}
-static bool testBuffer(const rfb::PixelFormat &dstpf,
- const rfb::PixelFormat &srcpf)
+TEST_P(Conv, bufferFromBuffer)
{
int i, x, y, unaligned;
uint8_t bufIn[fbMalloc], bufOut[fbMalloc];
+ const rfb::PixelFormat &srcpf = GetParam().first;
+ const rfb::PixelFormat &dstpf = GetParam().second;
+
// Once aligned, and once unaligned
for (unaligned = 0;unaligned < 2;unaligned++) {
for (i = 0;i < fbArea;i++)
@@ -139,8 +151,9 @@ static bool testBuffer(const rfb::PixelFormat &dstpf,
bufIn + unaligned, fbArea);
for (i = 0;i < fbArea;i++) {
- if (!verifyPixel(dstpf, srcpf, bufOut + unaligned + i*dstpf.bpp/8))
- return false;
+ verifyPixel(dstpf, srcpf, bufOut + unaligned + i*dstpf.bpp/8);
+ if (testing::Test::HasFailure())
+ return;
}
memset(bufIn, 0, sizeof(bufIn));
@@ -155,29 +168,29 @@ static bool testBuffer(const rfb::PixelFormat &dstpf,
for (y = 0;y < fbHeight;y++) {
for (x = 0;x < fbWidth;x++) {
+ const uint8_t* pixel;
+ pixel = bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8;
if (x < fbWidth/2) {
- if (!verifyPixel(dstpf, srcpf,
- bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8))
- return false;
+ verifyPixel(dstpf, srcpf, pixel);
} else {
const uint8_t zero[4] = { 0, 0, 0, 0 };
- if (memcmp(bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8, zero,
- dstpf.bpp/8) != 0)
- return false;
+ EXPECT_EQ(memcmp(pixel, zero, dstpf.bpp/8), 0);
}
+ if (testing::Test::HasFailure())
+ return;
}
}
}
-
- return true;
}
-static bool testRGB(const rfb::PixelFormat &dstpf,
- const rfb::PixelFormat &srcpf)
+TEST_P(Conv, bufferToFromRGB)
{
int i, x, y, unaligned;
uint8_t bufIn[fbMalloc], bufRGB[fbMalloc], bufOut[fbMalloc];
+ const rfb::PixelFormat &srcpf = GetParam().first;
+ const rfb::PixelFormat &dstpf = GetParam().second;
+
// Once aligned, and once unaligned
for (unaligned = 0;unaligned < 2;unaligned++) {
for (i = 0;i < fbArea;i++)
@@ -190,8 +203,9 @@ static bool testRGB(const rfb::PixelFormat &dstpf,
dstpf.bufferFromRGB(bufOut + unaligned, bufRGB + unaligned, fbArea);
for (i = 0;i < fbArea;i++) {
- if (!verifyPixel(dstpf, srcpf, bufOut + unaligned + i*dstpf.bpp/8))
- return false;
+ verifyPixel(dstpf, srcpf, bufOut + unaligned + i*dstpf.bpp/8);
+ if (testing::Test::HasFailure())
+ return;
}
memset(bufIn, 0, sizeof(bufIn));
@@ -210,31 +224,31 @@ static bool testRGB(const rfb::PixelFormat &dstpf,
for (y = 0;y < fbHeight;y++) {
for (x = 0;x < fbWidth;x++) {
+ const uint8_t* pixel;
+ pixel = bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8;
if (x < fbWidth/2) {
- if (!verifyPixel(dstpf, srcpf,
- bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8))
- return false;
+ verifyPixel(dstpf, srcpf, pixel);
} else {
const uint8_t zero[4] = { 0, 0, 0, 0 };
- if (memcmp(bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8, zero,
- dstpf.bpp/8) != 0)
- return false;
+ EXPECT_EQ(memcmp(pixel, zero, dstpf.bpp/8), 0);
}
+ if (testing::Test::HasFailure())
+ return;
}
}
}
-
- return true;
}
-static bool testPixelRGB(const rfb::PixelFormat &dstpf,
- const rfb::PixelFormat &srcpf)
+TEST_P(Conv, pixelToFromRGB)
{
rfb::Pixel p;
uint16_t r16, g16, b16;
uint8_t r8, g8, b8;
uint8_t buffer[4];
+ const rfb::PixelFormat &srcpf = GetParam().first;
+ const rfb::PixelFormat &dstpf = GetParam().second;
+
makePixel(srcpf, buffer);
p = srcpf.pixelFromBuffer(buffer);
@@ -243,8 +257,7 @@ static bool testPixelRGB(const rfb::PixelFormat &dstpf,
memset(buffer, 0, sizeof(buffer));
dstpf.bufferFromPixel(buffer, p);
- if (!verifyPixel(dstpf, srcpf, buffer))
- return false;
+ verifyPixel(dstpf, srcpf, buffer);
makePixel(srcpf, buffer);
@@ -254,112 +267,84 @@ static bool testPixelRGB(const rfb::PixelFormat &dstpf,
memset(buffer, 0, sizeof(buffer));
dstpf.bufferFromPixel(buffer, p);
- if (!verifyPixel(dstpf, srcpf, buffer))
- return false;
-
- return true;
-}
-
-struct TestEntry tests[] = {
- {"Pixel from pixel", testPixel},
- {"Buffer from buffer", testBuffer},
- {"Buffer to/from RGB", testRGB},
- {"Pixel to/from RGB", testPixelRGB},
-};
-
-static void doTests(const rfb::PixelFormat &dstpf,
- const rfb::PixelFormat &srcpf)
-{
- size_t i;
- char dstb[256], srcb[256];
-
- dstpf.print(dstb, sizeof(dstb));
- srcpf.print(srcb, sizeof(srcb));
-
- printf("\n");
- printf("%s to %s\n", srcb, dstb);
- printf("\n");
-
- for (i = 0;i < sizeof(tests)/sizeof(tests[0]);i++) {
- printf(" %s: ", tests[i].label);
- fflush(stdout);
- if (tests[i].fn(dstpf, srcpf))
- printf("OK");
- else
- printf("FAILED");
- printf("\n");
- }
+ verifyPixel(dstpf, srcpf, buffer);
}
-int main(int /*argc*/, char** /*argv*/)
+static std::list<TestPair> paramGenerator()
{
+ std::list<TestPair> params;
rfb::PixelFormat dstpf, srcpf;
- printf("Pixel Conversion Correctness Test\n");
-
/* rgb888 targets */
dstpf.parse("rgb888");
srcpf.parse("rgb888");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
srcpf.parse("bgr888");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
srcpf.parse("rgb565");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
srcpf.parse("rgb232");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
/* rgb565 targets */
dstpf.parse("rgb565");
srcpf.parse("rgb888");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
srcpf.parse("bgr565");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
srcpf.parse("rgb232");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
/* rgb232 targets */
dstpf.parse("rgb232");
srcpf.parse("rgb888");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
srcpf.parse("rgb565");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
srcpf.parse("bgr232");
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
/* endian conversion (both ways) */
dstpf = rfb::PixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
srcpf = rfb::PixelFormat(32, 24, true, true, 255, 255, 255, 0, 8, 16);
- doTests(dstpf, srcpf);
-
- doTests(srcpf, dstpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
+ params.push_back(std::make_pair(dstpf, srcpf));
dstpf = rfb::PixelFormat(16, 16, false, true, 31, 63, 31, 0, 5, 11);
srcpf = rfb::PixelFormat(16, 16, true, true, 31, 63, 31, 0, 5, 11);
- doTests(dstpf, srcpf);
-
- doTests(srcpf, dstpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
+ params.push_back(std::make_pair(dstpf, srcpf));
// Pesky case that is very asymetrical
dstpf = rfb::PixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
srcpf = rfb::PixelFormat(32, 24, true, true, 255, 255, 255, 0, 24, 8);
- doTests(dstpf, srcpf);
+ params.push_back(std::make_pair(srcpf, dstpf));
+ params.push_back(std::make_pair(dstpf, srcpf));
- doTests(srcpf, dstpf);
+ return params;
+}
+
+INSTANTIATE_TEST_SUITE_P(, Conv, testing::ValuesIn(paramGenerator()));
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tests/unit/convertlf.cxx b/tests/unit/convertlf.cxx
index 1645532a..3392725a 100644
--- a/tests/unit/convertlf.cxx
+++ b/tests/unit/convertlf.cxx
@@ -1,4 +1,4 @@
-/* Copyright 2019 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2019-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,105 +20,56 @@
#include <config.h>
#endif
-#include <stdio.h>
+#include <gtest/gtest.h>
-#include <rfb/util.h>
+#include <core/string.h>
-static const char* escape(const char* input)
+TEST(ConvertLF, convertLF)
{
- static char output[4096];
-
- const char* in;
- char* out;
-
- in = input;
- out = output;
- do {
- if (*in == '\r') {
- *out++ = '\\';
- *out++ = 'r';
- } else if (*in == '\n') {
- *out++ = '\\';
- *out++ = 'n';
- } else {
- *out++ = *in;
- }
- } while (*in++ != '\0');
-
- return output;
-}
-
-static void testLF(const char* input, const char* expected)
-{
- std::string output;
-
- printf("convertLF(\"%s\"): ", escape(input));
-
- output = rfb::convertLF(input);
-
- if (output != expected)
- printf("FAILED: got \"%s\"", escape(output.c_str()));
- else
- printf("OK");
- printf("\n");
- fflush(stdout);
+ EXPECT_EQ(core::convertLF(""), "");
+ EXPECT_EQ(core::convertLF("no EOL"), "no EOL");
+
+ EXPECT_EQ(core::convertLF("\n"), "\n");
+ EXPECT_EQ(core::convertLF("already correct\n"), "already correct\n");
+ EXPECT_EQ(core::convertLF("multiple\nlines\n"), "multiple\nlines\n");
+ EXPECT_EQ(core::convertLF("empty lines\n\n"), "empty lines\n\n");
+ EXPECT_EQ(core::convertLF("\ninitial line"), "\ninitial line");
+
+ EXPECT_EQ(core::convertLF("\r\n"), "\n");
+ EXPECT_EQ(core::convertLF("one line\r\n"), "one line\n");
+ EXPECT_EQ(core::convertLF("multiple\r\nlines\r\n"), "multiple\nlines\n");
+ EXPECT_EQ(core::convertLF("empty lines\r\n\r\n"), "empty lines\n\n");
+ EXPECT_EQ(core::convertLF("\r\ninitial line"), "\ninitial line");
+ EXPECT_EQ(core::convertLF("mixed\r\nlines\n"), "mixed\nlines\n");
+
+ EXPECT_EQ(core::convertLF("cropped\r"), "cropped\n");
+ EXPECT_EQ(core::convertLF("old\rmac\rformat"), "old\nmac\nformat");
}
-static void testCRLF(const char* input, const char* expected)
+TEST(ConvertLF, convertCRLF)
{
- std::string output;
-
- printf("convertCRLF(\"%s\"): ", escape(input));
-
- output = rfb::convertCRLF(input);
-
- if (output != expected)
- printf("FAILED: got \"%s\"", escape(output.c_str()));
- else
- printf("OK");
- printf("\n");
- fflush(stdout);
+ EXPECT_EQ(core::convertCRLF(""), "");
+ EXPECT_EQ(core::convertCRLF("no EOL"), "no EOL");
+
+ EXPECT_EQ(core::convertCRLF("\r\n"), "\r\n");
+ EXPECT_EQ(core::convertCRLF("already correct\r\n"), "already correct\r\n");
+ EXPECT_EQ(core::convertCRLF("multiple\r\nlines\r\n"), "multiple\r\nlines\r\n");
+ EXPECT_EQ(core::convertCRLF("empty lines\r\n\r\n"), "empty lines\r\n\r\n");
+ EXPECT_EQ(core::convertCRLF("\r\ninitial line"), "\r\ninitial line");
+
+ EXPECT_EQ(core::convertCRLF("\n"), "\r\n");
+ EXPECT_EQ(core::convertCRLF("one line\n"), "one line\r\n");
+ EXPECT_EQ(core::convertCRLF("multiple\nlines\n"), "multiple\r\nlines\r\n");
+ EXPECT_EQ(core::convertCRLF("empty lines\n\n"), "empty lines\r\n\r\n");
+ EXPECT_EQ(core::convertCRLF("\ninitial line"), "\r\ninitial line");
+ EXPECT_EQ(core::convertCRLF("mixed\r\nlines\n"), "mixed\r\nlines\r\n");
+
+ EXPECT_EQ(core::convertCRLF("cropped\r"), "cropped\r\n");
+ EXPECT_EQ(core::convertCRLF("old\rmac\rformat"), "old\r\nmac\r\nformat");
}
-int main(int /*argc*/, char** /*argv*/)
+int main(int argc, char** argv)
{
- testLF("", "");
- testLF("no EOL", "no EOL");
-
- testLF("\n", "\n");
- testLF("already correct\n", "already correct\n");
- testLF("multiple\nlines\n", "multiple\nlines\n");
- testLF("empty lines\n\n", "empty lines\n\n");
- testLF("\ninitial line", "\ninitial line");
-
- testLF("\r\n", "\n");
- testLF("one line\r\n", "one line\n");
- testLF("multiple\r\nlines\r\n", "multiple\nlines\n");
- testLF("empty lines\r\n\r\n", "empty lines\n\n");
- testLF("\r\ninitial line", "\ninitial line");
- testLF("mixed\r\nlines\n", "mixed\nlines\n");
-
- testLF("cropped\r", "cropped\n");
- testLF("old\rmac\rformat", "old\nmac\nformat");
-
- testCRLF("", "");
- testCRLF("no EOL", "no EOL");
-
- testCRLF("\r\n", "\r\n");
- testCRLF("already correct\r\n", "already correct\r\n");
- testCRLF("multiple\r\nlines\r\n", "multiple\r\nlines\r\n");
- testCRLF("empty lines\r\n\r\n", "empty lines\r\n\r\n");
- testCRLF("\r\ninitial line", "\r\ninitial line");
-
- testCRLF("\n", "\r\n");
- testCRLF("one line\n", "one line\r\n");
- testCRLF("multiple\nlines\n", "multiple\r\nlines\r\n");
- testCRLF("empty lines\n\n", "empty lines\r\n\r\n");
- testCRLF("\ninitial line", "\r\ninitial line");
- testCRLF("mixed\r\nlines\n", "mixed\r\nlines\r\n");
-
- testCRLF("cropped\r", "cropped\r\n");
- testCRLF("old\rmac\rformat", "old\r\nmac\r\nformat");
-
- return 0;
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tests/unit/emulatemb.cxx b/tests/unit/emulatemb.cxx
index 6db8ea38..d59ce509 100644
--- a/tests/unit/emulatemb.cxx
+++ b/tests/unit/emulatemb.cxx
@@ -1,4 +1,5 @@
/* Copyright 2020 Alex Tanskanen <aleta@cendio.se> for Cendio AB
+ * Copyright 2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,12 +21,15 @@
#include <config.h>
#endif
-#include <stdio.h>
-#include <vector>
#include <unistd.h>
-#include <rfb/Rect.h>
-#include <rfb/Configuration.h>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <core/Rect.h>
+#include <core/Configuration.h>
+
#include "EmulateMB.h"
// The button masks for the mouse buttons
@@ -37,19 +41,19 @@ static const int right = 0x04;
static const int both = 0x05;
static const int middleAndRight = 0x06;
-rfb::BoolParameter emulateMiddleButton("dummy_name", "dummy_desc", true);
+core::BoolParameter emulateMiddleButton("dummy_name", "dummy_desc", true);
class TestClass : public EmulateMB
{
public:
- void sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask) override;
+ void sendPointerEvent(const core::Point& pos, uint16_t buttonMask) override;
- struct PointerEventParams {rfb::Point pos; uint16_t mask; };
+ struct PointerEventParams {core::Point pos; uint16_t mask; };
std::vector<PointerEventParams> results;
};
-void TestClass::sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask)
+void TestClass::sendPointerEvent(const core::Point& pos, uint16_t buttonMask)
{
PointerEventParams params;
params.pos = pos;
@@ -57,435 +61,347 @@ void TestClass::sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask)
results.push_back(params);
}
-#define ASSERT_EQ(expr, val) if ((expr) != (val)) { \
- printf("FAILED on line %d (%s equals %d, expected %d)\n", __LINE__, #expr, (int)(expr), (int)(val)); \
- return; \
-}
-
-void testDisabledOption()
+TEST(EmulateMB, disabledOption)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(false);
- test.filterPointerEvent(rfb::Point(0, 10), left);
+ test.filterPointerEvent({0, 10}, left);
ASSERT_EQ(test.results.size(), 1);
- ASSERT_EQ(test.results[0].pos.x, 0);
- ASSERT_EQ(test.results[0].pos.y, 10);
- ASSERT_EQ(test.results[0].mask, left);
-
- printf("OK\n");
+ EXPECT_EQ(test.results[0].pos.x, 0);
+ EXPECT_EQ(test.results[0].pos.y, 10);
+ EXPECT_EQ(test.results[0].mask, left);
}
-void testLeftClick()
+TEST(EmulateMB, leftClick)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(0, 0), left);
- test.filterPointerEvent(rfb::Point(0, 0), empty);
+ test.filterPointerEvent({0, 0}, left);
+ test.filterPointerEvent({0, 0}, empty);
ASSERT_EQ(test.results.size(), 3);
- ASSERT_EQ(test.results[0].pos.x, 0);
- ASSERT_EQ(test.results[0].pos.y, 0);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 0);
- ASSERT_EQ(test.results[1].pos.y, 0);
- ASSERT_EQ(test.results[1].mask, left);
+ EXPECT_EQ(test.results[0].pos.x, 0);
+ EXPECT_EQ(test.results[0].pos.y, 0);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[2].pos.x, 0);
- ASSERT_EQ(test.results[2].pos.y, 0);
- ASSERT_EQ(test.results[2].mask, empty);
+ EXPECT_EQ(test.results[1].pos.x, 0);
+ EXPECT_EQ(test.results[1].pos.y, 0);
+ EXPECT_EQ(test.results[1].mask, left);
- printf("OK\n");
+ EXPECT_EQ(test.results[2].pos.x, 0);
+ EXPECT_EQ(test.results[2].pos.y, 0);
+ EXPECT_EQ(test.results[2].mask, empty);
}
-void testNormalLeftPress()
+TEST(EmulateMB, normalLeftPress)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(10, 20), left);
+ test.filterPointerEvent({10, 20}, left);
usleep(100000); // 0.1s
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.results.size(), 2);
- ASSERT_EQ(test.results[0].pos.x, 10);
- ASSERT_EQ(test.results[0].pos.y, 20);
- ASSERT_EQ(test.results[0].mask, empty);
+ EXPECT_EQ(test.results[0].pos.x, 10);
+ EXPECT_EQ(test.results[0].pos.y, 20);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[1].pos.x, 10);
- ASSERT_EQ(test.results[1].pos.y, 20);
- ASSERT_EQ(test.results[1].mask, left);
-
- printf("OK\n");
+ EXPECT_EQ(test.results[1].pos.x, 10);
+ EXPECT_EQ(test.results[1].pos.y, 20);
+ EXPECT_EQ(test.results[1].mask, left);
}
-void testNormalMiddlePress()
+TEST(EmulateMB, normalMiddlePress)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(0, 0), middle);
+ test.filterPointerEvent({0, 0}, middle);
ASSERT_EQ(test.results.size(), 1);
- ASSERT_EQ(test.results[0].pos.x, 0);
- ASSERT_EQ(test.results[0].pos.y, 0);
- ASSERT_EQ(test.results[0].mask, middle);
-
- printf("OK\n");
+ EXPECT_EQ(test.results[0].pos.x, 0);
+ EXPECT_EQ(test.results[0].pos.y, 0);
+ EXPECT_EQ(test.results[0].mask, middle);
}
-void testNormalRightPress()
+TEST(EmulateMB, normalRightPress)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(0, 0), right);
+ test.filterPointerEvent({0, 0}, right);
usleep(100000); // 0.1s
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.results.size(), 2);
- ASSERT_EQ(test.results[0].pos.x, 0);
- ASSERT_EQ(test.results[0].pos.y, 0);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 0);
- ASSERT_EQ(test.results[1].pos.y, 0);
- ASSERT_EQ(test.results[1].mask, right);
+ EXPECT_EQ(test.results[0].pos.x, 0);
+ EXPECT_EQ(test.results[0].pos.y, 0);
+ EXPECT_EQ(test.results[0].mask, empty);
- printf("OK\n");
+ EXPECT_EQ(test.results[1].pos.x, 0);
+ EXPECT_EQ(test.results[1].pos.y, 0);
+ EXPECT_EQ(test.results[1].mask, right);
}
-void testEmulateMiddleMouseButton()
+TEST(EmulateMB, emulateMiddleMouseButton)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(20, 30), right);
- test.filterPointerEvent(rfb::Point(20, 30), both);
+ test.filterPointerEvent({20, 30}, right);
+ test.filterPointerEvent({20, 30}, both);
ASSERT_EQ(test.results.size(), 2);
- ASSERT_EQ(test.results[0].pos.x, 20);
- ASSERT_EQ(test.results[0].pos.y, 30);
- ASSERT_EQ(test.results[0].mask, empty);
+ EXPECT_EQ(test.results[0].pos.x, 20);
+ EXPECT_EQ(test.results[0].pos.y, 30);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[1].pos.x, 20);
- ASSERT_EQ(test.results[1].pos.y, 30);
- ASSERT_EQ(test.results[1].mask, middle);
-
- printf("OK\n");
+ EXPECT_EQ(test.results[1].pos.x, 20);
+ EXPECT_EQ(test.results[1].pos.y, 30);
+ EXPECT_EQ(test.results[1].mask, middle);
}
-void testLeftReleaseAfterEmulate()
+TEST(EmulateMB, leftReleaseAfterEmulate)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(20, 30), left);
- test.filterPointerEvent(rfb::Point(20, 30), both);
- test.filterPointerEvent(rfb::Point(20, 30), right); // left released
+ test.filterPointerEvent({20, 30}, left);
+ test.filterPointerEvent({20, 30}, both);
+ test.filterPointerEvent({20, 30}, right); // left released
ASSERT_EQ(test.results.size(), 3);
- ASSERT_EQ(test.results[0].pos.x, 20);
- ASSERT_EQ(test.results[0].pos.y, 30);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 20);
- ASSERT_EQ(test.results[1].pos.y, 30);
- ASSERT_EQ(test.results[1].mask, middle);
+ EXPECT_EQ(test.results[0].pos.x, 20);
+ EXPECT_EQ(test.results[0].pos.y, 30);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[2].pos.x, 20);
- ASSERT_EQ(test.results[2].pos.y, 30);
- ASSERT_EQ(test.results[2].mask, middle);
+ EXPECT_EQ(test.results[1].pos.x, 20);
+ EXPECT_EQ(test.results[1].pos.y, 30);
+ EXPECT_EQ(test.results[1].mask, middle);
- printf("OK\n");
+ EXPECT_EQ(test.results[2].pos.x, 20);
+ EXPECT_EQ(test.results[2].pos.y, 30);
+ EXPECT_EQ(test.results[2].mask, middle);
}
-void testRightReleaseAfterEmulate()
+TEST(EmulateMB, rightReleaseAfterEmulate)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(20, 30), right);
- test.filterPointerEvent(rfb::Point(20, 30), both);
- test.filterPointerEvent(rfb::Point(20, 30), left); // right released
+ test.filterPointerEvent({20, 30}, right);
+ test.filterPointerEvent({20, 30}, both);
+ test.filterPointerEvent({20, 30}, left); // right released
ASSERT_EQ(test.results.size(), 3);
- ASSERT_EQ(test.results[0].pos.x, 20);
- ASSERT_EQ(test.results[0].pos.y, 30);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 20);
- ASSERT_EQ(test.results[1].pos.y, 30);
- ASSERT_EQ(test.results[1].mask, middle);
+ EXPECT_EQ(test.results[0].pos.x, 20);
+ EXPECT_EQ(test.results[0].pos.y, 30);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[2].pos.x, 20);
- ASSERT_EQ(test.results[2].pos.y, 30);
- ASSERT_EQ(test.results[2].mask, middle);
+ EXPECT_EQ(test.results[1].pos.x, 20);
+ EXPECT_EQ(test.results[1].pos.y, 30);
+ EXPECT_EQ(test.results[1].mask, middle);
- printf("OK\n");
+ EXPECT_EQ(test.results[2].pos.x, 20);
+ EXPECT_EQ(test.results[2].pos.y, 30);
+ EXPECT_EQ(test.results[2].mask, middle);
}
-void testLeftRepressAfterEmulate()
+TEST(EmulateMB, leftRepressAfterEmulate)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(20, 30), left);
- test.filterPointerEvent(rfb::Point(20, 30), both);
- test.filterPointerEvent(rfb::Point(20, 30), right); // left released
- test.filterPointerEvent(rfb::Point(20, 30), both);
+ test.filterPointerEvent({20, 30}, left);
+ test.filterPointerEvent({20, 30}, both);
+ test.filterPointerEvent({20, 30}, right); // left released
+ test.filterPointerEvent({20, 30}, both);
ASSERT_EQ(test.results.size(), 4);
- ASSERT_EQ(test.results[0].pos.x, 20);
- ASSERT_EQ(test.results[0].pos.y, 30);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 20);
- ASSERT_EQ(test.results[1].pos.y, 30);
- ASSERT_EQ(test.results[1].mask, middle);
+ EXPECT_EQ(test.results[0].pos.x, 20);
+ EXPECT_EQ(test.results[0].pos.y, 30);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[2].pos.x, 20);
- ASSERT_EQ(test.results[2].pos.y, 30);
- ASSERT_EQ(test.results[2].mask, middle);
+ EXPECT_EQ(test.results[1].pos.x, 20);
+ EXPECT_EQ(test.results[1].pos.y, 30);
+ EXPECT_EQ(test.results[1].mask, middle);
- ASSERT_EQ(test.results[3].pos.x, 20);
- ASSERT_EQ(test.results[3].pos.y, 30);
- ASSERT_EQ(test.results[3].mask, middleAndLeft);
+ EXPECT_EQ(test.results[2].pos.x, 20);
+ EXPECT_EQ(test.results[2].pos.y, 30);
+ EXPECT_EQ(test.results[2].mask, middle);
- printf("OK\n");
+ EXPECT_EQ(test.results[3].pos.x, 20);
+ EXPECT_EQ(test.results[3].pos.y, 30);
+ EXPECT_EQ(test.results[3].mask, middleAndLeft);
}
-void testRightRepressAfterEmulate()
+TEST(EmulateMB, rightRepressAfterEmulate)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(20, 30), right);
- test.filterPointerEvent(rfb::Point(20, 30), both);
- test.filterPointerEvent(rfb::Point(20, 30), left); // right released
- test.filterPointerEvent(rfb::Point(20, 30), both);
+ test.filterPointerEvent({20, 30}, right);
+ test.filterPointerEvent({20, 30}, both);
+ test.filterPointerEvent({20, 30}, left); // right released
+ test.filterPointerEvent({20, 30}, both);
ASSERT_EQ(test.results.size(), 4);
- ASSERT_EQ(test.results[0].pos.x, 20);
- ASSERT_EQ(test.results[0].pos.y, 30);
- ASSERT_EQ(test.results[0].mask, empty);
+ EXPECT_EQ(test.results[0].pos.x, 20);
+ EXPECT_EQ(test.results[0].pos.y, 30);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[1].pos.x, 20);
- ASSERT_EQ(test.results[1].pos.y, 30);
- ASSERT_EQ(test.results[1].mask, middle);
+ EXPECT_EQ(test.results[1].pos.x, 20);
+ EXPECT_EQ(test.results[1].pos.y, 30);
+ EXPECT_EQ(test.results[1].mask, middle);
- ASSERT_EQ(test.results[2].pos.x, 20);
- ASSERT_EQ(test.results[2].pos.y, 30);
- ASSERT_EQ(test.results[2].mask, middle);
+ EXPECT_EQ(test.results[2].pos.x, 20);
+ EXPECT_EQ(test.results[2].pos.y, 30);
+ EXPECT_EQ(test.results[2].mask, middle);
- ASSERT_EQ(test.results[3].pos.x, 20);
- ASSERT_EQ(test.results[3].pos.y, 30);
- ASSERT_EQ(test.results[3].mask, middleAndRight);
-
- printf("OK\n");
+ EXPECT_EQ(test.results[3].pos.x, 20);
+ EXPECT_EQ(test.results[3].pos.y, 30);
+ EXPECT_EQ(test.results[3].mask, middleAndRight);
}
-void testBothPressAfterLeftTimeout()
+TEST(EmulateMB, bothPressAfterLeftTimeout)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(10, 20), left);
+ test.filterPointerEvent({10, 20}, left);
usleep(100000); // 0.1s
- rfb::Timer::checkTimeouts();
- test.filterPointerEvent(rfb::Point(10, 20), both);
+ core::Timer::checkTimeouts();
+ test.filterPointerEvent({10, 20}, both);
ASSERT_EQ(test.results.size(), 3);
- ASSERT_EQ(test.results[0].pos.x, 10);
- ASSERT_EQ(test.results[0].pos.y, 20);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 10);
- ASSERT_EQ(test.results[1].pos.y, 20);
- ASSERT_EQ(test.results[1].mask, left);
+ EXPECT_EQ(test.results[0].pos.x, 10);
+ EXPECT_EQ(test.results[0].pos.y, 20);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[2].pos.x, 10);
- ASSERT_EQ(test.results[2].pos.y, 20);
- ASSERT_EQ(test.results[2].mask, both);
+ EXPECT_EQ(test.results[1].pos.x, 10);
+ EXPECT_EQ(test.results[1].pos.y, 20);
+ EXPECT_EQ(test.results[1].mask, left);
- printf("OK\n");
+ EXPECT_EQ(test.results[2].pos.x, 10);
+ EXPECT_EQ(test.results[2].pos.y, 20);
+ EXPECT_EQ(test.results[2].mask, both);
}
-void testBothPressAfterRightTimeout()
+TEST(EmulateMB, bothPressAfterRightTimeout)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(10, 20), right);
+ test.filterPointerEvent({10, 20}, right);
usleep(100000); // 0.1s
- rfb::Timer::checkTimeouts();
- test.filterPointerEvent(rfb::Point(10, 20), both);
+ core::Timer::checkTimeouts();
+ test.filterPointerEvent({10, 20}, both);
ASSERT_EQ(test.results.size(), 3);
- ASSERT_EQ(test.results[0].pos.x, 10);
- ASSERT_EQ(test.results[0].pos.y, 20);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 10);
- ASSERT_EQ(test.results[1].pos.y, 20);
- ASSERT_EQ(test.results[1].mask, right);
+ EXPECT_EQ(test.results[0].pos.x, 10);
+ EXPECT_EQ(test.results[0].pos.y, 20);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[2].pos.x, 10);
- ASSERT_EQ(test.results[2].pos.y, 20);
- ASSERT_EQ(test.results[2].mask, both);
+ EXPECT_EQ(test.results[1].pos.x, 10);
+ EXPECT_EQ(test.results[1].pos.y, 20);
+ EXPECT_EQ(test.results[1].mask, right);
- printf("OK\n");
+ EXPECT_EQ(test.results[2].pos.x, 10);
+ EXPECT_EQ(test.results[2].pos.y, 20);
+ EXPECT_EQ(test.results[2].mask, both);
}
-void testTimeoutAndDrag()
+TEST(EmulateMB, timeoutAndDrag)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(0, 0), left);
+ test.filterPointerEvent({0, 0}, left);
usleep(100000); //0.1s
- rfb::Timer::checkTimeouts();
- test.filterPointerEvent(rfb::Point(10, 10), left);
+ core::Timer::checkTimeouts();
+ test.filterPointerEvent({10, 10}, left);
ASSERT_EQ(test.results.size(), 3);
- ASSERT_EQ(test.results[0].pos.x, 0);
- ASSERT_EQ(test.results[0].pos.y, 0);
- ASSERT_EQ(test.results[0].mask, empty);
+ EXPECT_EQ(test.results[0].pos.x, 0);
+ EXPECT_EQ(test.results[0].pos.y, 0);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[1].pos.x, 0);
- ASSERT_EQ(test.results[1].pos.y, 0);
- ASSERT_EQ(test.results[1].mask, left);
+ EXPECT_EQ(test.results[1].pos.x, 0);
+ EXPECT_EQ(test.results[1].pos.y, 0);
+ EXPECT_EQ(test.results[1].mask, left);
- ASSERT_EQ(test.results[2].pos.x, 10);
- ASSERT_EQ(test.results[2].pos.y, 10);
- ASSERT_EQ(test.results[2].mask, left);
-
- printf("OK\n");
+ EXPECT_EQ(test.results[2].pos.x, 10);
+ EXPECT_EQ(test.results[2].pos.y, 10);
+ EXPECT_EQ(test.results[2].mask, left);
}
-void testDragAndTimeout()
+TEST(EmulateMB, dragAndTimeout)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(10, 10), left);
- test.filterPointerEvent(rfb::Point(30, 30), left);
+ test.filterPointerEvent({10, 10}, left);
+ test.filterPointerEvent({30, 30}, left);
usleep(100000); //0.1s
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.results.size(), 3);
- ASSERT_EQ(test.results[0].pos.x, 10);
- ASSERT_EQ(test.results[0].pos.y, 10);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 10);
- ASSERT_EQ(test.results[1].pos.y, 10);
- ASSERT_EQ(test.results[1].mask, left);
+ EXPECT_EQ(test.results[0].pos.x, 10);
+ EXPECT_EQ(test.results[0].pos.y, 10);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[2].pos.x, 30);
- ASSERT_EQ(test.results[2].pos.y, 30);
- ASSERT_EQ(test.results[2].mask, left);
+ EXPECT_EQ(test.results[1].pos.x, 10);
+ EXPECT_EQ(test.results[1].pos.y, 10);
+ EXPECT_EQ(test.results[1].mask, left);
- printf("OK\n");
+ EXPECT_EQ(test.results[2].pos.x, 30);
+ EXPECT_EQ(test.results[2].pos.y, 30);
+ EXPECT_EQ(test.results[2].mask, left);
}
-void testDragAndRelease()
+TEST(EmulateMB, dragAndRelease)
{
TestClass test;
- printf("%s: ", __func__);
-
emulateMiddleButton.setParam(true);
- test.filterPointerEvent(rfb::Point(10, 10), left);
- test.filterPointerEvent(rfb::Point(20, 20), empty);
+ test.filterPointerEvent({10, 10}, left);
+ test.filterPointerEvent({20, 20}, empty);
ASSERT_EQ(test.results.size(), 3);
- ASSERT_EQ(test.results[0].pos.x, 10);
- ASSERT_EQ(test.results[0].pos.y, 10);
- ASSERT_EQ(test.results[0].mask, empty);
-
- ASSERT_EQ(test.results[1].pos.x, 10);
- ASSERT_EQ(test.results[1].pos.y, 10);
- ASSERT_EQ(test.results[1].mask, left);
+ EXPECT_EQ(test.results[0].pos.x, 10);
+ EXPECT_EQ(test.results[0].pos.y, 10);
+ EXPECT_EQ(test.results[0].mask, empty);
- ASSERT_EQ(test.results[2].pos.x, 20);
- ASSERT_EQ(test.results[2].pos.y, 20);
- ASSERT_EQ(test.results[2].mask, empty);
+ EXPECT_EQ(test.results[1].pos.x, 10);
+ EXPECT_EQ(test.results[1].pos.y, 10);
+ EXPECT_EQ(test.results[1].mask, left);
- printf("OK\n");
+ EXPECT_EQ(test.results[2].pos.x, 20);
+ EXPECT_EQ(test.results[2].pos.y, 20);
+ EXPECT_EQ(test.results[2].mask, empty);
}
-int main(int /*argc*/, char** /*argv*/)
+int main(int argc, char** argv)
{
- testDisabledOption();
-
- testLeftClick();
-
- testNormalLeftPress();
- testNormalMiddlePress();
- testNormalRightPress();
-
- testEmulateMiddleMouseButton();
-
- testLeftReleaseAfterEmulate();
- testRightReleaseAfterEmulate();
-
- testLeftRepressAfterEmulate();
- testRightRepressAfterEmulate();
-
- testBothPressAfterLeftTimeout();
- testBothPressAfterRightTimeout();
-
- testTimeoutAndDrag();
-
- testDragAndTimeout();
- testDragAndRelease();
-
- return 0;
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tests/unit/gesturehandler.cxx b/tests/unit/gesturehandler.cxx
index 73b8c62c..cf2e5b6b 100644
--- a/tests/unit/gesturehandler.cxx
+++ b/tests/unit/gesturehandler.cxx
@@ -1,4 +1,4 @@
-/* Copyright 2020 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2020-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,11 +20,12 @@
#include <config.h>
#endif
-#include <stdio.h>
#include <unistd.h>
#include <vector>
+#include <gtest/gtest.h>
+
#include "../../vncviewer/GestureHandler.h"
class TestClass : public GestureHandler
@@ -41,18 +42,10 @@ void TestClass::handleGestureEvent(const GestureEvent& event)
events.push_back(event);
}
-// FIXME: handle doubles
-#define ASSERT_EQ(expr, val) if ((expr) != (val)) { \
- printf("FAILED on line %d (%s equals %d, expected %d)\n", __LINE__, #expr, (int)(expr), (int)(val)); \
- return; \
-}
-
-void testOneTapNormal()
+TEST(GestureHandler, oneTapNormal)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
ASSERT_EQ(test.events.size(), 0);
@@ -61,25 +54,21 @@ void testOneTapNormal()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureOneTap);
- ASSERT_EQ(test.events[0].eventX, 20.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
-
- ASSERT_EQ(test.events[1].type, GestureEnd);
- ASSERT_EQ(test.events[1].gesture, GestureOneTap);
- ASSERT_EQ(test.events[1].eventX, 20.0);
- ASSERT_EQ(test.events[1].eventY, 30.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureOneTap);
+ EXPECT_EQ(test.events[0].eventX, 20.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
- printf("OK\n");
+ EXPECT_EQ(test.events[1].type, GestureEnd);
+ EXPECT_EQ(test.events[1].gesture, GestureOneTap);
+ EXPECT_EQ(test.events[1].eventX, 20.0);
+ EXPECT_EQ(test.events[1].eventY, 30.0);
}
-void testTwoTapNormal()
+TEST(GestureHandler, twoTapNormal)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 50.0);
@@ -93,85 +82,69 @@ void testTwoTapNormal()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureTwoTap);
- ASSERT_EQ(test.events[0].eventX, 25.0);
- ASSERT_EQ(test.events[0].eventY, 40.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoTap);
+ EXPECT_EQ(test.events[0].eventX, 25.0);
+ EXPECT_EQ(test.events[0].eventY, 40.0);
- ASSERT_EQ(test.events[1].type, GestureEnd);
- ASSERT_EQ(test.events[1].gesture, GestureTwoTap);
- ASSERT_EQ(test.events[1].eventX, 25.0);
- ASSERT_EQ(test.events[1].eventY, 40.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[1].type, GestureEnd);
+ EXPECT_EQ(test.events[1].gesture, GestureTwoTap);
+ EXPECT_EQ(test.events[1].eventX, 25.0);
+ EXPECT_EQ(test.events[1].eventY, 40.0);
}
-void testTwoTapSlowBegin()
+TEST(GestureHandler, twoTapSlowBegin)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
usleep(500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
test.handleTouchBegin(2, 30.0, 50.0);
test.handleTouchEnd(1);
test.handleTouchEnd(2);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testTwoTapSlowEnd()
+TEST(GestureHandler, twoTapSlowEnd)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 50.0);
test.handleTouchEnd(1);
usleep(500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
test.handleTouchEnd(2);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testTwoTapTimeout()
+TEST(GestureHandler, twoTapTimeout)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 50.0);
usleep(1500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
test.handleTouchEnd(1);
test.handleTouchEnd(2);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testThreeTapNormal()
+TEST(GestureHandler, threeTapNormal)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 50.0);
test.handleTouchBegin(3, 40.0, 40.0);
@@ -190,30 +163,26 @@ void testThreeTapNormal()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureThreeTap);
- ASSERT_EQ(test.events[0].eventX, 30.0);
- ASSERT_EQ(test.events[0].eventY, 40.0);
-
- ASSERT_EQ(test.events[1].type, GestureEnd);
- ASSERT_EQ(test.events[1].gesture, GestureThreeTap);
- ASSERT_EQ(test.events[1].eventX, 30.0);
- ASSERT_EQ(test.events[1].eventY, 40.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureThreeTap);
+ EXPECT_EQ(test.events[0].eventX, 30.0);
+ EXPECT_EQ(test.events[0].eventY, 40.0);
- printf("OK\n");
+ EXPECT_EQ(test.events[1].type, GestureEnd);
+ EXPECT_EQ(test.events[1].gesture, GestureThreeTap);
+ EXPECT_EQ(test.events[1].eventX, 30.0);
+ EXPECT_EQ(test.events[1].eventY, 40.0);
}
-void testThreeTapSlowBegin()
+TEST(GestureHandler, threeTapSlowBegin)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 50.0);
usleep(500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
test.handleTouchBegin(3, 40.0, 40.0);
test.handleTouchEnd(1);
@@ -221,16 +190,12 @@ void testThreeTapSlowBegin()
test.handleTouchEnd(3);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testThreeTapSlowEnd()
+TEST(GestureHandler, threeTapSlowEnd)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 50.0);
test.handleTouchBegin(3, 40.0, 40.0);
@@ -238,21 +203,17 @@ void testThreeTapSlowEnd()
test.handleTouchEnd(2);
usleep(500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
test.handleTouchEnd(3);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testThreeTapDrag()
+TEST(GestureHandler, threeTapDrag)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 50.0);
test.handleTouchBegin(3, 40.0, 40.0);
@@ -266,38 +227,30 @@ void testThreeTapDrag()
test.handleTouchEnd(3);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testThreeTapTimeout()
+TEST(GestureHandler, threeTapTimeout)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 50.0);
test.handleTouchBegin(3, 40.0, 40.0);
usleep(1500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
test.handleTouchEnd(1);
test.handleTouchEnd(2);
test.handleTouchEnd(3);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testDragHoriz()
+TEST(GestureHandler, dragHoriz)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
ASSERT_EQ(test.events.size(), 0);
@@ -310,15 +263,15 @@ void testDragHoriz()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 20.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 20.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureDrag);
- ASSERT_EQ(test.events[1].eventX, 80.0);
- ASSERT_EQ(test.events[1].eventY, 30.0);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureDrag);
+ EXPECT_EQ(test.events[1].eventX, 80.0);
+ EXPECT_EQ(test.events[1].eventY, 30.0);
test.events.clear();
@@ -326,20 +279,16 @@ void testDragHoriz()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 80.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 80.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
}
-void testDragVert()
+TEST(GestureHandler, dragVert)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
ASSERT_EQ(test.events.size(), 0);
@@ -352,15 +301,15 @@ void testDragVert()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 20.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 20.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureDrag);
- ASSERT_EQ(test.events[1].eventX, 20.0);
- ASSERT_EQ(test.events[1].eventY, 90.0);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureDrag);
+ EXPECT_EQ(test.events[1].eventX, 20.0);
+ EXPECT_EQ(test.events[1].eventY, 90.0);
test.events.clear();
@@ -368,20 +317,16 @@ void testDragVert()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 20.0);
- ASSERT_EQ(test.events[0].eventY, 90.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 20.0);
+ EXPECT_EQ(test.events[0].eventY, 90.0);
}
-void testDragDiag()
+TEST(GestureHandler, dragDiag)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 120.0, 130.0);
ASSERT_EQ(test.events.size(), 0);
@@ -394,15 +339,15 @@ void testDragDiag()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 120.0);
- ASSERT_EQ(test.events[0].eventY, 130.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 120.0);
+ EXPECT_EQ(test.events[0].eventY, 130.0);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureDrag);
- ASSERT_EQ(test.events[1].eventX, 60.0);
- ASSERT_EQ(test.events[1].eventY, 70.0);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureDrag);
+ EXPECT_EQ(test.events[1].eventX, 60.0);
+ EXPECT_EQ(test.events[1].eventY, 70.0);
test.events.clear();
@@ -410,33 +355,29 @@ void testDragDiag()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 60.0);
- ASSERT_EQ(test.events[0].eventY, 70.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 60.0);
+ EXPECT_EQ(test.events[0].eventY, 70.0);
}
-void testLongPressNormal()
+TEST(GestureHandler, longPressNormal)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
ASSERT_EQ(test.events.size(), 0);
usleep(1500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureLongPress);
- ASSERT_EQ(test.events[0].eventX, 20.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureLongPress);
+ EXPECT_EQ(test.events[0].eventX, 20.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
test.events.clear();
@@ -444,33 +385,29 @@ void testLongPressNormal()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureLongPress);
- ASSERT_EQ(test.events[0].eventX, 20.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureLongPress);
+ EXPECT_EQ(test.events[0].eventX, 20.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
}
-void testLongPressDrag()
+TEST(GestureHandler, longPressDrag)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
ASSERT_EQ(test.events.size(), 0);
usleep(1500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureLongPress);
- ASSERT_EQ(test.events[0].eventX, 20.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureLongPress);
+ EXPECT_EQ(test.events[0].eventX, 20.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
test.events.clear();
@@ -478,10 +415,10 @@ void testLongPressDrag()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureUpdate);
- ASSERT_EQ(test.events[0].gesture, GestureLongPress);
- ASSERT_EQ(test.events[0].eventX, 120.0);
- ASSERT_EQ(test.events[0].eventY, 50.0);
+ EXPECT_EQ(test.events[0].type, GestureUpdate);
+ EXPECT_EQ(test.events[0].gesture, GestureLongPress);
+ EXPECT_EQ(test.events[0].eventX, 120.0);
+ EXPECT_EQ(test.events[0].eventY, 50.0);
test.events.clear();
@@ -489,20 +426,16 @@ void testLongPressDrag()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureLongPress);
- ASSERT_EQ(test.events[0].eventX, 120.0);
- ASSERT_EQ(test.events[0].eventY, 50.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureLongPress);
+ EXPECT_EQ(test.events[0].eventX, 120.0);
+ EXPECT_EQ(test.events[0].eventY, 50.0);
}
-void testTwoDragFastDistinctHoriz()
+TEST(GestureHandler, twoDragFastDistinctHoriz)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 30.0);
@@ -521,19 +454,19 @@ void testTwoDragFastDistinctHoriz()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 25.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
- ASSERT_EQ(test.events[0].magnitudeX, 0.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 25.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[1].eventX, 25.0);
- ASSERT_EQ(test.events[1].eventY, 30.0);
- ASSERT_EQ(test.events[1].magnitudeX, 60.0);
- ASSERT_EQ(test.events[1].magnitudeY, 0.0);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[1].eventX, 25.0);
+ EXPECT_EQ(test.events[1].eventY, 30.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 60.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 0.0);
test.events.clear();
@@ -541,22 +474,18 @@ void testTwoDragFastDistinctHoriz()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 25.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
- ASSERT_EQ(test.events[0].magnitudeX, 60.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 25.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 60.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
}
-void testTwoDragFastDistinctVert()
+TEST(GestureHandler, twoDragFastDistinctVert)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 30.0);
@@ -574,19 +503,19 @@ void testTwoDragFastDistinctVert()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 25.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
- ASSERT_EQ(test.events[0].magnitudeX, 0.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 25.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[1].eventX, 25.0);
- ASSERT_EQ(test.events[1].eventY, 30.0);
- ASSERT_EQ(test.events[1].magnitudeX, 0.0);
- ASSERT_EQ(test.events[1].magnitudeY, 65.0);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[1].eventX, 25.0);
+ EXPECT_EQ(test.events[1].eventY, 30.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 65.0);
test.events.clear();
@@ -594,22 +523,18 @@ void testTwoDragFastDistinctVert()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 25.0);
- ASSERT_EQ(test.events[0].eventY, 30.0);
- ASSERT_EQ(test.events[0].magnitudeX, 0.0);
- ASSERT_EQ(test.events[0].magnitudeY, 65.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 25.0);
+ EXPECT_EQ(test.events[0].eventY, 30.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 65.0);
}
-void testTwoDragFastDistinctDiag()
+TEST(GestureHandler, twoDragFastDistinctDiag)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 120.0, 130.0);
test.handleTouchBegin(2, 130.0, 130.0);
@@ -627,19 +552,19 @@ void testTwoDragFastDistinctDiag()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 125.0);
- ASSERT_EQ(test.events[0].eventY, 130.0);
- ASSERT_EQ(test.events[0].magnitudeX, 0.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 125.0);
+ EXPECT_EQ(test.events[0].eventY, 130.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[1].eventX, 125.0);
- ASSERT_EQ(test.events[1].eventY, 130.0);
- ASSERT_EQ(test.events[1].magnitudeX, -55.0);
- ASSERT_EQ(test.events[1].magnitudeY, -50.0);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[1].eventX, 125.0);
+ EXPECT_EQ(test.events[1].eventY, 130.0);
+ EXPECT_EQ(test.events[1].magnitudeX, -55.0);
+ EXPECT_EQ(test.events[1].magnitudeY, -50.0);
test.events.clear();
@@ -647,22 +572,18 @@ void testTwoDragFastDistinctDiag()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 125.0);
- ASSERT_EQ(test.events[0].eventY, 130.0);
- ASSERT_EQ(test.events[0].magnitudeX, -55.0);
- ASSERT_EQ(test.events[0].magnitudeY, -50.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 125.0);
+ EXPECT_EQ(test.events[0].eventY, 130.0);
+ EXPECT_EQ(test.events[0].magnitudeX, -55.0);
+ EXPECT_EQ(test.events[0].magnitudeY, -50.0);
}
-void testTwoDragFastAlmost()
+TEST(GestureHandler, twoDragFastAlmost)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 30.0);
test.handleTouchUpdate(1, 80.0, 30.0);
@@ -673,19 +594,15 @@ void testTwoDragFastAlmost()
ASSERT_EQ(test.events.size(), 0);
usleep(500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testTwoDragSlowHoriz()
+TEST(GestureHandler, twoDragSlowHoriz)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 50.0, 40.0);
test.handleTouchBegin(2, 60.0, 40.0);
test.handleTouchUpdate(2, 80.0, 40.0);
@@ -694,32 +611,29 @@ void testTwoDragSlowHoriz()
ASSERT_EQ(test.events.size(), 0);
usleep(60000); // 60ms
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 55.0);
- ASSERT_EQ(test.events[0].eventY, 40.0);
- ASSERT_EQ(test.events[0].magnitudeX, 0.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
-
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[1].eventX, 55.0);
- ASSERT_EQ(test.events[1].eventY, 40.0);
- ASSERT_EQ(test.events[1].magnitudeX, 40.0);
- ASSERT_EQ(test.events[1].magnitudeY, 0.0);
-
- printf("OK\n");
+
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 55.0);
+ EXPECT_EQ(test.events[0].eventY, 40.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
+
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[1].eventX, 55.0);
+ EXPECT_EQ(test.events[1].eventY, 40.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 40.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 0.0);
}
-void testTwoDragSlowVert()
+TEST(GestureHandler, twoDragSlowVert)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 40.0, 40.0);
test.handleTouchBegin(2, 40.0, 60.0);
test.handleTouchUpdate(2, 40.0, 80.0);
@@ -728,32 +642,29 @@ void testTwoDragSlowVert()
ASSERT_EQ(test.events.size(), 0);
usleep(60000); // 60ms
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 40.0);
- ASSERT_EQ(test.events[0].eventY, 50.0);
- ASSERT_EQ(test.events[0].magnitudeX, 0.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
-
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[1].eventX, 40.0);
- ASSERT_EQ(test.events[1].eventY, 50.0);
- ASSERT_EQ(test.events[1].magnitudeX, 0.0);
- ASSERT_EQ(test.events[1].magnitudeY, 40.0);
-
- printf("OK\n");
+
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 40.0);
+ EXPECT_EQ(test.events[0].eventY, 50.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
+
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[1].eventX, 40.0);
+ EXPECT_EQ(test.events[1].eventY, 50.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 40.0);
}
-void testTwoDragSlowDiag()
+TEST(GestureHandler, twoDragSlowDiag)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 50.0, 40.0);
test.handleTouchBegin(2, 40.0, 60.0);
test.handleTouchUpdate(1, 70.0, 60.0);
@@ -762,52 +673,45 @@ void testTwoDragSlowDiag()
ASSERT_EQ(test.events.size(), 0);
usleep(60000); // 60ms
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[0].eventX, 45.0);
- ASSERT_EQ(test.events[0].eventY, 50.0);
- ASSERT_EQ(test.events[0].magnitudeX, 0.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
-
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[1].eventX, 45.0);
- ASSERT_EQ(test.events[1].eventY, 50.0);
- ASSERT_EQ(test.events[1].magnitudeX, 35.0);
- ASSERT_EQ(test.events[1].magnitudeY, 35.0);
-
- printf("OK\n");
+
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].eventX, 45.0);
+ EXPECT_EQ(test.events[0].eventY, 50.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 0.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
+
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[1].eventX, 45.0);
+ EXPECT_EQ(test.events[1].eventY, 50.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 35.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 35.0);
}
-void testTwoDragTooSlow()
+TEST(GestureHandler, twoDragTooSlow)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
usleep(500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
test.handleTouchBegin(2, 30.0, 30.0);
test.handleTouchUpdate(2, 50.0, 30.0);
test.handleTouchUpdate(1, 80.0, 30.0);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testPinchFastDistinctIn()
+TEST(GestureHandler, pinchFastDistinctIn)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 0.0, 0.0);
test.handleTouchBegin(2, 130.0, 130.0);
@@ -822,19 +726,19 @@ void testPinchFastDistinctIn()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GesturePinch);
- ASSERT_EQ(test.events[0].eventX, 65.0);
- ASSERT_EQ(test.events[0].eventY, 65.0);
- ASSERT_EQ(test.events[0].magnitudeX, 130.0);
- ASSERT_EQ(test.events[0].magnitudeY, 130.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GesturePinch);
+ EXPECT_EQ(test.events[0].eventX, 65.0);
+ EXPECT_EQ(test.events[0].eventY, 65.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 130.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 130.0);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GesturePinch);
- ASSERT_EQ(test.events[1].eventX, 65.0);
- ASSERT_EQ(test.events[1].eventY, 65.0);
- ASSERT_EQ(test.events[1].magnitudeX, 10.0);
- ASSERT_EQ(test.events[1].magnitudeY, 30.0);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GesturePinch);
+ EXPECT_EQ(test.events[1].eventX, 65.0);
+ EXPECT_EQ(test.events[1].eventY, 65.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 10.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 30.0);
test.events.clear();
@@ -842,22 +746,18 @@ void testPinchFastDistinctIn()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GesturePinch);
- ASSERT_EQ(test.events[0].eventX, 65.0);
- ASSERT_EQ(test.events[0].eventY, 65.0);
- ASSERT_EQ(test.events[0].magnitudeX, 10.0);
- ASSERT_EQ(test.events[0].magnitudeY, 30.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GesturePinch);
+ EXPECT_EQ(test.events[0].eventX, 65.0);
+ EXPECT_EQ(test.events[0].eventY, 65.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 10.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 30.0);
}
-void testPinchFastDistinctOut()
+TEST(GestureHandler, pinchFastDistinctOut)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 100.0, 100.0);
test.handleTouchBegin(2, 110.0, 100.0);
@@ -872,19 +772,19 @@ void testPinchFastDistinctOut()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GesturePinch);
- ASSERT_EQ(test.events[0].eventX, 105.0);
- ASSERT_EQ(test.events[0].eventY, 100.0);
- ASSERT_EQ(test.events[0].magnitudeX, 10.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GesturePinch);
+ EXPECT_EQ(test.events[0].eventX, 105.0);
+ EXPECT_EQ(test.events[0].eventY, 100.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 10.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GesturePinch);
- ASSERT_EQ(test.events[1].eventX, 105.0);
- ASSERT_EQ(test.events[1].eventY, 100.0);
- ASSERT_EQ(test.events[1].magnitudeX, 180.0);
- ASSERT_EQ(test.events[1].magnitudeY, 180.0);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GesturePinch);
+ EXPECT_EQ(test.events[1].eventX, 105.0);
+ EXPECT_EQ(test.events[1].eventY, 100.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 180.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 180.0);
test.events.clear();
@@ -892,22 +792,18 @@ void testPinchFastDistinctOut()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GesturePinch);
- ASSERT_EQ(test.events[0].eventX, 105.0);
- ASSERT_EQ(test.events[0].eventY, 100.0);
- ASSERT_EQ(test.events[0].magnitudeX, 180.0);
- ASSERT_EQ(test.events[0].magnitudeY, 180.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GesturePinch);
+ EXPECT_EQ(test.events[0].eventX, 105.0);
+ EXPECT_EQ(test.events[0].eventY, 100.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 180.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 180.0);
}
-void testPinchFastAlmost()
+TEST(GestureHandler, pinchFastAlmost)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 130.0, 130.0);
test.handleTouchUpdate(1, 80.0, 70.0);
@@ -917,19 +813,15 @@ void testPinchFastAlmost()
ASSERT_EQ(test.events.size(), 0);
usleep(500000);
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testPinchSlowIn()
+TEST(GestureHandler, pinchSlowIn)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 0.0, 0.0);
test.handleTouchBegin(2, 130.0, 130.0);
@@ -941,33 +833,29 @@ void testPinchSlowIn()
ASSERT_EQ(test.events.size(), 0);
usleep(60000); // 60ms
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GesturePinch);
- ASSERT_EQ(test.events[0].eventX, 65.0);
- ASSERT_EQ(test.events[0].eventY, 65.0);
- ASSERT_EQ(test.events[0].magnitudeX, 130.0);
- ASSERT_EQ(test.events[0].magnitudeY, 130.0);
-
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GesturePinch);
- ASSERT_EQ(test.events[1].eventX, 65.0);
- ASSERT_EQ(test.events[1].eventY, 65.0);
- ASSERT_EQ(test.events[1].magnitudeX, 50.0);
- ASSERT_EQ(test.events[1].magnitudeY, 90.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GesturePinch);
+ EXPECT_EQ(test.events[0].eventX, 65.0);
+ EXPECT_EQ(test.events[0].eventY, 65.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 130.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 130.0);
+
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GesturePinch);
+ EXPECT_EQ(test.events[1].eventX, 65.0);
+ EXPECT_EQ(test.events[1].eventY, 65.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 50.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 90.0);
}
-void testPinchSlowOut()
+TEST(GestureHandler, pinchSlowOut)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 100.0, 130.0);
test.handleTouchBegin(2, 110.0, 130.0);
@@ -978,64 +866,56 @@ void testPinchSlowOut()
ASSERT_EQ(test.events.size(), 0);
usleep(60000); // 60ms
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GesturePinch);
- ASSERT_EQ(test.events[0].eventX, 105.0);
- ASSERT_EQ(test.events[0].eventY, 130.0);
- ASSERT_EQ(test.events[0].magnitudeX, 10.0);
- ASSERT_EQ(test.events[0].magnitudeY, 0.0);
-
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GesturePinch);
- ASSERT_EQ(test.events[1].eventX, 105.0);
- ASSERT_EQ(test.events[1].eventY, 130.0);
- ASSERT_EQ(test.events[1].magnitudeX, 100.0);
- ASSERT_EQ(test.events[1].magnitudeY, 0.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GesturePinch);
+ EXPECT_EQ(test.events[0].eventX, 105.0);
+ EXPECT_EQ(test.events[0].eventY, 130.0);
+ EXPECT_EQ(test.events[0].magnitudeX, 10.0);
+ EXPECT_EQ(test.events[0].magnitudeY, 0.0);
+
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GesturePinch);
+ EXPECT_EQ(test.events[1].eventX, 105.0);
+ EXPECT_EQ(test.events[1].eventY, 130.0);
+ EXPECT_EQ(test.events[1].magnitudeX, 100.0);
+ EXPECT_EQ(test.events[1].magnitudeY, 0.0);
}
-void testPinchTooSlow()
+TEST(GestureHandler, pinchTooSlow)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 0.0, 0.0);
usleep(60000); // 60ms
- rfb::Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
test.handleTouchBegin(2, 130.0, 130.0);
test.handleTouchUpdate(2, 100.0, 130.0);
test.handleTouchUpdate(1, 50.0, 40.0);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testExtraIgnore()
+TEST(GestureHandler, extraIgnore)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchUpdate(1, 40.0, 30.0);
test.handleTouchUpdate(1, 80.0, 30.0);
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureDrag);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureDrag);
test.events.clear();
@@ -1047,10 +927,10 @@ void testExtraIgnore()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureUpdate);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 100.0);
- ASSERT_EQ(test.events[0].eventY, 50.0);
+ EXPECT_EQ(test.events[0].type, GestureUpdate);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 100.0);
+ EXPECT_EQ(test.events[0].eventY, 50.0);
test.events.clear();
@@ -1058,20 +938,16 @@ void testExtraIgnore()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 100.0);
- ASSERT_EQ(test.events[0].eventY, 50.0);
-
- printf("OK\n");
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 100.0);
+ EXPECT_EQ(test.events[0].eventY, 50.0);
}
-void testIgnoreWhenAwaitingGestureEnd()
+TEST(GestureHandler, ignoreWhenAwaitingGestureEnd)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchBegin(2, 30.0, 30.0);
test.handleTouchUpdate(1, 40.0, 30.0);
@@ -1080,11 +956,11 @@ void testIgnoreWhenAwaitingGestureEnd()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureTwoDrag);
test.events.clear();
@@ -1092,8 +968,8 @@ void testIgnoreWhenAwaitingGestureEnd()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureTwoDrag);
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureTwoDrag);
test.events.clear();
@@ -1101,27 +977,23 @@ void testIgnoreWhenAwaitingGestureEnd()
test.handleTouchEnd(3);
ASSERT_EQ(test.events.size(), 0);
-
- printf("OK\n");
}
-void testIgnoreAfterGesture()
+TEST(GestureHandler, ignoreAfterGesture)
{
TestClass test;
- printf("%s: ", __func__);
-
test.handleTouchBegin(1, 20.0, 30.0);
test.handleTouchUpdate(1, 40.0, 30.0);
test.handleTouchUpdate(1, 80.0, 30.0);
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[1].type, GestureUpdate);
- ASSERT_EQ(test.events[1].gesture, GestureDrag);
+ EXPECT_EQ(test.events[1].type, GestureUpdate);
+ EXPECT_EQ(test.events[1].gesture, GestureDrag);
test.events.clear();
@@ -1134,10 +1006,10 @@ void testIgnoreAfterGesture()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureUpdate);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 100.0);
- ASSERT_EQ(test.events[0].eventY, 50.0);
+ EXPECT_EQ(test.events[0].type, GestureUpdate);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 100.0);
+ EXPECT_EQ(test.events[0].eventY, 50.0);
test.events.clear();
@@ -1145,10 +1017,10 @@ void testIgnoreAfterGesture()
ASSERT_EQ(test.events.size(), 1);
- ASSERT_EQ(test.events[0].type, GestureEnd);
- ASSERT_EQ(test.events[0].gesture, GestureDrag);
- ASSERT_EQ(test.events[0].eventX, 100.0);
- ASSERT_EQ(test.events[0].eventY, 50.0);
+ EXPECT_EQ(test.events[0].type, GestureEnd);
+ EXPECT_EQ(test.events[0].gesture, GestureDrag);
+ EXPECT_EQ(test.events[0].eventX, 100.0);
+ EXPECT_EQ(test.events[0].eventY, 50.0);
// End ignored event
test.handleTouchEnd(2);
@@ -1161,88 +1033,14 @@ void testIgnoreAfterGesture()
ASSERT_EQ(test.events.size(), 2);
- ASSERT_EQ(test.events[0].type, GestureBegin);
- ASSERT_EQ(test.events[0].gesture, GestureOneTap);
- ASSERT_EQ(test.events[1].type, GestureEnd);
- ASSERT_EQ(test.events[1].gesture, GestureOneTap);
-
- printf("OK\n");
-}
-
-void testOneTap()
-{
- testOneTapNormal();
-}
-
-void testTwoTap()
-{
- testTwoTapNormal();
- testTwoTapSlowBegin();
- testTwoTapSlowEnd();
- testTwoTapTimeout();
-}
-
-void testThreeTap()
-{
- testThreeTapNormal();
- testThreeTapSlowBegin();
- testThreeTapSlowEnd();
- testThreeTapDrag();
- testThreeTapTimeout();
-}
-
-void testDrag()
-{
- testDragHoriz();
- testDragVert();
- testDragDiag();
-}
-
-void testLongPress()
-{
- testLongPressNormal();
- testLongPressDrag();
-}
-
-void testTwoDrag()
-{
- testTwoDragFastDistinctHoriz();
- testTwoDragFastDistinctVert();
- testTwoDragFastDistinctDiag();
- testTwoDragFastAlmost();
- testTwoDragSlowHoriz();
- testTwoDragSlowVert();
- testTwoDragSlowDiag();
- testTwoDragTooSlow();
-}
-
-void testPinch()
-{
- testPinchFastDistinctIn();
- testPinchFastDistinctOut();
- testPinchFastAlmost();
- testPinchSlowIn();
- testPinchSlowOut();
- testPinchTooSlow();
-}
-
-void testIgnore()
-{
- testExtraIgnore();
- testIgnoreWhenAwaitingGestureEnd();
- testIgnoreAfterGesture();
+ EXPECT_EQ(test.events[0].type, GestureBegin);
+ EXPECT_EQ(test.events[0].gesture, GestureOneTap);
+ EXPECT_EQ(test.events[1].type, GestureEnd);
+ EXPECT_EQ(test.events[1].gesture, GestureOneTap);
}
-int main(int /*argc*/, char** /*argv*/)
+int main(int argc, char** argv)
{
- testOneTap();
- testTwoTap();
- testThreeTap();
- testDrag();
- testLongPress();
- testTwoDrag();
- testPinch();
- testIgnore();
-
- return 0;
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tests/unit/hostport.cxx b/tests/unit/hostport.cxx
index d82c3d51..164a7877 100644
--- a/tests/unit/hostport.cxx
+++ b/tests/unit/hostport.cxx
@@ -1,4 +1,4 @@
-/* Copyright 2016 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2016-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,75 +20,108 @@
#include <config.h>
#endif
-#include <stdio.h>
+#include <gtest/gtest.h>
-#include <rfb/Hostname.h>
+#include <network/TcpSocket.h>
-static void doTest(const char* hostAndPort,
- const char* expectedHost, int expectedPort)
+struct result {
+ std::string host;
+ int port;
+};
+
+static bool operator==(const result& a, const result& b)
+{
+ return a.host == b.host && a.port == b.port;
+}
+
+static std::ostream& operator<<(std::ostream& os, const result& r)
+{
+ return os << r.host << ":" << r.port;
+}
+
+static result getHostAndPort(const char* hostAndPort)
+{
+ std::string host;
+ int port;
+ network::getHostAndPort(hostAndPort, &host, &port);
+ return {host, port};
+}
+
+TEST(HostPost, localDisplay)
+{
+ EXPECT_EQ(getHostAndPort(":5"), result({"localhost", 5905}));
+}
+
+TEST(HostPost, noDisplay)
+{
+ EXPECT_EQ(getHostAndPort("1.2.3.4"), result({"1.2.3.4", 5900}));
+}
+
+TEST(HostPost, display)
+{
+ EXPECT_EQ(getHostAndPort("1.2.3.4:5"), result({"1.2.3.4", 5905}));
+ EXPECT_EQ(getHostAndPort("1.2.3.4:99"), result({"1.2.3.4", 5999}));
+ EXPECT_EQ(getHostAndPort("1.2.3.4:100"), result({"1.2.3.4", 100}));
+ EXPECT_EQ(getHostAndPort("1.2.3.4:5901"), result({"1.2.3.4", 5901}));
+}
+
+TEST(HostPost, port)
{
- std::string host;
- int port;
+ EXPECT_EQ(getHostAndPort("1.2.3.4::5"), result({"1.2.3.4", 5}));
+ EXPECT_EQ(getHostAndPort("1.2.3.4::99"), result({"1.2.3.4", 99}));
+ EXPECT_EQ(getHostAndPort("1.2.3.4::5901"), result({"1.2.3.4", 5901}));
+}
- printf("\"%s\": ", hostAndPort);
+TEST(HostPost, bracketedIpv4)
+{
+ EXPECT_EQ(getHostAndPort("[1.2.3.4]"), result({"1.2.3.4", 5900}));
+ EXPECT_EQ(getHostAndPort("[1.2.3.4]:5"), result({"1.2.3.4", 5905}));
+ EXPECT_EQ(getHostAndPort("[1.2.3.4]:100"), result({"1.2.3.4", 100}));
+ EXPECT_EQ(getHostAndPort("[1.2.3.4]::5"), result({"1.2.3.4", 5}));
+ EXPECT_EQ(getHostAndPort("[1.2.3.4]::100"), result({"1.2.3.4", 100}));
+}
- rfb::getHostAndPort(hostAndPort, &host, &port);
+TEST(HostPost, portOne)
+{
+ // Ambigiuous. For now we'll keep the old behaviour...
+ EXPECT_EQ(getHostAndPort("::1"), result({"localhost", 1}));
+}
- if (host != expectedHost)
- printf("FAILED (\"%s\" != \"%s\")", host.c_str(), expectedHost);
- else if (port != expectedPort)
- printf("FAILED (%d != %d)", port, expectedPort);
- else
- printf("OK");
- printf("\n");
- fflush(stdout);
+TEST(HostPost, bareIpv6)
+{
+ EXPECT_EQ(getHostAndPort("2001:1234::20:1"), result({"2001:1234::20:1", 5900}));
+}
+
+TEST(HostPost, bracketedIpv6)
+{
+ EXPECT_EQ(getHostAndPort("[::1]"), result({"::1", 5900}));
+ EXPECT_EQ(getHostAndPort("[2001:1234::20:1]"), result({"2001:1234::20:1", 5900}));
+}
+
+TEST(HostPost, ipv6WithDisplay)
+{
+ EXPECT_EQ(getHostAndPort("[2001:1234::20:1]:5"), result({"2001:1234::20:1", 5905}));
+ EXPECT_EQ(getHostAndPort("[2001:1234::20:1]:99"), result({"2001:1234::20:1", 5999}));
+ EXPECT_EQ(getHostAndPort("[2001:1234::20:1]:100"), result({"2001:1234::20:1", 100}));
+ EXPECT_EQ(getHostAndPort("[2001:1234::20:1]:5901"), result({"2001:1234::20:1", 5901}));
+}
+
+TEST(HostPort, padding)
+{
+ EXPECT_EQ(getHostAndPort(" 1.2.3.4 "), result({"1.2.3.4", 5900}));
+ EXPECT_EQ(getHostAndPort(" 1.2.3.4:5901 "), result({"1.2.3.4", 5901}));
+ EXPECT_EQ(getHostAndPort(" 1.2.3.4 :5901 "), result({"1.2.3.4", 5901}));
+ EXPECT_EQ(getHostAndPort(" [1.2.3.4]:5902 "), result({"1.2.3.4", 5902}));
+ EXPECT_EQ(getHostAndPort(" :5903 "), result({"localhost", 5903}));
+ EXPECT_EQ(getHostAndPort(" ::4 "), result({"localhost", 4}));
+ EXPECT_EQ(getHostAndPort(" [::1] "), result({"::1", 5900}));
+ EXPECT_EQ(getHostAndPort(" 2001:1234::20:1 "), result({"2001:1234::20:1", 5900}));
+ EXPECT_EQ(getHostAndPort(" [2001:1234::20:1] "), result({"2001:1234::20:1", 5900}));
+ EXPECT_EQ(getHostAndPort(" [2001:1234::20:1]:5905 "), result({"2001:1234::20:1", 5905}));
}
-int main(int /*argc*/, char** /*argv*/)
+int main(int argc, char** argv)
{
- doTest(":5", "localhost", 5905);
-
- doTest("1.2.3.4", "1.2.3.4", 5900);
-
- doTest("1.2.3.4:5", "1.2.3.4", 5905);
- doTest("1.2.3.4:99", "1.2.3.4", 5999);
- doTest("1.2.3.4:100", "1.2.3.4", 100);
- doTest("1.2.3.4:5901", "1.2.3.4", 5901);
-
- doTest("1.2.3.4::5", "1.2.3.4", 5);
- doTest("1.2.3.4::99", "1.2.3.4", 99);
- doTest("1.2.3.4::5901", "1.2.3.4", 5901);
-
- doTest("[1.2.3.4]", "1.2.3.4", 5900);
- doTest("[1.2.3.4]:5", "1.2.3.4", 5905);
- doTest("[1.2.3.4]:100", "1.2.3.4", 100);
- doTest("[1.2.3.4]::5", "1.2.3.4", 5);
- doTest("[1.2.3.4]::100", "1.2.3.4", 100);
-
- // Ambigiuous. For now we'll keep the old behaviour...
- doTest("::1", "localhost", 1);
-
- doTest("2001:1234::20:1", "2001:1234::20:1", 5900);
-
- doTest("[::1]", "::1", 5900);
- doTest("[2001:1234::20:1]", "2001:1234::20:1", 5900);
-
- doTest("[2001:1234::20:1]:5", "2001:1234::20:1", 5905);
- doTest("[2001:1234::20:1]:99", "2001:1234::20:1", 5999);
- doTest("[2001:1234::20:1]:100", "2001:1234::20:1", 100);
- doTest("[2001:1234::20:1]:5901", "2001:1234::20:1", 5901);
-
- doTest(" 1.2.3.4 ", "1.2.3.4", 5900);
- doTest(" 1.2.3.4:5901 ", "1.2.3.4", 5901);
- doTest(" 1.2.3.4: 5901 ", "1.2.3.4", 5901);
- doTest(" 1.2.3.4 :5901 ", "1.2.3.4", 5901);
- doTest(" [1.2.3.4]:5902 ", "1.2.3.4", 5902);
- doTest(" :5903 ", "localhost", 5903);
- doTest(" ::4 ", "localhost", 4);
- doTest(" [::1] ", "::1", 5900);
- doTest(" 2001:1234::20:1 ", "2001:1234::20:1", 5900);
- doTest(" [2001:1234::20:1] ", "2001:1234::20:1", 5900);
- doTest(" [2001:1234::20:1]:5905 ", "2001:1234::20:1", 5905);
-
- return 0;
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tests/unit/parameters.cxx b/tests/unit/parameters.cxx
new file mode 100644
index 00000000..e120f988
--- /dev/null
+++ b/tests/unit/parameters.cxx
@@ -0,0 +1,839 @@
+/* Copyright 2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdexcept>
+
+#include <gtest/gtest.h>
+
+#include <core/Configuration.h>
+
+namespace core {
+
+// Generic comparison for our list parameters types that preserves
+// the type (doesn't use any common base class)
+template<typename IterL, typename IterR,
+ std::enable_if_t<std::is_member_function_pointer<decltype(&IterL::begin)>::value, bool> = true>
+static bool operator==(const IterL& lhs, const IterR& rhs)
+{
+ if (std::distance(lhs.begin(), lhs.end()) !=
+ std::distance(rhs.begin(), rhs.end()))
+ return false;
+ if (!std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()))
+ return false;
+ return true;
+}
+
+static std::ostream& operator<<(std::ostream& os,
+ const core::EnumListEntry& e)
+{
+ return os << '"' << e.getValueStr() << '"';
+}
+
+}
+
+TEST(BoolParameter, values)
+{
+ core::BoolParameter bools("boolparam", "", false);
+
+ bools.setParam(true);
+ EXPECT_TRUE(bools);
+
+ bools.setParam(false);
+ EXPECT_FALSE(bools);
+}
+
+TEST(BoolParameter, strings)
+{
+ core::BoolParameter strings("boolparam", "", false);
+
+ strings.setParam("on");
+ EXPECT_TRUE(strings);
+
+ strings.setParam("off");
+ EXPECT_FALSE(strings);
+
+ strings.setParam("1");
+ EXPECT_TRUE(strings);
+
+ strings.setParam("0");
+ EXPECT_FALSE(strings);
+
+ strings.setParam("true");
+ EXPECT_TRUE(strings);
+
+ strings.setParam("false");
+ EXPECT_FALSE(strings);
+
+ strings.setParam("yes");
+ EXPECT_TRUE(strings);
+
+ strings.setParam("no");
+ EXPECT_FALSE(strings);
+}
+
+TEST(BoolParameter, validation)
+{
+ core::BoolParameter valid("boolparam", "", false);
+
+ EXPECT_TRUE(valid.setParam("yes"));
+ EXPECT_TRUE(valid);
+
+ EXPECT_FALSE(valid.setParam("foo"));
+ EXPECT_TRUE(valid);
+}
+
+TEST(BoolParameter, encoding)
+{
+ core::BoolParameter encoding("boolparam", "", false);
+
+ encoding.setParam(true);
+ EXPECT_EQ(encoding.getValueStr(), "on");
+
+ encoding.setParam(false);
+ EXPECT_EQ(encoding.getValueStr(), "off");
+}
+
+TEST(BoolParameter, default)
+{
+ core::BoolParameter def("boolparam", "", false);
+
+ EXPECT_TRUE(def.isDefault());
+
+ def.setParam(true);
+ EXPECT_FALSE(def.isDefault());
+
+ def.setParam(false);
+ EXPECT_TRUE(def.isDefault());
+}
+
+TEST(BoolParameter, immutable)
+{
+ core::BoolParameter immutable("boolparam", "", false);
+
+ immutable.setImmutable();
+ immutable.setParam(true);
+ immutable.setParam("on");
+ EXPECT_FALSE(immutable);
+}
+
+TEST(IntParameter, values)
+{
+ core::IntParameter ints("intparam", "", 0);
+
+ ints.setParam(123);
+ EXPECT_EQ(ints, 123);
+
+ ints.setParam(-456);
+ EXPECT_EQ(ints, -456);
+}
+
+TEST(IntParameter, strings)
+{
+ core::IntParameter strings("intparam", "", 0);
+
+ strings.setParam("123");
+ EXPECT_EQ(strings, 123);
+
+ strings.setParam("-456");
+ EXPECT_EQ(strings, -456);
+}
+
+TEST(IntParameter, minmax)
+{
+ core::IntParameter bounds("intparam", "", 30, 20, 100);
+
+ EXPECT_TRUE(bounds.setParam(57));
+ EXPECT_EQ(bounds, 57);
+
+ EXPECT_FALSE(bounds.setParam(123));
+ EXPECT_EQ(bounds, 57);
+
+ EXPECT_FALSE(bounds.setParam("123"));
+ EXPECT_EQ(bounds, 57);
+
+ EXPECT_FALSE(bounds.setParam(-30));
+ EXPECT_EQ(bounds, 57);
+
+ EXPECT_FALSE(bounds.setParam("-30"));
+ EXPECT_EQ(bounds, 57);
+}
+
+TEST(IntParameter, minmaxdefault)
+{
+ EXPECT_THROW({
+ core::IntParameter defbounds("intparam", "", 10, 20, 100);
+ }, std::invalid_argument);
+}
+
+TEST(IntParameter, validation)
+{
+ core::IntParameter valid("intparam", "", 0);
+
+ EXPECT_TRUE(valid.setParam("123"));
+ EXPECT_EQ(valid, 123);
+
+ EXPECT_FALSE(valid.setParam("foo"));
+ EXPECT_EQ(valid, 123);
+}
+
+TEST(IntParameter, encoding)
+{
+ core::IntParameter encoding("intparam", "", 0);
+
+ encoding.setParam(123);
+ EXPECT_EQ(encoding.getValueStr(), "123");
+
+ encoding.setParam(-456);
+ EXPECT_EQ(encoding.getValueStr(), "-456");
+}
+
+TEST(IntParameter, default)
+{
+ core::IntParameter def("intparam", "", 30);
+
+ EXPECT_TRUE(def.isDefault());
+
+ def.setParam(123);
+ EXPECT_FALSE(def.isDefault());
+
+ def.setParam(30);
+ EXPECT_TRUE(def.isDefault());
+}
+
+TEST(IntParameter, immutable)
+{
+ core::IntParameter immutable("intparam", "", 0);
+
+ immutable.setImmutable();
+ immutable.setParam(123);
+ immutable.setParam("-456");
+ EXPECT_EQ(immutable, 0);
+}
+
+TEST(StringParameter, values)
+{
+ core::StringParameter strings("stringparam", "", "");
+
+ strings.setParam("foo");
+ EXPECT_STREQ(strings, "foo");
+
+ strings.setParam("bar");
+ EXPECT_STREQ(strings, "bar");
+}
+
+TEST(StringParameter, null)
+{
+ // NULL value
+ core::StringParameter null("stringparam", "", "");
+ EXPECT_THROW({
+ null.setParam(nullptr);
+ }, std::invalid_argument);
+
+ // NULL default value
+ EXPECT_THROW({
+ core::StringParameter defnull("stringparam", "", nullptr);
+ }, std::invalid_argument);
+}
+
+TEST(StringParameter, encoding)
+{
+ core::StringParameter encoding("stringparam", "", "");
+
+ encoding.setParam("foo");
+ EXPECT_EQ(encoding.getValueStr(), "foo");
+
+ encoding.setParam("bar");
+ EXPECT_EQ(encoding.getValueStr(), "bar");
+}
+
+TEST(StringParameter, default)
+{
+ core::StringParameter def("stringparam", "", "test");
+
+ EXPECT_TRUE(def.isDefault());
+
+ def.setParam("foo");
+ EXPECT_FALSE(def.isDefault());
+
+ def.setParam("test");
+ EXPECT_TRUE(def.isDefault());
+}
+
+TEST(StringParameter, immutable)
+{
+ core::StringParameter immutable("stringparam", "", "");
+
+ immutable.setImmutable();
+ immutable.setParam("foo");
+ immutable.setParam("bar");
+ EXPECT_STREQ(immutable, "");
+}
+
+TEST(EnumParameter, values)
+{
+ core::EnumParameter enums("enumparam", "", {"a", "b", "c"}, "a");
+
+ enums.setParam("b");
+ EXPECT_FALSE(enums == "a");
+ EXPECT_TRUE(enums == "b");
+ EXPECT_FALSE(enums == "c");
+ EXPECT_FALSE(enums == "foo");
+ EXPECT_FALSE(enums != "b");
+ EXPECT_TRUE(enums != "c");
+
+ enums.setParam("c");
+ EXPECT_FALSE(enums == "a");
+ EXPECT_FALSE(enums == "b");
+ EXPECT_TRUE(enums == "c");
+ EXPECT_FALSE(enums == "foo");
+ EXPECT_TRUE(enums != "b");
+ EXPECT_FALSE(enums != "c");
+}
+
+TEST(EnumParameter, caseinsensitive)
+{
+ core::EnumParameter casecmp("enumparam", "", {"a", "b", "c"}, "a");
+
+ casecmp.setParam("B");
+ EXPECT_FALSE(casecmp == "a");
+ EXPECT_TRUE(casecmp == "b");
+ EXPECT_TRUE(casecmp == "B");
+ EXPECT_FALSE(casecmp == "c");
+ EXPECT_FALSE(casecmp != "b");
+ EXPECT_TRUE(casecmp != "c");
+}
+
+TEST(EnumParameter, validation)
+{
+ core::EnumParameter valid("enumparam", "", {"a", "b", "c"}, "a");
+
+ EXPECT_TRUE(valid.setParam("b"));
+ EXPECT_EQ(valid.getValueStr(), "b");
+ EXPECT_FALSE(valid.setParam("foo"));
+ EXPECT_EQ(valid.getValueStr(), "b");
+
+ // Valid default value
+ EXPECT_THROW({
+ core::EnumParameter defvalid("enumparam", "", {"a", "b", "c"}, "d");
+ }, std::invalid_argument);
+}
+
+TEST(EnumParameter, null)
+{
+ // NULL value
+ core::EnumParameter null("enumparam", "", {"a", "b", "c"}, "a");
+ EXPECT_THROW({
+ null.setParam(nullptr);
+ }, std::invalid_argument);
+
+ // NULL default value
+ EXPECT_THROW({
+ core::EnumParameter defnull("enumparam", "", {""}, nullptr);
+ }, std::invalid_argument);
+
+ // NULL enum value
+ EXPECT_THROW({
+ core::EnumParameter nullenum("enumparam", "", {"a", nullptr, "b"}, "a");
+ }, std::invalid_argument);
+}
+
+TEST(EnumParameter, encoding)
+{
+ core::EnumParameter encoding("enumparam", "", {"a", "b", "c"}, "a");
+
+ encoding.setParam("b");
+ EXPECT_EQ(encoding.getValueStr(), "b");
+
+ encoding.setParam("C");
+ EXPECT_EQ(encoding.getValueStr(), "c");
+}
+
+TEST(EnumParameter, default)
+{
+ core::EnumParameter def("enumparam", "", {"a", "b", "c"}, "a");
+
+ EXPECT_TRUE(def.isDefault());
+
+ def.setParam("b");
+ EXPECT_FALSE(def.isDefault());
+
+ def.setParam("A");
+ EXPECT_TRUE(def.isDefault());
+}
+
+TEST(EnumParameter, immutable)
+{
+ core::EnumParameter immutable("enumparam", "", {"a", "b", "c"}, "a");
+
+ immutable.setImmutable();
+ immutable.setParam("b");
+ immutable.setParam("c");
+ EXPECT_EQ(immutable.getValueStr(), "a");
+}
+
+TEST(BinaryParameter, values)
+{
+ std::vector<uint8_t> data;
+
+ core::BinaryParameter binary("binaryparam", "", nullptr, 0);
+
+ data = {1, 2, 3};
+ binary.setParam(data.data(), data.size());
+ ASSERT_EQ(binary.getData().size(), 3);
+ EXPECT_EQ(binary.getData()[0], 1);
+ EXPECT_EQ(binary.getData()[1], 2);
+ EXPECT_EQ(binary.getData()[2], 3);
+}
+
+TEST(BinaryParameter, copy)
+{
+ std::vector<uint8_t> data;
+
+ core::BinaryParameter copy("binaryparam", "", nullptr, 0);
+
+ data = {1, 2, 3};
+ copy.setParam(data.data(), data.size());
+ ASSERT_EQ(copy.getData().size(), 3);
+ EXPECT_EQ(copy.getData()[0], 1);
+ EXPECT_EQ(copy.getData()[1], 2);
+ EXPECT_EQ(copy.getData()[2], 3);
+
+ data[0] = 4;
+ EXPECT_EQ(copy.getData()[0], 1);
+}
+
+TEST(BinaryParameter, strings)
+{
+ core::BinaryParameter strings("binaryparam", "", nullptr, 0);
+
+ strings.setParam("010203");
+ ASSERT_EQ(strings.getData().size(), 3);
+ EXPECT_EQ(strings.getData()[0], 1);
+ EXPECT_EQ(strings.getData()[1], 2);
+ EXPECT_EQ(strings.getData()[2], 3);
+
+ strings.setParam("deadbeef");
+ ASSERT_EQ(strings.getData().size(), 4);
+ EXPECT_EQ(strings.getData()[0], 0xde);
+ EXPECT_EQ(strings.getData()[1], 0xad);
+ EXPECT_EQ(strings.getData()[2], 0xbe);
+ EXPECT_EQ(strings.getData()[3], 0xef);
+}
+
+TEST(BinaryParameter, validation)
+{
+ core::BinaryParameter valid("binaryparam", "", nullptr, 0);
+
+ EXPECT_TRUE(valid.setParam("010203"));
+ ASSERT_EQ(valid.getData().size(), 3);
+ EXPECT_EQ(valid.getData()[0], 1);
+ EXPECT_EQ(valid.getData()[1], 2);
+ EXPECT_EQ(valid.getData()[2], 3);
+
+ EXPECT_FALSE(valid.setParam("foo"));
+ ASSERT_EQ(valid.getData().size(), 3);
+ EXPECT_EQ(valid.getData()[0], 1);
+ EXPECT_EQ(valid.getData()[1], 2);
+ EXPECT_EQ(valid.getData()[2], 3);
+}
+
+TEST(BinaryParameter, encoding)
+{
+ std::vector<uint8_t> data;
+
+ core::BinaryParameter encoding("binaryparam", "", nullptr, 0);
+
+ data = {1, 2, 3};
+ encoding.setParam(data.data(), data.size());
+ EXPECT_EQ(encoding.getValueStr(), "010203");
+
+ data = {0xde, 0xad, 0xbe, 0xef};
+ encoding.setParam(data.data(), data.size());
+ EXPECT_EQ(encoding.getValueStr(), "deadbeef");
+}
+
+TEST(BinaryParameter, default)
+{
+ std::vector<uint8_t> data;
+
+ data = {1, 2, 3};
+ core::BinaryParameter def("binaryparam", "", data.data(), data.size());
+
+ EXPECT_TRUE(def.isDefault());
+
+ data = {4, 5, 6};
+ def.setParam(data.data(), data.size());
+ EXPECT_FALSE(def.isDefault());
+
+ data = {1, 2, 3};
+ def.setParam(data.data(), data.size());
+ EXPECT_TRUE(def.isDefault());
+}
+
+TEST(BinaryParameter, immutable)
+{
+ std::vector<uint8_t> data;
+
+ core::BinaryParameter immutable("binaryparam", "", nullptr, 0);
+
+ immutable.setImmutable();
+ data = {1, 2, 3};
+ immutable.setParam(data.data(), data.size());
+ immutable.setParam("deadbeef");
+ EXPECT_EQ(immutable.getData().size(), 0);
+}
+
+TEST(IntListParameter, values)
+{
+ std::list<int> data;
+
+ core::IntListParameter list("listparam", "", {});
+
+ list.setParam({1, 2, 3, 4});
+ data = {1, 2, 3, 4};
+ EXPECT_EQ(list, data);
+}
+
+TEST(IntListParameter, strings)
+{
+ std::list<int> data;
+
+ core::IntListParameter strings("listparam", "", {});
+
+ strings.setParam("1,2,3,4");
+ data = {1, 2, 3, 4};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("5 , 6 , 7,8");
+ data = {5, 6, 7, 8};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("9,\n10,\t11,\t12");
+ data = {9, 10, 11, 12};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("");
+ data = {};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam(" ");
+ data = {};
+ EXPECT_EQ(strings, data);
+}
+
+TEST(IntListParameter, minmax)
+{
+ std::list<int> data;
+
+ core::IntListParameter bounds("listparam", "", {}, 20, 100);
+
+ EXPECT_TRUE(bounds.setParam({57, 73}));
+ data = {57, 73};
+ EXPECT_EQ(bounds, data);
+
+ EXPECT_FALSE(bounds.setParam({57, 123}));
+ data = {57, 73};
+ EXPECT_EQ(bounds, data);
+
+ EXPECT_FALSE(bounds.setParam("57,123"));
+ data = {57, 73};
+ EXPECT_EQ(bounds, data);
+
+ EXPECT_FALSE(bounds.setParam({57, -30}));
+ data = {57, 73};
+ EXPECT_EQ(bounds, data);
+
+ EXPECT_FALSE(bounds.setParam("57,-30"));
+ data = {57, 73};
+ EXPECT_EQ(bounds, data);
+}
+
+TEST(IntListParameter, minmaxdefault)
+{
+ EXPECT_THROW({
+ core::IntListParameter defbounds("listparam", "", {10}, 20, 100);
+ }, std::invalid_argument);
+}
+
+TEST(IntListParameter, validation)
+{
+ std::list<int> data;
+
+ core::IntListParameter valid("listparam", "", {});
+
+ EXPECT_TRUE(valid.setParam("1,2,3,4"));
+ data = {1, 2, 3, 4};
+ EXPECT_EQ(valid, data);
+
+ EXPECT_FALSE(valid.setParam("foo"));
+ data = {1, 2, 3, 4};
+ EXPECT_EQ(valid, data);
+
+ EXPECT_FALSE(valid.setParam("1,2,x,4"));
+ data = {1, 2, 3, 4};
+ EXPECT_EQ(valid, data);
+}
+
+TEST(IntListParameter, encoding)
+{
+ std::list<int> data;
+
+ core::IntListParameter encoding("listparam", "", {});
+
+ encoding.setParam({1, 2, 3, 4});
+ EXPECT_EQ(encoding.getValueStr(), "1,2,3,4");
+}
+
+TEST(IntListParameter, default)
+{
+ std::list<int> data;
+
+ core::IntListParameter def("listparam", "", {1, 2, 3});
+
+ EXPECT_TRUE(def.isDefault());
+
+ def.setParam({4, 5, 6});
+ EXPECT_FALSE(def.isDefault());
+
+ def.setParam({1, 2, 3});
+ EXPECT_TRUE(def.isDefault());
+}
+
+TEST(IntListParameter, immutable)
+{
+ std::list<int> data;
+
+ core::IntListParameter immutable("listparam", "", {});
+
+ immutable.setImmutable();
+ immutable.setParam({1, 2, 3, 4});
+ immutable.setParam("1,2,3,4");
+ EXPECT_TRUE(immutable.begin() == immutable.end());
+}
+
+TEST(StringListParameter, values)
+{
+ std::list<std::string> data;
+
+ core::StringListParameter list("listparam", "", {});
+
+ list.setParam({"1", "2", "3", "4"});
+ data = {"1", "2", "3", "4"};
+ EXPECT_EQ(list, data);
+}
+
+TEST(StringListParameter, strings)
+{
+ std::list<std::string> data;
+
+ core::StringListParameter strings("listparam", "", {});
+
+ strings.setParam("1,2,3,4");
+ data = {"1", "2", "3", "4"};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("5 , 6 , 7,8");
+ data = {"5", "6", "7", "8"};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("9,\n10,\t11,\t12");
+ data = {"9", "10", "11", "12"};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("");
+ data = {};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam(" ");
+ data = {};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("a, , b");
+ data = {"a", "", "b"};
+ EXPECT_EQ(strings, data);
+}
+
+TEST(StringListParameter, null)
+{
+ // NULL default value
+ EXPECT_THROW({
+ core::StringListParameter defnull("enumparam", "", {nullptr});
+ }, std::invalid_argument);
+}
+
+TEST(StringListParameter, encoding)
+{
+ core::StringListParameter encoding("listparam", "", {});
+
+ encoding.setParam({"1", "2", "3", "4"});
+ EXPECT_EQ(encoding.getValueStr(), "1,2,3,4");
+}
+
+TEST(StringListParameter, default)
+{
+ core::StringListParameter def("listparam", "", {"1", "2", "3"});
+
+ EXPECT_TRUE(def.isDefault());
+
+ def.setParam({"4", "5", "6"});
+ EXPECT_FALSE(def.isDefault());
+
+ def.setParam({"1", "2", "3"});
+ EXPECT_TRUE(def.isDefault());
+}
+
+TEST(StringListParameter, immutable)
+{
+ std::list<std::string> data;
+
+ core::StringListParameter immutable("listparam", "", {"a", "b"});
+
+ immutable.setImmutable();
+ immutable.setParam({"1", "2", "3", "4"});
+ immutable.setParam("1,2,3,4");
+ data = {"a", "b"};
+ EXPECT_EQ(immutable, data);
+}
+
+TEST(EnumListParameter, values)
+{
+ std::list<std::string> data;
+
+ core::EnumListParameter list("listparam", "", {"a", "b", "c"}, {"a"});
+
+ list.setParam({"a", "b", "c"});
+ data = {"a", "b", "c"};
+ EXPECT_EQ(list, data);
+}
+
+TEST(EnumListParameter, caseinsensitive)
+{
+ std::list<std::string> data;
+
+ core::EnumListParameter casecmp("listparam", "", {"a", "b", "c"}, {"a"});
+
+ casecmp.setParam({"A", "B", "C"});
+ data = {"a", "B", "c"};
+ EXPECT_EQ(casecmp, data);
+}
+
+TEST(EnumListParameter, strings)
+{
+ std::list<std::string> data;
+
+ core::EnumListParameter strings("listparam", "", {"a", "b", "c"}, {"a"});
+
+ strings.setParam("a,b,c");
+ data = {"a", "b", "c"};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("c , b , a,a");
+ data = {"c", "b", "a", "a"};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("b,\na,\tc,\tb");
+ data = {"b", "a", "c", "b"};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam("");
+ data = {};
+ EXPECT_EQ(strings, data);
+
+ strings.setParam(" ");
+ data = {};
+ EXPECT_EQ(strings, data);
+}
+
+TEST(EnumListParameter, validation)
+{
+ std::list<std::string> data;
+
+ core::EnumListParameter valid("enumparam", "", {"a", "b", "c"}, {"a"});
+
+ EXPECT_TRUE(valid.setParam({"a", "b", "c"}));
+ data = {"a", "b", "c"};
+ EXPECT_EQ(valid, data);
+
+ EXPECT_FALSE(valid.setParam({"a", "foo", "c"}));
+ data = {"a", "b", "c"};
+ EXPECT_EQ(valid, data);
+}
+
+TEST(EnumListParameter, validdefault)
+{
+ EXPECT_THROW({
+ core::EnumListParameter defvalid("enumparam", "", {"a", "b", "c"}, {"d"});
+ }, std::invalid_argument);
+}
+
+TEST(EnumListParameter, null)
+{
+ // NULL default value
+ EXPECT_THROW({
+ core::EnumListParameter defnull("enumparam", "", {""}, {nullptr});
+ }, std::invalid_argument);
+
+ // NULL enum value
+ EXPECT_THROW({
+ core::EnumListParameter nullenum("enumparam", "", {"a", nullptr, "b"}, {"a"});
+ }, std::invalid_argument);
+}
+
+TEST(EnumListParameter, encoding)
+{
+ core::EnumListParameter encoding("listparam", "", {"a", "b", "c"}, {"a"});
+
+ encoding.setParam({"a", "b", "C"});
+ EXPECT_EQ(encoding.getValueStr(), "a,b,c");
+}
+
+TEST(EnumListParameter, default)
+{
+ core::EnumListParameter def("listparam", "", {"a", "b", "c"}, {"a"});
+
+ EXPECT_TRUE(def.isDefault());
+
+ def.setParam({"a", "b", "c"});
+ EXPECT_FALSE(def.isDefault());
+
+ def.setParam("A");
+ EXPECT_TRUE(def.isDefault());
+}
+
+TEST(EnumListParameter, immutable)
+{
+ std::list<std::string> data;
+
+ core::EnumListParameter immutable("listparam", "", {"a", "b", "c"}, {"a"});
+
+ immutable.setImmutable();
+ immutable.setParam({"a", "b", "c"});
+ immutable.setParam("a,b,c");
+ data = {"a"};
+ EXPECT_EQ(immutable, data);
+}
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tests/unit/pixelformat.cxx b/tests/unit/pixelformat.cxx
index 54e68ccf..57d23cdf 100644
--- a/tests/unit/pixelformat.cxx
+++ b/tests/unit/pixelformat.cxx
@@ -1,4 +1,4 @@
-/* Copyright 2019 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2019-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,174 +20,233 @@
#include <config.h>
#endif
-#include <stdio.h>
-
+#include <list>
#include <stdexcept>
+#include <gtest/gtest.h>
+
#include <rfb/PixelFormat.h>
-static void doTest(bool should_fail, int b, int d, bool e, bool t,
- int rm, int gm, int bm, int rs, int gs, int bs)
+struct Params {
+ int b;
+ int d;
+ bool e;
+ bool t;
+ int rm;
+ int gm;
+ int bm;
+ int rs;
+ int gs;
+ int bs;
+};
+
+static std::ostream& operator<<(std::ostream& os, const Params& p)
{
- rfb::PixelFormat* pf;
-
- printf("PixelFormat(%d, %d, %s, %s, %d, %d, %d, %d, %d, %d): ",
- b, d, e ? "true" : "false", t ? "true": "false",
- rm, gm, bm, rs, gs, bs);
-
- try {
- pf = new rfb::PixelFormat(b, d, e, t, rm, gm, bm, rs, gs, bs);
- } catch(std::exception&) {
- if (should_fail)
- printf("OK");
- else
- printf("FAILED");
- printf("\n");
- fflush(stdout);
- return;
- }
-
- delete pf;
-
- if (should_fail)
- printf("FAILED");
- else
- printf("OK");
- printf("\n");
- fflush(stdout);
+ return os << p.b << ", " << p.d << ", " <<
+ (p.e ? "true" : "false") << " " <<
+ (p.t ? "true" : "false") << ", " <<
+ p.rm << ", " << p.gm << ", " << p.bm << ", "
+ << p.rs << ", " << p.gs << ", " << p.bs;
}
-static void do888Test(bool expected, int b, int d, bool e, bool t,
- int rm, int gm, int bm, int rs, int gs, int bs)
+typedef testing::TestWithParam<Params> PixelFormatValid;
+
+TEST_P(PixelFormatValid, constructor)
{
- rfb::PixelFormat* pf;
+ Params params;
+ rfb::PixelFormat* pf;
+
+ params = GetParam();
+ pf = nullptr;
+
+ EXPECT_NO_THROW({
+ pf = new rfb::PixelFormat(params.b, params.d, params.e, params.t,
+ params.rm, params.gm, params.bm,
+ params.rs, params.gs, params.bs);
+ });
- printf("PixelFormat(%d, %d, %s, %s, %d, %d, %d, %d, %d, %d): ",
- b, d, e ? "true" : "false", t ? "true": "false",
- rm, gm, bm, rs, gs, bs);
+ delete pf;
+}
+
+typedef testing::TestWithParam<Params> PixelFormatInvalid;
+
+TEST_P(PixelFormatInvalid, constructor)
+{
+ Params params;
+ rfb::PixelFormat* pf;
- pf = new rfb::PixelFormat(b, d, e, t, rm, gm, bm, rs, gs, bs);
+ params = GetParam();
+ pf = nullptr;
- if (pf->is888() == expected)
- printf("OK");
- else
- printf("FAILED");
- printf("\n");
- fflush(stdout);
+ EXPECT_THROW({
+ pf = new rfb::PixelFormat(params.b, params.d, params.e, params.t,
+ params.rm, params.gm, params.bm,
+ params.rs, params.gs, params.bs);
+ }, std::invalid_argument);
- delete pf;
+ delete pf;
}
-static void sanityTests()
+typedef testing::TestWithParam<Params> PixelFormatIs888;
+
+TEST_P(PixelFormatIs888, constructor)
{
- printf("Sanity checks:\n\n");
+ Params params;
+ rfb::PixelFormat* pf;
+
+ params = GetParam();
+ pf = new rfb::PixelFormat(params.b, params.d, params.e, params.t,
+ params.rm, params.gm, params.bm,
+ params.rs, params.gs, params.bs);
+ EXPECT_TRUE(pf->is888());
- /* Normal true color formats */
+ delete pf;
+}
- doTest(false, 32, 24, false, true, 255, 255, 255, 0, 8, 16);
- doTest(false, 32, 24, false, true, 255, 255, 255, 24, 16, 8);
+typedef testing::TestWithParam<Params> PixelFormatNot888;
- doTest(false, 16, 16, false, true, 15, 31, 15, 0, 5, 11);
+TEST_P(PixelFormatNot888, constructor)
+{
+ Params params;
+ rfb::PixelFormat* pf;
- doTest(false, 8, 8, false, true, 3, 7, 3, 0, 2, 5);
+ params = GetParam();
+ pf = new rfb::PixelFormat(params.b, params.d, params.e, params.t,
+ params.rm, params.gm, params.bm,
+ params.rs, params.gs, params.bs);
+ EXPECT_FALSE(pf->is888());
- /* Excessive bpp */
+ delete pf;
+}
- doTest(false, 32, 16, false, true, 15, 31, 15, 0, 5, 11);
+static std::list<Params> validFormats()
+{
+ std::list<Params> params;
- doTest(false, 16, 16, false, true, 15, 31, 15, 0, 5, 11);
+ /* Normal true color formats */
- doTest(false, 32, 8, false, true, 3, 7, 3, 0, 2, 5);
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 8, 16});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 24, 16, 8});
- doTest(false, 16, 8, false, true, 3, 7, 3, 0, 2, 5);
+ params.push_back(Params{16, 16, false, true, 15, 31, 15, 0, 5, 11});
- /* Colour map */
+ params.push_back(Params{8, 8, false, true, 3, 7, 3, 0, 2, 5});
- doTest(false, 8, 8, false, false, 0, 0, 0, 0, 0, 0);
+ /* Excessive bpp */
- /* Invalid bpp */
+ params.push_back(Params{32, 16, false, true, 15, 31, 15, 0, 5, 11});
- doTest(true, 64, 24, false, true, 255, 255, 255, 0, 8, 16);
+ params.push_back(Params{16, 16, false, true, 15, 31, 15, 0, 5, 11});
- doTest(true, 18, 16, false, true, 15, 31, 15, 0, 5, 11);
+ params.push_back(Params{32, 8, false, true, 3, 7, 3, 0, 2, 5});
- doTest(true, 3, 3, false, true, 1, 1, 1, 0, 1, 2);
+ params.push_back(Params{16, 8, false, true, 3, 7, 3, 0, 2, 5});
- /* Invalid depth */
+ /* Colour map */
- doTest(true, 16, 24, false, true, 15, 31, 15, 0, 5, 11);
+ params.push_back(Params{8, 8, false, false, 0, 0, 0, 0, 0, 0});
- doTest(true, 8, 24, false, true, 3, 7, 3, 0, 2, 5);
- doTest(true, 8, 16, false, true, 3, 7, 3, 0, 2, 5);
+ return params;
+}
- doTest(true, 32, 24, false, false, 0, 0, 0, 0, 0, 0);
+INSTANTIATE_TEST_SUITE_P(, PixelFormatValid, testing::ValuesIn(validFormats()));
- /* Invalid max values */
+static std::list<Params> invalidFormats()
+{
+ std::list<Params> params;
- doTest(true, 32, 24, false, true, 254, 255, 255, 0, 8, 16);
- doTest(true, 32, 24, false, true, 255, 253, 255, 0, 8, 16);
- doTest(true, 32, 24, false, true, 255, 255, 252, 0, 8, 16);
+ params.push_back(Params{64, 24, false, true, 255, 255, 255, 0, 8, 16});
- doTest(true, 32, 24, false, true, 511, 127, 127, 0, 16, 20);
- doTest(true, 32, 24, false, true, 127, 511, 127, 0, 4, 20);
- doTest(true, 32, 24, false, true, 127, 127, 511, 0, 4, 8);
+ params.push_back(Params{18, 16, false, true, 15, 31, 15, 0, 5, 11});
- /* Insufficient depth */
+ params.push_back(Params{3, 3, false, true, 1, 1, 1, 0, 1, 2});
- doTest(true, 32, 16, false, true, 255, 255, 255, 0, 8, 16);
+ /* Invalid depth */
- /* Invalid shift values */
+ params.push_back(Params{16, 24, false, true, 15, 31, 15, 0, 5, 11});
- doTest(true, 32, 24, false, true, 255, 255, 255, 25, 8, 16);
- doTest(true, 32, 24, false, true, 255, 255, 255, 0, 25, 16);
- doTest(true, 32, 24, false, true, 255, 255, 255, 0, 8, 25);
+ params.push_back(Params{8, 24, false, true, 3, 7, 3, 0, 2, 5});
+ params.push_back(Params{8, 16, false, true, 3, 7, 3, 0, 2, 5});
- /* Overlapping channels */
+ params.push_back(Params{32, 24, false, false, 0, 0, 0, 0, 0, 0});
- doTest(true, 32, 24, false, true, 255, 255, 255, 0, 7, 16);
- doTest(true, 32, 24, false, true, 255, 255, 255, 0, 8, 15);
- doTest(true, 32, 24, false, true, 255, 255, 255, 0, 16, 7);
+ /* Invalid max values */
- printf("\n");
+ params.push_back(Params{32, 24, false, true, 254, 255, 255, 0, 8, 16});
+ params.push_back(Params{32, 24, false, true, 255, 253, 255, 0, 8, 16});
+ params.push_back(Params{32, 24, false, true, 255, 255, 252, 0, 8, 16});
+
+ params.push_back(Params{32, 24, false, true, 511, 127, 127, 0, 16, 20});
+ params.push_back(Params{32, 24, false, true, 127, 511, 127, 0, 4, 20});
+ params.push_back(Params{32, 24, false, true, 127, 127, 511, 0, 4, 8});
+
+ /* Insufficient depth */
+
+ params.push_back(Params{32, 16, false, true, 255, 255, 255, 0, 8, 16});
+
+ /* Invalid shift values */
+
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 25, 8, 16});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 25, 16});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 8, 25});
+
+ /* Overlapping channels */
+
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 7, 16});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 8, 15});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 16, 7});
+
+ return params;
}
-void is888Tests()
+INSTANTIATE_TEST_SUITE_P(, PixelFormatInvalid, testing::ValuesIn(invalidFormats()));
+
+static std::list<Params> is888Formats()
{
- printf("Simple format detection:\n\n");
+ std::list<Params> params;
+
+ /* Positive cases */
+
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 8, 16});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 24, 16, 8});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 24, 8, 0});
+
+ return params;
+}
- /* Positive cases */
+INSTANTIATE_TEST_SUITE_P(, PixelFormatIs888, testing::ValuesIn(is888Formats()));
- do888Test(true, 32, 24, false, true, 255, 255, 255, 0, 8, 16);
- do888Test(true, 32, 24, false, true, 255, 255, 255, 24, 16, 8);
- do888Test(true, 32, 24, false, true, 255, 255, 255, 24, 8, 0);
+static std::list<Params> not888Formats()
+{
+ std::list<Params> params;
- /* Low depth */
+ /* Low depth */
- do888Test(false, 32, 16, false, true, 15, 31, 15, 0, 8, 16);
- do888Test(false, 32, 8, false, true, 3, 7, 3, 0, 8, 16);
+ params.push_back(Params{32, 16, false, true, 15, 31, 15, 0, 8, 16});
+ params.push_back(Params{32, 8, false, true, 3, 7, 3, 0, 8, 16});
- /* Low bpp and depth */
+ /* Low bpp and depth */
- do888Test(false, 16, 16, false, true, 15, 31, 15, 0, 5, 11);
- do888Test(false, 8, 8, false, true, 3, 7, 3, 0, 2, 5);
+ params.push_back(Params{16, 16, false, true, 15, 31, 15, 0, 5, 11});
+ params.push_back(Params{8, 8, false, true, 3, 7, 3, 0, 2, 5});
- /* Colour map */
+ /* Colour map */
- do888Test(false, 8, 8, false, false, 0, 0, 0, 0, 0, 0);
+ params.push_back(Params{8, 8, false, false, 0, 0, 0, 0, 0, 0});
- /* Odd shifts */
+ /* Odd shifts */
- do888Test(false, 32, 24, false, true, 255, 255, 255, 0, 8, 18);
- do888Test(false, 32, 24, false, true, 255, 255, 255, 0, 11, 24);
- do888Test(false, 32, 24, false, true, 255, 255, 255, 4, 16, 24);
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 8, 18});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 0, 11, 24});
+ params.push_back(Params{32, 24, false, true, 255, 255, 255, 4, 16, 24});
- printf("\n");
+ return params;
}
-int main(int /*argc*/, char** /*argv*/)
-{
- sanityTests();
- is888Tests();
+INSTANTIATE_TEST_SUITE_P(, PixelFormatNot888, testing::ValuesIn(not888Formats()));
- return 0;
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tests/unit/shortcuthandler.cxx b/tests/unit/shortcuthandler.cxx
new file mode 100644
index 00000000..aa005155
--- /dev/null
+++ b/tests/unit/shortcuthandler.cxx
@@ -0,0 +1,607 @@
+/* Copyright 2021-2025 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtest/gtest.h>
+
+#define XK_LATIN1
+#define XK_MISCELLANY
+#include <rfb/keysymdef.h>
+
+#include "ShortcutHandler.h"
+
+TEST(ShortcutHandler, noModifiers)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(0);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_a), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Hyper_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, singleArmed)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyUnarm);
+}
+
+TEST(ShortcutHandler, singleDualArmed)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyUnarm);
+}
+
+TEST(ShortcutHandler, singleShortcut)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, singleRightShortcut)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, singleDualShortcut)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, singleShortcutReordered)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyShortcut);
+}
+
+TEST(ShortcutHandler, singleDualShortcutReordered)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_R), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, singleShortcutRepeated)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, singleShortcutMultipleKeys)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_b), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_c), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, singleWedgeNormal)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_b), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_a), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, singleWedgeModifier)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_a), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, singleWedgeModifierArmed)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_a), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, singleWedgeModifierFiring)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, singleUnwedge)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control);
+
+ handler.handleKeyPress(1, XK_Shift_L);
+ handler.handleKeyPress(2, XK_Control_L);
+ handler.handleKeyRelease(1);
+ handler.handleKeyRelease(2);
+
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, multiArmed)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyUnarm);
+}
+
+TEST(ShortcutHandler, multiRearmed)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyUnarm);
+}
+
+TEST(ShortcutHandler, multiFailedArm)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, multiDualArmed)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Alt_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyUnarm);
+}
+
+TEST(ShortcutHandler, multiShortcut)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, multiRightShortcut)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, multiDualShortcut)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Alt_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(6, XK_Shift_R), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(7, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(7), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(6), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, multiShortcutReordered)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyShortcut);
+}
+
+TEST(ShortcutHandler, multiDualShortcutReordered)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(7, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_R), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Alt_R), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyPress(6, XK_Shift_R), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(6), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(7), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, multiShortcutRepeated)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, multiShortcutMultipleKeys)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_b), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyPress(6, XK_c), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(6), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, multiWedgeNormal)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_b), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_a), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, multiWedgeModifier)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Super_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_a), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, multiWedgeArming)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(1, XK_b), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_a), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, multiWedgeModifierArming)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Super_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, multiWedgeModifierArmed)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Super_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyNormal);
+}
+
+TEST(ShortcutHandler, multiWedgeModifierFiring)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ EXPECT_EQ(handler.handleKeyPress(1, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_Super_L), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(1), ShortcutHandler::KeyIgnore);
+}
+
+TEST(ShortcutHandler, multiUnwedge)
+{
+ ShortcutHandler handler;
+
+ handler.setModifiers(ShortcutHandler::Control |
+ ShortcutHandler::Shift |
+ ShortcutHandler::Alt);
+
+ handler.handleKeyPress(1, XK_Super_L);
+ handler.handleKeyPress(2, XK_Control_L);
+ handler.handleKeyPress(3, XK_Alt_L);
+ handler.handleKeyPress(4, XK_Shift_L);
+ handler.handleKeyRelease(1);
+ handler.handleKeyRelease(2);
+ handler.handleKeyRelease(3);
+ handler.handleKeyRelease(4);
+
+ EXPECT_EQ(handler.handleKeyPress(2, XK_Control_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(3, XK_Alt_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(4, XK_Shift_L), ShortcutHandler::KeyNormal);
+ EXPECT_EQ(handler.handleKeyPress(5, XK_a), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(5), ShortcutHandler::KeyShortcut);
+ EXPECT_EQ(handler.handleKeyRelease(4), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(3), ShortcutHandler::KeyIgnore);
+ EXPECT_EQ(handler.handleKeyRelease(2), ShortcutHandler::KeyIgnore);
+}
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tests/unit/unicode.cxx b/tests/unit/unicode.cxx
index 71815042..00e09c15 100644
--- a/tests/unit/unicode.cxx
+++ b/tests/unit/unicode.cxx
@@ -1,4 +1,4 @@
-/* Copyright 2020 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2020-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,11 +20,12 @@
#include <config.h>
#endif
-#include <stdio.h>
#include <string.h>
#include <wchar.h>
-#include <rfb/util.h>
+#include <gtest/gtest.h>
+
+#include <core/string.h>
struct _ucs4utf8 {
unsigned ucs4;
@@ -112,149 +113,138 @@ const wchar_t *invalidutf16[] = {
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a))
-int main(int /*argc*/, char** /*argv*/)
+TEST(Unicode, ucs4ToUTF8)
{
- int failures;
- size_t i;
+ size_t i;
+ for (i = 0;i < ARRAY_SIZE(ucs4utf8);i++) {
+ size_t len;
+ char utf8[5];
+
+ /* Expected failure? */
+ if (ucs4utf8[i].ucs4 == 0xfffd)
+ continue;
+
+ len = core::ucs4ToUTF8(ucs4utf8[i].ucs4, utf8);
+ EXPECT_STREQ(utf8, ucs4utf8[i].utf8);
+ EXPECT_EQ(len, strlen(utf8));
+ }
+}
+TEST(Unicode, utf8ToUCS4)
+{
+ size_t i;
+ for (i = 0;i < ARRAY_SIZE(ucs4utf8);i++) {
+ size_t len;
unsigned ucs4;
- char utf8[5];
+
+ /* Expected failure? */
+ if (strcmp(ucs4utf8[i].utf8, "\xef\xbf\xbd") == 0)
+ continue;
+
+ len = core::utf8ToUCS4(ucs4utf8[i].utf8, strlen(ucs4utf8[i].utf8), &ucs4);
+ EXPECT_EQ(ucs4, ucs4utf8[i].ucs4);
+ EXPECT_EQ(len, strlen(ucs4utf8[i].utf8));
+ }
+}
+
+TEST(Unicode, ucs4ToUTF16)
+{
+ size_t i;
+ for (i = 0;i < ARRAY_SIZE(ucs4utf16);i++) {
+ size_t len;
wchar_t utf16[3];
- std::string out;
- std::wstring wout;
+
+ /* Expected failure? */
+ if (ucs4utf16[i].ucs4 == 0xfffd)
+ continue;
+
+ len = core::ucs4ToUTF16(ucs4utf16[i].ucs4, utf16);
+ EXPECT_STREQ(utf16, ucs4utf16[i].utf16);
+ EXPECT_EQ(len, wcslen(utf16));
+ }
+}
+
+TEST(Unicode, utf16ToUCS4)
+{
+ size_t i;
+ for (i = 0;i < ARRAY_SIZE(ucs4utf16);i++) {
size_t len;
+ unsigned ucs4;
- failures = 0;
-
- for (i = 0;i < ARRAY_SIZE(ucs4utf8);i++) {
- /* Expected failure? */
- if (ucs4utf8[i].ucs4 == 0xfffd)
- continue;
-
- len = rfb::ucs4ToUTF8(ucs4utf8[i].ucs4, utf8);
- if ((len != strlen(utf8)) ||
- (strcmp(utf8, ucs4utf8[i].utf8) != 0)) {
- printf("FAILED: ucs4ToUTF8() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(ucs4utf8);i++) {
- /* Expected failure? */
- if (strcmp(ucs4utf8[i].utf8, "\xef\xbf\xbd") == 0)
- continue;
-
- len = rfb::utf8ToUCS4(ucs4utf8[i].utf8, strlen(ucs4utf8[i].utf8), &ucs4);
- if ((len != strlen(ucs4utf8[i].utf8)) ||
- (ucs4 != ucs4utf8[i].ucs4)) {
- printf("FAILED: utf8ToUCS4() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(ucs4utf16);i++) {
- /* Expected failure? */
- if (ucs4utf16[i].ucs4 == 0xfffd)
- continue;
-
- len = rfb::ucs4ToUTF16(ucs4utf16[i].ucs4, utf16);
- if ((len != wcslen(utf16)) ||
- (wcscmp(utf16, ucs4utf16[i].utf16) != 0)) {
- printf("FAILED: ucs4ToUTF16() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(ucs4utf16);i++) {
- /* Expected failure? */
- if (wcscmp(ucs4utf16[i].utf16, L"\xfffd") == 0)
- continue;
-
- len = rfb::utf16ToUCS4(ucs4utf16[i].utf16, wcslen(ucs4utf16[i].utf16), &ucs4);
- if ((len != wcslen(ucs4utf16[i].utf16)) ||
- (ucs4 != ucs4utf16[i].ucs4)) {
- printf("FAILED: utf16ToUCS4() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(latin1utf8);i++) {
- /* Expected failure? */
- if (strchr(latin1utf8[i].latin1, '?') != nullptr)
- continue;
-
- out = rfb::latin1ToUTF8(latin1utf8[i].latin1);
- if (out != latin1utf8[i].utf8) {
- printf("FAILED: latin1ToUTF8() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(latin1utf8);i++) {
- out = rfb::utf8ToLatin1(latin1utf8[i].utf8);
- if (out != latin1utf8[i].latin1) {
- printf("FAILED: utf8ToLatin1() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(utf8utf16);i++) {
- /* Expected failure? */
- if (wcscmp(utf8utf16[i].utf16, L"\xfffd") == 0)
- continue;
-
- out = rfb::utf16ToUTF8(utf8utf16[i].utf16);
- if (out != utf8utf16[i].utf8) {
- printf("FAILED: utf16ToUTF8() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(utf8utf16);i++) {
- /* Expected failure? */
- if (strstr(utf8utf16[i].utf8, "\xef\xbf\xbd") != nullptr)
- continue;
-
- wout = rfb::utf8ToUTF16(utf8utf16[i].utf8);
- if (wout != utf8utf16[i].utf16) {
- printf("FAILED: utf8ToUTF16() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(validutf8);i++) {
- if (!rfb::isValidUTF8(validutf8[i])) {
- printf("FAILED: isValidUTF8() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(invalidutf8);i++) {
- if (rfb::isValidUTF8(invalidutf8[i])) {
- printf("FAILED: ! isValidUTF8() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(validutf16);i++) {
- if (!rfb::isValidUTF16(validutf16[i])) {
- printf("FAILED: isValidUTF16() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- for (i = 0;i < ARRAY_SIZE(invalidutf16);i++) {
- if (rfb::isValidUTF16(invalidutf16[i])) {
- printf("FAILED: ! isValidUTF16() #%d\n", (int)i+1);
- failures++;
- }
- }
-
- if (failures == 0) {
- printf("OK\n");
- } else {
- printf("FAIL: %d failures\n", failures);
- }
-
- return 0;
+ /* Expected failure? */
+ if (wcscmp(ucs4utf16[i].utf16, L"\xfffd") == 0)
+ continue;
+
+ len = core::utf16ToUCS4(ucs4utf16[i].utf16, wcslen(ucs4utf16[i].utf16), &ucs4);
+ EXPECT_EQ(ucs4, ucs4utf16[i].ucs4);
+ EXPECT_EQ(len, wcslen(ucs4utf16[i].utf16));
+ }
+}
+
+TEST(Unicode, latin1ToUTF8)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(latin1utf8); i++) {
+ /* Expected failure? */
+ if (strchr(latin1utf8[i].latin1, '?') != nullptr)
+ continue;
+
+ EXPECT_EQ(core::latin1ToUTF8(latin1utf8[i].latin1), latin1utf8[i].utf8);
+ }
+}
+
+TEST(Unicode, utf8ToLatin1)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(latin1utf8); i++)
+ EXPECT_EQ(core::utf8ToLatin1(latin1utf8[i].utf8), latin1utf8[i].latin1);
+}
+
+TEST(Unicode, utf16ToUTF8)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(utf8utf16); i++) {
+ /* Expected failure? */
+ if (wcscmp(utf8utf16[i].utf16, L"\xfffd") == 0)
+ continue;
+
+ EXPECT_EQ(core::utf16ToUTF8(utf8utf16[i].utf16), utf8utf16[i].utf8);
+ }
+}
+
+TEST(Unicode, utf8ToUTF16)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(utf8utf16); i++) {
+ /* Expected failure? */
+ if (strstr(utf8utf16[i].utf8, "\xef\xbf\xbd") != nullptr)
+ continue;
+
+ EXPECT_EQ(core::utf8ToUTF16(utf8utf16[i].utf8), utf8utf16[i].utf16);
+ }
+}
+
+TEST(Unicode, isValidUTF8)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(validutf8); i++)
+ EXPECT_TRUE(core::isValidUTF8(validutf8[i]));
+ for (i = 0; i < ARRAY_SIZE(invalidutf8); i++)
+ EXPECT_FALSE(core::isValidUTF8(invalidutf8[i]));
+}
+
+TEST(Unicode, isValidUTF16)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(validutf16); i++)
+ EXPECT_TRUE(core::isValidUTF16(validutf16[i]));
+ for (i = 0; i < ARRAY_SIZE(invalidutf16); i++)
+ EXPECT_FALSE(core::isValidUTF16(invalidutf16[i]));
+}
+
+int main(int argc, char** argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/unix/common/CMakeLists.txt b/unix/common/CMakeLists.txt
index 87e2ae79..72662fdb 100644
--- a/unix/common/CMakeLists.txt
+++ b/unix/common/CMakeLists.txt
@@ -3,6 +3,7 @@ add_library(unixcommon STATIC
target_include_directories(unixcommon PUBLIC ${CMAKE_SOURCE_DIR}/common)
target_include_directories(unixcommon PUBLIC ${CMAKE_SOURCE_DIR}/unix/common)
+target_link_libraries(unixcommon core rfb)
if(UNIX)
libtool_create_control_file(unixcommon)
diff --git a/unix/common/randr.cxx b/unix/common/randr.cxx
index e4e2d7be..7f38f3c0 100644
--- a/unix/common/randr.cxx
+++ b/unix/common/randr.cxx
@@ -26,10 +26,15 @@
#include <stdlib.h>
#include <unixcommon.h>
+
+#include <core/LogWriter.h>
+
#include <rfb/screenTypes.h>
-#include <rfb/LogWriter.h>
+#include <rfb/ScreenSet.h>
+
#include <RandrGlue.h>
-static rfb::LogWriter vlog("RandR");
+
+static core::LogWriter vlog("RandR");
static int ResizeScreen(bool dryrun, int fb_width, int fb_height,
std::set<unsigned int>* disabledOutputs)
diff --git a/unix/common/unixcommon.h b/unix/common/unixcommon.h
index d04c3ae9..1f6cd8eb 100644
--- a/unix/common/unixcommon.h
+++ b/unix/common/unixcommon.h
@@ -20,9 +20,12 @@
#ifndef UNIXCOMMON_H
#define UNIXCOMMON_H
+#include <stdint.h>
+
#include <map>
+#include <set>
-#include <rfb/ScreenSet.h>
+namespace rfb { struct ScreenSet; }
typedef std::map<unsigned int, uint32_t> OutputIdMap;
diff --git a/unix/tx/CMakeLists.txt b/unix/tx/CMakeLists.txt
index e28621a6..4967f1bc 100644
--- a/unix/tx/CMakeLists.txt
+++ b/unix/tx/CMakeLists.txt
@@ -6,4 +6,4 @@ target_include_directories(tx SYSTEM PUBLIC ${X11_INCLUDE_DIR})
target_include_directories(tx PUBLIC ${CMAKE_SOURCE_DIR}/common)
target_include_directories(tx PUBLIC ${CMAKE_SOURCE_DIR}/common/rfb)
-target_link_libraries(tx ${X11_LIBRARIES})
+target_link_libraries(tx core ${X11_LIBRARIES})
diff --git a/unix/tx/TXButton.h b/unix/tx/TXButton.h
index 88964833..f94561e3 100644
--- a/unix/tx/TXButton.h
+++ b/unix/tx/TXButton.h
@@ -26,8 +26,9 @@
#ifndef __TXBUTTON_H__
#define __TXBUTTON_H__
+#include <algorithm>
+
#include "TXWindow.h"
-#include <rfb/util.h>
// TXButtonCallback's buttonActivate() method is called when a button is
// activated.
@@ -63,8 +64,8 @@ public:
text = text_;
int textWidth = XTextWidth(defaultFS, text.data(), text.size());
int textHeight = (defaultFS->ascent + defaultFS->descent);
- int newWidth = __rfbmax(width(), textWidth + xPad*2 + bevel*2);
- int newHeight = __rfbmax(height(), textHeight + yPad*2 + bevel*2);
+ int newWidth = std::max(width(), textWidth + xPad*2 + bevel*2);
+ int newHeight = std::max(height(), textHeight + yPad*2 + bevel*2);
if (width() < newWidth || height() < newHeight) {
resize(newWidth, newHeight);
}
diff --git a/unix/tx/TXCheckbox.h b/unix/tx/TXCheckbox.h
index 179e3e84..64d56074 100644
--- a/unix/tx/TXCheckbox.h
+++ b/unix/tx/TXCheckbox.h
@@ -33,8 +33,9 @@
#ifndef __TXCHECKBOX_H__
#define __TXCHECKBOX_H__
+#include <algorithm>
+
#include "TXWindow.h"
-#include <rfb/util.h>
// TXCheckboxCallback's checkboxSelect() method is called when the state of a
// checkbox changes.
@@ -72,8 +73,8 @@ public:
text = strdup((char*)text_);
int textWidth = XTextWidth(defaultFS, text, strlen(text));
int textHeight = (defaultFS->ascent + defaultFS->descent);
- int newWidth = __rfbmax(width(), textWidth + xPad*2 + boxPad*2 + boxSize);
- int newHeight = __rfbmax(height(), textHeight + yPad*2);
+ int newWidth = std::max(width(), textWidth + xPad*2 + boxPad*2 + boxSize);
+ int newHeight = std::max(height(), textHeight + yPad*2);
if (width() < newWidth || height() < newHeight) {
resize(newWidth, newHeight);
}
diff --git a/unix/tx/TXDialog.h b/unix/tx/TXDialog.h
index 6533377f..a04f0742 100644
--- a/unix/tx/TXDialog.h
+++ b/unix/tx/TXDialog.h
@@ -28,7 +28,7 @@
#ifndef __TXDIALOG_H__
#define __TXDIALOG_H__
-#include <rdr/Exception.h>
+#include <core/Exception.h>
#include "TXWindow.h"
#include <errno.h>
@@ -65,7 +65,7 @@ public:
FD_ZERO(&rfds);
FD_SET(ConnectionNumber(dpy), &rfds);
int n = select(FD_SETSIZE, &rfds, nullptr, nullptr, nullptr);
- if (n < 0) throw rdr::socket_error("select", errno);
+ if (n < 0) throw core::socket_error("select", errno);
}
}
return true;
diff --git a/unix/tx/TXLabel.h b/unix/tx/TXLabel.h
index 1e0cc0e5..3d8245d2 100644
--- a/unix/tx/TXLabel.h
+++ b/unix/tx/TXLabel.h
@@ -27,8 +27,11 @@
#define __TXLABEL_H__
#include <stdlib.h>
+
+#include <algorithm>
+
#include "TXWindow.h"
-#include <rfb/util.h>
+#include <core/string.h>
class TXLabel : public TXWindow, public TXEventHandler {
public:
@@ -63,8 +66,8 @@ public:
} while (i < text.size());
int textHeight = ((defaultFS->ascent + defaultFS->descent + lineSpacing)
* lines);
- int newWidth = __rfbmax(width(), textWidth + xPad*2);
- int newHeight = __rfbmax(height(), textHeight + yPad*2);
+ int newWidth = std::max(width(), textWidth + xPad*2);
+ int newHeight = std::max(height(), textHeight + yPad*2);
if (width() < newWidth || height() < newHeight) {
resize(newWidth, newHeight);
}
diff --git a/unix/vncconfig/CMakeLists.txt b/unix/vncconfig/CMakeLists.txt
index 0589f161..4882dc71 100644
--- a/unix/vncconfig/CMakeLists.txt
+++ b/unix/vncconfig/CMakeLists.txt
@@ -9,7 +9,7 @@ target_include_directories(vncconfig SYSTEM PUBLIC ${X11_INCLUDE_DIR})
target_include_directories(vncconfig PUBLIC ${CMAKE_SOURCE_DIR}/common)
target_include_directories(vncconfig PUBLIC ${CMAKE_SOURCE_DIR}/unix/tx)
-target_link_libraries(vncconfig tx rfb network rdr ${X11_LIBRARIES})
+target_link_libraries(vncconfig core tx rfb ${X11_LIBRARIES})
install(TARGETS vncconfig DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
install(FILES vncconfig.man DESTINATION ${CMAKE_INSTALL_FULL_MANDIR}/man1 RENAME vncconfig.1)
diff --git a/unix/vncconfig/QueryConnectDialog.cxx b/unix/vncconfig/QueryConnectDialog.cxx
index a265356f..1d495ea5 100644
--- a/unix/vncconfig/QueryConnectDialog.cxx
+++ b/unix/vncconfig/QueryConnectDialog.cxx
@@ -21,7 +21,9 @@
#endif
#include <stdio.h>
-#include <rdr/Exception.h>
+
+#include <algorithm>
+
#include "QueryConnectDialog.h"
#include "vncExt.h"
@@ -43,7 +45,7 @@ QueryConnectDialog::QueryConnectDialog(Display* dpy_,
{
const int pad = 4;
int y=pad;
- int lblWidth = __rfbmax(addressLbl.width(), userLbl.width());
+ int lblWidth = std::max(addressLbl.width(), userLbl.width());
userLbl.move(pad+lblWidth-userLbl.width(), y);
user.move(pad+lblWidth, y);
addressLbl.move(pad+lblWidth-addressLbl.width(), y+=userLbl.height());
@@ -51,9 +53,9 @@ QueryConnectDialog::QueryConnectDialog(Display* dpy_,
timeoutLbl.move(pad, y+=addressLbl.height());
timeout.move(pad+timeoutLbl.width(), y);
accept.move(pad, y+=addressLbl.height());
- int maxWidth = __rfbmax(user.width(), address.width()+pad+lblWidth);
- maxWidth = __rfbmax(maxWidth, accept.width()*3);
- maxWidth = __rfbmax(maxWidth, timeoutLbl.width()+timeout.width()+pad);
+ int maxWidth = std::max(user.width(), address.width()+pad+lblWidth);
+ maxWidth = std::max(maxWidth, accept.width()*3);
+ maxWidth = std::max(maxWidth, timeoutLbl.width()+timeout.width()+pad);
reject.move(maxWidth-reject.width(), y);
resize(maxWidth + pad, y+reject.height()+pad);
setBorderWidth(1);
@@ -74,7 +76,8 @@ void QueryConnectDialog::buttonActivate(TXButton* b) {
callback->queryRejected();
}
-void QueryConnectDialog::handleTimeout(rfb::Timer* t) {
+void QueryConnectDialog::handleTimeout(core::Timer* t)
+{
if (timeUntilReject-- == 0) {
unmap();
callback->queryTimedOut();
diff --git a/unix/vncconfig/QueryConnectDialog.h b/unix/vncconfig/QueryConnectDialog.h
index 5763e1ce..7e9450b0 100644
--- a/unix/vncconfig/QueryConnectDialog.h
+++ b/unix/vncconfig/QueryConnectDialog.h
@@ -19,7 +19,8 @@
#ifndef __QUERYCONNECTDIALOG_H__
#define __QUERYCONNECTDIALOG_H__
-#include <rfb/Timer.h>
+#include <core/Timer.h>
+
#include "TXLabel.h"
#include "TXButton.h"
#include "TXDialog.h"
@@ -34,7 +35,7 @@ class QueryResultCallback {
class QueryConnectDialog : public TXDialog, public TXEventHandler,
public TXButtonCallback,
- public rfb::Timer::Callback
+ public core::Timer::Callback
{
public:
QueryConnectDialog(Display* dpy, const char* address_,
@@ -43,14 +44,14 @@ class QueryConnectDialog : public TXDialog, public TXEventHandler,
void handleEvent(TXWindow*, XEvent* ) override { }
void deleteWindow(TXWindow*) override;
void buttonActivate(TXButton* b) override;
- void handleTimeout(rfb::Timer* t) override;
+ void handleTimeout(core::Timer* t) override;
private:
void refreshTimeout();
TXLabel addressLbl, address, userLbl, user, timeoutLbl, timeout;
TXButton accept, reject;
QueryResultCallback* callback;
int timeUntilReject;
- rfb::Timer timer;
+ core::Timer timer;
};
#endif
diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c
index 4ec671b8..482af829 100644
--- a/unix/vncconfig/vncExt.c
+++ b/unix/vncconfig/vncExt.c
@@ -55,22 +55,26 @@ Bool XVncExtQueryExtension(Display* dpy, int* event_basep, int* error_basep)
return True;
}
-Bool XVncExtSetParam(Display* dpy, const char* param)
+Bool XVncExtSetParam(Display* dpy, const char* param, const char* value)
{
xVncExtSetParamReq* req;
xVncExtSetParamReply rep;
int paramLen = strlen(param);
- if (paramLen > 255) return False;
+ if (paramLen > 65535) return False;
+ int valueLen = strlen(value);
+ if (valueLen > 65535) return False;
if (!checkExtension(dpy)) return False;
LockDisplay(dpy);
GetReq(VncExtSetParam, req);
req->reqType = codes->major_opcode;
req->vncExtReqType = X_VncExtSetParam;
- req->length += (paramLen + 3) >> 2;
+ req->length += ((paramLen + 3) >> 2) + ((valueLen + 3) >> 2);
req->paramLen = paramLen;
+ req->valueLen = valueLen;
Data(dpy, param, paramLen);
+ Data(dpy, value, valueLen);
if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
UnlockDisplay(dpy);
SyncHandle();
diff --git a/unix/vncconfig/vncExt.h b/unix/vncconfig/vncExt.h
index 5de1685d..ca8df699 100644
--- a/unix/vncconfig/vncExt.h
+++ b/unix/vncconfig/vncExt.h
@@ -40,7 +40,7 @@ extern "C" {
#ifndef _VNCEXT_SERVER_
Bool XVncExtQueryExtension(Display* dpy, int* event_basep, int* error_basep);
-Bool XVncExtSetParam(Display* dpy, const char* param);
+Bool XVncExtSetParam(Display* dpy, const char* param, const char* value);
Bool XVncExtGetParam(Display* dpy, const char* param, char** value, int* len);
char* XVncExtGetParamDesc(Display* dpy, const char* param);
char** XVncExtListParams(Display* dpy, int* nParams);
@@ -69,24 +69,23 @@ typedef struct {
typedef struct {
CARD8 reqType; /* always VncExtReqCode */
CARD8 vncExtReqType; /* always VncExtSetParam */
- CARD16 length B16;
- CARD8 paramLen;
- CARD8 pad0;
- CARD16 pad1 B16;
+ CARD16 length;
+ CARD16 paramLen;
+ CARD16 valueLen;
} xVncExtSetParamReq;
#define sz_xVncExtSetParamReq 8
typedef struct {
BYTE type; /* X_Reply */
BYTE success;
- CARD16 sequenceNumber B16;
- CARD32 length B32;
- CARD32 pad0 B32;
- CARD32 pad1 B32;
- CARD32 pad2 B32;
- CARD32 pad3 B32;
- CARD32 pad4 B32;
- CARD32 pad5 B32;
+ CARD16 sequenceNumber;
+ CARD32 length;
+ CARD32 pad0;
+ CARD32 pad1;
+ CARD32 pad2;
+ CARD32 pad3;
+ CARD32 pad4;
+ CARD32 pad5;
} xVncExtSetParamReply;
#define sz_xVncExtSetParamReply 32
@@ -94,25 +93,25 @@ typedef struct {
typedef struct {
CARD8 reqType; /* always VncExtReqCode */
CARD8 vncExtReqType; /* always VncExtGetParam */
- CARD16 length B16;
+ CARD16 length;
CARD8 paramLen;
CARD8 pad0;
- CARD16 pad1 B16;
+ CARD16 pad1;
} xVncExtGetParamReq;
#define sz_xVncExtGetParamReq 8
typedef struct {
BYTE type; /* X_Reply */
BYTE success;
- CARD16 sequenceNumber B16;
- CARD32 length B32;
- CARD16 valueLen B16;
- CARD16 pad0 B16;
- CARD32 pad1 B32;
- CARD32 pad2 B32;
- CARD32 pad3 B32;
- CARD32 pad4 B32;
- CARD32 pad5 B32;
+ CARD16 sequenceNumber;
+ CARD32 length;
+ CARD16 valueLen;
+ CARD16 pad0;
+ CARD32 pad1;
+ CARD32 pad2;
+ CARD32 pad3;
+ CARD32 pad4;
+ CARD32 pad5;
} xVncExtGetParamReply;
#define sz_xVncExtGetParamReply 32
@@ -120,25 +119,25 @@ typedef struct {
typedef struct {
CARD8 reqType; /* always VncExtReqCode */
CARD8 vncExtReqType; /* always VncExtGetParamDesc */
- CARD16 length B16;
+ CARD16 length;
CARD8 paramLen;
CARD8 pad0;
- CARD16 pad1 B16;
+ CARD16 pad1;
} xVncExtGetParamDescReq;
#define sz_xVncExtGetParamDescReq 8
typedef struct {
BYTE type; /* X_Reply */
BYTE success;
- CARD16 sequenceNumber B16;
- CARD32 length B32;
- CARD16 descLen B16;
- CARD16 pad0 B16;
- CARD32 pad1 B32;
- CARD32 pad2 B32;
- CARD32 pad3 B32;
- CARD32 pad4 B32;
- CARD32 pad5 B32;
+ CARD16 sequenceNumber;
+ CARD32 length;
+ CARD16 descLen;
+ CARD16 pad0;
+ CARD32 pad1;
+ CARD32 pad2;
+ CARD32 pad3;
+ CARD32 pad4;
+ CARD32 pad5;
} xVncExtGetParamDescReply;
#define sz_xVncExtGetParamDescReply 32
@@ -146,22 +145,22 @@ typedef struct {
typedef struct {
CARD8 reqType; /* always VncExtReqCode */
CARD8 vncExtReqType; /* always VncExtListParams */
- CARD16 length B16;
+ CARD16 length;
} xVncExtListParamsReq;
#define sz_xVncExtListParamsReq 4
typedef struct {
BYTE type; /* X_Reply */
BYTE pad0;
- CARD16 sequenceNumber B16;
- CARD32 length B32;
- CARD16 nParams B16;
- CARD16 pad1 B16;
- CARD32 pad2 B32;
- CARD32 pad3 B32;
- CARD32 pad4 B32;
- CARD32 pad5 B32;
- CARD32 pad6 B32;
+ CARD16 sequenceNumber;
+ CARD32 length;
+ CARD16 nParams;
+ CARD16 pad1;
+ CARD32 pad2;
+ CARD32 pad3;
+ CARD32 pad4;
+ CARD32 pad5;
+ CARD32 pad6;
} xVncExtListParamsReply;
#define sz_xVncExtListParamsReply 32
@@ -169,9 +168,9 @@ typedef struct {
typedef struct {
CARD8 reqType; /* always VncExtReqCode */
CARD8 vncExtReqType; /* always VncExtSelectInput */
- CARD16 length B16;
- CARD32 window B32;
- CARD32 mask B32;
+ CARD16 length;
+ CARD32 window;
+ CARD32 mask;
} xVncExtSelectInputReq;
#define sz_xVncExtSelectInputReq 12
@@ -179,24 +178,24 @@ typedef struct {
typedef struct {
CARD8 reqType; /* always VncExtReqCode */
CARD8 vncExtReqType; /* always VncExtConnect */
- CARD16 length B16;
+ CARD16 length;
CARD8 strLen;
CARD8 viewOnly;
- CARD16 pad1 B16;
+ CARD16 pad1;
} xVncExtConnectReq;
#define sz_xVncExtConnectReq 8
typedef struct {
BYTE type; /* X_Reply */
BYTE success;
- CARD16 sequenceNumber B16;
- CARD32 length B32;
- CARD32 pad0 B32;
- CARD32 pad1 B32;
- CARD32 pad2 B32;
- CARD32 pad3 B32;
- CARD32 pad4 B32;
- CARD32 pad5 B32;
+ CARD16 sequenceNumber;
+ CARD32 length;
+ CARD32 pad0;
+ CARD32 pad1;
+ CARD32 pad2;
+ CARD32 pad3;
+ CARD32 pad4;
+ CARD32 pad5;
} xVncExtConnectReply;
#define sz_xVncExtConnectReply 32
@@ -204,32 +203,32 @@ typedef struct {
typedef struct {
CARD8 reqType; /* always VncExtReqCode */
CARD8 vncExtReqType; /* always VncExtGetQueryConnect */
- CARD16 length B16;
+ CARD16 length;
} xVncExtGetQueryConnectReq;
#define sz_xVncExtGetQueryConnectReq 4
typedef struct {
BYTE type; /* X_Reply */
BYTE pad0;
- CARD16 sequenceNumber B16;
- CARD32 length B32;
- CARD32 addrLen B32;
- CARD32 userLen B32;
- CARD32 timeout B32;
- CARD32 opaqueId B32;
- CARD32 pad4 B32;
- CARD32 pad5 B32;
+ CARD16 sequenceNumber;
+ CARD32 length;
+ CARD32 addrLen;
+ CARD32 userLen;
+ CARD32 timeout;
+ CARD32 opaqueId;
+ CARD32 pad4;
+ CARD32 pad5;
} xVncExtGetQueryConnectReply;
#define sz_xVncExtGetQueryConnectReply 32
typedef struct {
CARD8 reqType; /* always VncExtReqCode */
CARD8 vncExtReqType; /* always VncExtApproveConnect */
- CARD16 length B16;
+ CARD16 length;
CARD8 approve;
CARD8 pad0;
CARD16 pad1;
- CARD32 opaqueId B32;
+ CARD32 opaqueId;
} xVncExtApproveConnectReq;
#define sz_xVncExtApproveConnectReq 12
@@ -238,14 +237,14 @@ typedef struct {
typedef struct {
BYTE type; /* always eventBase + VncExtQueryConnectNotify */
BYTE pad0;
- CARD16 sequenceNumber B16;
- CARD32 window B32;
- CARD32 pad6 B32;
- CARD32 pad1 B32;
- CARD32 pad2 B32;
- CARD32 pad3 B32;
- CARD32 pad4 B32;
- CARD32 pad5 B32;
+ CARD16 sequenceNumber;
+ CARD32 window;
+ CARD32 pad6;
+ CARD32 pad1;
+ CARD32 pad2;
+ CARD32 pad3;
+ CARD32 pad4;
+ CARD32 pad5;
} xVncExtQueryConnectNotifyEvent;
#define sz_xVncExtQueryConnectNotifyEvent 32
diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx
index bacbfb3f..b1a5232b 100644
--- a/unix/vncconfig/vncconfig.cxx
+++ b/unix/vncconfig/vncconfig.cxx
@@ -39,22 +39,22 @@
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include "vncExt.h"
-#include <rdr/Exception.h>
-#include <rfb/Configuration.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/LogWriter.h>
+
+#include <core/Configuration.h>
+#include <core/Exception.h>
+#include <core/Logger_stdio.h>
+#include <core/LogWriter.h>
+
#include "TXWindow.h"
#include "TXCheckbox.h"
#include "TXLabel.h"
#include "QueryConnectDialog.h"
-using namespace rfb;
-
-static LogWriter vlog("vncconfig");
+static core::LogWriter vlog("vncconfig");
-StringParameter displayname("display", "The X display", "");
-BoolParameter noWindow("nowin", "Don't display a window", 0);
-BoolParameter iconic("iconic", "Start with window iconified", 0);
+core::StringParameter displayname("display", "The X display", "");
+core::BoolParameter noWindow("nowin", "Don't display a window", 0);
+core::BoolParameter iconic("iconic", "Start with window iconified", 0);
#define ACCEPT_CUT_TEXT "AcceptCutText"
#define SEND_CUT_TEXT "SendCutText"
@@ -141,19 +141,19 @@ public:
// TXCheckboxCallback method
void checkboxSelect(TXCheckbox* checkbox) override {
if (checkbox == &acceptClipboard) {
- XVncExtSetParam(dpy, (acceptClipboard.checked()
- ? ACCEPT_CUT_TEXT "=1" : ACCEPT_CUT_TEXT "=0"));
+ XVncExtSetParam(dpy, ACCEPT_CUT_TEXT,
+ acceptClipboard.checked() ? "1" : "0");
setPrimaryCB.disabled(!acceptClipboard.checked());
} else if (checkbox == &sendClipboard) {
- XVncExtSetParam(dpy, (sendClipboard.checked()
- ? SEND_CUT_TEXT "=1" : SEND_CUT_TEXT "=0"));
+ XVncExtSetParam(dpy, SEND_CUT_TEXT,
+ sendClipboard.checked() ? "1" : "0");
sendPrimaryCB.disabled(!sendClipboard.checked());
} else if (checkbox == &setPrimaryCB) {
- XVncExtSetParam(dpy, (setPrimaryCB.checked()
- ? SET_PRIMARY "=1" : SET_PRIMARY "=0"));
+ XVncExtSetParam(dpy, SET_PRIMARY,
+ setPrimaryCB.checked() ? "1" : "0");
} else if (checkbox == &sendPrimaryCB) {
- XVncExtSetParam(dpy, (sendPrimaryCB.checked()
- ? SEND_PRIMARY "=1" : SEND_PRIMARY "=0"));
+ XVncExtSetParam(dpy, SEND_PRIMARY,
+ sendPrimaryCB.checked() ? "1" : "0");
}
}
@@ -192,7 +192,7 @@ static void usage()
"Other valid forms are <param>=<value> -<param>=<value> "
"--<param>=<value>\n"
"Parameter names are case-insensitive. The parameters are:\n\n");
- Configuration::listParams(79, 14);
+ core::Configuration::listParams(79, 14);
exit(1);
}
@@ -207,21 +207,30 @@ void removeArgs(int* argc, char** argv, int first, int n)
int main(int argc, char** argv)
{
programName = argv[0];
- rfb::initStdIOLoggers();
- rfb::LogWriter::setLogParams("*:stderr:30");
+ core::initStdIOLoggers();
+ core::LogWriter::setLogParams("*:stderr:30");
// Process vncconfig's own parameters first, then we process the
// other arguments when we have the X display.
int i;
- for (i = 1; i < argc; i++) {
- if (Configuration::setParam(argv[i]))
- continue;
+ for (i = 1; i < argc;) {
+ int ret;
- if (argv[i][0] == '-' && i+1 < argc &&
- Configuration::setParam(&argv[i][1], argv[i+1])) {
- i++;
+ ret = core::Configuration::handleParamArg(argc, argv, i);
+ if (ret > 0) {
+ i += ret;
continue;
}
+
+ if (strcmp(argv[i], "-help") == 0) {
+ usage();
+ }
+
+ if (strcmp(argv[i], "-version") == 0) {
+ fprintf(stderr, "vncconfig (TigerVNC) %s\n", PACKAGE_VERSION);
+ exit(0);
+ }
+
break;
}
@@ -285,13 +294,42 @@ int main(int argc, char** argv)
} else if (strcmp(argv[i], "-set") == 0) {
i++;
if (i >= argc) usage();
- if (!XVncExtSetParam(dpy, argv[i])) {
- fprintf(stderr, "Setting param %s failed\n",argv[i]);
+
+ char* equal = strchr(argv[i], '=');
+ if (!equal) {
+ fprintf(stderr, "%s: Invalid parameter syntax '%s'\n",
+ programName, argv[i]);
+ fprintf(stderr, "See '%s -help' for more information.\n",
+ programName);
+ exit(1);
}
- } else if (XVncExtSetParam(dpy, argv[i])) {
- fprintf(stderr, "Set parameter %s\n",argv[i]);
+
+ std::string name(argv[i], equal-argv[i]);
+ std::string value(equal+1);
+
+ if (!XVncExtSetParam(dpy, name.c_str(), value.c_str()))
+ fprintf(stderr, "Setting param %s failed\n",argv[i]);
+ } else if (argv[i][0] == '-') {
+ fprintf(stderr, "%s: Unrecognized option '%s'\n",
+ programName, argv[i]);
+ fprintf(stderr, "See '%s -help' for more information.\n",
+ programName);
+ exit(1);
} else {
- usage();
+ char* equal = strchr(argv[i], '=');
+ if (!equal) {
+ fprintf(stderr, "%s: Invalid parameter syntax '%s'\n",
+ programName, argv[i]);
+ fprintf(stderr, "See '%s -help' for more information.\n",
+ programName);
+ exit(1);
+ }
+
+ std::string name(argv[i], equal-argv[i]);
+ std::string value(equal+1);
+
+ if (!XVncExtSetParam(dpy, name.c_str(), value.c_str()))
+ fprintf(stderr, "Setting param %s failed\n",argv[i]);
}
}
@@ -312,7 +350,7 @@ int main(int argc, char** argv)
TXWindow::handleXEvents(dpy);
// Process expired timers and get the time until the next one
- int timeoutMs = Timer::checkTimeouts();
+ int timeoutMs = core::Timer::checkTimeouts();
if (timeoutMs >= 0) {
tv.tv_sec = timeoutMs / 1000;
tv.tv_usec = (timeoutMs % 1000) * 1000;
@@ -330,7 +368,7 @@ int main(int argc, char** argv)
FD_ZERO(&rfds);
FD_SET(ConnectionNumber(dpy), &rfds);
int n = select(FD_SETSIZE, &rfds, nullptr, nullptr, tvp);
- if (n < 0) throw rdr::socket_error("select", errno);
+ if (n < 0) throw core::socket_error("select", errno);
}
XCloseDisplay(dpy);
diff --git a/unix/vncconfig/vncconfig.man b/unix/vncconfig/vncconfig.man
index b07c02f4..7c26dff6 100644
--- a/unix/vncconfig/vncconfig.man
+++ b/unix/vncconfig/vncconfig.man
@@ -64,27 +64,27 @@ instead. The \fB-view-only\fP option specifies that the server must ignore all
keyboard or mouse events sent by the client.
.
.TP
+.B \-desc \fIXvnc-param\fP
+Prints a short description of the given Xvnc parameter.
+.
+.TP
.B \-disconnect
This causes Xvnc to disconnect from all viewers so that the VNC desktop is not
displayed anywhere.
.
.TP
-[\fB-set\fP] \fIXvnc-param\fP=\fIvalue\fP
-Sets an Xvnc parameter to the given value. Note that some of Xvnc's parameters
-are read only once at startup so that changing them in this way may not have
-any effect.
+.B \-get \fIXvnc-param\fP
+Prints the current value of the given Xvnc parameter.
.
.TP
.B \-list
Lists all the parameters supported by Xvnc.
.
.TP
-.B \-get \fIXvnc-param\fP
-Prints the current value of the given Xvnc parameter.
-.
-.TP
-.B \-desc \fIXvnc-param\fP
-Prints a short description of the given Xvnc parameter.
+[\fB-set\fP] \fIXvnc-param\fP=\fIvalue\fP
+Sets an Xvnc parameter to the given value. Note that some of Xvnc's parameters
+are read only once at startup so that changing them in this way may not have
+any effect.
.SH PARAMETERS
.B vncconfig
@@ -102,12 +102,12 @@ Other valid forms are \fIparam\fP\fB=\fP\fIvalue\fP -\fIparam\fP=\fIvalue\fP
Specifies the Xvnc server to control.
.
.TP
-.B \-nowin
-When run as a "helper" app, don't put up a window.
-.
-.TP
.B \-iconic
When run as a "helper" app, make the window iconified at startup.
+.
+.TP
+.B \-nowin
+When run as a "helper" app, don't put up a window.
.SH SEE ALSO
.BR vncpasswd (1),
diff --git a/unix/vncpasswd/CMakeLists.txt b/unix/vncpasswd/CMakeLists.txt
index f490a933..2acc9288 100644
--- a/unix/vncpasswd/CMakeLists.txt
+++ b/unix/vncpasswd/CMakeLists.txt
@@ -2,10 +2,11 @@ add_executable(vncpasswd
vncpasswd.cxx)
target_include_directories(vncpasswd PUBLIC ${CMAKE_SOURCE_DIR}/common)
-target_link_libraries(vncpasswd tx rfb os)
+target_link_libraries(vncpasswd core tx rfb)
if(PWQUALITY_FOUND)
- target_link_libraries(vncpasswd pwquality)
+ target_include_directories(vncpasswd SYSTEM PRIVATE ${PWQUALITY_INCLUDE_DIRS})
+ target_link_libraries(vncpasswd ${PWQUALITY_LIBRARIES})
endif()
install(TARGETS vncpasswd DESTINATION ${CMAKE_INSTALL_FULL_BINDIR})
diff --git a/unix/vncpasswd/vncpasswd.cxx b/unix/vncpasswd/vncpasswd.cxx
index 368bd40a..466aa1a2 100644
--- a/unix/vncpasswd/vncpasswd.cxx
+++ b/unix/vncpasswd/vncpasswd.cxx
@@ -31,7 +31,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <os/os.h>
+
+#include <core/xdgdirs.h>
#include <rfb/obfuscate.h>
@@ -41,8 +42,6 @@
#include <pwquality.h>
#endif
-using namespace rfb;
-
char* prog;
static void usage()
@@ -88,7 +87,7 @@ static int encrypt_pipe() {
if (!result)
break;
- std::vector<uint8_t> obfuscated = obfuscate(result);
+ std::vector<uint8_t> obfuscated = rfb::obfuscate(result);
if (fwrite(obfuscated.data(), obfuscated.size(), 1, stdout) != 1) {
fprintf(stderr,"Writing to stdout failed\n");
return 1;
@@ -177,7 +176,7 @@ static std::vector<uint8_t> readpassword() {
continue;
}
- return obfuscate(first.c_str());
+ return rfb::obfuscate(first.c_str());
}
}
@@ -190,11 +189,21 @@ int main(int argc, char** argv)
fname[0] = '\0';
for (int i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-q") == 0) { // allowed for backwards compatibility
+ if ((strcmp(argv[i], "-h") == 0) ||
+ (strcmp(argv[i], "--help") == 0)) {
+ usage();
+ } else if ((strcmp(argv[i], "-v") == 0) ||
+ (strcmp(argv[i], "--version") == 0)) {
+ fprintf(stderr, "vncpasswd (TigerVNC) %s\n", PACKAGE_VERSION);
+ exit(0);
+ } else if (strcmp(argv[i], "-q") == 0) {
+ // allowed for backwards compatibility
} else if (strncmp(argv[i], "-f", 2) == 0) {
return encrypt_pipe();
} else if (argv[i][0] == '-') {
- usage();
+ fprintf(stderr, "%s: Unrecognized option '%s'\n", prog, argv[i]);
+ fprintf(stderr, "See '%s --help' for more information.\n", prog);
+ exit(1);
} else if (fname[0] == '\0') {
if (strlen(argv[i]) >= sizeof(fname)) {
fprintf(stderr, "Too long filename specified\n");
@@ -202,17 +211,19 @@ int main(int argc, char** argv)
}
strcpy(fname, argv[i]);
} else {
- usage();
+ fprintf(stderr, "%s: Extra argument '%s'\n", prog, argv[i]);
+ fprintf(stderr, "See '%s --help' for more information.\n", prog);
+ exit(1);
}
}
if (fname[0] == '\0') {
- const char *configDir = os::getvncconfigdir();
+ const char* configDir = core::getvncconfigdir();
if (configDir == nullptr) {
fprintf(stderr, "Could not determine VNC config directory path\n");
exit(1);
}
- if (os::mkdir_p(configDir, 0777) == -1) {
+ if (core::mkdir_p(configDir, 0777) == -1) {
if (errno != EEXIST) {
fprintf(stderr, "Could not create VNC config directory \"%s\": %s\n",
configDir, strerror(errno));
diff --git a/unix/vncserver/CMakeLists.txt b/unix/vncserver/CMakeLists.txt
index ae69dc09..ed259c22 100644
--- a/unix/vncserver/CMakeLists.txt
+++ b/unix/vncserver/CMakeLists.txt
@@ -1,5 +1,8 @@
add_executable(vncsession vncsession.c)
-target_link_libraries(vncsession ${PAM_LIBS} ${SELINUX_LIBS})
+target_include_directories(vncsession SYSTEM PRIVATE ${PAM_INCLUDE_DIRS})
+target_include_directories(vncsession SYSTEM PRIVATE ${SELINUX_INCLUDE_DIRS})
+target_link_libraries(vncsession ${PAM_LIBRARIES})
+target_link_libraries(vncsession ${SELINUX_LIBRARIES})
configure_file(vncserver@.service.in vncserver@.service @ONLY)
configure_file(vncsession-start.in vncsession-start @ONLY)
diff --git a/unix/vncserver/selinux/vncsession.te b/unix/vncserver/selinux/vncsession.te
index d92f1bda..2ce4fc81 100644
--- a/unix/vncserver/selinux/vncsession.te
+++ b/unix/vncserver/selinux/vncsession.te
@@ -37,6 +37,10 @@ allow vnc_session_t self:fifo_file rw_fifo_file_perms;
allow vnc_session_t vnc_session_var_run_t:file manage_file_perms;
files_pid_filetrans(vnc_session_t, vnc_session_var_run_t, file)
+# Allow access to /proc/sys/fs/nr_open
+# Needed when the nofile limit is set to unlimited.
+kernel_read_fs_sysctls(vnc_session_t)
+
# Allowed to create ~/.local
optional_policy(`
gnome_filetrans_home_content(vnc_session_t)
@@ -48,6 +52,14 @@ optional_policy(`
create_dirs_pattern(vnc_session_t, gconf_home_t, gconf_home_t)
')
+# Allowed to create /root/.local
+optional_policy(`
+ gen_require(`
+ type admin_home_t;
+ ')
+ create_dirs_pattern(vnc_session_t, admin_home_t, admin_home_t)
+')
+
# Manage TigerVNC files (mainly ~/.local/state/*.log)
create_dirs_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
manage_files_pattern(vnc_session_t, vnc_home_t, vnc_home_t)
@@ -88,6 +100,7 @@ optional_policy(`
gen_require(`
attribute userdomain;
type gconf_home_t;
+ type admin_home_t;
')
userdom_admin_home_dir_filetrans(userdomain, vnc_home_t, dir, ".vnc")
userdom_user_home_dir_filetrans(userdomain, vnc_home_t, dir, ".vnc")
@@ -95,5 +108,6 @@ optional_policy(`
gnome_config_filetrans(userdomain, vnc_home_t, dir, "tigervnc")
gnome_data_filetrans(userdomain, vnc_home_t, dir, "tigervnc")
filetrans_pattern(userdomain, gconf_home_t, vnc_home_t, dir, "tigervnc")
+ filetrans_pattern(vnc_session_t, admin_home_t, vnc_home_t, dir, "tigervnc")
filetrans_pattern(vnc_session_t, gconf_home_t, vnc_home_t, dir, "tigervnc")
')
diff --git a/unix/vncserver/vncserver@.service.in b/unix/vncserver/vncserver@.service.in
index 592ddb67..336498ac 100644
--- a/unix/vncserver/vncserver@.service.in
+++ b/unix/vncserver/vncserver@.service.in
@@ -31,7 +31,7 @@
[Unit]
Description=Remote desktop service (VNC)
-After=syslog.target network.target systemd-user-sessions.service
+After=network.target systemd-user-sessions.service
[Service]
Type=forking
diff --git a/unix/vncserver/vncsession.c b/unix/vncserver/vncsession.c
index 0830e81a..79683ff9 100644
--- a/unix/vncserver/vncsession.c
+++ b/unix/vncserver/vncsession.c
@@ -134,7 +134,7 @@ begin_daemon(void)
static void
finish_daemon(void)
{
- write(daemon_pipe_fd, "+", 1);
+ if (write(daemon_pipe_fd, "+", 1) == -1) {}
close(daemon_pipe_fd);
daemon_pipe_fd = -1;
}
@@ -545,8 +545,12 @@ run_script(const char *username, const char *display, char **envp)
switch_user(pwent->pw_name, pwent->pw_uid, pwent->pw_gid);
- if (chdir(pwent->pw_dir) == -1)
- chdir("/");
+ if (chdir(pwent->pw_dir) == -1) {
+ syslog(LOG_CRIT, "chdir(\"%s\") failed: %s", pwent->pw_dir, strerror(errno));
+ // fallback to "/"
+ if (chdir("/") == -1)
+ syslog(LOG_CRIT, "chdir(\"%s\") failed: %s", "/", strerror(errno));
+ }
close_fds();
diff --git a/unix/x0vncserver/CMakeLists.txt b/unix/x0vncserver/CMakeLists.txt
index 9d6d2133..4ea09dd8 100644
--- a/unix/x0vncserver/CMakeLists.txt
+++ b/unix/x0vncserver/CMakeLists.txt
@@ -20,11 +20,12 @@ target_include_directories(x0vncserver PUBLIC ${CMAKE_SOURCE_DIR}/unix/common)
target_include_directories(x0vncserver PUBLIC ${CMAKE_SOURCE_DIR}/unix/tx)
target_include_directories(x0vncserver PUBLIC ${CMAKE_SOURCE_DIR}/unix)
target_include_directories(x0vncserver PUBLIC ${CMAKE_SOURCE_DIR}/common)
-target_link_libraries(x0vncserver tx rfb network rdr unixcommon)
+target_link_libraries(x0vncserver core tx rfb network rdr unixcommon)
# systemd support (socket activation)
-if (LIBSYSTEMD_FOUND)
- target_link_libraries(x0vncserver ${LIBSYSTEMD_LIBRARIES})
+if (SYSTEMD_FOUND)
+ target_include_directories(x0vncserver SYSTEM PRIVATE ${SYSTEMD_INCLUDE_DIRS})
+ target_link_libraries(x0vncserver ${SYSTEMD_LIBRARIES})
endif()
if(X11_XTest_LIB)
diff --git a/unix/x0vncserver/Geometry.cxx b/unix/x0vncserver/Geometry.cxx
index 28e71be4..0a848cbb 100644
--- a/unix/x0vncserver/Geometry.cxx
+++ b/unix/x0vncserver/Geometry.cxx
@@ -26,14 +26,13 @@
#include <string.h>
-#include <rfb/LogWriter.h>
-#include <x0vncserver/Geometry.h>
+#include <core/LogWriter.h>
-using namespace rfb;
+#include <x0vncserver/Geometry.h>
-static LogWriter vlog("Geometry");
+static core::LogWriter vlog("Geometry");
-StringParameter Geometry::m_geometryParam("Geometry",
+core::StringParameter Geometry::m_geometryParam("Geometry",
"Screen area shown to VNC clients. "
"Format is <width>x<height>+<offset_x>+<offset_y>, "
"more information in man X, section GEOMETRY SPECIFICATIONS. "
@@ -67,9 +66,9 @@ void Geometry::recalc(int fullWidth, int fullHeight)
width(), height(), offsetLeft(), offsetTop());
}
-Rect Geometry::parseString(const char *arg) const
+core::Rect Geometry::parseString(const char* arg) const
{
- Rect result; // empty by default
+ core::Rect result; // empty by default
if (arg != nullptr && strlen(arg) > 0) {
int w, h;
@@ -83,7 +82,7 @@ Rect Geometry::parseString(const char *arg) const
x = m_fullWidth - w - x;
if (sign_y[0] == '-')
y = m_fullHeight - h - y;
- Rect partRect(x, y, x + w, y + h);
+ core::Rect partRect(x, y, x + w, y + h);
result = partRect.intersect(m_rect);
if (result.area() <= 0) {
vlog.error("Requested area is out of the desktop boundaries");
diff --git a/unix/x0vncserver/Geometry.h b/unix/x0vncserver/Geometry.h
index d938d63f..709d5e35 100644
--- a/unix/x0vncserver/Geometry.h
+++ b/unix/x0vncserver/Geometry.h
@@ -23,8 +23,9 @@
#ifndef __GEOMETRY_H__
#define __GEOMETRY_H__
-#include <rfb/Rect.h>
-#include <rfb/Configuration.h>
+#include <core/Rect.h>
+
+namespace core { class StringParameter; }
class Geometry
{
@@ -42,18 +43,18 @@ public:
int offsetTop() const { return m_rect.tl.y; }
// Return the same information as a Rect structure.
- const rfb::Rect& getRect() const { return m_rect; }
+ const core::Rect& getRect() const { return m_rect; }
protected:
// Parse a string, extract size and coordinates,
// and return that rectangle clipped to m_rect.
- rfb::Rect parseString(const char *arg) const;
+ core::Rect parseString(const char* arg) const;
- static rfb::StringParameter m_geometryParam;
+ static core::StringParameter m_geometryParam;
int m_fullWidth;
int m_fullHeight;
- rfb::Rect m_rect;
+ core::Rect m_rect;
};
#endif // __GEOMETRY_H__
diff --git a/unix/x0vncserver/Image.cxx b/unix/x0vncserver/Image.cxx
index bd48c88d..88467c61 100644
--- a/unix/x0vncserver/Image.cxx
+++ b/unix/x0vncserver/Image.cxx
@@ -32,7 +32,8 @@
#include <sys/ipc.h>
#include <sys/shm.h>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+
#include <x0vncserver/Image.h>
//
@@ -60,7 +61,7 @@ ImageCleanup imageCleanup;
// Image class implementation.
//
-static rfb::LogWriter vlog("Image");
+static core::LogWriter vlog("Image");
Image::Image(Display *d)
: xim(nullptr), dpy(d)
diff --git a/unix/x0vncserver/PollingManager.cxx b/unix/x0vncserver/PollingManager.cxx
index 1761e358..04c3d065 100644
--- a/unix/x0vncserver/PollingManager.cxx
+++ b/unix/x0vncserver/PollingManager.cxx
@@ -27,17 +27,18 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
+
#include <X11/Xlib.h>
-#include <rfb/LogWriter.h>
+
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+
#include <rfb/VNCServer.h>
-#include <rfb/Configuration.h>
#include <rfb/ServerCore.h>
#include <x0vncserver/PollingManager.h>
-using namespace rfb;
-
-static LogWriter vlog("PollingMgr");
+static core::LogWriter vlog("PollingMgr");
const int PollingManager::m_pollingOrder[32] = {
0, 16, 8, 24, 4, 20, 12, 28,
@@ -123,7 +124,7 @@ void PollingManager::debugAfterPoll()
// Search for changed rectangles on the screen.
//
-void PollingManager::poll(VNCServer *server)
+void PollingManager::poll(rfb::VNCServer* server)
{
#ifdef DEBUG
debugBeforePoll();
@@ -142,7 +143,7 @@ void PollingManager::poll(VNCServer *server)
#define DBG_REPORT_CHANGES(title)
#endif
-bool PollingManager::pollScreen(VNCServer *server)
+bool PollingManager::pollScreen(rfb::VNCServer* server)
{
if (!server)
return false;
@@ -259,12 +260,12 @@ int PollingManager::checkColumn(int x, int y, int h, bool *pChangeFlags)
return nTilesChanged;
}
-int PollingManager::sendChanges(VNCServer *server) const
+int PollingManager::sendChanges(rfb::VNCServer* server) const
{
const bool *pChangeFlags = m_changeFlags;
int nTilesChanged = 0;
- Rect rect;
+ core::Rect rect;
for (int y = 0; y < m_heightTiles; y++) {
for (int x = 0; x < m_widthTiles; x++) {
if (*pChangeFlags++) {
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index b43e3f79..b52b20e1 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -28,9 +28,11 @@
#include <algorithm>
+#include <core/LogWriter.h>
+
#include <network/Socket.h>
-#include <rfb/LogWriter.h>
+#include <rfb/ScreenSet.h>
#include <x0vncserver/XDesktop.h>
@@ -56,25 +58,27 @@ void vncSetGlueContext(Display *dpy, void *res);
#include <x0vncserver/Geometry.h>
#include <x0vncserver/XPixelBuffer.h>
-using namespace rfb;
-
extern const unsigned short code_map_qnum_to_xorgevdev[];
extern const unsigned int code_map_qnum_to_xorgevdev_len;
extern const unsigned short code_map_qnum_to_xorgkbd[];
extern const unsigned int code_map_qnum_to_xorgkbd_len;
-BoolParameter useShm("UseSHM", "Use MIT-SHM extension if available", true);
-BoolParameter rawKeyboard("RawKeyboard",
- "Send keyboard events straight through and "
- "avoid mapping them to the current keyboard "
- "layout", false);
-IntParameter queryConnectTimeout("QueryConnectTimeout",
- "Number of seconds to show the 'Accept connection' dialog before "
- "rejecting the connection",
- 10);
-
-static rfb::LogWriter vlog("XDesktop");
+core::BoolParameter
+ useShm("UseSHM", "Use MIT-SHM extension if available", true);
+core::BoolParameter
+ rawKeyboard("RawKeyboard",
+ "Send keyboard events straight through and avoid "
+ "mapping them to the current keyboard layout",
+ false);
+core::IntParameter
+ queryConnectTimeout("QueryConnectTimeout",
+ "Number of seconds to show the 'Accept "
+ "connection' dialog before rejecting the "
+ "connection",
+ 10, 0, INT_MAX);
+
+static core::LogWriter vlog("XDesktop");
// order is important as it must match RFB extension
static const char * ledNames[XDESKTOP_N_LEDS] = {
@@ -234,12 +238,12 @@ void XDesktop::poll() {
&x, &y, &wx, &wy, &mask)) {
x -= geometry->offsetLeft();
y -= geometry->offsetTop();
- server->setCursorPos(rfb::Point(x, y), false);
+ server->setCursorPos({x, y}, false);
}
}
}
-void XDesktop::init(VNCServer* vs)
+void XDesktop::init(rfb::VNCServer* vs)
{
server = vs;
}
@@ -347,7 +351,9 @@ void XDesktop::queryConnection(network::Socket* sock,
queryConnectDialog->map();
}
-void XDesktop::pointerEvent(const Point& pos, uint16_t buttonMask) {
+void XDesktop::pointerEvent(const core::Point& pos,
+ uint16_t buttonMask)
+{
#ifdef HAVE_XTEST
if (!haveXtest) return;
XTestFakeMotionEvent(dpy, DefaultScreen(dpy),
@@ -605,9 +611,9 @@ void XDesktop::keyEvent(uint32_t keysym, uint32_t xtcode, bool down) {
#endif
}
-ScreenSet XDesktop::computeScreenLayout()
+rfb::ScreenSet XDesktop::computeScreenLayout()
{
- ScreenSet layout;
+ rfb::ScreenSet layout;
char buffer[2048];
#ifdef HAVE_XRANDR
@@ -622,8 +628,8 @@ ScreenSet XDesktop::computeScreenLayout()
XRRFreeScreenResources(res);
// Adjust the layout relative to the geometry
- ScreenSet::iterator iter, iter_next;
- Point offset(-geometry->offsetLeft(), -geometry->offsetTop());
+ rfb::ScreenSet::iterator iter, iter_next;
+ core::Point offset(-geometry->offsetLeft(), -geometry->offsetTop());
for (iter = layout.begin();iter != layout.end();iter = iter_next) {
iter_next = iter; ++iter_next;
iter->dimensions = iter->dimensions.intersect(geometry->getRect());
@@ -705,9 +711,9 @@ unsigned int XDesktop::setScreenLayout(int fb_width, int fb_height,
} else {
vlog.debug("Impossible layout - trying to adjust");
- ScreenSet::const_iterator firstscreen = layout.begin();
+ rfb::ScreenSet::const_iterator firstscreen = layout.begin();
adjustedLayout.add_screen(*firstscreen);
- ScreenSet::iterator iter = adjustedLayout.begin();
+ rfb::ScreenSet::iterator iter = adjustedLayout.begin();
RROutput outputId = None;
for (int i = 0;i < vncRandRGetOutputCount();i++) {
@@ -861,15 +867,15 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
#ifdef HAVE_XDAMAGE
} else if (ev->type == xdamageEventBase) {
XDamageNotifyEvent* dev;
- Rect rect;
+ core::Rect rect;
if (!running)
return true;
dev = (XDamageNotifyEvent*)ev;
rect.setXYWH(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
- rect = rect.translate(Point(-geometry->offsetLeft(),
- -geometry->offsetTop()));
+ rect = rect.translate({-geometry->offsetLeft(),
+ -geometry->offsetTop()});
server->add_changed(rect);
return true;
@@ -940,7 +946,7 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
server->setPixelBuffer(pb, computeScreenLayout());
// Mark entire screen as changed
- server->add_changed(rfb::Region(Rect(0, 0, cev->width, cev->height)));
+ server->add_changed({{0, 0, cev->width, cev->height}});
}
return true;
@@ -985,7 +991,7 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
if (cev->window == cev->root)
return false;
- server->setCursor(0, 0, Point(), nullptr);
+ server->setCursor(0, 0, {}, nullptr);
return true;
#endif
}
@@ -1046,7 +1052,7 @@ bool XDesktop::setCursor()
}
try {
- server->setCursor(cim->width, cim->height, Point(cim->xhot, cim->yhot),
+ server->setCursor(cim->width, cim->height, {cim->xhot, cim->yhot},
cursorData);
} catch (std::exception& e) {
vlog.error("XserverDesktop::setCursor: %s",e.what());
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index a27a1eae..89e2531d 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -63,7 +63,8 @@ public:
bool isRunning();
void queryConnection(network::Socket* sock,
const char* userName) override;
- void pointerEvent(const rfb::Point& pos, uint16_t buttonMask) override;
+ void pointerEvent(const core::Point& pos,
+ uint16_t buttonMask) override;
void keyEvent(uint32_t keysym, uint32_t xtcode, bool down) override;
unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout) override;
diff --git a/unix/x0vncserver/XPixelBuffer.cxx b/unix/x0vncserver/XPixelBuffer.cxx
index 0e24cc51..5e89a342 100644
--- a/unix/x0vncserver/XPixelBuffer.cxx
+++ b/unix/x0vncserver/XPixelBuffer.cxx
@@ -25,15 +25,17 @@
#include <config.h>
#endif
+#include <string.h>
#include <vector>
-#include <rfb/Region.h>
+
#include <X11/Xlib.h>
-#include <x0vncserver/XPixelBuffer.h>
-using namespace rfb;
+#include <core/Region.h>
+
+#include <x0vncserver/XPixelBuffer.h>
XPixelBuffer::XPixelBuffer(Display *dpy, ImageFactory &factory,
- const Rect &rect)
+ const core::Rect& rect)
: FullFramePixelBuffer(),
m_poller(nullptr),
m_dpy(dpy),
@@ -42,16 +44,16 @@ XPixelBuffer::XPixelBuffer(Display *dpy, ImageFactory &factory,
m_offsetTop(rect.tl.y)
{
// Fill in the PixelFormat structure of the parent class.
- format = PixelFormat(m_image->xim->bits_per_pixel,
- m_image->xim->depth,
- (m_image->xim->byte_order == MSBFirst),
- true,
- m_image->xim->red_mask >> (ffs(m_image->xim->red_mask) - 1),
- m_image->xim->green_mask >> (ffs(m_image->xim->green_mask) - 1),
- m_image->xim->blue_mask >> (ffs(m_image->xim->blue_mask) - 1),
- ffs(m_image->xim->red_mask) - 1,
- ffs(m_image->xim->green_mask) - 1,
- ffs(m_image->xim->blue_mask) - 1);
+ format = rfb::PixelFormat(m_image->xim->bits_per_pixel,
+ m_image->xim->depth,
+ (m_image->xim->byte_order == MSBFirst),
+ true,
+ m_image->xim->red_mask >> (ffs(m_image->xim->red_mask) - 1),
+ m_image->xim->green_mask >> (ffs(m_image->xim->green_mask) - 1),
+ m_image->xim->blue_mask >> (ffs(m_image->xim->blue_mask) - 1),
+ ffs(m_image->xim->red_mask) - 1,
+ ffs(m_image->xim->green_mask) - 1,
+ ffs(m_image->xim->blue_mask) - 1);
// Set up the remaining data of the parent class.
setBuffer(rect.width(), rect.height(), (uint8_t *)m_image->xim->data,
@@ -72,10 +74,10 @@ XPixelBuffer::~XPixelBuffer()
}
void
-XPixelBuffer::grabRegion(const rfb::Region& region)
+XPixelBuffer::grabRegion(const core::Region& region)
{
- std::vector<Rect> rects;
- std::vector<Rect>::const_iterator i;
+ std::vector<core::Rect> rects;
+ std::vector<core::Rect>::const_iterator i;
region.get_rects(&rects);
for (i = rects.begin(); i != rects.end(); i++) {
grabRect(*i);
diff --git a/unix/x0vncserver/XPixelBuffer.h b/unix/x0vncserver/XPixelBuffer.h
index 7556e6ef..727d0867 100644
--- a/unix/x0vncserver/XPixelBuffer.h
+++ b/unix/x0vncserver/XPixelBuffer.h
@@ -24,10 +24,12 @@
#define __XPIXELBUFFER_H__
#include <rfb/PixelBuffer.h>
-#include <rfb/VNCServer.h>
+
#include <x0vncserver/Image.h>
#include <x0vncserver/PollingManager.h>
+namespace rfb { class VNCServer; }
+
//
// XPixelBuffer is an Image-based implementation of FullFramePixelBuffer.
//
@@ -35,7 +37,7 @@
class XPixelBuffer : public rfb::FullFramePixelBuffer
{
public:
- XPixelBuffer(Display *dpy, ImageFactory &factory, const rfb::Rect &rect);
+ XPixelBuffer(Display* dpy, ImageFactory& factory, const core::Rect& rect);
virtual ~XPixelBuffer();
// Provide access to the underlying Image object.
@@ -45,7 +47,7 @@ public:
inline void poll(rfb::VNCServer *server) { m_poller->poll(server); }
// Override PixelBuffer::grabRegion().
- void grabRegion(const rfb::Region& region) override;
+ void grabRegion(const core::Region& region) override;
protected:
PollingManager *m_poller;
@@ -57,7 +59,7 @@ protected:
// Copy pixels from the screen to the pixel buffer,
// for the specified rectangular area of the buffer.
- inline void grabRect(const rfb::Rect &r) {
+ inline void grabRect(const core::Rect& r) {
m_image->get(DefaultRootWindow(m_dpy),
m_offsetLeft + r.tl.x, m_offsetTop + r.tl.y,
r.width(), r.height(), r.tl.x, r.tl.y);
diff --git a/unix/x0vncserver/XSelection.cxx b/unix/x0vncserver/XSelection.cxx
index c724d2ac..5de171d1 100644
--- a/unix/x0vncserver/XSelection.cxx
+++ b/unix/x0vncserver/XSelection.cxx
@@ -17,19 +17,23 @@
*/
#include <X11/Xatom.h>
-#include <rfb/Configuration.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <x0vncserver/XSelection.h>
-rfb::BoolParameter setPrimary("SetPrimary",
- "Set the PRIMARY as well as the CLIPBOARD selection",
- true);
-rfb::BoolParameter sendPrimary("SendPrimary",
- "Send the PRIMARY as well as the CLIPBOARD selection",
- true);
+core::BoolParameter
+ setPrimary("SetPrimary",
+ "Set the PRIMARY as well as the CLIPBOARD selection",
+ true);
+core::BoolParameter
+ sendPrimary("SendPrimary",
+ "Send the PRIMARY as well as the CLIPBOARD selection",
+ true);
-static rfb::LogWriter vlog("XSelection");
+static core::LogWriter vlog("XSelection");
XSelection::XSelection(Display* dpy_, XSelectionHandler* handler_)
: TXWindow(dpy_, 1, 1, nullptr), handler(handler_), announcedSelection(None)
@@ -89,7 +93,7 @@ bool XSelection::selectionRequest(Window requestor, Atom selection, Atom target,
return false;
if (target == XA_STRING) {
- std::string latin1 = rfb::utf8ToLatin1(clientData.data(), clientData.length());
+ std::string latin1 = core::utf8ToLatin1(clientData.data(), clientData.length());
XChangeProperty(dpy, requestor, property, XA_STRING, 8, PropModeReplace,
(unsigned char*)latin1.data(), latin1.length());
return true;
@@ -184,11 +188,11 @@ void XSelection::selectionNotify(XSelectionEvent* ev, Atom type, int format,
return;
if (type == xaUTF8_STRING) {
- std::string result = rfb::convertLF((char*)data, nitems);
+ std::string result = core::convertLF((char*)data, nitems);
handler->handleXSelectionData(result.c_str());
} else if (type == XA_STRING) {
- std::string result = rfb::convertLF((char*)data, nitems);
- result = rfb::latin1ToUTF8(result.data(), result.length());
+ std::string result = core::convertLF((char*)data, nitems);
+ result = core::latin1ToUTF8(result.data(), result.length());
handler->handleXSelectionData(result.c_str());
}
}
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index 7ea427ed..b8b631aa 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -31,13 +31,20 @@
#include <errno.h>
#include <pwd.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/LogWriter.h>
+#include <core/Configuration.h>
+#include <core/Logger_stdio.h>
+#include <core/LogWriter.h>
+#include <core/Timer.h>
+
+#include <rdr/FdInStream.h>
+#include <rdr/FdOutStream.h>
+
+#include <rfb/UnixPasswordValidator.h>
#include <rfb/VNCServerST.h>
-#include <rfb/Configuration.h>
-#include <rfb/Timer.h>
+
#include <network/TcpSocket.h>
#include <network/UnixSocket.h>
+
#ifdef HAVE_LIBSYSTEMD
# include <systemd/sd-daemon.h>
#endif
@@ -54,30 +61,40 @@
extern char buildtime[];
-using namespace rfb;
-using namespace network;
-
-static LogWriter vlog("Main");
+static core::LogWriter vlog("Main");
static const char* defaultDesktopName();
-IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling "
- "cycle; actual interval may be dynamically "
- "adjusted to satisfy MaxProcessorUsage setting", 30);
-IntParameter maxProcessorUsage("MaxProcessorUsage", "Maximum percentage of "
- "CPU time to be consumed", 35);
-StringParameter desktopName("desktop", "Name of VNC desktop", defaultDesktopName());
-StringParameter displayname("display", "The X display", "");
-IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
-StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", "");
-IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600);
-StringParameter hostsFile("HostsFile", "File with IP access control rules", "");
-BoolParameter localhostOnly("localhost",
- "Only allow connections from localhost",
- false);
-StringParameter interface("interface",
- "Listen on the specified network address",
- "all");
+core::IntParameter
+ pollingCycle("PollingCycle",
+ "Milliseconds per one polling cycle; actual interval "
+ "may be dynamically adjusted to satisfy "
+ "MaxProcessorUsage setting", 30, 0, INT_MAX);
+core::IntParameter
+ maxProcessorUsage("MaxProcessorUsage",
+ "Maximum percentage of CPU time to be consumed",
+ 35, 0, 100);
+core::StringParameter
+ desktopName("desktop", "Name of VNC desktop", defaultDesktopName());
+core::StringParameter
+ displayname("display", "The X display", "");
+core::IntParameter
+ rfbport("rfbport",
+ "TCP port to listen for RFB protocol", 5900, -1, 65535);
+core::StringParameter
+ rfbunixpath("rfbunixpath",
+ "Unix socket to listen for RFB protocol", "");
+core::IntParameter
+ rfbunixmode("rfbunixmode",
+ "Unix socket access mode", 0600, 0000, 0777);
+core::StringParameter
+ hostsFile("HostsFile", "File with IP access control rules", "");
+core::BoolParameter
+ localhostOnly("localhost",
+ "Only allow connections from localhost", false);
+core::StringParameter
+ interface("interface",
+ "Listen on the specified network address", "all");
static const char* defaultDesktopName()
{
@@ -127,7 +144,7 @@ static bool hasSystemdListeners()
#endif
}
-static int createSystemdListeners(std::list<SocketListener*> *listeners)
+static int createSystemdListeners(std::list<network::SocketListener*> *listeners)
{
#ifdef HAVE_LIBSYSTEMD
int count = sd_listen_fds(0);
@@ -138,7 +155,7 @@ static int createSystemdListeners(std::list<SocketListener*> *listeners)
}
for (int i = 0; i < count; ++i)
- listeners->push_back(new TcpListener(SD_LISTEN_FDS_START + i));
+ listeners->push_back(new network::TcpListener(SD_LISTEN_FDS_START + i));
return count;
#else
@@ -148,7 +165,7 @@ static int createSystemdListeners(std::list<SocketListener*> *listeners)
}
-class FileTcpFilter : public TcpFilter
+class FileTcpFilter : public network::TcpFilter
{
public:
@@ -166,7 +183,7 @@ public:
free(fileName);
}
- bool verifyConnection(Socket* s) override
+ bool verifyConnection(network::Socket* s) override
{
if (!reloadRules()) {
vlog.error("Could not read IP filtering rules, rejecting all clients");
@@ -267,59 +284,72 @@ static void usage()
"Other valid forms are <param>=<value> -<param>=<value> "
"--<param>=<value>\n"
"Parameter names are case-insensitive. The parameters are:\n\n");
- Configuration::listParams(79, 14);
+ core::Configuration::listParams(79, 14);
exit(1);
}
int main(int argc, char** argv)
{
- initStdIOLoggers();
- LogWriter::setLogParams("*:stderr:30");
+ core::initStdIOLoggers();
+ core::LogWriter::setLogParams("*:stderr:30");
programName = argv[0];
Display* dpy;
- Configuration::enableServerParams();
-
// Assume different defaults when socket activated
if (hasSystemdListeners())
rfbport.setParam(-1);
- for (int i = 1; i < argc; i++) {
- if (Configuration::setParam(argv[i]))
+ for (int i = 1; i < argc;) {
+ int ret;
+
+ ret = core::Configuration::handleParamArg(argc, argv, i);
+ if (ret > 0) {
+ i += ret;
continue;
+ }
- if (argv[i][0] == '-') {
- if (i+1 < argc) {
- if (Configuration::setParam(&argv[i][1], argv[i+1])) {
- i++;
- continue;
- }
- }
- if (strcmp(argv[i], "-v") == 0 ||
- strcmp(argv[i], "-version") == 0 ||
- strcmp(argv[i], "--version") == 0) {
- printVersion(stdout);
- return 0;
- }
+ if (strcmp(argv[i], "-h") == 0 ||
+ strcmp(argv[i], "-help") == 0 ||
+ strcmp(argv[i], "--help") == 0) {
usage();
}
- usage();
+ if (strcmp(argv[i], "-v") == 0 ||
+ strcmp(argv[i], "-version") == 0 ||
+ strcmp(argv[i], "--version") == 0) {
+ printVersion(stdout);
+ return 0;
+ }
+
+ if (argv[i][0] == '-') {
+ fprintf(stderr, "%s: Unrecognized option '%s'\n",
+ programName, argv[i]);
+ fprintf(stderr, "See '%s --help' for more information.\n",
+ programName);
+ exit(1);
+ }
+
+ fprintf(stderr, "%s: Extra argument '%s'\n", programName, argv[i]);
+ fprintf(stderr, "See '%s --help' for more information.\n",
+ programName);
+ exit(1);
}
+ const char *displayName = XDisplayName(displayname);
if (!(dpy = XOpenDisplay(displayname))) {
// FIXME: Why not vlog.error(...)?
fprintf(stderr,"%s: Unable to open display \"%s\"\r\n",
- programName, XDisplayName(displayname));
+ programName, displayName);
exit(1);
}
+ rfb::UnixPasswordValidator::setDisplayName(displayName);
signal(SIGHUP, CleanupSignalHandler);
signal(SIGINT, CleanupSignalHandler);
signal(SIGTERM, CleanupSignalHandler);
- std::list<SocketListener*> listeners;
+ std::list<network::SocketListener*> listeners;
try {
TXWindow::init(dpy,"x0vncserver");
@@ -331,7 +361,9 @@ int main(int argc, char** argv)
}
XDesktop desktop(dpy, &geo);
- VNCServerST server(desktopName, &desktop);
+ rfb::VNCServerST server(desktopName, &desktop);
+
+ FileTcpFilter fileTcpFilter(hostsFile);
if (createSystemdListeners(&listeners) > 0) {
// When systemd is in charge of listeners, do not listen to anything else
@@ -361,9 +393,8 @@ int main(int argc, char** argv)
(int)rfbport);
}
- FileTcpFilter fileTcpFilter(hostsFile);
if (strlen(hostsFile) != 0)
- for (SocketListener* listener : listeners)
+ for (network::SocketListener* listener : listeners)
listener->setFilter(&fileTcpFilter);
}
@@ -378,8 +409,8 @@ int main(int argc, char** argv)
int wait_ms, nextTimeout;
struct timeval tv;
fd_set rfds, wfds;
- std::list<Socket*> sockets;
- std::list<Socket*>::iterator i;
+ std::list<network::Socket*> sockets;
+ std::list<network::Socket*>::iterator i;
// Process any incoming X events
TXWindow::handleXEvents(dpy);
@@ -388,21 +419,16 @@ int main(int argc, char** argv)
FD_ZERO(&wfds);
FD_SET(ConnectionNumber(dpy), &rfds);
- for (SocketListener* listener : listeners)
+ for (network::SocketListener* listener : listeners)
FD_SET(listener->getFd(), &rfds);
server.getSockets(&sockets);
int clients_connected = 0;
for (i = sockets.begin(); i != sockets.end(); i++) {
- if ((*i)->isShutdown()) {
- server.removeSocket(*i);
- delete (*i);
- } else {
- FD_SET((*i)->getFd(), &rfds);
- if ((*i)->outStream().hasBufferedData())
- FD_SET((*i)->getFd(), &wfds);
- clients_connected++;
- }
+ FD_SET((*i)->getFd(), &rfds);
+ if ((*i)->outStream().hasBufferedData())
+ FD_SET((*i)->getFd(), &wfds);
+ clients_connected++;
}
if (!clients_connected)
@@ -418,7 +444,7 @@ int main(int argc, char** argv)
}
// Trigger timers and check when the next will expire
- nextTimeout = Timer::checkTimeouts();
+ nextTimeout = core::Timer::checkTimeouts();
if (nextTimeout >= 0 && (wait_ms == -1 || nextTimeout < wait_ms))
wait_ms = nextTimeout;
@@ -436,14 +462,14 @@ int main(int argc, char** argv)
vlog.debug("Interrupted select() system call");
continue;
} else {
- throw rdr::socket_error("select", errno);
+ throw core::socket_error("select", errno);
}
}
// Accept new VNC connections
- for (SocketListener* listener : listeners) {
+ for (network::SocketListener* listener : listeners) {
if (FD_ISSET(listener->getFd(), &rfds)) {
- Socket* sock = listener->accept();
+ network::Socket* sock = listener->accept();
if (sock) {
server.addSocket(sock);
} else {
@@ -452,7 +478,7 @@ int main(int argc, char** argv)
}
}
- Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
// Client list could have been changed.
server.getSockets(&sockets);
@@ -467,6 +493,29 @@ int main(int argc, char** argv)
server.processSocketReadEvent(*i);
if (FD_ISSET((*i)->getFd(), &wfds))
server.processSocketWriteEvent(*i);
+
+ // Do a graceful close by waiting for the peer to close their
+ // end
+ if ((*i)->isShutdown()) {
+ bool done;
+
+ done = false;
+ while (true) {
+ try {
+ (*i)->inStream().skip((*i)->inStream().avail());
+ if (!(*i)->inStream().hasData(1))
+ break;
+ } catch (std::exception&) {
+ done = true;
+ break;
+ }
+ }
+
+ if (done) {
+ server.removeSocket(*i);
+ delete (*i);
+ }
+ }
}
if (desktop.isRunning() && sched.goodTimeToPoll()) {
@@ -483,7 +532,7 @@ int main(int argc, char** argv)
TXWindow::handleXEvents(dpy);
// Run listener destructors; remove UNIX sockets etc
- for (SocketListener* listener : listeners)
+ for (network::SocketListener* listener : listeners)
delete listener;
vlog.info("Terminated");
diff --git a/unix/x0vncserver/x0vncserver.man b/unix/x0vncserver/x0vncserver.man
index ce4bd6a9..f1a28f54 100644
--- a/unix/x0vncserver/x0vncserver.man
+++ b/unix/x0vncserver/x0vncserver.man
@@ -20,7 +20,7 @@ will fall back to polling the screen for changes.
.SH OPTIONS
.B x0vncserver
interprets the command line as a list of parameters with optional values.
-Running \fBx0vncserver -h\fP will show a list of all valid parameters with
+Running \fBx0vncserver \-h\fP will show a list of all valid parameters with
short descriptions. All parameters are optional, but normally you would have
to use the \fBPasswordFile\fP parameter (see its description below).
.PP
@@ -47,47 +47,76 @@ arbitrary.
.SH PARAMETERS
.TP
-.B \-desktop \fIdesktop-name\fP
-Each desktop has a name which may be displayed by the viewer. It defaults to
-"<user>@<hostname>".
+.B \-AcceptKeyEvents
+Accept key press and release events from clients. Default is on.
.
.TP
-.B \-display \fIdisplay\fP
-The X display name. If not specified, it defaults to the value of the
-DISPLAY environment variable.
+.B \-AcceptPointerEvents
+Accept pointer movement and button events from clients. Default is on.
.
.TP
-.B \-rfbport \fIport\fP
-Specifies the TCP port on which x0vncserver listens for connections from
-viewers (the protocol used in VNC is called RFB - "remote framebuffer").
-Specify \fB-1\fP to disable listening on a TCP port. The default port is
-5900 when started directly, and -1 when activated by a systemd socket.
+.B \-AcceptSetDesktopSize
+Accept requests to resize the size of the desktop. Default is on.
.
.TP
-.B \-UseIPv4
-Use IPv4 for incoming and outgoing connections. Default is on.
+.B \-AlwaysShared
+Always treat incoming connections as shared, regardless of the client-specified
+setting. Default is off.
.
.TP
-.B \-UseIPv6
-Use IPv6 for incoming and outgoing connections. Default is on.
+.B \-BlacklistThreshold \fIcount\fP
+The number of unauthenticated connection attempts allowed from any individual
+host before that host is black-listed. Default is 5.
.
.TP
-.B \-rfbunixpath \fIpath\fP
-Specifies the path of a Unix domain socket on which x0vncserver listens for
-connections from viewers. Default is to not listen to any Unix domain
-socket.
+.B \-BlacklistTimeout \fIseconds\fP
+The initial timeout applied when a host is first black-listed. The host
+cannot re-attempt a connection until the timeout expires. Default is 10.
.
.TP
-.B \-rfbunixmode \fImode\fP
-Specifies the mode of the Unix domain socket. The default is 0600.
+.B \-CompareFB \fImode\fP
+Perform pixel comparison on framebuffer to reduce unnecessary updates. Can
+be either \fB0\fP (off), \fB1\fP (always) or \fB2\fP (auto). Default is
+\fB2\fP.
.
.TP
-.B \-Log \fIlogname\fP:\fIdest\fP:\fIlevel\fP
-Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP,
-\fBstdout\fP or \fBsyslog\fP, and \fIlevel\fP is between 0 and 100, 100 meaning
-most verbose output. \fIlogname\fP is usually \fB*\fP meaning all, but you can
-target a specific source file if you know the name of its "LogWriter". Default
-is \fB*:stderr:30\fP.
+.B \-desktop \fIdesktop-name\fP
+Each desktop has a name which may be displayed by the viewer. It defaults to
+"<user>@<hostname>".
+.
+.TP
+.B \-DisconnectClients
+Disconnect existing clients if an incoming connection is non-shared. Default is
+on. If \fBDisconnectClients\fP is false, then a new non-shared connection will
+be refused while there is a client active. When combined with
+\fBNeverShared\fP this means only one client is allowed at a time.
+.
+.TP
+.B \-display \fIdisplay\fP
+The X display name. If not specified, it defaults to the value of the
+DISPLAY environment variable.
+.
+.TP
+.B \-FrameRate \fIfps\fP
+The maximum number of updates per second sent to each client. If the screen
+updates any faster then those changes will be aggregated and sent in a single
+update to the client. Note that this only controls the maximum rate and a
+client may get a lower rate when resources are limited. Default is \fB60\fP.
+.
+.TP
+.B \-Geometry \fIgeometry\fP
+This option specifies the screen area that will be shown to VNC clients. The
+format is
+.B \fIwidth\fPx\fIheight\fP+\fIxoffset\fP+\fIyoffset\fP
+, where `+' signs can be replaced with `\-' signs to specify offsets from the
+right and/or from the bottom of the screen. Offsets are optional, +0+0 is
+assumed by default (top left corner). If the argument is empty, full screen
+is shown to VNC clients (this is the default).
+.
+.TP
+.B \-GnuTLSPriority \fIpriority\fP
+GnuTLS priority string that controls the TLS session’s handshake algorithms.
+See the GnuTLS manual for possible values. Default is \fBNORMAL\fP.
.
.TP
.B \-HostsFile \fIfilename\fP
@@ -102,124 +131,108 @@ include only an action sign (+, - or ?) will match any IP address.
Default is to accept connections from any IP address.
.
.TP
-.B \-SecurityTypes \fIsec-types\fP
-Specify which security scheme to use for incoming connections. Valid values
-are a comma separated list of \fBNone\fP, \fBVncAuth\fP, \fBPlain\fP,
-\fBTLSNone\fP, \fBTLSVnc\fP, \fBTLSPlain\fP, \fBX509None\fP, \fBX509Vnc\fP,
-\fBX509Plain\fP, \fBRA2\fP, \fBRA2ne\fP, \fBRA2_256\fP and \fBRA2ne_256\fP.
-Default is \fBTLSVnc,VncAuth\fP.
-.
-.TP
-.B \-rfbauth \fIpasswd-file\fP, \-PasswordFile \fIpasswd-file\fP
-Password file for VNC authentication. There is no default, you should
-specify the password file explicitly. Password file should be created with
-the \fBvncpasswd\fP(1) utility. The file is accessed each time a connection
-comes in, so it can be changed on the fly.
-.
-.TP
-.B \-Password \fIpassword\fP
-Obfuscated binary encoding of the password which clients must supply to
-access the server. Using this parameter is insecure, use \fBPasswordFile\fP
-parameter instead.
-.
-.TP
-.B \-PlainUsers \fIuser-list\fP
-A comma separated list of user names that are allowed to authenticate via
-any of the "Plain" security types (Plain, TLSPlain, etc.). Specify \fB*\fP
-to allow any user to authenticate using this security type. Specify \fB%u\fP
-to allow the user of the server process. Default is to deny all users.
-.
-.TP
-.B \-pam_service \fIname\fP, \-PAMService \fIname\fP
-PAM service name to use when authentication users using any of the "Plain"
-security types. Default is \fBvnc\fP.
+.B \-IdleTimeout \fIseconds\fP
+The number of seconds after which an idle VNC connection will be dropped.
+Default is 0, which means that idle connections will never be dropped.
.
.TP
-.B \-X509Cert \fIpath\fP
-Path to a X509 certificate in PEM format to be used for all X509 based
-security types (X509None, X509Vnc, etc.).
+.B \-ImprovedHextile
+Use improved compression algorithm for Hextile encoding which achieves better
+compression ratios by the cost of using slightly more CPU time. Default is
+on.
.
.TP
-.B \-X509Key \fIpath\fP
-Private key counter part to the certificate given in \fBX509Cert\fP. Must
-also be in PEM format.
+.B \-interface \fIIP address\fP
+Listen on interface. By default x0vncserver listens on all available interfaces.
.
.TP
-.B \-GnuTLSPriority \fIpriority\fP
-GnuTLS priority string that controls the TLS session’s handshake algorithms.
-See the GnuTLS manual for possible values. Default is \fBNORMAL\fP.
+.B \-localhost
+Only allow connections from the same machine. Useful if you use SSH and want to
+stop non-SSH connections from any other hosts.
.
.TP
-.B \-RSAKey \fIpath\fP
-Path to the RSA key for the RSA-AES security types (\fBRA2\fP, \fBRA2ne\fP,
-\fBRA2_256\fP and \fBRA2ne_256\fP) in PEM format.
+.B \-Log \fIlogname\fP:\fIdest\fP:\fIlevel\fP[, ...]
+Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP,
+\fBstdout\fP or \fBsyslog\fP, and \fIlevel\fP is between 0 and 100, 100 meaning
+most verbose output. \fIlogname\fP is usually \fB*\fP meaning all, but you can
+target a specific source file if you know the name of its "LogWriter". Default
+is \fB*:stderr:30\fP.
.
.TP
-.B \-RequireUsername
-Require username for the RSA-AES security types. Default is off.
+.B \-MaxConnectionTime \fIseconds\fP
+Terminate when a client has been connected for \fIN\fP seconds. Default is
+0.
.
.TP
-.B \-UseBlacklist
-Temporarily reject connections from a host if it repeatedly fails to
-authenticate. Default is on.
+.B \-MaxDisconnectionTime \fIseconds\fP
+Terminate when no client has been connected for \fIN\fP seconds. Default is
+0.
.
.TP
-.B \-BlacklistThreshold \fIcount\fP
-The number of unauthenticated connection attempts allowed from any individual
-host before that host is black-listed. Default is 5.
+.B \-MaxIdleTime \fIseconds\fP
+Terminate after \fIN\fP seconds of user inactivity. Default is 0.
.
.TP
-.B \-BlacklistTimeout \fIseconds\fP
-The initial timeout applied when a host is first black-listed. The host
-cannot re-attempt a connection until the timeout expires. Default is 10.
+.B \-MaxProcessorUsage \fIpercent\fP
+Maximum percentage of CPU time to be consumed when polling the
+screen. Default is 35.
.
.TP
-.B \-QueryConnect
-Prompts the user of the desktop to explicitly accept or reject incoming
-connections. Default is off.
+.B \-NeverShared
+Never treat incoming connections as shared, regardless of the client-specified
+setting. Default is off.
.
.TP
-.B \-QueryConnectTimeout \fIseconds\fP
-Number of seconds to show the Accept connection dialog before rejecting the
-connection. Default is \fB10\fP.
+.B \-pam_service \fIname\fP, \-PAMService \fIname\fP
+PAM service name to use when authentication users using any of the "Plain"
+security types. Default is \fBvnc\fP.
.
.TP
-.B \-localhost
-Only allow connections from the same machine. Useful if you use SSH and want to
-stop non-SSH connections from any other hosts.
+.B \-Password \fIpassword\fP
+Obfuscated binary encoding of the password which clients must supply to
+access the server. Using this parameter is insecure, use \fBPasswordFile\fP
+parameter instead.
.
.TP
-.B \-interface \fIIP address\fP
-Listen on interface. By default x0vncserver listens on all available interfaces.
+.B \-PasswordFile \fIpasswd-file\fP, \-rfbauth \fIpasswd-file\fP
+Password file for VNC authentication. There is no default, you should
+specify the password file explicitly. Password file should be created with
+the \fBvncpasswd\fP(1) utility. The file is accessed each time a connection
+comes in, so it can be changed on the fly.
.
.TP
-.B \-AlwaysShared
-Always treat incoming connections as shared, regardless of the client-specified
-setting. Default is off.
+.B \-PlainUsers \fIuser-list\fP
+A comma separated list of user names that are allowed to authenticate via
+any of the "Plain" security types (Plain, TLSPlain, etc.). Specify \fB*\fP
+to allow any user to authenticate using this security type. Specify \fB%u\fP
+to allow the user of the server process. Default is to deny all users.
.
.TP
-.B \-NeverShared
-Never treat incoming connections as shared, regardless of the client-specified
-setting. Default is off.
+.B \-PollingCycle \fImilliseconds\fP
+Milliseconds per one polling cycle. Actual interval may be dynamically
+adjusted to satisfy \fBMaxProcessorUsage\fP setting. Default is 30.
.
.TP
-.B \-DisconnectClients
-Disconnect existing clients if an incoming connection is non-shared. Default is
-on. If \fBDisconnectClients\fP is false, then a new non-shared connection will
-be refused while there is a client active. When combined with
-\fBNeverShared\fP this means only one client is allowed at a time.
+.B \-Protocol3.3
+Always use protocol version 3.3 for backwards compatibility with badly-behaved
+clients. Default is off.
.
.TP
-.B \-AcceptKeyEvents
-Accept key press and release events from clients. Default is on.
+.B \-QueryConnect
+Prompts the user of the desktop to explicitly accept or reject incoming
+connections. Default is off.
.
.TP
-.B \-AcceptPointerEvents
-Accept pointer movement and button events from clients. Default is on.
+.B \-QueryConnectTimeout \fIseconds\fP
+Number of seconds to show the Accept connection dialog before rejecting the
+connection. Default is \fB10\fP.
.
.TP
-.B \-AcceptSetDesktopSize
-Accept requests to resize the size of the desktop. Default is on.
+.B \-RawKeyboard
+Send keyboard events straight through and avoid mapping them to the current
+keyboard layout. This effectively makes the keyboard behave according to the
+layout configured on the server instead of the layout configured on the
+client. Default is off.
.
.TP
.B \-AcceptCutText
@@ -259,79 +272,66 @@ RemapKeys=0x22<>0x40
.RE
.
.TP
-.B \-RawKeyboard
-Send keyboard events straight through and avoid mapping them to the current
-keyboard layout. This effectively makes the keyboard behave according to the
-layout configured on the server instead of the layout configured on the
-client. Default is off.
-.
-.TP
-.B \-Protocol3.3
-Always use protocol version 3.3 for backwards compatibility with badly-behaved
-clients. Default is off.
+.B \-RequireUsername
+Require username for the RSA-AES security types. Default is off.
.
.TP
-.B \-Geometry \fIgeometry\fP
-This option specifies the screen area that will be shown to VNC clients. The
-format is
-.B \fIwidth\fPx\fIheight\fP+\fIxoffset\fP+\fIyoffset\fP
-, where `+' signs can be replaced with `\-' signs to specify offsets from the
-right and/or from the bottom of the screen. Offsets are optional, +0+0 is
-assumed by default (top left corner). If the argument is empty, full screen
-is shown to VNC clients (this is the default).
+.B \-rfbport \fIport\fP
+Specifies the TCP port on which x0vncserver listens for connections from
+viewers (the protocol used in VNC is called RFB - "remote framebuffer").
+Specify \fB-1\fP to disable listening on a TCP port. The default port is
+5900 when started directly, and -1 when activated by a systemd socket.
.
.TP
-.B \-MaxProcessorUsage \fIpercent\fP
-Maximum percentage of CPU time to be consumed when polling the
-screen. Default is 35.
+.B \-rfbunixmode \fImode\fP
+Specifies the mode of the Unix domain socket. The default is 0600.
.
.TP
-.B \-PollingCycle \fImilliseconds\fP
-Milliseconds per one polling cycle. Actual interval may be dynamically
-adjusted to satisfy \fBMaxProcessorUsage\fP setting. Default is 30.
+.B \-rfbunixpath \fIpath\fP
+Specifies the path of a Unix domain socket on which x0vncserver listens for
+connections from viewers. Default is to not listen to any Unix domain
+socket.
.
.TP
-.B \-FrameRate \fIfps\fP
-The maximum number of updates per second sent to each client. If the screen
-updates any faster then those changes will be aggregated and sent in a single
-update to the client. Note that this only controls the maximum rate and a
-client may get a lower rate when resources are limited. Default is \fB60\fP.
+.B \-RSAKey \fIpath\fP
+Path to the RSA key for the RSA-AES security types (\fBRA2\fP, \fBRA2ne\fP,
+\fBRA2_256\fP and \fBRA2ne_256\fP) in PEM format.
.
.TP
-.B \-CompareFB \fImode\fP
-Perform pixel comparison on framebuffer to reduce unnecessary updates. Can
-be either \fB0\fP (off), \fB1\fP (always) or \fB2\fP (auto). Default is
-\fB2\fP.
+.B \-SecurityTypes \fIsec-types\fP
+Specify which security scheme to use for incoming connections. Valid values
+are a comma separated list of \fBNone\fP, \fBVncAuth\fP, \fBPlain\fP,
+\fBTLSNone\fP, \fBTLSVnc\fP, \fBTLSPlain\fP, \fBX509None\fP, \fBX509Vnc\fP,
+\fBX509Plain\fP, \fBRA2\fP, \fBRA2ne\fP, \fBRA2_256\fP and \fBRA2ne_256\fP.
+Default is \fBTLSVnc,VncAuth\fP.
.
.TP
-.B \-UseSHM
-Use MIT-SHM extension if available. Using that extension accelerates reading
-the screen. Default is on.
+.B \-UseBlacklist
+Temporarily reject connections from a host if it repeatedly fails to
+authenticate. Default is on.
.
.TP
-.B \-ImprovedHextile
-Use improved compression algorithm for Hextile encoding which achieves better
-compression ratios by the cost of using slightly more CPU time. Default is
-on.
+.B \-UseIPv4
+Use IPv4 for incoming and outgoing connections. Default is on.
.
.TP
-.B \-IdleTimeout \fIseconds\fP
-The number of seconds after which an idle VNC connection will be dropped.
-Default is 0, which means that idle connections will never be dropped.
+.B \-UseIPv6
+Use IPv6 for incoming and outgoing connections. Default is on.
.
.TP
-.B \-MaxDisconnectionTime \fIseconds\fP
-Terminate when no client has been connected for \fIN\fP seconds. Default is
-0.
+.B \-UseSHM
+Use MIT-SHM extension if available. Using that extension accelerates reading
+the screen. Default is on.
.
.TP
-.B \-MaxConnectionTime \fIseconds\fP
-Terminate when a client has been connected for \fIN\fP seconds. Default is
-0.
+.B \-X509Cert \fIpath\fP
+Path to a X509 certificate in PEM format to be used for all X509 based
+security types (X509None, X509Vnc, etc.).
.
.TP
-.B \-MaxIdleTime \fIseconds\fP
-Terminate after \fIN\fP seconds of user inactivity. Default is 0.
+.B \-X509Key \fIpath\fP
+Private key counter part to the certificate given in \fBX509Cert\fP. Must
+also be in PEM format.
.SH SEE ALSO
.BR Xvnc (1),
diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am
index 4049bafa..337d8f97 100644
--- a/unix/xserver/hw/vnc/Makefile.am
+++ b/unix/xserver/hw/vnc/Makefile.am
@@ -1,15 +1,12 @@
-TIGERVNC_SRCDIR=${top_srcdir}/../..
-TIGERVNC_BUILDDIR=${TIGERVNC_SRCDIR}
-
-# FIXME: We add an extra / to the paths to trick libtool in to adding
-# the libraries twice, to work around the dependency cycles we
-# have
-RFB_LIB=$(TIGERVNC_BUILDDIR)//common/rfb/librfb.la
-RDR_LIB=$(TIGERVNC_BUILDDIR)//common/rdr/librdr.la
-OS_LIB=$(TIGERVNC_BUILDDIR)//common/os/libos.la
-NETWORK_LIB=$(TIGERVNC_BUILDDIR)//common/network/libnetwork.la
-UNIXCOMMON_LIB=$(TIGERVNC_BUILDDIR)//unix/common/libunixcommon.la
-COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(OS_LIB) $(UNIXCOMMON_LIB)
+TIGERVNC_SRCDIR=$(abspath ${top_srcdir}/../..)
+TIGERVNC_BUILDDIR=$(abspath ${top_builddir}/../..)
+
+RFB_LIB=$(TIGERVNC_BUILDDIR)/common/rfb/librfb.la
+RDR_LIB=$(TIGERVNC_BUILDDIR)/common/rdr/librdr.la
+OS_LIB=$(TIGERVNC_BUILDDIR)/common/os/libos.la
+NETWORK_LIB=$(TIGERVNC_BUILDDIR)/common/network/libnetwork.la
+UNIXCOMMON_LIB=$(TIGERVNC_BUILDDIR)/unix/common/libunixcommon.la
+COMMON_LIBS=$(UNIXCOMMON_LIB) $(RFB_LIB) $(NETWORK_LIB) $(RDR_LIB) $(CORE_LIB)
AM_CPPFLAGS = \
-I$(TIGERVNC_BUILDDIR) \
diff --git a/unix/xserver/hw/vnc/RFBGlue.cc b/unix/xserver/hw/vnc/RFBGlue.cc
index 2295bee8..f217906a 100644
--- a/unix/xserver/hw/vnc/RFBGlue.cc
+++ b/unix/xserver/hw/vnc/RFBGlue.cc
@@ -22,35 +22,36 @@
#endif
#include <stdlib.h>
+#include <string.h>
+
+#include <core/Configuration.h>
+#include <core/Logger_stdio.h>
+#include <core/Logger_syslog.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
#include <network/TcpSocket.h>
-#include <rfb/Configuration.h>
-#include <rfb/LogWriter.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/Logger_syslog.h>
-#include <rfb/util.h>
-#include "RFBGlue.h"
+#include <rfb/UnixPasswordValidator.h>
-using namespace rfb;
+#include "RFBGlue.h"
// Loggers used by C code must be created here
-static LogWriter inputLog("Input");
-static LogWriter selectionLog("Selection");
+static core::LogWriter inputLog("Input");
+static core::LogWriter selectionLog("Selection");
void vncInitRFB(void)
{
- rfb::initStdIOLoggers();
- rfb::initSyslogLogger();
- rfb::LogWriter::setLogParams("*:stderr:30");
- rfb::Configuration::enableServerParams();
+ core::initStdIOLoggers();
+ core::initSyslogLogger();
+ core::LogWriter::setLogParams("*:stderr:30");
}
void vncLogError(const char *name, const char *format, ...)
{
- LogWriter *vlog;
+ core::LogWriter* vlog;
va_list ap;
- vlog = LogWriter::getLogWriter(name);
+ vlog = core::LogWriter::getLogWriter(name);
if (vlog == nullptr)
return;
va_start(ap, format);
@@ -60,9 +61,9 @@ void vncLogError(const char *name, const char *format, ...)
void vncLogStatus(const char *name, const char *format, ...)
{
- LogWriter *vlog;
+ core::LogWriter* vlog;
va_list ap;
- vlog = LogWriter::getLogWriter(name);
+ vlog = core::LogWriter::getLogWriter(name);
if (vlog == nullptr)
return;
va_start(ap, format);
@@ -72,9 +73,9 @@ void vncLogStatus(const char *name, const char *format, ...)
void vncLogInfo(const char *name, const char *format, ...)
{
- LogWriter *vlog;
+ core::LogWriter* vlog;
va_list ap;
- vlog = LogWriter::getLogWriter(name);
+ vlog = core::LogWriter::getLogWriter(name);
if (vlog == nullptr)
return;
va_start(ap, format);
@@ -84,9 +85,9 @@ void vncLogInfo(const char *name, const char *format, ...)
void vncLogDebug(const char *name, const char *format, ...)
{
- LogWriter *vlog;
+ core::LogWriter* vlog;
va_list ap;
- vlog = LogWriter::getLogWriter(name);
+ vlog = core::LogWriter::getLogWriter(name);
if (vlog == nullptr)
return;
va_start(ap, format);
@@ -97,30 +98,25 @@ void vncLogDebug(const char *name, const char *format, ...)
int vncSetParam(const char *name, const char *value)
{
if (value != nullptr)
- return rfb::Configuration::setParam(name, value);
+ return core::Configuration::setParam(name, value);
else {
- VoidParameter *param;
- param = rfb::Configuration::getParam(name);
+ core::VoidParameter* param;
+ param = core::Configuration::getParam(name);
if (param == nullptr)
return false;
return param->setParam();
}
}
-int vncSetParamSimple(const char *nameAndValue)
-{
- return rfb::Configuration::setParam(nameAndValue);
-}
-
char* vncGetParam(const char *name)
{
- VoidParameter *param;
+ core::VoidParameter* param;
// Hack to avoid exposing password!
if (strcasecmp(name, "Password") == 0)
return nullptr;
- param = rfb::Configuration::getParam(name);
+ param = core::Configuration::getParam(name);
if (param == nullptr)
return nullptr;
@@ -129,40 +125,18 @@ char* vncGetParam(const char *name)
const char* vncGetParamDesc(const char *name)
{
- rfb::VoidParameter *param;
+ core::VoidParameter* param;
- param = rfb::Configuration::getParam(name);
+ param = core::Configuration::getParam(name);
if (param == nullptr)
return nullptr;
return param->getDescription();
}
-int vncIsParamBool(const char *name)
-{
- VoidParameter *param;
- BoolParameter *bparam;
-
- param = rfb::Configuration::getParam(name);
- if (param == nullptr)
- return false;
-
- bparam = dynamic_cast<BoolParameter*>(param);
- if (bparam == nullptr)
- return false;
-
- return true;
-}
-
int vncGetParamCount(void)
{
- int count;
-
- count = 0;
- for (ParameterIterator i; i.param; i.next())
- count++;
-
- return count;
+ return core::Configuration::global()->size();
}
char *vncGetParamList(void)
@@ -172,8 +146,8 @@ char *vncGetParamList(void)
len = 0;
- for (ParameterIterator i; i.param; i.next()) {
- int l = strlen(i.param->getName());
+ for (core::VoidParameter *param: *core::Configuration::global()) {
+ int l = strlen(param->getName());
if (l <= 255)
len += l + 1;
}
@@ -183,11 +157,11 @@ char *vncGetParamList(void)
return nullptr;
ptr = data;
- for (ParameterIterator i; i.param; i.next()) {
- int l = strlen(i.param->getName());
+ for (core::VoidParameter *param: *core::Configuration::global()) {
+ int l = strlen(param->getName());
if (l <= 255) {
*ptr++ = l;
- memcpy(ptr, i.param->getName(), l);
+ memcpy(ptr, param->getName(), l);
ptr += l;
}
}
@@ -198,7 +172,12 @@ char *vncGetParamList(void)
void vncListParams(int width, int nameWidth)
{
- rfb::Configuration::listParams(width, nameWidth);
+ core::Configuration::listParams(width, nameWidth);
+}
+
+int vncHandleParamArg(int argc, char* argv[], int index)
+{
+ return core::Configuration::handleParamArg(argc, argv, index);
}
int vncGetSocketPort(int fd)
@@ -225,7 +204,7 @@ int vncIsTCPPortUsed(int port)
char* vncConvertLF(const char* src, size_t bytes)
{
try {
- return strdup(convertLF(src, bytes).c_str());
+ return strdup(core::convertLF(src, bytes).c_str());
} catch (...) {
return nullptr;
}
@@ -234,7 +213,7 @@ char* vncConvertLF(const char* src, size_t bytes)
char* vncLatin1ToUTF8(const char* src, size_t bytes)
{
try {
- return strdup(latin1ToUTF8(src, bytes).c_str());
+ return strdup(core::latin1ToUTF8(src, bytes).c_str());
} catch (...) {
return nullptr;
}
@@ -243,7 +222,7 @@ char* vncLatin1ToUTF8(const char* src, size_t bytes)
char* vncUTF8ToLatin1(const char* src, size_t bytes)
{
try {
- return strdup(utf8ToLatin1(src, bytes).c_str());
+ return strdup(core::utf8ToLatin1(src, bytes).c_str());
} catch (...) {
return nullptr;
}
@@ -252,8 +231,15 @@ char* vncUTF8ToLatin1(const char* src, size_t bytes)
int vncIsValidUTF8(const char* str, size_t bytes)
{
try {
- return isValidUTF8(str, bytes);
+ return core::isValidUTF8(str, bytes);
} catch (...) {
return 0;
}
}
+
+void vncSetDisplayName(const char *displayNumStr)
+{
+ std::string displayName(":");
+ displayName += displayNumStr;
+ rfb::UnixPasswordValidator::setDisplayName(displayName);
+}
diff --git a/unix/xserver/hw/vnc/RFBGlue.h b/unix/xserver/hw/vnc/RFBGlue.h
index 30c13bd2..86304ad5 100644
--- a/unix/xserver/hw/vnc/RFBGlue.h
+++ b/unix/xserver/hw/vnc/RFBGlue.h
@@ -36,15 +36,15 @@ void vncLogDebug(const char *name, const char *format, ...)
__attribute__((__format__ (__printf__, 2, 3)));
int vncSetParam(const char *name, const char *value);
-int vncSetParamSimple(const char *nameAndValue);
char* vncGetParam(const char *name);
const char* vncGetParamDesc(const char *name);
-int vncIsParamBool(const char *name);
int vncGetParamCount(void);
char *vncGetParamList(void);
void vncListParams(int width, int nameWidth);
+int vncHandleParamArg(int argc, char* argv[], int index);
+
int vncGetSocketPort(int fd);
int vncIsTCPPortUsed(int port);
@@ -55,6 +55,8 @@ char* vncUTF8ToLatin1(const char* src, size_t bytes);
int vncIsValidUTF8(const char* str, size_t bytes);
+void vncSetDisplayName(const char *displayNumStr);
+
#ifdef __cplusplus
}
#endif
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 260ed3a6..1a7a06db 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -37,10 +37,15 @@
#include <fcntl.h>
#include <sys/utsname.h>
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
+
+#include <rdr/FdInStream.h>
+#include <rdr/FdOutStream.h>
+
#include <network/Socket.h>
+
#include <rfb/VNCServerST.h>
-#include <rfb/LogWriter.h>
-#include <rfb/Configuration.h>
#include <rfb/ServerCore.h>
#include "XserverDesktop.h"
@@ -56,20 +61,17 @@ void vncSetGlueContext(int screenIndex);
void vncPresentMscEvent(uint64_t id, uint64_t msc);
}
-using namespace rfb;
-using namespace network;
+static core::LogWriter vlog("XserverDesktop");
-static LogWriter vlog("XserverDesktop");
-
-BoolParameter rawKeyboard("RawKeyboard",
- "Send keyboard events straight through and "
- "avoid mapping them to the current keyboard "
- "layout", false);
-IntParameter queryConnectTimeout("QueryConnectTimeout",
- "Number of seconds to show the "
- "Accept connection dialog before "
- "rejecting the connection",
- 10);
+core::BoolParameter
+ rawKeyboard("RawKeyboard",
+ "Send keyboard events straight through and avoid mapping "
+ "them to the current keyboard layout", false);
+core::IntParameter
+ queryConnectTimeout("QueryConnectTimeout",
+ "Number of seconds to show the 'Accept "
+ "connection' dialog before rejecting the "
+ "connection", 10, 0, INT_MAX);
XserverDesktop::XserverDesktop(int screenIndex_,
@@ -84,10 +86,10 @@ XserverDesktop::XserverDesktop(int screenIndex_,
{
format = pf;
- server = new VNCServerST(name, this);
+ server = new rfb::VNCServerST(name, this);
setFramebuffer(width, height, fbptr, stride_);
- for (SocketListener* listener : listeners)
+ for (network::SocketListener* listener : listeners)
vncSetNotifyFd(listener->getFd(), screenIndex, true, false);
}
@@ -115,7 +117,7 @@ void XserverDesktop::unblockUpdates()
void XserverDesktop::setFramebuffer(int w, int h, void* fbptr, int stride_)
{
- ScreenSet layout;
+ rfb::ScreenSet layout;
if (shadowFramebuffer) {
delete [] shadowFramebuffer;
@@ -265,7 +267,7 @@ void XserverDesktop::setCursor(int width, int height, int hotX, int hotY,
}
try {
- server->setCursor(width, height, Point(hotX, hotY), cursorData);
+ server->setCursor(width, height, {hotX, hotY}, cursorData);
} catch (std::exception& e) {
vlog.error("XserverDesktop::setCursor: %s",e.what());
}
@@ -276,13 +278,13 @@ void XserverDesktop::setCursor(int width, int height, int hotX, int hotY,
void XserverDesktop::setCursorPos(int x, int y, bool warped)
{
try {
- server->setCursorPos(Point(x, y), warped);
+ server->setCursorPos({x, y}, warped);
} catch (std::exception& e) {
vlog.error("XserverDesktop::setCursorPos: %s",e.what());
}
}
-void XserverDesktop::add_changed(const rfb::Region &region)
+void XserverDesktop::add_changed(const core::Region& region)
{
try {
server->add_changed(region);
@@ -291,7 +293,8 @@ void XserverDesktop::add_changed(const rfb::Region &region)
}
}
-void XserverDesktop::add_copied(const rfb::Region &dest, const rfb::Point &delta)
+void XserverDesktop::add_copied(const core::Region& dest,
+ const core::Point& delta)
{
try {
server->add_copied(dest, delta);
@@ -318,10 +321,10 @@ void XserverDesktop::handleSocketEvent(int fd, bool read, bool write)
}
bool XserverDesktop::handleListenerEvent(int fd,
- std::list<SocketListener*>* sockets,
- VNCServer* sockserv)
+ std::list<network::SocketListener*>* sockets,
+ rfb::VNCServer* sockserv)
{
- std::list<SocketListener*>::iterator i;
+ std::list<network::SocketListener*>::iterator i;
for (i = sockets->begin(); i != sockets->end(); i++) {
if ((*i)->getFd() == fd)
@@ -331,7 +334,7 @@ bool XserverDesktop::handleListenerEvent(int fd,
if (i == sockets->end())
return false;
- Socket* sock = (*i)->accept();
+ network::Socket* sock = (*i)->accept();
vlog.debug("New client, sock %d", sock->getFd());
sockserv->addSocket(sock);
vncSetNotifyFd(sock->getFd(), screenIndex, true, false);
@@ -340,11 +343,11 @@ bool XserverDesktop::handleListenerEvent(int fd,
}
bool XserverDesktop::handleSocketEvent(int fd,
- VNCServer* sockserv,
+ rfb::VNCServer* sockserv,
bool read, bool write)
{
- std::list<Socket*> sockets;
- std::list<Socket*>::iterator i;
+ std::list<network::Socket*> sockets;
+ std::list<network::Socket*>::iterator i;
sockserv->getSockets(&sockets);
for (i = sockets.begin(); i != sockets.end(); i++) {
@@ -361,6 +364,31 @@ bool XserverDesktop::handleSocketEvent(int fd,
if (write)
sockserv->processSocketWriteEvent(*i);
+ // Do a graceful close by waiting for the peer to close their end
+ if ((*i)->isShutdown()) {
+ bool done;
+
+ done = false;
+ while (true) {
+ try {
+ (*i)->inStream().skip((*i)->inStream().avail());
+ if (!(*i)->inStream().hasData(1))
+ break;
+ } catch (std::exception&) {
+ done = true;
+ break;
+ }
+ }
+
+ if (done) {
+ vlog.debug("Client gone, sock %d",fd);
+ vncRemoveNotifyFd(fd);
+ sockserv->removeSocket(*i);
+ vncClientGone(fd);
+ delete (*i);
+ }
+ }
+
return true;
}
@@ -373,21 +401,13 @@ void XserverDesktop::blockHandler(int* timeout)
vncInitInputDevice();
try {
- std::list<Socket*> sockets;
- std::list<Socket*>::iterator i;
+ std::list<network::Socket*> sockets;
+ std::list<network::Socket*>::iterator i;
server->getSockets(&sockets);
for (i = sockets.begin(); i != sockets.end(); i++) {
int fd = (*i)->getFd();
- if ((*i)->isShutdown()) {
- vlog.debug("Client gone, sock %d",fd);
- vncRemoveNotifyFd(fd);
- server->removeSocket(*i);
- vncClientGone(fd);
- delete (*i);
- } else {
- /* Update existing NotifyFD to listen for write (or not) */
- vncSetNotifyFd(fd, screenIndex, true, (*i)->outStream().hasBufferedData());
- }
+ /* Update existing NotifyFD to listen for write (or not) */
+ vncSetNotifyFd(fd, screenIndex, true, (*i)->outStream().hasBufferedData());
}
// We are responsible for propagating mouse movement between clients
@@ -402,7 +422,7 @@ void XserverDesktop::blockHandler(int* timeout)
}
// Trigger timers and check when the next will expire
- int nextTimeout = Timer::checkTimeouts();
+ int nextTimeout = core::Timer::checkTimeouts();
if (nextTimeout >= 0 && (*timeout == -1 || nextTimeout < *timeout))
*timeout = nextTimeout;
} catch (std::exception& e) {
@@ -410,10 +430,12 @@ void XserverDesktop::blockHandler(int* timeout)
}
}
-void XserverDesktop::addClient(Socket* sock, bool reverse, bool viewOnly)
+void XserverDesktop::addClient(network::Socket* sock,
+ bool reverse, bool viewOnly)
{
vlog.debug("New client, sock %d reverse %d",sock->getFd(),reverse);
- server->addSocket(sock, reverse, viewOnly ? AccessView : AccessDefault);
+ server->addSocket(sock, reverse,
+ viewOnly ? rfb::AccessView : rfb::AccessDefault);
vncSetNotifyFd(sock->getFd(), screenIndex, true, false);
}
@@ -462,7 +484,8 @@ void XserverDesktop::terminate()
kill(getpid(), SIGTERM);
}
-void XserverDesktop::pointerEvent(const Point& pos, uint16_t buttonMask)
+void XserverDesktop::pointerEvent(const core::Point& pos,
+ uint16_t buttonMask)
{
vncPointerMove(pos.x + vncGetScreenX(screenIndex),
pos.y + vncGetScreenY(screenIndex));
@@ -515,13 +538,13 @@ void XserverDesktop::handleClipboardData(const char* data_)
vncHandleClipboardData(data_);
}
-void XserverDesktop::grabRegion(const rfb::Region& region)
+void XserverDesktop::grabRegion(const core::Region& region)
{
if (shadowFramebuffer == nullptr)
return;
- std::vector<rfb::Rect> rects;
- std::vector<rfb::Rect>::iterator i;
+ std::vector<core::Rect> rects;
+ std::vector<core::Rect>::iterator i;
region.get_rects(&rects);
for (i = rects.begin(); i != rects.end(); i++) {
uint8_t *buffer;
@@ -542,7 +565,7 @@ void XserverDesktop::keyEvent(uint32_t keysym, uint32_t keycode, bool down)
vncKeyboardEvent(keysym, keycode, down);
}
-void XserverDesktop::handleTimeout(Timer* t)
+void XserverDesktop::handleTimeout(core::Timer* t)
{
if (t == &queryConnectTimer) {
server->approveConnection(queryConnectSocket, false,
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 8c543db7..37f5b1b5 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -31,11 +31,13 @@
#include <stdint.h>
+#include <core/Timer.h>
+
#include <rfb/SDesktop.h>
#include <rfb/PixelBuffer.h>
-#include <rfb/Configuration.h>
-#include <rfb/Timer.h>
+
#include <unixcommon.h>
+
#include "vncInput.h"
namespace rfb {
@@ -45,7 +47,7 @@ namespace rfb {
namespace network { class SocketListener; class Socket; }
class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
- public rfb::Timer::Callback {
+ public core::Timer::Callback {
public:
XserverDesktop(int screenIndex,
@@ -71,8 +73,8 @@ public:
void setCursor(int width, int height, int hotX, int hotY,
const unsigned char *rgbaData);
void setCursorPos(int x, int y, bool warped);
- void add_changed(const rfb::Region &region);
- void add_copied(const rfb::Region &dest, const rfb::Point &delta);
+ void add_changed(const core::Region& region);
+ void add_copied(const core::Region& dest, const core::Point& delta);
void handleSocketEvent(int fd, bool read, bool write);
void blockHandler(int* timeout);
void addClient(network::Socket* sock, bool reverse, bool viewOnly);
@@ -95,7 +97,8 @@ public:
void terminate() override;
void queryConnection(network::Socket* sock,
const char* userName) override;
- void pointerEvent(const rfb::Point& pos, uint16_t buttonMask) override;
+ void pointerEvent(const core::Point& pos,
+ uint16_t buttonMask) override;
void keyEvent(uint32_t keysym, uint32_t keycode, bool down) override;
unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout) override;
@@ -105,7 +108,7 @@ public:
void handleClipboardData(const char* data) override;
// rfb::PixelBuffer callbacks
- void grabRegion(const rfb::Region& r) override;
+ void grabRegion(const core::Region& r) override;
protected:
bool handleListenerEvent(int fd,
@@ -115,7 +118,7 @@ protected:
rfb::VNCServer* sockserv,
bool read, bool write);
- void handleTimeout(rfb::Timer* t) override;
+ void handleTimeout(core::Timer* t) override;
private:
@@ -128,12 +131,12 @@ private:
network::Socket* queryConnectSocket;
std::string queryConnectAddress;
std::string queryConnectUsername;
- rfb::Timer queryConnectTimer;
+ core::Timer queryConnectTimer;
OutputIdMap outputIdMap;
std::map<uint64_t, uint64_t> pendingMsc;
- rfb::Point oldCursorPos;
+ core::Point oldCursorPos;
};
#endif
diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man
index 49b1dc8a..d6b1664d 100644
--- a/unix/xserver/hw/vnc/Xvnc.man
+++ b/unix/xserver/hw/vnc/Xvnc.man
@@ -31,16 +31,25 @@ command-line, there are also "parameters" which can be set both via the
command-line and through the \fBvncconfig\fP(1) program.
.TP
-.B \-geometry \fIwidth\fPx\fIheight\fP
-Specify the size of the desktop to be created. Default is 1024x768.
-.
-.TP
.B \-depth \fIdepth\fP
Specify the pixel depth in bits of the desktop to be created. Default is 24,
other possible values are 16 and 32. Anything else is likely to cause strange
behaviour by applications and may prevent the server from starting at all.
.
.TP
+.B \-geometry \fIwidth\fPx\fIheight\fP
+Specify the size of the desktop to be created. Default is 1024x768.
+.
+.TP
+.B \-help
+List all the options and parameters
+.
+.TP
+.B \-inetd
+This significantly changes Xvnc's behaviour so that it can be launched from
+inetd. See the section below on usage with inetd.
+.
+.TP
.B \-pixelformat \fIformat\fP
Specify pixel format for server to use (BGRnnn or RGBnnn). The default for
depth 16 is RGB565 and for depth 24 and 32 is RGB888.
@@ -50,19 +59,6 @@ depth 16 is RGB565 and for depth 24 and 32 is RGB888.
DRM render node to use for DRI3 GPU acceleration. Specify an empty path to
disable DRI3. Default is \fBauto\fP which makes \fBXvnc\fP pick a suitable
available render node.
-.
-.TP
-.B \-interface \fIIP address\fP
-Listen on interface. By default Xvnc listens on all available interfaces.
-.
-.TP
-.B \-inetd
-This significantly changes Xvnc's behaviour so that it can be launched from
-inetd. See the section below on usage with inetd.
-.
-.TP
-.B \-help
-List all the options and parameters
.SH PARAMETERS
VNC parameters can be set both via the command-line and through the
@@ -76,70 +72,59 @@ Parameters can be turned on with -\fIparam\fP or off with
case-insensitive.
.TP
-.B \-desktop \fIdesktop-name\fP
-Each desktop has a name which may be displayed by the viewer. It defaults to
-"<user>@<hostname>".
-.
-.TP
-.B \-rfbport \fIport\fP
-Specifies the TCP port on which Xvnc listens for connections from viewers (the
-protocol used in VNC is called RFB - "remote framebuffer"). The default is
-5900 plus the display number. Specify \fB-1\fP to disable listening on a TCP
-port.
-.
-.TP
-.B \-UseIPv4
-Use IPv4 for incoming and outgoing connections. Default is on.
-.
-.TP
-.B \-UseIPv6
-Use IPv6 for incoming and outgoing connections. Default is on.
+.B \-AcceptCutText
+Accept clipboard updates from clients. Default is on.
.
.TP
-.B \-rfbunixpath \fIpath\fP
-Specifies the path of a Unix domain socket on which Xvnc listens for
-connections from viewers.
+.B \-AcceptKeyEvents
+Accept key press and release events from clients. Default is on.
.
.TP
-.B \-rfbunixmode \fImode\fP
-Specifies the mode of the Unix domain socket. The default is 0600.
+.B \-AcceptPointerEvents
+Accept pointer movement and button events from clients. Default is on.
.
.TP
-.B \-rfbauth \fIpasswd-file\fP, \-PasswordFile \fIpasswd-file\fP
-Password file for VNC authentication. There is no default, you should
-specify the password file explicitly. Password file should be created with
-the \fBvncpasswd\fP(1) utility. The file is accessed each time a connection
-comes in, so it can be changed on the fly.
+.B \-AcceptSetDesktopSize
+Accept requests to resize the size of the desktop. Default is on.
.
.TP
-.B \-AcceptCutText
-Accept clipboard updates from clients. Default is on.
+.B \-AllowOverride
+Comma separated list of parameters that can be modified using VNC extension.
+Parameters can be modified for example using \fBvncconfig\fP(1) program from
+inside a running session.
.
.TP
-.B \-MaxCutText \fIbytes\fP
-The maximum size of a clipboard update that will be accepted from a client.
-Default is \fB262144\fP.
+.B \-AlwaysShared
+Always treat incoming connections as shared, regardless of the client-specified
+setting. Default is off.
.
.TP
-.B \-SendCutText
-Send clipboard changes to clients. Default is on.
+.B \-AvoidShiftNumLock
+Key affected by NumLock often require a fake Shift to be inserted in order
+for the correct symbol to be generated. Turning on this option avoids these
+extra fake Shift events but may result in a slightly different symbol
+(e.g. a Return instead of a keypad Enter).
.
.TP
-.B \-SendPrimary
-Send the primary selection and cut buffer to the server as well as the
-clipboard selection. Default is on.
+.B \-BlacklistThreshold \fIcount\fP
+The number of unauthenticated connection attempts allowed from any individual
+host before that host is black-listed. Default is 5.
.
.TP
-.B \-AcceptPointerEvents
-Accept pointer movement and button events from clients. Default is on.
+.B \-BlacklistTimeout \fIseconds\fP
+The initial timeout applied when a host is first black-listed. The host
+cannot re-attempt a connection until the timeout expires. Default is 10.
.
.TP
-.B \-AcceptKeyEvents
-Accept key press and release events from clients. Default is on.
+.B \-CompareFB \fImode\fP
+Perform pixel comparison on framebuffer to reduce unnecessary updates. Can
+be either \fB0\fP (off), \fB1\fP (always) or \fB2\fP (auto). Default is
+\fB2\fP.
.
.TP
-.B \-AcceptSetDesktopSize
-Accept requests to resize the size of the desktop. Default is on.
+.B \-desktop \fIdesktop-name\fP
+Each desktop has a name which may be displayed by the viewer. It defaults to
+"<user>@<hostname>".
.
.TP
.B \-DisconnectClients
@@ -149,21 +134,6 @@ be refused while there is a client active. When combined with
\fBNeverShared\fP this means only one client is allowed at a time.
.
.TP
-.B \-NeverShared
-Never treat incoming connections as shared, regardless of the client-specified
-setting. Default is off.
-.
-.TP
-.B \-AlwaysShared
-Always treat incoming connections as shared, regardless of the client-specified
-setting. Default is off.
-.
-.TP
-.B \-Protocol3.3
-Always use protocol version 3.3 for backwards compatibility with badly-behaved
-clients. Default is off.
-.
-.TP
.B \-FrameRate \fIfps\fP
The maximum number of updates per second sent to each client. If the screen
updates any faster then those changes will be aggregated and sent in a single
@@ -171,10 +141,16 @@ update to the client. Note that this only controls the maximum rate and a
client may get a lower rate when resources are limited. Default is \fB60\fP.
.
.TP
-.B \-CompareFB \fImode\fP
-Perform pixel comparison on framebuffer to reduce unnecessary updates. Can
-be either \fB0\fP (off), \fB1\fP (always) or \fB2\fP (auto). Default is
-\fB2\fP.
+.B \-GnuTLSPriority \fIpriority\fP
+GnuTLS priority string that controls the TLS session’s handshake algorithms.
+See the GnuTLS manual for possible values. For GnuTLS < 3.6.3 the default
+value will be \fBNORMAL\fP to use upstream default. For newer versions
+of GnuTLS system-wide crypto policy will be used.
+.
+.TP
+.B \-IdleTimeout \fIseconds\fP
+The number of seconds after which an idle VNC connection will be dropped.
+Default is 0, which means that idle connections will never be dropped.
.
.TP
.B \-ImprovedHextile
@@ -183,90 +159,75 @@ compression ratios by the cost of using slightly more CPU time. Default is
on.
.
.TP
-.B \-SecurityTypes \fIsec-types\fP
-Specify which security scheme to use for incoming connections. Valid values
-are a comma separated list of \fBNone\fP, \fBVncAuth\fP, \fBPlain\fP,
-\fBTLSNone\fP, \fBTLSVnc\fP, \fBTLSPlain\fP, \fBX509None\fP, \fBX509Vnc\fP,
-\fBX509Plain\fP, \fBRA2\fP, \fBRA2ne\fP, \fBRA2_256\fP and \fBRA2ne_256\fP.
-Default is \fBTLSVnc,VncAuth\fP.
-.
-.TP
-.B \-Password \fIpassword\fP
-Obfuscated binary encoding of the password which clients must supply to
-access the server. Using this parameter is insecure, use \fBPasswordFile\fP
-parameter instead.
-.
-.TP
-.B \-PlainUsers \fIuser-list\fP
-A comma separated list of user names that are allowed to authenticate via
-any of the "Plain" security types (Plain, TLSPlain, etc.). Specify \fB*\fP
-to allow any user to authenticate using this security type. Specify \fB%u\fP
-to allow the user of the server process. Default is to deny all users.
-.
-.TP
-.B \-pam_service \fIname\fP, \-PAMService \fIname\fP
-PAM service name to use when authentication users using any of the "Plain"
-security types. Default is \fBvnc\fP.
+.B \-interface \fIIP address\fP
+Listen on interface. By default Xvnc listens on all available interfaces.
.
.TP
-.B \-X509Cert \fIpath\fP
-Path to a X509 certificate in PEM format to be used for all X509 based
-security types (X509None, X509Vnc, etc.).
+.B \-localhost
+Only allow connections from the same machine. Useful if you use SSH and want to
+stop non-SSH connections from any other hosts.
.
.TP
-.B \-X509Key \fIpath\fP
-Private key counter part to the certificate given in \fBX509Cert\fP. Must
-also be in PEM format.
+.B \-Log \fIlogname\fP:\fIdest\fP:\fIlevel\fP[, ...]
+Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP,
+\fBstdout\fP or \fBsyslog\fP, and \fIlevel\fP is between 0 and 100, 100 meaning
+most verbose output. \fIlogname\fP is usually \fB*\fP meaning all, but you can
+target a specific source file if you know the name of its "LogWriter". Default
+is \fB*:stderr:30\fP.
.
.TP
-.B \-GnuTLSPriority \fIpriority\fP
-GnuTLS priority string that controls the TLS session’s handshake algorithms.
-See the GnuTLS manual for possible values. For GnuTLS < 3.6.3 the default
-value will be \fBNORMAL\fP to use upstream default. For newer versions
-of GnuTLS system-wide crypto policy will be used.
+.B \-MaxConnectionTime \fIseconds\fP
+Terminate when a client has been connected for \fIN\fP seconds. Default is
+0.
.
.TP
-.B \-RSAKey \fIpath\fP
-Path to the RSA key for the RSA-AES security types (\fBRA2\fP, \fBRA2ne\fP,
-\fBRA2_256\fP and \fBRA2ne_256\fP) in PEM format.
+.B \-MaxCutText \fIbytes\fP
+The maximum size of a clipboard update that will be accepted from a client.
+Default is \fB262144\fP.
.
.TP
-.B \-RequireUsername
-Require username for the RSA-AES security types. Default is off.
+.B \-MaxDisconnectionTime \fIseconds\fP
+Terminate when no client has been connected for \fIN\fP seconds. Default is
+0.
.
.TP
-.B \-UseBlacklist
-Temporarily reject connections from a host if it repeatedly fails to
-authenticate. Default is on.
+.B \-MaxIdleTime \fIseconds\fP
+Terminate after \fIN\fP seconds of user inactivity. Default is 0.
.
.TP
-.B \-BlacklistThreshold \fIcount\fP
-The number of unauthenticated connection attempts allowed from any individual
-host before that host is black-listed. Default is 5.
+.B \-NeverShared
+Never treat incoming connections as shared, regardless of the client-specified
+setting. Default is off.
.
.TP
-.B \-BlacklistTimeout \fIseconds\fP
-The initial timeout applied when a host is first black-listed. The host
-cannot re-attempt a connection until the timeout expires. Default is 10.
+.B \-pam_service \fIname\fP, \-PAMService \fIname\fP
+PAM service name to use when authentication users using any of the "Plain"
+security types. Default is \fBvnc\fP.
.
.TP
-.B \-IdleTimeout \fIseconds\fP
-The number of seconds after which an idle VNC connection will be dropped.
-Default is 0, which means that idle connections will never be dropped.
+.B \-Password \fIpassword\fP
+Obfuscated binary encoding of the password which clients must supply to
+access the server. Using this parameter is insecure, use \fBPasswordFile\fP
+parameter instead.
.
.TP
-.B \-MaxDisconnectionTime \fIseconds\fP
-Terminate when no client has been connected for \fIN\fP seconds. Default is
-0.
+.B \-PasswordFile \fIpasswd-file\fP, \-rfbauth \fIpasswd-file\fP
+Password file for VNC authentication. There is no default, you should
+specify the password file explicitly. Password file should be created with
+the \fBvncpasswd\fP(1) utility. The file is accessed each time a connection
+comes in, so it can be changed on the fly.
.
.TP
-.B \-MaxConnectionTime \fIseconds\fP
-Terminate when a client has been connected for \fIN\fP seconds. Default is
-0.
+.B \-PlainUsers \fIuser-list\fP
+A comma separated list of user names that are allowed to authenticate via
+any of the "Plain" security types (Plain, TLSPlain, etc.). Specify \fB*\fP
+to allow any user to authenticate using this security type. Specify \fB%u\fP
+to allow the user of the server process. Default is to deny all users.
.
.TP
-.B \-MaxIdleTime \fIseconds\fP
-Terminate after \fIN\fP seconds of user inactivity. Default is 0.
+.B \-Protocol3.3
+Always use protocol version 3.3 for backwards compatibility with badly-behaved
+clients. Default is off.
.
.TP
.B \-QueryConnect
@@ -282,17 +243,11 @@ Number of seconds to show the Accept connection dialog before rejecting the
connection. Default is \fB10\fP.
.
.TP
-.B \-localhost
-Only allow connections from the same machine. Useful if you use SSH and want to
-stop non-SSH connections from any other hosts.
-.
-.TP
-.B \-Log \fIlogname\fP:\fIdest\fP:\fIlevel\fP
-Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP,
-\fBstdout\fP or \fBsyslog\fP, and \fIlevel\fP is between 0 and 100, 100 meaning
-most verbose output. \fIlogname\fP is usually \fB*\fP meaning all, but you can
-target a specific source file if you know the name of its "LogWriter". Default
-is \fB*:stderr:30\fP.
+.B \-RawKeyboard
+Send keyboard events straight through and avoid mapping them to the current
+keyboard layout. This effectively makes the keyboard behave according to the
+layout configured on the server instead of the layout configured on the
+client. Default is off.
.
.TP
.B \-RemapKeys \fImapping
@@ -311,24 +266,74 @@ RemapKeys=0x22<>0x40
.RE
.
.TP
-.B \-AvoidShiftNumLock
-Key affected by NumLock often require a fake Shift to be inserted in order
-for the correct symbol to be generated. Turning on this option avoids these
-extra fake Shift events but may result in a slightly different symbol
-(e.g. a Return instead of a keypad Enter).
+.B \-RequireUsername
+Require username for the RSA-AES security types. Default is off.
.
.TP
-.B \-RawKeyboard
-Send keyboard events straight through and avoid mapping them to the current
-keyboard layout. This effectively makes the keyboard behave according to the
-layout configured on the server instead of the layout configured on the
-client. Default is off.
+.B \-rfbport \fIport\fP
+Specifies the TCP port on which Xvnc listens for connections from viewers (the
+protocol used in VNC is called RFB - "remote framebuffer"). The default is
+5900 plus the display number. Specify \fB-1\fP to disable listening on a TCP
+port.
.
.TP
-.B \-AllowOverride
-Comma separated list of parameters that can be modified using VNC extension.
-Parameters can be modified for example using \fBvncconfig\fP(1) program from
-inside a running session.
+.B \-rfbunixmode \fImode\fP
+Specifies the mode of the Unix domain socket. The default is 0600.
+.
+.TP
+.B \-rfbunixpath \fIpath\fP
+Specifies the path of a Unix domain socket on which Xvnc listens for
+connections from viewers.
+.
+.TP
+.B \-RSAKey \fIpath\fP
+Path to the RSA key for the RSA-AES security types (\fBRA2\fP, \fBRA2ne\fP,
+\fBRA2_256\fP and \fBRA2ne_256\fP) in PEM format.
+.
+.TP
+.B \-SecurityTypes \fIsec-types\fP
+Specify which security scheme to use for incoming connections. Valid values
+are a comma separated list of \fBNone\fP, \fBVncAuth\fP, \fBPlain\fP,
+\fBTLSNone\fP, \fBTLSVnc\fP, \fBTLSPlain\fP, \fBX509None\fP, \fBX509Vnc\fP,
+\fBX509Plain\fP, \fBRA2\fP, \fBRA2ne\fP, \fBRA2_256\fP and \fBRA2ne_256\fP.
+Default is \fBTLSVnc,VncAuth\fP.
+.
+.TP
+.B \-SendCutText
+Send clipboard changes to clients. Default is on.
+.
+.TP
+.B \-SendPrimary
+Send the primary selection and cut buffer to the server as well as the
+clipboard selection. Default is on.
+.
+.TP
+.B \-SetPrimary
+Set the primary selection as well as the clipboard selection.
+Default is on.
+.
+.TP
+.B \-UseBlacklist
+Temporarily reject connections from a host if it repeatedly fails to
+authenticate. Default is on.
+.
+.TP
+.B \-UseIPv4
+Use IPv4 for incoming and outgoing connections. Default is on.
+.
+.TP
+.B \-UseIPv6
+Use IPv6 for incoming and outgoing connections. Default is on.
+.
+.TP
+.B \-X509Cert \fIpath\fP
+Path to a X509 certificate in PEM format to be used for all X509 based
+security types (X509None, X509Vnc, etc.).
+.
+.TP
+.B \-X509Key \fIpath\fP
+Private key counter part to the certificate given in \fBX509Cert\fP. Must
+also be in PEM format.
Allowing override of parameters such as \fBPAMService\fP or \fBPasswordFile\fP
can negatively impact security if Xvnc runs under different user than the
diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c
index e98275c2..d664c744 100644
--- a/unix/xserver/hw/vnc/vncExt.c
+++ b/unix/xserver/hw/vnc/vncExt.c
@@ -103,11 +103,13 @@ int vncNotifyQueryConnect(void)
static int ProcVncExtSetParam(ClientPtr client)
{
- char *param;
+ char *param, *value;
xVncExtSetParamReply rep;
REQUEST(xVncExtSetParamReq);
- REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen);
+ REQUEST_FIXED_SIZE(xVncExtSetParamReq,
+ ((stuff->paramLen + 3) & ~3) +
+ ((stuff->valueLen + 3) & ~3));
param = malloc(stuff->paramLen+1);
if (param == NULL)
@@ -115,6 +117,14 @@ static int ProcVncExtSetParam(ClientPtr client)
strncpy(param, (char*)&stuff[1], stuff->paramLen);
param[stuff->paramLen] = '\0';
+ value = malloc(stuff->valueLen+1);
+ if (value == NULL) {
+ free(param);
+ return BadAlloc;
+ }
+ strncpy(value, (char*)&stuff[1] + ((stuff->paramLen + 3) & ~3), stuff->valueLen);
+ value[stuff->valueLen] = '\0';
+
rep.type = X_Reply;
rep.length = 0;
rep.success = 0;
@@ -124,21 +134,22 @@ static int ProcVncExtSetParam(ClientPtr client)
* Prevent change of clipboard related parameters if clipboard is disabled.
*/
if (vncNoClipboard &&
- (strncasecmp(param, "SendCutText", 11) == 0 ||
- strncasecmp(param, "AcceptCutText", 13) == 0))
+ (strcasecmp(param, "SendCutText") == 0 ||
+ strcasecmp(param, "AcceptCutText") == 0))
goto deny;
- if (!vncOverrideParam(param))
+ if (!vncOverrideParam(param, value))
goto deny;
rep.success = 1;
// Send DesktopName update if desktop name has been changed
- if (strncasecmp(param, "desktop", 7) == 0)
+ if (strcasecmp(param, "desktop") == 0)
vncUpdateDesktopName();
deny:
free(param);
+ free(value);
if (client->swapped) {
swaps(&rep.sequenceNumber);
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index 367481ac..e9924d70 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -27,18 +27,17 @@
#include <sys/types.h>
#include <pwd.h>
-#include <set>
#include <string>
-#include <rfb/Configuration.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/LogWriter.h>
+#include <core/Configuration.h>
+#include <core/Logger_stdio.h>
+#include <core/LogWriter.h>
+#include <core/Region.h>
+
#include <rfb/ServerCore.h>
#include <rdr/HexOutStream.h>
-#include <rfb/LogWriter.h>
-#include <rfb/Hostname.h>
-#include <rfb/Region.h>
#include <rfb/ledStates.h>
+
#include <network/TcpSocket.h>
#include <network/UnixSocket.h>
@@ -55,9 +54,7 @@ extern "C" {
void vncSetGlueContext(int screenIndex);
}
-using namespace rfb;
-
-static rfb::LogWriter vlog("vncext");
+static core::LogWriter vlog("vncext");
// We can't safely get this from Xorg
#define MAXSCREENS 16
@@ -70,38 +67,43 @@ int vncFbstride[MAXSCREENS];
int vncInetdSock = -1;
-struct CaseInsensitiveCompare {
- bool operator() (const std::string &a, const std::string &b) const {
- return strcasecmp(a.c_str(), b.c_str()) < 0;
- }
-};
-
-typedef std::set<std::string, CaseInsensitiveCompare> ParamSet;
-static ParamSet allowOverrideSet;
-
static const char* defaultDesktopName();
-rfb::IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",0);
-rfb::StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", "");
-rfb::IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600);
-rfb::StringParameter desktopName("desktop", "Name of VNC desktop", defaultDesktopName());
-rfb::BoolParameter localhostOnly("localhost",
- "Only allow connections from localhost",
- false);
-rfb::StringParameter interface("interface",
- "Listen on the specified network address",
- "all");
-rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock",
- "Avoid fake Shift presses for keys affected by NumLock.",
- true);
-rfb::StringParameter allowOverride("AllowOverride",
- "Comma separated list of parameters that can be modified using VNC extension.",
- "desktop,AcceptPointerEvents,SendCutText,AcceptCutText,SendPrimary,SetPrimary");
-rfb::BoolParameter setPrimary("SetPrimary", "Set the PRIMARY as well "
- "as the CLIPBOARD selection", true);
-rfb::BoolParameter sendPrimary("SendPrimary",
- "Send the PRIMARY as well as the CLIPBOARD selection",
- true);
+core::IntParameter
+ rfbport("rfbport",
+ "TCP port to listen for RFB protocol", 0, -1, 65535);
+core::StringParameter
+ rfbunixpath("rfbunixpath",
+ "Unix socket to listen for RFB protocol", "");
+core::IntParameter
+ rfbunixmode("rfbunixmode",
+ "Unix socket access mode", 0600, 0000, 0777);
+core::StringParameter
+ desktopName("desktop", "Name of VNC desktop", defaultDesktopName());
+core::BoolParameter
+ localhostOnly("localhost",
+ "Only allow connections from localhost", false);
+core::StringParameter
+ interface("interface",
+ "Listen on the specified network address", "all");
+core::BoolParameter
+ avoidShiftNumLock("AvoidShiftNumLock",
+ "Avoid fake Shift presses for keys affected by "
+ "NumLock.", true);
+core::StringListParameter
+ allowOverride("AllowOverride",
+ "Comma separated list of parameters that can be "
+ "modified using VNC extension.",
+ {"desktop", "AcceptPointerEvents", "SendCutText",
+ "AcceptCutText", "SendPrimary", "SetPrimary"});
+core::BoolParameter
+ setPrimary("SetPrimary",
+ "Set the PRIMARY as well as the CLIPBOARD selection",
+ true);
+core::BoolParameter
+ sendPrimary("SendPrimary",
+ "Send the PRIMARY as well as the CLIPBOARD selection",
+ true);
static const char* defaultDesktopName()
{
@@ -128,7 +130,7 @@ static const char* defaultDesktopName()
return name;
}
-static PixelFormat vncGetPixelFormat(int scrIdx)
+static rfb::PixelFormat vncGetPixelFormat(int scrIdx)
{
int depth, bpp;
int trueColour, bigEndian;
@@ -152,22 +154,9 @@ static PixelFormat vncGetPixelFormat(int scrIdx)
greenMax = greenMask >> greenShift;
blueMax = blueMask >> blueShift;
- return PixelFormat(bpp, depth, bigEndian, trueColour,
- redMax, greenMax, blueMax,
- redShift, greenShift, blueShift);
-}
-
-static void parseOverrideList(const char *text, ParamSet &out)
-{
- for (const char* iter = text; ; ++iter) {
- if (*iter == ',' || *iter == '\0') {
- out.insert(std::string(text, iter));
- text = iter + 1;
-
- if (*iter == '\0')
- break;
- }
- }
+ return rfb::PixelFormat(bpp, depth, bigEndian, trueColour,
+ redMax, greenMax, blueMax,
+ redShift, greenShift, blueShift);
}
void vncExtensionInit(void)
@@ -189,9 +178,8 @@ void vncExtensionInit(void)
try {
if (!initialised) {
- rfb::initStdIOLoggers();
+ core::initStdIOLoggers();
- parseOverrideList(allowOverride, allowOverrideSet);
allowOverride.setImmutable();
initialised = true;
@@ -252,7 +240,7 @@ void vncExtensionInit(void)
if (!inetd && listeners.empty())
throw std::runtime_error("No path or port configured for incoming connections");
- PixelFormat pf = vncGetPixelFormat(scr);
+ rfb::PixelFormat pf = vncGetPixelFormat(scr);
vncSetGlueContext(scr);
desktop[scr] = new XserverDesktop(scr,
@@ -358,7 +346,7 @@ int vncConnectClient(const char *addr, int viewOnly)
std::string host;
int port;
- getHostAndPort(addr, &host, &port, 5500);
+ network::getHostAndPort(addr, &host, &port, 5500);
try {
network::Socket* sock = new network::TcpSocket(host.c_str(), port);
@@ -403,11 +391,11 @@ void vncSetLEDState(unsigned long leds)
state = 0;
if (leds & (1 << 0))
- state |= ledCapsLock;
+ state |= rfb::ledCapsLock;
if (leds & (1 << 1))
- state |= ledNumLock;
+ state |= rfb::ledNumLock;
if (leds & (1 << 2))
- state |= ledScrollLock;
+ state |= rfb::ledScrollLock;
for (int scr = 0; scr < vncGetScreenCount(); scr++)
desktop[scr]->setLEDState(state);
@@ -417,8 +405,8 @@ void vncAddChanged(int scrIdx, int nRects,
const struct UpdateRect *rects)
{
for (int i = 0;i < nRects;i++) {
- desktop[scrIdx]->add_changed(Region(Rect(rects[i].x1, rects[i].y1,
- rects[i].x2, rects[i].y2)));
+ desktop[scrIdx]->add_changed({{rects[i].x1, rects[i].y1,
+ rects[i].x2, rects[i].y2}});
}
}
@@ -427,9 +415,9 @@ void vncAddCopied(int scrIdx, int nRects,
int dx, int dy)
{
for (int i = 0;i < nRects;i++) {
- desktop[scrIdx]->add_copied(Region(Rect(rects[i].x1, rects[i].y1,
- rects[i].x2, rects[i].y2)),
- Point(dx, dy));
+ desktop[scrIdx]->add_copied({{rects[i].x1, rects[i].y1,
+ rects[i].x2, rects[i].y2}},
+ {dx, dy});
}
}
@@ -471,7 +459,7 @@ void vncPostScreenResize(int scrIdx, int success, int width, int height)
if (success) {
// Mark entire screen as changed
- desktop[scrIdx]->add_changed(Region(Rect(0, 0, width, height)));
+ desktop[scrIdx]->add_changed({{0, 0, width, height}});
}
}
@@ -511,15 +499,12 @@ void vncAbortMsc(int scrIdx, uint64_t id)
}
}
-int vncOverrideParam(const char *nameAndValue)
+int vncOverrideParam(const char *param, const char *value)
{
- const char* equalSign = strchr(nameAndValue, '=');
- if (!equalSign)
- return 0;
-
- std::string key(nameAndValue, equalSign);
- if (allowOverrideSet.find(key) == allowOverrideSet.end())
- return 0;
+ for (const char* allowed : allowOverride) {
+ if (strcasecmp(allowed, param) == 0)
+ return core::Configuration::setParam(param, value);
+ }
- return rfb::Configuration::setParam(nameAndValue);
+ return 0;
}
diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h
index 6b37fe62..425aa9b7 100644
--- a/unix/xserver/hw/vnc/vncExtInit.h
+++ b/unix/xserver/hw/vnc/vncExtInit.h
@@ -91,7 +91,7 @@ uint64_t vncGetMsc(int scrIdx);
void vncQueueMsc(int scrIdx, uint64_t id, uint64_t msc);
void vncAbortMsc(int scrIdx, uint64_t id);
-int vncOverrideParam(const char *nameAndValue);
+int vncOverrideParam(const char *param, const char *value);
#ifdef __cplusplus
}
diff --git a/unix/xserver/hw/vnc/vncInput.c b/unix/xserver/hw/vnc/vncInput.c
index a705a85a..f83806ff 100644
--- a/unix/xserver/hw/vnc/vncInput.c
+++ b/unix/xserver/hw/vnc/vncInput.c
@@ -167,7 +167,7 @@ void vncPointerMove(int x, int y)
void vncGetPointerPos(int *x, int *y)
{
- if (vncPointerDev != NULL) {
+ if ((vncPointerDev != NULL) && (vncPointerDev->public.on)) {
ScreenPtr ptrScreen;
miPointerGetPosition(vncPointerDev, &cursorPosX, &cursorPosY);
diff --git a/unix/xserver/hw/vnc/vncModule.c b/unix/xserver/hw/vnc/vncModule.c
index 5f0886a3..bff317b5 100644
--- a/unix/xserver/hw/vnc/vncModule.c
+++ b/unix/xserver/hw/vnc/vncModule.c
@@ -50,7 +50,7 @@ ExtensionModule vncExt =
static XF86ModuleVersionInfo vncVersRec =
{
"vnc",
- "TigerVNC project",
+ "TigerVNC",
MODINFOSTRING1,
MODINFOSTRING2,
VENDOR_RELEASE,
diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c
index 31301f6c..5cf673aa 100644
--- a/unix/xserver/hw/vnc/xvnc.c
+++ b/unix/xserver/hw/vnc/xvnc.c
@@ -73,8 +73,8 @@ extern char buildtime[];
#include "version-config.h"
-#define XVNCVERSION "TigerVNC 1.14.80"
-#define XVNCCOPYRIGHT ("Copyright (C) 1999-2024 TigerVNC Team and many others (see README.rst)\n" \
+#define XVNCVERSION "TigerVNC 1.15.80"
+#define XVNCCOPYRIGHT ("Copyright (C) 1999-2025 TigerVNC team and many others (see README.rst)\n" \
"See https://www.tigervnc.org for information on TigerVNC.\n")
#define VNC_DEFAULT_WIDTH 1024
@@ -110,7 +110,6 @@ static VncScreenInfo vncScreenInfo = {
static Bool vncPixmapDepths[33];
static Bool Render = TRUE;
-static Bool displaySpecified = FALSE;
static char displayNumStr[16];
static int vncVerbose = 0;
@@ -176,15 +175,20 @@ ddxGiveUp(enum ExitCode error)
vncFreeFramebufferMemory(&vncScreenInfo.fb);
}
+#if XORG_OLDER_THAN(1, 21, 1)
void
AbortDDX(enum ExitCode error)
{
ddxGiveUp(error);
}
+#endif
void
OsVendorInit(void)
{
+ /* At this point, display has been set, so we can use it to
+ * initialize UnixPasswordValidator */
+ vncSetDisplayName(display);
}
void
@@ -214,8 +218,6 @@ ddxInputThreadInit(void)
void
ddxUseMsg(void)
{
- vncPrintBanner();
-
ErrorF("-pixdepths list-of-int support given pixmap depths\n");
ErrorF("+/-render turn on/off RENDER extension support"
"(default on)\n");
@@ -278,14 +280,16 @@ ddxProcessArgument(int argc, char *argv[], int i)
}
if (argv[i][0] == ':')
- displaySpecified = TRUE;
+ return 0;
+#if XORG_OLDER_THAN(1, 21, 1)
#define CHECK_FOR_REQUIRED_ARGUMENTS(num) \
if (((i + num) >= argc) || (!argv[i + num])) { \
ErrorF("Required argument to %s not specified\n", argv[i]); \
UseMsg(); \
FatalError("Required argument to %s not specified\n", argv[i]); \
}
+#endif
if (strcmp(argv[i], "-pixdepths") == 0) { /* -pixdepths list-of-depth */
int depth, ret = 1;
@@ -384,7 +388,7 @@ ddxProcessArgument(int argc, char *argv[], int i)
dup2(nullfd, 2);
close(nullfd);
- if (!displaySpecified) {
+ if (!explicit_display) {
int port = vncGetSocketPort(vncInetdSock);
int displayNum = port - 5900;
@@ -398,9 +402,9 @@ ddxProcessArgument(int argc, char *argv[], int i)
FatalError
("Xvnc error: No free display number for -inetd\n");
}
-
- display = displayNumStr;
sprintf(displayNumStr, "%d", displayNum);
+ display = displayNumStr;
+ explicit_display = TRUE;
}
return 1;
@@ -448,28 +452,7 @@ ddxProcessArgument(int argc, char *argv[], int i)
exit(0);
}
- /* We need to resolve an ambiguity for booleans */
- if (argv[i][0] == '-' && i + 1 < argc && vncIsParamBool(&argv[i][1])) {
- if ((strcasecmp(argv[i + 1], "0") == 0) ||
- (strcasecmp(argv[i + 1], "1") == 0) ||
- (strcasecmp(argv[i + 1], "true") == 0) ||
- (strcasecmp(argv[i + 1], "false") == 0) ||
- (strcasecmp(argv[i + 1], "yes") == 0) ||
- (strcasecmp(argv[i + 1], "no") == 0)) {
- vncSetParam(&argv[i][1], argv[i + 1]);
- return 2;
- }
- }
-
- if (vncSetParamSimple(argv[i]))
- return 1;
-
- if (argv[i][0] == '-' && i + 1 < argc) {
- if (vncSetParam(&argv[i][1], argv[i + 1]))
- return 2;
- }
-
- return 0;
+ return vncHandleParamArg(argc, argv, i);
}
static Bool
@@ -765,12 +748,13 @@ vncRandRModeGet(int width, int height)
xRRModeInfo modeInfo;
char name[100];
RRModePtr mode;
+#ifdef HAVE_LIBXCVT
+ struct libxcvt_mode_info *cvtMode;
+#endif
memset(&modeInfo, 0, sizeof(modeInfo));
#ifdef HAVE_LIBXCVT
- struct libxcvt_mode_info *cvtMode;
-
cvtMode = libxcvt_gen_mode_info(width, height, 60.0, false, false);
modeInfo.width = cvtMode->hdisplay;
@@ -903,7 +887,7 @@ vncRandRCreateScreenOutputs(int scrIdx, int extraOutputs)
/* Creating and modifying modes, used by XserverDesktop and init here */
int
-vncRandRCanCreateModes()
+vncRandRCanCreateModes(void)
{
return 1;
}
@@ -1170,10 +1154,11 @@ InitOutput(ScreenInfo * scrInfo, int argc, char **argv)
int i;
int NumFormats = 0;
- vncPrintBanner();
+ if (serverGeneration == 1) {
+ vncPrintBanner();
- if (serverGeneration == 1)
LoadExtensionList(vncExtensions, ARRAY_SIZE(vncExtensions), TRUE);
+ }
#if XORG_AT_LEAST(1, 20, 0)
xorgGlxCreateVendor();
@@ -1230,11 +1215,13 @@ DDXRingBell(int percent, int pitch, int duration)
vncBell();
}
+#if XORG_OLDER_THAN(1, 21, 1)
Bool
LegalModifier(unsigned int key, DeviceIntPtr pDev)
{
return TRUE;
}
+#endif
void
ProcessInputEvents(void)
@@ -1261,3 +1248,9 @@ vncClientGone(int fd)
GiveUp(0);
}
}
+
+int
+main(int argc, char *argv[], char *envp[])
+{
+ return dix_main(argc, argv, envp);
+}
diff --git a/unix/xserver120.patch b/unix/xserver120.patch
index d36e5075..1a01f854 100644
--- a/unix/xserver120.patch
+++ b/unix/xserver120.patch
@@ -15,7 +15,7 @@ index 0909cc5b4..c01873200 100644
fi
+dnl Xvnc DDX
-+AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"])
++AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB"])
+AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"])
+
+PKG_CHECK_MODULES(GBM, "$LIBGBM", [GBM=yes], [GBM=no])
diff --git a/unix/xserver21.patch b/unix/xserver21.patch
index c4258adf..4d2b44bf 100644
--- a/unix/xserver21.patch
+++ b/unix/xserver21.patch
@@ -15,7 +15,7 @@ index fad7b5769..2c167de3d 100644
fi
+dnl Xvnc DDX
-+AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"])
++AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB"])
+AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"])
+
+PKG_CHECK_MODULES(GBM, "$LIBGBM", [GBM=yes], [GBM=no])
diff --git a/vncviewer/BaseTouchHandler.cxx b/vncviewer/BaseTouchHandler.cxx
index 6552634b..3100f86b 100644
--- a/vncviewer/BaseTouchHandler.cxx
+++ b/vncviewer/BaseTouchHandler.cxx
@@ -24,9 +24,10 @@
#include <stdlib.h>
#include <math.h>
+#include <core/time.h>
+
#define XK_MISCELLANY
#include <rfb/keysymdef.h>
-#include <rfb/util.h>
#include "GestureHandler.h"
#include "BaseTouchHandler.h"
@@ -172,7 +173,7 @@ void BaseTouchHandler::handleTapEvent(const GestureEvent& ev,
// If the user quickly taps multiple times we assume they meant to
// hit the same spot, so slightly adjust coordinates
- if ((rfb::msSince(&lastTapTime) < DOUBLE_TAP_TIMEOUT) &&
+ if ((core::msSince(&lastTapTime) < DOUBLE_TAP_TIMEOUT) &&
(firstDoubleTapEvent.type == ev.type)) {
double dx = firstDoubleTapEvent.eventX - ev.eventX;
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index f8e80429..da99c8f1 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -27,17 +27,21 @@
#include <unistd.h>
#endif
-#include <rdr/Exception.h>
+#include <core/LogWriter.h>
+#include <core/Timer.h>
+#include <core/string.h>
+#include <core/time.h>
+
+#include <rdr/FdInStream.h>
+#include <rdr/FdOutStream.h>
#include <rfb/CMsgWriter.h>
#include <rfb/CSecurity.h>
#include <rfb/Exception.h>
-#include <rfb/Hostname.h>
-#include <rfb/LogWriter.h>
#include <rfb/Security.h>
-#include <rfb/screenTypes.h>
#include <rfb/fenceTypes.h>
-#include <rfb/Timer.h>
+#include <rfb/screenTypes.h>
+
#include <network/TcpSocket.h>
#ifndef WIN32
#include <network/UnixSocket.h>
@@ -58,29 +62,27 @@
#include "win32.h"
#endif
-using namespace rfb;
-
-static rfb::LogWriter vlog("CConn");
+static core::LogWriter vlog("CConn");
// 8 colours (1 bit per component)
-static const PixelFormat verylowColourPF(8, 3,false, true,
- 1, 1, 1, 2, 1, 0);
+static const rfb::PixelFormat verylowColourPF(8, 3,false, true,
+ 1, 1, 1, 2, 1, 0);
// 64 colours (2 bits per component)
-static const PixelFormat lowColourPF(8, 6, false, true,
- 3, 3, 3, 4, 2, 0);
+static const rfb::PixelFormat lowColourPF(8, 6, false, true,
+ 3, 3, 3, 4, 2, 0);
// 256 colours (2-3 bits per component)
-static const PixelFormat mediumColourPF(8, 8, false, true,
- 7, 7, 3, 5, 2, 0);
+static const rfb::PixelFormat mediumColourPF(8, 8, false, true,
+ 7, 7, 3, 5, 2, 0);
// Time new bandwidth estimates are weighted against (in ms)
static const unsigned bpsEstimateWindow = 1000;
-CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)
- : serverPort(0), desktop(nullptr), updateCount(0), pixelCount(0),
+CConn::CConn()
+ : serverPort(0), sock(nullptr), desktop(nullptr),
+ updateCount(0), pixelCount(0),
lastServerEncoding((unsigned int)-1), bpsEstimate(20000000)
{
setShared(::shared);
- sock = socket;
supportsLocalCursor = true;
supportsCursorPosition = true;
@@ -93,6 +95,61 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)
if (!noJpeg)
setQualityLevel(::qualityLevel);
+ OptionsDialog::addCallback(handleOptions, this);
+}
+
+CConn::~CConn()
+{
+ close();
+
+ OptionsDialog::removeCallback(handleOptions);
+ Fl::remove_timeout(handleUpdateTimeout, this);
+
+ if (desktop)
+ delete desktop;
+
+ if (sock) {
+ struct timeval now;
+
+ sock->shutdown();
+
+ // Do a graceful close by waiting for the peer (up to 250 ms)
+ // FIXME: should do this asynchronously
+ gettimeofday(&now, nullptr);
+ while (core::msSince(&now) < 250) {
+ bool done;
+
+ done = false;
+ while (true) {
+ try {
+ sock->inStream().skip(sock->inStream().avail());
+ if (!sock->inStream().hasData(1))
+ break;
+ } catch (std::exception&) {
+ done = true;
+ break;
+ }
+ }
+
+ if (done)
+ break;
+
+ #ifdef WIN32
+ Sleep(10);
+ #else
+ usleep(10000);
+ #endif
+ }
+
+ Fl::remove_fd(sock->getFd());
+
+ delete sock;
+ }
+}
+
+void CConn::connect(const char* vncServerName, network::Socket* socket)
+{
+ sock = socket;
if(sock == nullptr) {
try {
#ifndef WIN32
@@ -103,7 +160,7 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)
} else
#endif
{
- getHostAndPort(vncServerName, &serverHost, &serverPort);
+ network::getHostAndPort(vncServerName, &serverHost, &serverPort);
sock = new network::TcpSocket(serverHost.c_str(), serverPort);
vlog.info(_("Connected to host %s port %d"),
@@ -123,23 +180,6 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)
setStreams(&sock->inStream(), &sock->outStream());
initialiseProtocol();
-
- OptionsDialog::addCallback(handleOptions, this);
-}
-
-CConn::~CConn()
-{
- close();
-
- OptionsDialog::removeCallback(handleOptions);
- Fl::remove_timeout(handleUpdateTimeout, this);
-
- if (desktop)
- delete desktop;
-
- if (sock)
- Fl::remove_fd(sock->getFd());
- delete sock;
}
std::string CConn::connectionInfo()
@@ -148,46 +188,41 @@ std::string CConn::connectionInfo()
char pfStr[100];
- infoText += format(_("Desktop name: %.80s"), server.name());
+ infoText += core::format(_("Desktop name: %.80s"), server.name());
infoText += "\n";
- infoText += format(_("Host: %.80s port: %d"),
- serverHost.c_str(), serverPort);
+ infoText += core::format(_("Host: %.80s port: %d"),
+ serverHost.c_str(), serverPort);
infoText += "\n";
- infoText += format(_("Size: %d x %d"),
- server.width(), server.height());
+ infoText += core::format(_("Size: %d x %d"),
+ server.width(), server.height());
infoText += "\n";
// TRANSLATORS: Will be filled in with a string describing the
// protocol pixel format in a fairly language neutral way
server.pf().print(pfStr, 100);
- infoText += format(_("Pixel format: %s"), pfStr);
+ infoText += core::format(_("Pixel format: %s"), pfStr);
infoText += "\n";
- // TRANSLATORS: Similar to the earlier "Pixel format" string
- serverPF.print(pfStr, 100);
- infoText += format(_("(server default %s)"), pfStr);
+ infoText += core::format(_("Requested encoding: %s"),
+ rfb::encodingName(getPreferredEncoding()));
infoText += "\n";
- infoText += format(_("Requested encoding: %s"),
- encodingName(getPreferredEncoding()));
+ infoText += core::format(_("Last used encoding: %s"),
+ rfb::encodingName(lastServerEncoding));
infoText += "\n";
- infoText += format(_("Last used encoding: %s"),
- encodingName(lastServerEncoding));
+ infoText += core::format(_("Line speed estimate: %d kbit/s"),
+ (int)(bpsEstimate / 1000));
infoText += "\n";
- infoText += format(_("Line speed estimate: %d kbit/s"),
- (int)(bpsEstimate / 1000));
+ infoText += core::format(_("Protocol version: %d.%d"),
+ server.majorVersion, server.minorVersion);
infoText += "\n";
- infoText += format(_("Protocol version: %d.%d"),
- server.majorVersion, server.minorVersion);
- infoText += "\n";
-
- infoText += format(_("Security method: %s"),
- secTypeName(csecurity->getType()));
+ infoText += core::format(_("Security method: %s"),
+ rfb::secTypeName(csecurity->getType()));
infoText += "\n";
return infoText;
@@ -236,7 +271,7 @@ void CConn::socketEvent(FL_SOCKET fd, void *data)
// Make sure that the FLTK handling and the timers gets some CPU
// time in case of back to back messages
Fl::check();
- Timer::checkTimeouts();
+ core::Timer::checkTimeouts();
// Also check if we need to stop reading and terminate
if (should_disconnect())
@@ -282,7 +317,7 @@ void CConn::resetPassword()
////////////////////// CConnection callback methods //////////////////////
-bool CConn::showMsgBox(MsgBoxFlags flags, const char *title,
+bool CConn::showMsgBox(rfb::MsgBoxFlags flags, const char *title,
const char *text)
{
return dlg.showMsgBox(flags, title, text);
@@ -304,46 +339,29 @@ void CConn::initDone()
if (server.beforeVersion(3, 8) && autoSelect)
fullColour.setParam(true);
- serverPF = server.pf();
-
- desktop = new DesktopWindow(server.width(), server.height(),
- server.name(), serverPF, this);
+ desktop = new DesktopWindow(server.width(), server.height(), this);
fullColourPF = desktop->getPreferredPF();
// Force a switch to the format and encoding we'd like
+ updateEncoding();
updatePixelFormat();
- int encNum = encodingNum(::preferredEncoding);
- if (encNum != -1)
- setPreferredEncoding(encNum);
-}
-
-// setDesktopSize() is called when the desktop size changes (including when
-// it is set initially).
-void CConn::setDesktopSize(int w, int h)
-{
- CConnection::setDesktopSize(w,h);
- resizeFramebuffer();
}
-// setExtendedDesktopSize() is a more advanced version of setDesktopSize()
void CConn::setExtendedDesktopSize(unsigned reason, unsigned result,
- int w, int h, const rfb::ScreenSet& layout)
+ int w, int h,
+ const rfb::ScreenSet& layout)
{
CConnection::setExtendedDesktopSize(reason, result, w, h, layout);
- if ((reason == reasonClient) && (result != resultSuccess)) {
- vlog.error(_("SetDesktopSize failed: %d"), result);
- return;
- }
-
- resizeFramebuffer();
+ if (reason == rfb::reasonClient)
+ desktop->setDesktopSizeDone(result);
}
// setName() is called when the desktop name changes
void CConn::setName(const char* name)
{
CConnection::setName(name);
- desktop->setName(name);
+ desktop->updateCaption();
}
// framebufferUpdateStart() is called at the beginning of an update.
@@ -396,28 +414,25 @@ void CConn::framebufferUpdateEnd()
desktop->updateWindow();
// Compute new settings based on updated bandwidth values
- if (autoSelect)
- autoSelectFormatAndEncoding();
+ if (autoSelect) {
+ updateEncoding();
+ updateQualityLevel();
+ updatePixelFormat();
+ }
}
// The rest of the callbacks are fairly self-explanatory...
-void CConn::setColourMapEntries(int /*firstColour*/, int /*nColours*/,
- uint16_t* /*rgbs*/)
-{
- vlog.error(_("Invalid SetColourMapEntries from server!"));
-}
-
void CConn::bell()
{
fl_beep();
}
-bool CConn::dataRect(const Rect& r, int encoding)
+bool CConn::dataRect(const core::Rect& r, int encoding)
{
bool ret;
- if (encoding != encodingCopyRect)
+ if (encoding != rfb::encodingCopyRect)
lastServerEncoding = encoding;
ret = CConnection::dataRect(r, encoding);
@@ -428,28 +443,17 @@ bool CConn::dataRect(const Rect& r, int encoding)
return ret;
}
-void CConn::setCursor(int width, int height, const Point& hotspot,
+void CConn::setCursor(int width, int height, const core::Point& hotspot,
const uint8_t* data)
{
- desktop->setCursor(width, height, hotspot, data);
-}
+ CConnection::setCursor(width, height, hotspot, data);
-void CConn::setCursorPos(const Point& pos)
-{
- desktop->setCursorPos(pos);
+ desktop->setCursor();
}
-void CConn::fence(uint32_t flags, unsigned len, const uint8_t data[])
+void CConn::setCursorPos(const core::Point& pos)
{
- CMsgHandler::fence(flags, len, data);
-
- if (flags & fenceFlagRequest) {
- // We handle everything synchronously so we trivially honor these modes
- flags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter);
-
- writer()->writeFence(flags, len, data);
- return;
- }
+ desktop->setCursorPos(pos);
}
void CConn::setLEDState(unsigned int state)
@@ -482,44 +486,59 @@ void CConn::resizeFramebuffer()
desktop->resizeFramebuffer(server.width(), server.height());
}
-// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
-// to the connection speed:
-//
-// First we wait for at least one second of bandwidth measurement.
-//
-// Above 16Mbps (i.e. LAN), we choose the second highest JPEG quality,
-// which should be perceptually lossless.
-//
-// If the bandwidth is below that, we choose a more lossy JPEG quality.
-//
-// If the bandwidth drops below 256 Kbps, we switch to palette mode.
-//
-// Note: The system here is fairly arbitrary and should be replaced
-// with something more intelligent at the server end.
-//
-void CConn::autoSelectFormatAndEncoding()
+void CConn::updateEncoding()
+{
+ int encNum;
+
+ if (autoSelect)
+ encNum = rfb::encodingTight;
+ else
+ encNum = rfb::encodingNum(::preferredEncoding.getValueStr().c_str());
+
+ if (encNum != -1)
+ setPreferredEncoding(encNum);
+}
+
+void CConn::updateCompressLevel()
{
- bool newFullColour = fullColour;
- int newQualityLevel = ::qualityLevel;
+ if (customCompressLevel)
+ setCompressLevel(::compressLevel);
+ else
+ setCompressLevel(-1);
+}
- // Always use Tight
- setPreferredEncoding(encodingTight);
+void CConn::updateQualityLevel()
+{
+ int newQualityLevel;
+
+ if (noJpeg)
+ newQualityLevel = -1;
+ else if (!autoSelect)
+ newQualityLevel = ::qualityLevel;
+ else {
+ // Above 16Mbps (i.e. LAN), we choose the second highest JPEG
+ // quality, which should be perceptually lossless. If the bandwidth
+ // is below that, we choose a more lossy JPEG quality.
- // Select appropriate quality level
- if (!noJpeg) {
if (bpsEstimate > 16000000)
newQualityLevel = 8;
else
newQualityLevel = 6;
- if (newQualityLevel != ::qualityLevel) {
+ if (newQualityLevel != getQualityLevel()) {
vlog.info(_("Throughput %d kbit/s - changing to quality %d"),
(int)(bpsEstimate/1000), newQualityLevel);
- ::qualityLevel.setParam(newQualityLevel);
- setQualityLevel(newQualityLevel);
}
}
+ setQualityLevel(newQualityLevel);
+}
+
+void CConn::updatePixelFormat()
+{
+ bool useFullColour;
+ rfb::PixelFormat pf;
+
if (server.beforeVersion(3, 8)) {
// Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
// cursors "asynchronously". If this happens in the middle of a
@@ -530,28 +549,23 @@ void CConn::autoSelectFormatAndEncoding()
// old servers.
return;
}
-
- // Select best color level
- newFullColour = (bpsEstimate > 256000);
- if (newFullColour != fullColour) {
- if (newFullColour)
- vlog.info(_("Throughput %d kbit/s - full color is now enabled"),
- (int)(bpsEstimate/1000));
- else
- vlog.info(_("Throughput %d kbit/s - full color is now disabled"),
- (int)(bpsEstimate/1000));
- fullColour.setParam(newFullColour);
- updatePixelFormat();
- }
-}
-// requestNewUpdate() requests an update from the server, having set the
-// format and encoding appropriately.
-void CConn::updatePixelFormat()
-{
- PixelFormat pf;
+ useFullColour = fullColour;
+
+ // If the bandwidth drops below 256 Kbps, we switch to palette mode.
+ if (autoSelect) {
+ useFullColour = (bpsEstimate > 256000);
+ if (useFullColour != (server.pf() == fullColourPF)) {
+ if (useFullColour)
+ vlog.info(_("Throughput %d kbit/s - full color is now enabled"),
+ (int)(bpsEstimate/1000));
+ else
+ vlog.info(_("Throughput %d kbit/s - full color is now disabled"),
+ (int)(bpsEstimate/1000));
+ }
+ }
- if (fullColour) {
+ if (useFullColour) {
pf = fullColourPF;
} else {
if (lowColourLevel == 0)
@@ -562,37 +576,21 @@ void CConn::updatePixelFormat()
pf = mediumColourPF;
}
- char str[256];
- pf.print(str, 256);
- vlog.info(_("Using pixel format %s"),str);
- setPF(pf);
+ if (pf != server.pf()) {
+ char str[256];
+ pf.print(str, 256);
+ vlog.info(_("Using pixel format %s"),str);
+ setPF(pf);
+ }
}
void CConn::handleOptions(void *data)
{
CConn *self = (CConn*)data;
- // Checking all the details of the current set of encodings is just
- // a pain. Assume something has changed, as resending the encoding
- // list is cheap. Avoid overriding what the auto logic has selected
- // though.
- if (!autoSelect) {
- int encNum = encodingNum(::preferredEncoding);
-
- if (encNum != -1)
- self->setPreferredEncoding(encNum);
- }
-
- if (customCompressLevel)
- self->setCompressLevel(::compressLevel);
- else
- self->setCompressLevel(-1);
-
- if (!noJpeg && !autoSelect)
- self->setQualityLevel(::qualityLevel);
- else
- self->setQualityLevel(-1);
-
+ self->updateEncoding();
+ self->updateCompressLevel();
+ self->updateQualityLevel();
self->updatePixelFormat();
}
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
index a7b9afda..bc30d9b7 100644
--- a/vncviewer/CConn.h
+++ b/vncviewer/CConn.h
@@ -23,7 +23,7 @@
#include <FL/Fl.H>
#include <rfb/CConnection.h>
-#include <rdr/FdInStream.h>
+
#include "UserDialog.h"
namespace network { class Socket; }
@@ -33,15 +33,19 @@ class DesktopWindow;
class CConn : public rfb::CConnection
{
public:
- CConn(const char* vncServerName, network::Socket* sock);
+ CConn();
~CConn();
+ void connect(const char* vncServerName, network::Socket* sock=nullptr);
+
std::string connectionInfo();
unsigned getUpdateCount();
unsigned getPixelCount();
unsigned getPosition();
+protected:
+
// Callback when socket is ready (or broken)
static void socketEvent(FL_SOCKET fd, void *data);
@@ -57,28 +61,21 @@ public:
void initDone() override;
- void setDesktopSize(int w, int h) override;
void setExtendedDesktopSize(unsigned reason, unsigned result,
int w, int h,
const rfb::ScreenSet& layout) override;
void setName(const char* name) override;
- void setColourMapEntries(int firstColour, int nColours,
- uint16_t* rgbs) override;
-
void bell() override;
void framebufferUpdateStart() override;
void framebufferUpdateEnd() override;
- bool dataRect(const rfb::Rect& r, int encoding) override;
+ bool dataRect(const core::Rect& r, int encoding) override;
- void setCursor(int width, int height, const rfb::Point& hotspot,
+ void setCursor(int width, int height, const core::Point& hotspot,
const uint8_t* data) override;
- void setCursorPos(const rfb::Point& pos) override;
-
- void fence(uint32_t flags, unsigned len,
- const uint8_t data[]) override;
+ void setCursorPos(const core::Point& pos) override;
void setLEDState(unsigned int state) override;
@@ -90,7 +87,9 @@ private:
void resizeFramebuffer() override;
- void autoSelectFormatAndEncoding();
+ void updateEncoding();
+ void updateCompressLevel();
+ void updateQualityLevel();
void updatePixelFormat();
static void handleOptions(void *data);
@@ -107,7 +106,6 @@ private:
unsigned updateCount;
unsigned pixelCount;
- rfb::PixelFormat serverPF;
rfb::PixelFormat fullColourPF;
int lastServerEncoding;
diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt
index 72904b25..1ca6675d 100644
--- a/vncviewer/CMakeLists.txt
+++ b/vncviewer/CMakeLists.txt
@@ -6,13 +6,13 @@ add_executable(vncviewer
fltk/Fl_Monitor_Arrangement.cxx
fltk/Fl_Navigation.cxx
fltk/theme.cxx
- menukey.cxx
BaseTouchHandler.cxx
CConn.cxx
DesktopWindow.cxx
EmulateMB.cxx
UserDialog.cxx
ServerDialog.cxx
+ ShortcutHandler.cxx
Surface.cxx
OptionsDialog.cxx
PlatformPixelBuffer.cxx
@@ -49,9 +49,10 @@ else()
endif()
target_include_directories(vncviewer SYSTEM PUBLIC ${FLTK_INCLUDE_DIR})
-target_include_directories(vncviewer SYSTEM PUBLIC ${GETTEXT_INCLUDE_DIR})
+target_include_directories(vncviewer SYSTEM PUBLIC ${Intl_INCLUDE_DIR})
target_include_directories(vncviewer PUBLIC ${CMAKE_SOURCE_DIR}/common)
-target_link_libraries(vncviewer rfb network rdr os ${FLTK_LIBRARIES} ${GETTEXT_LIBRARIES})
+target_link_libraries(vncviewer core rfb network rdr)
+target_link_libraries(vncviewer ${FLTK_LIBRARIES} ${Intl_LIBRARIES})
if(WIN32)
target_link_libraries(vncviewer msimg32)
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 6dbd7d5f..831bb107 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright 2011-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,11 +26,16 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
+#include <unistd.h>
#include <sys/time.h>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+#include <core/time.h>
+
#include <rfb/CMsgWriter.h>
-#include <rfb/util.h>
+#include <rfb/ScreenSet.h>
#include "DesktopWindow.h"
#include "OptionsDialog.h"
@@ -70,21 +75,21 @@ static int edge_scroll_size_y = 96;
// default: roughly 60 fps for smooth motion
#define EDGE_SCROLL_SECONDS_PER_FRAME 0.016666
-using namespace rfb;
+// Time before we show an overlay tip again
+const time_t OVERLAY_REPEAT_TIMEOUT = 600;
-static rfb::LogWriter vlog("DesktopWindow");
+static core::LogWriter vlog("DesktopWindow");
// Global due to http://www.fltk.org/str.php?L2177 and the similar
// issue for Fl::event_dispatch.
static std::set<DesktopWindow *> instances;
-DesktopWindow::DesktopWindow(int w, int h, const char *name,
- const rfb::PixelFormat& serverPF,
- CConn* cc_)
- : Fl_Window(w, h), cc(cc_), offscreen(nullptr), overlay(nullptr),
+DesktopWindow::DesktopWindow(int w, int h, CConn* cc_)
+ : Fl_Window(w, h), cc(cc_), offscreen(nullptr),
firstUpdate(true),
- delayedFullscreen(false), delayedDesktopSize(false),
- keyboardGrabbed(false), mouseGrabbed(false),
+ delayedFullscreen(false), sentDesktopSize(false),
+ pendingRemoteResize(false), lastResize({0, 0}),
+ keyboardGrabbed(false), mouseGrabbed(false), regrabOnFocus(false),
statsLastUpdates(0), statsLastPixels(0), statsLastPosition(0),
statsGraph(nullptr)
{
@@ -95,7 +100,7 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
group->resizable(nullptr);
resizable(group);
- viewport = new Viewport(w, h, serverPF, cc);
+ viewport = new Viewport(w, h, cc);
// Position will be adjusted later
hscroll = new Fl_Scrollbar(0, 0, 0, 0);
@@ -108,7 +113,7 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
callback(handleClose, this);
- setName(name);
+ updateCaption();
OptionsDialog::addCallback(handleOptions, this);
@@ -174,7 +179,7 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
#ifdef __APPLE__
// On OS X we can do the maximize thing properly before the
// window is showned. Other platforms handled further down...
- if (maximize) {
+ if (::maximize) {
int dummy;
Fl::screen_work_area(dummy, dummy, w, h, geom_x, geom_y);
}
@@ -199,6 +204,11 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
show();
+#ifdef __APPLE__
+ // FLTK does its own full screen, so disable the system one
+ cocoa_prevent_native_fullscreen(this);
+#endif
+
// Full screen events are not sent out for a hidden window,
// so send a fake one here to set up things properly.
if (fullscreen_active())
@@ -208,7 +218,7 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
// maximized property on Windows and X11 before showing the window.
// See STR #2083 and STR #2178
#ifndef __APPLE__
- if (maximize) {
+ if (::maximize) {
maximizeWindow();
}
#endif
@@ -216,22 +226,22 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
// Adjust layout now that we're visible and know our final size
repositionWidgets();
- if (delayedFullscreen) {
- // Hack: Fullscreen requests may be ignored, so we need a timeout for
- // when we should stop waiting. We also really need to wait for the
- // resize, which can come after the fullscreen event.
- Fl::add_timeout(0.5, handleFullscreenTimeout, this);
- fullscreen_on();
- }
-
// Throughput graph for debugging
- if (vlog.getLevel() >= LogWriter::LEVEL_DEBUG) {
+ if (vlog.getLevel() >= core::LogWriter::LEVEL_DEBUG) {
memset(&stats, 0, sizeof(stats));
Fl::add_timeout(0, handleStatsTimeout, this);
}
- // Show hint about menu key
- Fl::add_timeout(0.5, menuOverlay, this);
+ // Show hint about menu shortcut
+ unsigned modifierMask;
+
+ modifierMask = 0;
+ for (core::EnumListEntry key : shortcutModifiers)
+ modifierMask |= ShortcutHandler::parseModifier(key.getValueStr().c_str());
+
+ if (modifierMask)
+ addOverlayTip(_("Press %sM to open the context menu"),
+ ShortcutHandler::modifierPrefix(modifierMask));
// By default we get a slight delay when we warp the pointer, something
// we don't want or we'll get jerky movement
@@ -252,17 +262,18 @@ DesktopWindow::~DesktopWindow()
// Unregister all timeouts in case they get a change tro trigger
// again later when this object is already gone.
- Fl::remove_timeout(handleGrab, this);
Fl::remove_timeout(handleResizeTimeout, this);
Fl::remove_timeout(handleFullscreenTimeout, this);
Fl::remove_timeout(handleEdgeScroll, this);
Fl::remove_timeout(handleStatsTimeout, this);
- Fl::remove_timeout(menuOverlay, this);
Fl::remove_timeout(updateOverlay, this);
OptionsDialog::removeCallback(handleOptions);
- delete overlay;
+ while (!overlays.empty()) {
+ delete overlays.front().surface;
+ overlays.pop_front();
+ }
delete offscreen;
delete statsGraph;
@@ -285,13 +296,50 @@ const rfb::PixelFormat &DesktopWindow::getPreferredPF()
}
-void DesktopWindow::setName(const char *name)
+void DesktopWindow::updateCaption()
{
- char windowNameStr[256];
+ const size_t maxLen = 100;
+ std::string windowName;
+ const char *labelFormat;
+ size_t maxNameSize;
+ std::string name;
+
+ // FIXME: All of this consideres bytes, not characters
+
+ if (keyboardGrabbed)
+ labelFormat = _("%s - TigerVNC (keyboard grabbed)");
+ else
+ labelFormat = _("%s - TigerVNC");
+
+ // Ignore the length of '%s' since it is
+ // a format marker which won't take up space
+ maxNameSize = maxLen - strlen(labelFormat) + 2;
+
+ name = cc->server.name();
+
+ if (name.size() > maxNameSize) {
+ if (maxNameSize <= strlen("...")) {
+ // Even an ellipsis won't fit
+ name.clear();
+ }
+ else {
+ int offset;
+
+ // We need to truncate, add an ellipsis
+ offset = maxNameSize - strlen("...");
+ name.resize(offset);
+ name += "...";
+ }
+ }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+ windowName = core::format(labelFormat, name.c_str());
- snprintf(windowNameStr, 256, "%.240s - TigerVNC", name);
+#pragma GCC diagnostic pop
- copy_label(windowNameStr);
+ copy_label(windowName.c_str());
}
@@ -301,15 +349,8 @@ void DesktopWindow::setName(const char *name)
void DesktopWindow::updateWindow()
{
if (firstUpdate) {
- if (cc->server.supportsSetDesktopSize) {
- // Hack: Wait until we're in the proper mode and position until
- // resizing things, otherwise we might send the wrong thing.
- if (delayedFullscreen)
- delayedDesktopSize = true;
- else
- handleDesktopSize();
- }
firstUpdate = false;
+ remoteResize();
}
viewport->updateWindow();
@@ -372,15 +413,26 @@ void DesktopWindow::resizeFramebuffer(int new_w, int new_h)
}
-void DesktopWindow::setCursor(int width, int height,
- const rfb::Point& hotspot,
- const uint8_t* data)
+void DesktopWindow::setDesktopSizeDone(unsigned result)
+{
+ pendingRemoteResize = false;
+
+ if (result != 0)
+ return;
+
+ // We might have resized again whilst waiting for the previous
+ // request, so check if we are in sync
+ remoteResize();
+}
+
+
+void DesktopWindow::setCursor()
{
- viewport->setCursor(width, height, hotspot, data);
+ viewport->setCursor();
}
-void DesktopWindow::setCursorPos(const rfb::Point& pos)
+void DesktopWindow::setCursorPos(const core::Point& pos)
{
if (!mouseGrabbed) {
// Do nothing if we do not have the mouse captured.
@@ -498,16 +550,19 @@ void DesktopWindow::draw()
}
// Overlay (if active)
- if (overlay) {
+ if (!overlays.empty()) {
int ox, oy, ow, oh;
int sx, sy, sw, sh;
+ struct Overlay overlay;
+
+ overlay = overlays.front();
// Make sure it's properly seen by adjusting it relative to the
// primary screen rather than the entire window
if (fullscreen_active()) {
assert(Fl::screen_count() >= 1);
- rfb::Rect windowRect, screenRect;
+ core::Rect windowRect, screenRect;
windowRect.setXYWH(x(), y(), w(), h());
bool foundEnclosedScreen = false;
@@ -538,18 +593,20 @@ void DesktopWindow::draw()
sw = w();
}
- ox = X = sx + (sw - overlay->width()) / 2;
+ ox = X = sx + (sw - overlay.surface->width()) / 2;
oy = Y = sy + 50;
- ow = overlay->width();
- oh = overlay->height();
+ ow = overlay.surface->width();
+ oh = overlay.surface->height();
fl_clip_box(ox, oy, ow, oh, ox, oy, ow, oh);
if ((ow != 0) && (oh != 0)) {
if (offscreen)
- overlay->blend(offscreen, ox - X, oy - Y, ox, oy, ow, oh, overlayAlpha);
+ overlay.surface->blend(offscreen, ox - X, oy - Y,
+ ox, oy, ow, oh, overlay.alpha);
else
- overlay->blend(ox - X, oy - Y, ox, oy, ow, oh, overlayAlpha);
+ overlay.surface->blend(ox - X, oy - Y,
+ ox, oy, ow, oh, overlay.alpha);
}
}
@@ -659,51 +716,59 @@ void DesktopWindow::resize(int x, int y, int w, int h)
Fl_Window::resize(x, y, w, h);
if (resizing) {
- // Try to get the remote size to match our window size, provided
- // the following conditions are true:
- //
- // a) The user has this feature turned on
- // b) The server supports it
- // c) We're not still waiting for a chance to handle DesktopSize
- // d) We're not still waiting for startup fullscreen to kick in
- //
- if (not firstUpdate and not delayedFullscreen and
- ::remoteResize and cc->server.supportsSetDesktopSize) {
- // We delay updating the remote desktop as we tend to get a flood
- // of resize events as the user is dragging the window.
- Fl::remove_timeout(handleResizeTimeout, this);
- Fl::add_timeout(0.5, handleResizeTimeout, this);
- }
+ remoteResize();
repositionWidgets();
}
-
- // Some systems require a grab after the window size has been changed.
- // Otherwise they might hold on to displays, resulting in them being unusable.
- maybeGrabKeyboard();
}
-
-void DesktopWindow::menuOverlay(void* data)
+void DesktopWindow::addOverlayTip(const char* text, ...)
{
- DesktopWindow *self;
+ va_list ap;
+ char textbuf[1024];
- self = (DesktopWindow*)data;
+ std::map<std::string, time_t>::iterator iter;
+
+ va_start(ap, text);
+ vsnprintf(textbuf, sizeof(textbuf), text, ap);
+ textbuf[sizeof(textbuf)-1] = '\0';
+ va_end(ap);
- if (strcmp((const char*)menuKey, "") != 0) {
- self->setOverlay(_("Press %s to open the context menu"),
- (const char*)menuKey);
+ // Purge all old entries
+ for (iter = overlayTimes.begin(); iter != overlayTimes.end(); ) {
+ if ((time(nullptr) - iter->second) >= OVERLAY_REPEAT_TIMEOUT)
+ overlayTimes.erase(iter++);
+ else
+ iter++;
}
+
+ // Recently shown?
+ if (overlayTimes.count(textbuf) > 0)
+ return;
+
+ overlayTimes[textbuf] = time(nullptr);
+
+ addOverlay(textbuf);
}
-void DesktopWindow::setOverlay(const char* text, ...)
+void DesktopWindow::addOverlayError(const char* text, ...)
{
- const Fl_Fontsize fontsize = 16;
- const int margin = 10;
-
va_list ap;
char textbuf[1024];
+ va_start(ap, text);
+ vsnprintf(textbuf, sizeof(textbuf), text, ap);
+ textbuf[sizeof(textbuf)-1] = '\0';
+ va_end(ap);
+
+ addOverlay(textbuf);
+}
+
+void DesktopWindow::addOverlay(const char *text)
+{
+ const Fl_Fontsize fontsize = 16;
+ const int margin = 10;
+
Fl_Image_Surface *surface;
Fl_RGB_Image* imageText;
@@ -717,13 +782,7 @@ void DesktopWindow::setOverlay(const char* text, ...)
unsigned char* a;
const unsigned char* b;
- delete overlay;
- Fl::remove_timeout(updateOverlay, this);
-
- va_start(ap, text);
- vsnprintf(textbuf, sizeof(textbuf), text, ap);
- textbuf[sizeof(textbuf)-1] = '\0';
- va_end(ap);
+ struct Overlay overlay;
#if !defined(WIN32) && !defined(__APPLE__)
// FLTK < 1.3.5 crashes if fl_gc is unset
@@ -733,7 +792,7 @@ void DesktopWindow::setOverlay(const char* text, ...)
fl_font(FL_HELVETICA, fontsize);
w = 0;
- fl_measure(textbuf, w, h);
+ fl_measure(text, w, h);
// Margins
w += margin * 2 * 2;
@@ -746,7 +805,7 @@ void DesktopWindow::setOverlay(const char* text, ...)
fl_font(FL_HELVETICA, fontsize);
fl_color(FL_WHITE);
- fl_draw(textbuf, 0, 0, w, h, FL_ALIGN_CENTER);
+ fl_draw(text, 0, 0, w, h, FL_ALIGN_CENTER);
imageText = surface->image();
delete surface;
@@ -782,39 +841,53 @@ void DesktopWindow::setOverlay(const char* text, ...)
delete imageText;
- overlay = new Surface(image);
- overlayAlpha = 0;
- gettimeofday(&overlayStart, nullptr);
+ overlay.surface = new Surface(image);
+ overlay.alpha = 0;
+ memset(&overlay.start, 0, sizeof(overlay.start));
+ overlays.push_back(overlay);
delete image;
delete [] buffer;
- Fl::add_timeout(1.0/60, updateOverlay, this);
+ if (overlays.size() == 1)
+ Fl::add_timeout(0.5, updateOverlay, this);
}
void DesktopWindow::updateOverlay(void *data)
{
DesktopWindow *self;
+ struct Overlay* overlay;
unsigned elapsed;
self = (DesktopWindow*)data;
- elapsed = msSince(&self->overlayStart);
+ if (self->overlays.empty())
+ return;
+
+ overlay = &self->overlays.front();
+
+ if (overlay->start.tv_sec == 0)
+ gettimeofday(&overlay->start, nullptr);
+
+ elapsed = core::msSince(&overlay->start);
if (elapsed < 500) {
- self->overlayAlpha = (unsigned)255 * elapsed / 500;
+ overlay->alpha = (unsigned)255 * elapsed / 500;
Fl::add_timeout(1.0/60, updateOverlay, self);
} else if (elapsed < 3500) {
- self->overlayAlpha = 255;
+ overlay->alpha = 255;
Fl::add_timeout(3.0, updateOverlay, self);
} else if (elapsed < 4000) {
- self->overlayAlpha = (unsigned)255 * (4000 - elapsed) / 500;
+ overlay->alpha = (unsigned)255 * (4000 - elapsed) / 500;
Fl::add_timeout(1.0/60, updateOverlay, self);
} else {
- delete self->overlay;
- self->overlay = nullptr;
+ delete overlay->surface;
+ self->overlays.pop_front();
+ if (!self->overlays.empty())
+ Fl::add_timeout(0.5, updateOverlay, self);
}
+ // FIXME: Only damage relevant area
self->damage(FL_DAMAGE_USER1);
}
@@ -828,10 +901,44 @@ int DesktopWindow::handle(int event)
// Update scroll bars
repositionWidgets();
- if (fullscreen_active())
- maybeGrabKeyboard();
- else
- ungrabKeyboard();
+ // Show how to get out of full screen
+ if (fullscreen_active()) {
+ unsigned modifierMask;
+
+ modifierMask = 0;
+ for (core::EnumListEntry key : shortcutModifiers)
+ modifierMask |= ShortcutHandler::parseModifier(key.getValueStr().c_str());
+
+ if (modifierMask)
+ addOverlayTip(_("Press %sEnter to leave full-screen mode"),
+ ShortcutHandler::modifierPrefix(modifierMask));
+ }
+
+#ifdef __APPLE__
+ // Complain to the user if we won't have permission to grab keyboard
+ if (fullscreenSystemKeys && fullscreen_active()) {
+ // FIXME: There is some race during initial full screen where we
+ // fail to give focus to the popup, but we can work around
+ // it using a timer
+ Fl::add_timeout(0, [](void*) { cocoa_is_trusted(true); }, nullptr);
+ }
+#endif
+
+ // Automatically toggle keyboard grab?
+ if (fullscreenSystemKeys) {
+ if (fullscreen_active())
+ grabKeyboard();
+ else
+ ungrabKeyboard();
+ }
+
+ // The window manager respected our full screen request, so stop
+ // waiting and delaying the session resize
+ if (delayedFullscreen && fullscreen_active()) {
+ Fl::remove_timeout(handleFullscreenTimeout, this);
+ delayedFullscreen = false;
+ remoteResize();
+ }
break;
@@ -892,6 +999,17 @@ int DesktopWindow::fltkDispatch(int event, Fl_Window *win)
if ((event == FL_MOVE) && (win == nullptr))
return 0;
+#if !defined(WIN32) && !defined(__APPLE__)
+ // FLTK passes through the fake grab focus events that can cause us
+ // to end up in an infinite loop
+ // https://github.com/fltk/fltk/issues/295
+ if ((event == FL_FOCUS) || (event == FL_UNFOCUS)) {
+ const XFocusChangeEvent* xfocus = &fl_xevent->xfocus;
+ if ((xfocus->mode == NotifyGrab) || (xfocus->mode == NotifyUngrab))
+ return 0;
+ }
+#endif
+
ret = Fl::handle_(event, win);
// This is hackish and the result of the dodgy focus handling in FLTK.
@@ -904,15 +1022,33 @@ int DesktopWindow::fltkDispatch(int event, Fl_Window *win)
if (dw) {
switch (event) {
// Focus might not stay with us just because we have grabbed the
- // keyboard. E.g. we might have sub windows, or we're not using
- // all monitors and the user clicked on another application.
- // Make sure we update our grabs with the focus changes.
+ // keyboard. E.g. we might have sub windows, or the user clicked on
+ // another application. Make sure we update our grabs with the focus
+ // changes.
case FL_FOCUS:
- dw->maybeGrabKeyboard();
+ if (dw->regrabOnFocus ||
+ (fullscreenSystemKeys && dw->fullscreen_active()))
+ dw->grabKeyboard();
+ dw->regrabOnFocus = false;
break;
case FL_UNFOCUS:
- if (fullscreenSystemKeys) {
- dw->ungrabKeyboard();
+ // If the grab is active when we lose focus, the user likely wants
+ // the grab to remain once we regain focus
+ if (dw->keyboardGrabbed)
+ dw->regrabOnFocus = true;
+ dw->ungrabKeyboard();
+ break;
+
+ case FL_SHOW:
+ // In this particular place, FL_SHOW means an actual MapNotify,
+ // which means we can continue enabling initial fullscreen.
+ if (dw->delayedFullscreen) {
+ // Hack: Fullscreen requests may be ignored, so we need a
+ // timeout for when we should stop waiting. We also really need
+ // to wait for the resize, which can come after the fullscreen
+ // event.
+ Fl::add_timeout(0.5, handleFullscreenTimeout, dw);
+ dw->fullscreen_on();
}
break;
@@ -941,14 +1077,6 @@ int DesktopWindow::fltkHandle(int event)
// not be resized to cover the new screen. A timer makes sense
// also on other systems, to make sure that whatever desktop
// environment has a chance to deal with things before we do.
- // Please note that when using FullscreenSystemKeys on macOS, the
- // display configuration cannot be changed: macOS will not detect
- // added or removed screens and there will be no
- // FL_SCREEN_CONFIGURATION_CHANGED event. This is by design:
- // "When you capture a display, you have exclusive use of the
- // display. Other applications and system services are not allowed
- // to use the display or change its configuration. In addition,
- // they are not notified of display changes"
Fl::remove_timeout(reconfigureFullscreen);
Fl::add_timeout(0.5, reconfigureFullscreen);
}
@@ -958,8 +1086,8 @@ int DesktopWindow::fltkHandle(int event)
void DesktopWindow::fullscreen_on()
{
- bool allMonitors = !strcasecmp(fullScreenMode, "all");
- bool selectedMonitors = !strcasecmp(fullScreenMode, "selected");
+ bool allMonitors = fullScreenMode == "all";
+ bool selectedMonitors = fullScreenMode == "selected";
int top, bottom, left, right;
if (not selectedMonitors and not allMonitors) {
@@ -972,7 +1100,7 @@ void DesktopWindow::fullscreen_on()
std::set<int> monitors;
if (selectedMonitors and not allMonitors) {
- std::set<int> selected = fullScreenSelectedMonitors.getParam();
+ std::set<int> selected = fullScreenSelectedMonitors.getMonitors();
monitors.insert(selected.begin(), selected.end());
} else {
for (int idx = 0; idx < Fl::screen_count(); idx++)
@@ -1024,40 +1152,13 @@ void DesktopWindow::fullscreen_on()
}
}
-#ifdef __APPLE__
- // This is a workaround for a bug in FLTK, see: https://github.com/fltk/fltk/pull/277
- int savedLevel;
- savedLevel = cocoa_get_level(this);
-#endif
+
fullscreen_screens(top, bottom, left, right);
-#ifdef __APPLE__
- // This is a workaround for a bug in FLTK, see: https://github.com/fltk/fltk/pull/277
- if (cocoa_get_level(this) != savedLevel)
- cocoa_set_level(this, savedLevel);
-#endif
if (!fullscreen_active())
fullscreen();
}
-#if !defined(WIN32) && !defined(__APPLE__)
-Bool eventIsFocusWithSerial(Display* /*display*/, XEvent *event,
- XPointer arg)
-{
- unsigned long serial;
-
- serial = *(unsigned long*)arg;
-
- if (event->xany.serial != serial)
- return False;
-
- if ((event->type != FocusIn) && (event->type != FocusOut))
- return False;
-
- return True;
-}
-#endif
-
bool DesktopWindow::hasFocus()
{
Fl_Widget* focus;
@@ -1072,66 +1173,66 @@ bool DesktopWindow::hasFocus()
return focus->window() == this;
}
-void DesktopWindow::maybeGrabKeyboard()
-{
- if (fullscreenSystemKeys && fullscreen_active() && hasFocus())
- grabKeyboard();
-}
-
void DesktopWindow::grabKeyboard()
{
+ unsigned modifierMask;
+
// Grabbing the keyboard is fairly safe as FLTK reroutes events to the
// correct widget regardless of which low level window got the system
// event.
// FIXME: Push this stuff into FLTK.
+ if (keyboardGrabbed)
+ return;
+
+ if (!hasFocus())
+ return;
+
#if defined(WIN32)
int ret;
ret = win32_enable_lowlevel_keyboard(fl_xid(this));
if (ret != 0) {
- vlog.error(_("Failure grabbing keyboard"));
+ vlog.error(_("Failure grabbing control of the keyboard"));
+ addOverlayError(_("Failure grabbing control of the keyboard"));
return;
}
#elif defined(__APPLE__)
- int ret;
-
- ret = cocoa_capture_displays(this);
- if (ret != 0) {
- vlog.error(_("Failure grabbing keyboard"));
+ bool ret;
+
+ ret = cocoa_tap_keyboard();
+ if (!ret) {
+ vlog.error(_("Failure grabbing control of the keyboard"));
+ addOverlayError(_("Failure grabbing control of the keyboard"));
return;
}
#else
int ret;
- XEvent xev;
- unsigned long serial;
-
- serial = XNextRequest(fl_display);
-
ret = XGrabKeyboard(fl_display, fl_xid(this), True,
GrabModeAsync, GrabModeAsync, CurrentTime);
if (ret) {
if (ret == AlreadyGrabbed) {
- // It seems like we can race with the WM in some cases.
- // Try again in a bit.
- if (!Fl::has_timeout(handleGrab, this))
- Fl::add_timeout(0.500, handleGrab, this);
- } else {
- vlog.error(_("Failure grabbing keyboard"));
+ // It seems like we can race with the WM in some cases, e.g. when
+ // the WM holds the keyboard as part of handling Alt+Tab.
+ // Repeat the request a few times and see if we get it...
+ for (int attempt = 0; attempt < 5; attempt++) {
+ usleep(100000);
+ // Also throttle based on how busy the X server is
+ XSync(fl_display, False);
+ ret = XGrabKeyboard(fl_display, fl_xid(this), True,
+ GrabModeAsync, GrabModeAsync, CurrentTime);
+ if (ret != AlreadyGrabbed)
+ break;
+ }
}
- return;
- }
- // Xorg 1.20+ generates FocusIn/FocusOut even when there is no actual
- // change of focus. This causes us to get stuck in an endless loop
- // grabbing and ungrabbing the keyboard. Avoid this by filtering out
- // any focus events generated by XGrabKeyboard().
- XSync(fl_display, False);
- while (XCheckIfEvent(fl_display, &xev, &eventIsFocusWithSerial,
- (XPointer)&serial) == True) {
- vlog.debug("Ignored synthetic focus event cause by grab change");
+ if (ret) {
+ vlog.error(_("Failure grabbing control of the keyboard"));
+ addOverlayError(_("Failure grabbing control of the keyboard"));
+ return;
+ }
}
#endif
@@ -1139,39 +1240,37 @@ void DesktopWindow::grabKeyboard()
if (contains(Fl::belowmouse()))
grabPointer();
+
+ updateCaption();
+
+ modifierMask = 0;
+ for (core::EnumListEntry key : shortcutModifiers)
+ modifierMask |= ShortcutHandler::parseModifier(key.getValueStr().c_str());
+
+ if (modifierMask)
+ addOverlayTip(_("Press %s to release keyboard control from the session"),
+ ShortcutHandler::modifierPrefix(modifierMask, true));
}
void DesktopWindow::ungrabKeyboard()
{
- Fl::remove_timeout(handleGrab, this);
-
keyboardGrabbed = false;
ungrabPointer();
+ updateCaption();
+
#if defined(WIN32)
win32_disable_lowlevel_keyboard(fl_xid(this));
#elif defined(__APPLE__)
- cocoa_release_displays(this);
+ cocoa_untap_keyboard();
#else
// FLTK has a grab so lets not mess with it
if (Fl::grab())
return;
- XEvent xev;
- unsigned long serial;
-
- serial = XNextRequest(fl_display);
-
XUngrabKeyboard(fl_display, CurrentTime);
-
- // See grabKeyboard()
- XSync(fl_display, False);
- while (XCheckIfEvent(fl_display, &xev, &eventIsFocusWithSerial,
- (XPointer)&serial) == True) {
- vlog.debug("Ignored synthetic focus event cause by grab change");
- }
#endif
}
@@ -1202,16 +1301,6 @@ void DesktopWindow::ungrabPointer()
}
-void DesktopWindow::handleGrab(void *data)
-{
- DesktopWindow *self = (DesktopWindow*)data;
-
- assert(self);
-
- self->maybeGrabKeyboard();
-}
-
-
#define _NET_WM_STATE_ADD 1 /* add/set property */
void DesktopWindow::maximizeWindow()
{
@@ -1252,32 +1341,13 @@ void DesktopWindow::maximizeWindow()
}
-void DesktopWindow::handleDesktopSize()
-{
- if (strcmp(desktopSize, "") != 0) {
- int width, height;
-
- // An explicit size has been requested
-
- if (sscanf(desktopSize, "%dx%d", &width, &height) != 2)
- return;
-
- remoteResize(width, height);
- } else if (::remoteResize) {
- // No explicit size, but remote resizing is on so make sure it
- // matches whatever size the window ended up being
- remoteResize(w(), h());
- }
-}
-
-
void DesktopWindow::handleResizeTimeout(void *data)
{
DesktopWindow *self = (DesktopWindow *)data;
assert(self);
- self->remoteResize(self->w(), self->h());
+ self->remoteResize();
}
@@ -1292,10 +1362,47 @@ void DesktopWindow::reconfigureFullscreen(void* /*data*/)
}
-void DesktopWindow::remoteResize(int width, int height)
+void DesktopWindow::remoteResize()
{
- ScreenSet layout;
- ScreenSet::const_iterator iter;
+ int width, height;
+ rfb::ScreenSet layout;
+ rfb::ScreenSet::const_iterator iter;
+
+ if (viewOnly)
+ return;
+
+ if (!::remoteResize)
+ return;
+ if (!cc->server.supportsSetDesktopSize)
+ return;
+
+ // Don't pester the server with a resize until we have our final size
+ if (delayedFullscreen)
+ return;
+
+ // Rate limit to one pending resize at a time
+ if (pendingRemoteResize)
+ return;
+
+ // And no more than once every 100ms
+ if (core::msSince(&lastResize) < 100) {
+ Fl::remove_timeout(handleResizeTimeout, this);
+ Fl::add_timeout((100.0 - core::msSince(&lastResize)) / 1000.0,
+ handleResizeTimeout, this);
+ return;
+ }
+
+ width = w();
+ height = h();
+
+ if (!sentDesktopSize && (strcmp(desktopSize, "") != 0)) {
+ // An explicit size has been requested
+
+ if (sscanf(desktopSize, "%dx%d", &width, &height) != 2)
+ return;
+
+ sentDesktopSize = true;
+ }
if (!fullscreen_active() || (width > w()) || (height > h())) {
// In windowed mode (or the framebuffer is so large that we need
@@ -1331,7 +1438,7 @@ void DesktopWindow::remoteResize(int width, int height)
} else {
uint32_t id;
int sx, sy, sw, sh;
- rfb::Rect viewport_rect, screen_rect;
+ core::Rect viewport_rect, screen_rect;
// In full screen we report all screens that are fully covered.
@@ -1415,6 +1522,8 @@ void DesktopWindow::remoteResize(int width, int height)
vlog.debug("%s", buffer);
}
+ pendingRemoteResize = true;
+ gettimeofday(&lastResize, nullptr);
cc->writer()->writeSetDesktopSize(width, height, layout);
}
@@ -1515,11 +1624,6 @@ void DesktopWindow::handleOptions(void *data)
{
DesktopWindow *self = (DesktopWindow*)data;
- if (fullscreenSystemKeys)
- self->maybeGrabKeyboard();
- else
- self->ungrabKeyboard();
-
// Call fullscreen_on even if active since it handles
// fullScreenMode
if (fullScreen)
@@ -1535,11 +1639,7 @@ void DesktopWindow::handleFullscreenTimeout(void *data)
assert(self);
self->delayedFullscreen = false;
-
- if (self->delayedDesktopSize) {
- self->handleDesktopSize();
- self->delayedDesktopSize = false;
- }
+ self->remoteResize();
}
void DesktopWindow::scrollTo(int x, int y)
@@ -1644,7 +1744,7 @@ void DesktopWindow::handleStatsTimeout(void *data)
updates = self->cc->getUpdateCount();
pixels = self->cc->getPixelCount();
pos = self->cc->getPosition();
- elapsed = msSince(&self->statsLastTime);
+ elapsed = core::msSince(&self->statsLastTime);
if (elapsed < 1)
elapsed = 1;
@@ -1719,11 +1819,11 @@ void DesktopWindow::handleStatsTimeout(void *data)
fl_draw(buffer, 5, statsHeight - 5);
fl_color(FL_YELLOW);
- fl_draw(siPrefix(self->stats[statsCount-1].pps, "pix/s").c_str(),
+ fl_draw(core::siPrefix(self->stats[statsCount-1].pps, "pix/s").c_str(),
5 + (statsWidth-10)/3, statsHeight - 5);
fl_color(FL_RED);
- fl_draw(siPrefix(self->stats[statsCount-1].bps * 8, "bps").c_str(),
+ fl_draw(core::siPrefix(self->stats[statsCount-1].bps * 8, "bps").c_str(),
5 + (statsWidth-10)*2/3, statsHeight - 5);
image = surface->image();
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index ce7960ce..ca4cf53a 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright 2011-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,12 +20,12 @@
#ifndef __DESKTOPWINDOW_H__
#define __DESKTOPWINDOW_H__
+#include <list>
#include <map>
+#include <string>
#include <sys/time.h>
-#include <rfb/Rect.h>
-
#include <FL/Fl_Window.H>
namespace rfb { class ModifiablePixelBuffer; }
@@ -39,8 +39,7 @@ class Fl_Scrollbar;
class DesktopWindow : public Fl_Window {
public:
- DesktopWindow(int w, int h, const char *name,
- const rfb::PixelFormat& serverPF, CConn* cc_);
+ DesktopWindow(int w, int h, CConn* cc_);
~DesktopWindow();
// Most efficient format (from DesktopWindow's point of view)
@@ -50,17 +49,19 @@ public:
void updateWindow();
// Updated session title
- void setName(const char *name);
+ void updateCaption();
// Resize the current framebuffer, but retain the contents
void resizeFramebuffer(int new_w, int new_h);
+ // A previous call to writeSetDesktopSize() has completed
+ void setDesktopSizeDone(unsigned result);
+
// New image for the locally rendered cursor
- void setCursor(int width, int height, const rfb::Point& hotspot,
- const uint8_t* data);
+ void setCursor();
// Server-provided cursor position
- void setCursorPos(const rfb::Point& pos);
+ void setCursorPos(const core::Point& pos);
// Change client LED state
void setLEDState(unsigned int state);
@@ -79,11 +80,16 @@ public:
void fullscreen_on();
-private:
- static void menuOverlay(void *data);
+ // Grab keyboard events from desktop environment
+ void grabKeyboard();
+ void ungrabKeyboard();
- void setOverlay(const char *text, ...)
+private:
+ void addOverlayTip(const char *text, ...)
__attribute__((__format__ (__printf__, 2, 3)));
+ void addOverlayError(const char *text, ...)
+ __attribute__((__format__ (__printf__, 2, 3)));
+ void addOverlay(const char *text);
static void updateOverlay(void *data);
static int fltkDispatch(int event, Fl_Window *win);
@@ -91,20 +97,14 @@ private:
bool hasFocus();
- void maybeGrabKeyboard();
- void grabKeyboard();
- void ungrabKeyboard();
void grabPointer();
void ungrabPointer();
- static void handleGrab(void *data);
-
void maximizeWindow();
- void handleDesktopSize();
static void handleResizeTimeout(void *data);
static void reconfigureFullscreen(void *data);
- void remoteResize(int width, int height);
+ void remoteResize();
void repositionWidgets();
@@ -125,17 +125,28 @@ private:
Fl_Scrollbar *hscroll, *vscroll;
Viewport *viewport;
Surface *offscreen;
- Surface *overlay;
- unsigned char overlayAlpha;
- struct timeval overlayStart;
+
+ struct Overlay {
+ Surface *surface;
+ unsigned char alpha;
+ struct timeval start;
+ };
+
+ std::list<Overlay> overlays;
+ std::map<std::string, time_t> overlayTimes;
bool firstUpdate;
bool delayedFullscreen;
- bool delayedDesktopSize;
+ bool sentDesktopSize;
+
+ bool pendingRemoteResize;
+ struct timeval lastResize;
bool keyboardGrabbed;
bool mouseGrabbed;
+ bool regrabOnFocus;
+
struct statsEntry {
unsigned ups;
unsigned pps;
diff --git a/vncviewer/EmulateMB.cxx b/vncviewer/EmulateMB.cxx
index 44d92752..89470274 100644
--- a/vncviewer/EmulateMB.cxx
+++ b/vncviewer/EmulateMB.cxx
@@ -199,7 +199,8 @@ EmulateMB::EmulateMB()
{
}
-void EmulateMB::filterPointerEvent(const rfb::Point& pos, uint16_t buttonMask)
+void EmulateMB::filterPointerEvent(const core::Point& pos,
+ uint16_t buttonMask)
{
int btstate;
int action1, action2;
@@ -277,7 +278,7 @@ void EmulateMB::filterPointerEvent(const rfb::Point& pos, uint16_t buttonMask)
}
}
-void EmulateMB::handleTimeout(rfb::Timer *t)
+void EmulateMB::handleTimeout(core::Timer* t)
{
int action1, action2;
uint16_t buttonMask;
@@ -312,7 +313,8 @@ void EmulateMB::handleTimeout(rfb::Timer *t)
state = stateTab[state][4][2];
}
-void EmulateMB::sendAction(const rfb::Point& pos, uint16_t buttonMask, int action)
+void EmulateMB::sendAction(const core::Point& pos,
+ uint16_t buttonMask, int action)
{
assert(action != 0);
@@ -332,4 +334,4 @@ int EmulateMB::createButtonMask(uint16_t buttonMask)
// Set the left and right buttons according to the action
return buttonMask |= emulatedButtonMask;
-} \ No newline at end of file
+}
diff --git a/vncviewer/EmulateMB.h b/vncviewer/EmulateMB.h
index 127c34a4..393655e4 100644
--- a/vncviewer/EmulateMB.h
+++ b/vncviewer/EmulateMB.h
@@ -19,22 +19,24 @@
#ifndef __EMULATEMB__
#define __EMULATEMB__
-#include <rfb/Timer.h>
-#include <rfb/Rect.h>
+#include <core/Rect.h>
+#include <core/Timer.h>
-class EmulateMB : public rfb::Timer::Callback {
+class EmulateMB : public core::Timer::Callback {
public:
EmulateMB();
- void filterPointerEvent(const rfb::Point& pos, uint16_t buttonMask);
+ void filterPointerEvent(const core::Point& pos, uint16_t buttonMask);
protected:
- virtual void sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask)=0;
+ virtual void sendPointerEvent(const core::Point& pos,
+ uint16_t buttonMask)=0;
- void handleTimeout(rfb::Timer *t) override;
+ void handleTimeout(core::Timer* t) override;
private:
- void sendAction(const rfb::Point& pos, uint16_t buttonMask, int action);
+ void sendAction(const core::Point& pos, uint16_t buttonMask,
+ int action);
int createButtonMask(uint16_t buttonMask);
@@ -42,8 +44,8 @@ private:
int state;
uint16_t emulatedButtonMask;
uint16_t lastButtonMask;
- rfb::Point lastPos, origPos;
- rfb::Timer timer;
+ core::Point lastPos, origPos;
+ core::Timer timer;
};
#endif
diff --git a/vncviewer/GestureHandler.cxx b/vncviewer/GestureHandler.cxx
index 121ceecf..2ede991b 100644
--- a/vncviewer/GestureHandler.cxx
+++ b/vncviewer/GestureHandler.cxx
@@ -24,12 +24,12 @@
#include <assert.h>
#include <math.h>
-#include <rfb/util.h>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+#include <core/time.h>
#include "GestureHandler.h"
-static rfb::LogWriter vlog("GestureHandler");
+static core::LogWriter vlog("GestureHandler");
static const unsigned char GH_NOGESTURE = 0;
static const unsigned char GH_ONETAP = 1;
@@ -81,7 +81,7 @@ void GestureHandler::handleTouchBegin(int id, double x, double y)
// Did it take too long between touches that we should no longer
// consider this a single gesture?
if ((tracked.size() > 0) &&
- (rfb::msSince(&tracked.begin()->second.started) > GH_MULTITOUCH_TIMEOUT)) {
+ (core::msSince(&tracked.begin()->second.started) > GH_MULTITOUCH_TIMEOUT)) {
state = GH_NOGESTURE;
ignored.insert(id);
return;
@@ -257,12 +257,12 @@ void GestureHandler::handleTouchEnd(int id)
// Waiting for all touches to release? (i.e. some tap)
if (waitingRelease) {
// Were all touches released at roughly the same time?
- if (rfb::msSince(&releaseStart) > GH_MULTITOUCH_TIMEOUT)
+ if (core::msSince(&releaseStart) > GH_MULTITOUCH_TIMEOUT)
state = GH_NOGESTURE;
// Did too long time pass between press and release?
for (iter = tracked.begin(); iter != tracked.end(); ++iter) {
- if (rfb::msSince(&iter->second.started) > GH_TAP_TIMEOUT) {
+ if (core::msSince(&iter->second.started) > GH_TAP_TIMEOUT) {
state = GH_NOGESTURE;
break;
}
@@ -323,7 +323,7 @@ bool GestureHandler::hasDetectedGesture()
return true;
}
-void GestureHandler::handleTimeout(rfb::Timer* t)
+void GestureHandler::handleTimeout(core::Timer* t)
{
if (t == &longpressTimer)
longpressTimeout();
diff --git a/vncviewer/GestureHandler.h b/vncviewer/GestureHandler.h
index 2b31703a..1c2134c0 100644
--- a/vncviewer/GestureHandler.h
+++ b/vncviewer/GestureHandler.h
@@ -23,11 +23,11 @@
#include <set>
#include <map>
-#include <rfb/Timer.h>
+#include <core/Timer.h>
#include "GestureEvent.h"
-class GestureHandler : public rfb::Timer::Callback {
+class GestureHandler : public core::Timer::Callback {
public:
GestureHandler();
virtual ~GestureHandler();
@@ -42,7 +42,7 @@ class GestureHandler : public rfb::Timer::Callback {
private:
bool hasDetectedGesture();
- void handleTimeout(rfb::Timer* t) override;
+ void handleTimeout(core::Timer* t) override;
void longpressTimeout();
void twoTouchTimeout();
@@ -74,8 +74,8 @@ class GestureHandler : public rfb::Timer::Callback {
bool waitingRelease;
struct timeval releaseStart;
- rfb::Timer longpressTimer;
- rfb::Timer twoTouchTimer;
+ core::Timer longpressTimer;
+ core::Timer twoTouchTimer;
};
#endif // __GESTUREHANDLER_H__
diff --git a/vncviewer/Keyboard.h b/vncviewer/Keyboard.h
index 81360252..aeab4e71 100644
--- a/vncviewer/Keyboard.h
+++ b/vncviewer/Keyboard.h
@@ -21,6 +21,8 @@
#include <stdint.h>
+#include <list>
+
class KeyboardHandler
{
public:
@@ -35,7 +37,10 @@ public:
Keyboard(KeyboardHandler* handler_) : handler(handler_) {};
virtual ~Keyboard() {};
+ virtual bool isKeyboardReset(const void* event) { (void)event; return false; }
+
virtual bool handleEvent(const void* event) = 0;
+ virtual std::list<uint32_t> translateToKeySyms(int systemKeyCode) = 0;
virtual void reset() {};
diff --git a/vncviewer/KeyboardMacOS.h b/vncviewer/KeyboardMacOS.h
index 0901664b..033c8539 100644
--- a/vncviewer/KeyboardMacOS.h
+++ b/vncviewer/KeyboardMacOS.h
@@ -23,10 +23,8 @@
#ifdef __OBJC__
@class NSEvent;
-@class NSString;
#else
class NSEvent;
-class NSString;
#endif
class KeyboardMacOS : public Keyboard
@@ -35,22 +33,21 @@ public:
KeyboardMacOS(KeyboardHandler* handler);
virtual ~KeyboardMacOS();
+ bool isKeyboardReset(const void* event) override;
+
bool handleEvent(const void* event) override;
+ std::list<uint32_t> translateToKeySyms(int systemKeyCode) override;
unsigned getLEDState() override;
void setLEDState(unsigned state) override;
- // Special helper on macOS
- static bool isKeyboardSync(const void* event);
-
protected:
bool isKeyboardEvent(const NSEvent* nsevent);
bool isKeyPress(const NSEvent* nsevent);
uint32_t translateSystemKeyCode(int systemKeyCode);
unsigned getSystemKeyCode(const NSEvent* nsevent);
- NSString* keyTranslate(unsigned keyCode, unsigned modifierFlags);
- uint32_t translateEventKeysym(const NSEvent* nsevent);
+ uint32_t translateToKeySym(unsigned keyCode, unsigned modifierFlags);
int openHID(unsigned int* ioc);
int getModifierLockState(int modifier, bool* on);
diff --git a/vncviewer/KeyboardMacOS.mm b/vncviewer/KeyboardMacOS.mm
index e0a10dc8..599612ec 100644
--- a/vncviewer/KeyboardMacOS.mm
+++ b/vncviewer/KeyboardMacOS.mm
@@ -22,6 +22,8 @@
#include <assert.h>
+#include <algorithm>
+
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
@@ -35,11 +37,12 @@ const int kVK_RightCommand = 0x36;
// And this is still missing
const int kVK_Menu = 0x6E;
+#include <core/LogWriter.h>
+
#define XK_LATIN1
#define XK_MISCELLANY
#include <rfb/keysymdef.h>
#include <rfb/XF86keysym.h>
-#include <rfb/LogWriter.h>
#include <rfb/ledStates.h>
#define NoSymbol 0
@@ -51,9 +54,9 @@ const int kVK_Menu = 0x6E;
extern const unsigned short code_map_osx_to_qnum[];
extern const unsigned int code_map_osx_to_qnum_len;
-static rfb::LogWriter vlog("KeyboardMacOS");
+static core::LogWriter vlog("KeyboardMacOS");
-static const int kvk_map[][2] = {
+static const unsigned kvk_map[][2] = {
{ kVK_Return, XK_Return },
{ kVK_Tab, XK_Tab },
{ kVK_Space, XK_space },
@@ -139,6 +142,25 @@ KeyboardMacOS::~KeyboardMacOS()
{
}
+bool KeyboardMacOS::isKeyboardReset(const void* event)
+{
+ const NSEvent* nsevent = (const NSEvent*)event;
+
+ assert(event);
+
+ // If we get a NSFlagsChanged event with key code 0 then this isn't
+ // an actual keyboard event but rather the system trying to sync up
+ // modifier state after it has stolen input for some reason (e.g.
+ // Cmd+Tab)
+
+ if ([nsevent type] != NSFlagsChanged)
+ return false;
+ if ([nsevent keyCode] != 0)
+ return false;
+
+ return true;
+}
+
bool KeyboardMacOS::handleEvent(const void* event)
{
const NSEvent* nsevent = (NSEvent*)event;
@@ -154,10 +176,25 @@ bool KeyboardMacOS::handleEvent(const void* event)
if (isKeyPress(nsevent)) {
uint32_t keyCode;
uint32_t keySym;
+ unsigned modifiers;
keyCode = translateSystemKeyCode(systemKeyCode);
- keySym = translateEventKeysym(nsevent);
+ // We want a "normal" symbol out of the event, which basically means
+ // we only respect the shift and alt/altgr modifiers. Cocoa can help
+ // us if we only wanted shift, but as we also want alt/altgr, we'll
+ // have to do some lookup ourselves. This matches our behaviour on
+ // other platforms.
+
+ modifiers = 0;
+ if ([nsevent modifierFlags] & NSAlphaShiftKeyMask)
+ modifiers |= alphaLock;
+ if ([nsevent modifierFlags] & NSShiftKeyMask)
+ modifiers |= shiftKey;
+ if ([nsevent modifierFlags] & NSAlternateKeyMask)
+ modifiers |= optionKey;
+
+ keySym = translateToKeySym([nsevent keyCode], modifiers);
if (keySym == NoSymbol) {
vlog.error(_("No symbol for key code 0x%02x (in the current state)"),
systemKeyCode);
@@ -176,6 +213,51 @@ bool KeyboardMacOS::handleEvent(const void* event)
return true;
}
+std::list<uint32_t> KeyboardMacOS::translateToKeySyms(int systemKeyCode)
+{
+ std::list<uint32_t> keySyms;
+ unsigned mods;
+
+ uint32_t ks;
+
+ // Start with no modifiers
+ ks = translateToKeySym(systemKeyCode, 0);
+ if (ks != NoSymbol)
+ keySyms.push_back(ks);
+
+ // Next just a single modifier at a time
+ for (mods = cmdKey; mods <= controlKey; mods <<= 1) {
+ std::list<uint32_t>::const_iterator iter;
+
+ ks = translateToKeySym(systemKeyCode, mods);
+ if (ks == NoSymbol)
+ continue;
+
+ iter = std::find(keySyms.begin(), keySyms.end(), ks);
+ if (iter != keySyms.end())
+ continue;
+
+ keySyms.push_back(ks);
+ }
+
+ // Finally everything
+ for (mods = cmdKey; mods < (controlKey << 1); mods += cmdKey) {
+ std::list<uint32_t>::const_iterator iter;
+
+ ks = translateToKeySym(systemKeyCode, mods);
+ if (ks == NoSymbol)
+ continue;
+
+ iter = std::find(keySyms.begin(), keySyms.end(), ks);
+ if (iter != keySyms.end())
+ continue;
+
+ keySyms.push_back(ks);
+ }
+
+ return keySyms;
+}
+
unsigned KeyboardMacOS::getLEDState()
{
unsigned state;
@@ -224,25 +306,6 @@ void KeyboardMacOS::setLEDState(unsigned state)
// No support for Scroll Lock //
}
-bool KeyboardMacOS::isKeyboardSync(const void* event)
-{
- const NSEvent* nsevent = (const NSEvent*)event;
-
- assert(event);
-
- // If we get a NSFlagsChanged event with key code 0 then this isn't
- // an actual keyboard event but rather the system trying to sync up
- // modifier state after it has stolen input for some reason (e.g.
- // Cmd+Tab)
-
- if ([nsevent type] != NSFlagsChanged)
- return false;
- if ([nsevent keyCode] != 0)
- return false;
-
- return true;
-}
-
bool KeyboardMacOS::isKeyboardEvent(const NSEvent* nsevent)
{
switch ([nsevent type]) {
@@ -250,7 +313,7 @@ bool KeyboardMacOS::isKeyboardEvent(const NSEvent* nsevent)
case NSKeyUp:
return true;
case NSFlagsChanged:
- if (isKeyboardSync(nsevent))
+ if (isKeyboardReset(nsevent))
return false;
return true;
default:
@@ -338,30 +401,35 @@ uint32_t KeyboardMacOS::translateSystemKeyCode(int systemKeyCode)
return code_map_osx_to_qnum[systemKeyCode];
}
-NSString* KeyboardMacOS::keyTranslate(unsigned keyCode,
- unsigned modifierFlags)
+uint32_t KeyboardMacOS::translateToKeySym(unsigned keyCode,
+ unsigned modifierFlags)
{
const UCKeyboardLayout *layout;
OSStatus err;
- layout = nullptr;
-
TISInputSourceRef keyboard;
CFDataRef uchr;
+ UInt32 dead_state;
+ UniCharCount max_len, actual_len;
+ UniChar string[255];
+
+ // Start with keys that either don't generate a symbol, or
+ // generate the same symbol as some other key.
+ for (size_t i = 0;i < sizeof(kvk_map)/sizeof(kvk_map[0]);i++) {
+ if (keyCode == kvk_map[i][0])
+ return kvk_map[i][1];
+ }
+
keyboard = TISCopyCurrentKeyboardLayoutInputSource();
uchr = (CFDataRef)TISGetInputSourceProperty(keyboard,
kTISPropertyUnicodeKeyLayoutData);
if (uchr == nullptr)
- return nil;
+ return NoSymbol;
layout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
if (layout == nullptr)
- return nil;
-
- UInt32 dead_state;
- UniCharCount max_len, actual_len;
- UniChar string[255];
+ return NoSymbol;
dead_state = 0;
max_len = sizeof(string)/sizeof(*string);
@@ -372,10 +440,12 @@ NSString* KeyboardMacOS::keyTranslate(unsigned keyCode,
LMGetKbdType(), 0, &dead_state, max_len, &actual_len,
string);
if (err != noErr)
- return nil;
+ return NoSymbol;
// Dead key?
if (dead_state != 0) {
+ unsigned combining;
+
// We have no fool proof way of asking what dead key this is.
// Assume we get a spacing equivalent if we press the
// same key again, and try to deduce something from that.
@@ -383,34 +453,28 @@ NSString* KeyboardMacOS::keyTranslate(unsigned keyCode,
LMGetKbdType(), 0, &dead_state, max_len, &actual_len,
string);
if (err != noErr)
- return nil;
- }
-
- return [NSString stringWithCharacters:string length:actual_len];
-}
-
-uint32_t KeyboardMacOS::translateEventKeysym(const NSEvent* nsevent)
-{
- UInt16 key_code;
- size_t i;
+ return NoSymbol;
- NSString *chars;
- UInt32 modifiers;
+ // FIXME: Some dead keys are given as NBSP + combining character
+ if (actual_len != 1)
+ return NoSymbol;
- key_code = [nsevent keyCode];
+ combining = ucs2combining(string[0]);
+ if (combining == (unsigned)-1)
+ return NoSymbol;
- // Start with keys that either don't generate a symbol, or
- // generate the same symbol as some other key.
- for (i = 0;i < sizeof(kvk_map)/sizeof(kvk_map[0]);i++) {
- if (key_code == kvk_map[i][0])
- return kvk_map[i][1];
+ return ucs2keysym(combining);
}
+ // Sanity check
+ if (actual_len != 1)
+ return NoSymbol;
+
// OS X always sends the same key code for the decimal key on the
// num pad, but X11 wants different keysyms depending on if it should
// be a comma or full stop.
- if (key_code == 0x41) {
- switch ([[nsevent charactersIgnoringModifiers] UTF8String][0]) {
+ if (keyCode == 0x41) {
+ switch (string[0]) {
case ',':
return XK_KP_Separator;
case '.':
@@ -420,33 +484,7 @@ uint32_t KeyboardMacOS::translateEventKeysym(const NSEvent* nsevent)
}
}
- // We want a "normal" symbol out of the event, which basically means
- // we only respect the shift and alt/altgr modifiers. Cocoa can help
- // us if we only wanted shift, but as we also want alt/altgr, we'll
- // have to do some lookup ourselves. This matches our behaviour on
- // other platforms.
-
- modifiers = 0;
- if ([nsevent modifierFlags] & NSAlphaShiftKeyMask)
- modifiers |= alphaLock;
- if ([nsevent modifierFlags] & NSShiftKeyMask)
- modifiers |= shiftKey;
- if ([nsevent modifierFlags] & NSAlternateKeyMask)
- modifiers |= optionKey;
-
- chars = keyTranslate(key_code, modifiers);
- if (chars == nil)
- return NoSymbol;
-
- // FIXME: Some dead keys are given as NBSP + combining character
- if ([chars length] != 1)
- return NoSymbol;
-
- // Dead key?
- if ([[nsevent characters] length] == 0)
- return ucs2keysym(ucs2combining([chars characterAtIndex:0]));
-
- return ucs2keysym([chars characterAtIndex:0]);
+ return ucs2keysym(string[0]);
}
int KeyboardMacOS::openHID(unsigned int* ioc)
diff --git a/vncviewer/KeyboardWin32.cxx b/vncviewer/KeyboardWin32.cxx
index 1caf4863..095927f1 100644
--- a/vncviewer/KeyboardWin32.cxx
+++ b/vncviewer/KeyboardWin32.cxx
@@ -24,6 +24,8 @@
#include <assert.h>
+#include <algorithm>
+
// Missing in at least some versions of MinGW
#ifndef MAPVK_VK_TO_CHAR
#define MAPVK_VK_TO_CHAR 2
@@ -31,12 +33,13 @@
#include <FL/Fl.H>
+#include <core/LogWriter.h>
+
#define XK_MISCELLANY
#define XK_XKB_KEYS
#define XK_KOREAN
#include <rfb/keysymdef.h>
#include <rfb/XF86keysym.h>
-#include <rfb/LogWriter.h>
#include <rfb/ledStates.h>
#define NoSymbol 0
@@ -50,7 +53,7 @@
// Used to detect fake input (0xaa is not a real key)
static const WORD SCAN_FAKE = 0xaa;
-static rfb::LogWriter vlog("KeyboardWin32");
+static core::LogWriter vlog("KeyboardWin32");
// Layout independent keys
static const UINT vkey_map[][3] = {
@@ -138,6 +141,8 @@ static const UINT vkey_map[][3] = {
{ VK_MEDIA_STOP, NoSymbol, XF86XK_AudioStop },
{ VK_MEDIA_PLAY_PAUSE, NoSymbol, XF86XK_AudioPlay },
{ VK_LAUNCH_MAIL, NoSymbol, XF86XK_Mail },
+ { VK_LAUNCH_MEDIA_SELECT, NoSymbol, XF86XK_AudioMedia },
+ { VK_LAUNCH_APP1, NoSymbol, XF86XK_MyComputer },
{ VK_LAUNCH_APP2, NoSymbol, XF86XK_Calculator },
};
@@ -202,6 +207,7 @@ bool KeyboardWin32::handleEvent(const void* event)
bool isExtended;
int systemKeyCode, keyCode;
uint32_t keySym;
+ BYTE state[256];
vKey = msg->wParam;
isExtended = (msg->lParam & (1 << 24)) != 0;
@@ -256,7 +262,23 @@ bool KeyboardWin32::handleEvent(const void* event)
keyCode = translateSystemKeyCode(systemKeyCode);
- keySym = translateVKey(vKey, isExtended);
+ GetKeyboardState(state);
+
+ // Pressing Ctrl wreaks havoc with the symbol lookup, so turn
+ // that off. But AltGr shows up as Ctrl+Alt in Windows, so keep
+ // Ctrl if Alt is active.
+ if (!(state[VK_LCONTROL] & 0x80) || !(state[VK_RMENU] & 0x80))
+ state[VK_CONTROL] = state[VK_LCONTROL] = state[VK_RCONTROL] = 0;
+
+ keySym = translateVKey(vKey, isExtended, state);
+
+ if (keySym == NoSymbol) {
+ // Most Ctrl+Alt combinations will fail to produce a symbol, so
+ // try it again with Ctrl unconditionally disabled.
+ state[VK_CONTROL] = state[VK_LCONTROL] = state[VK_RCONTROL] = 0;
+ keySym = translateVKey(vKey, isExtended, state);
+ }
+
if (keySym == NoSymbol) {
if (isExtended)
vlog.error(_("No symbol for extended virtual key 0x%02x"), (int)vKey);
@@ -354,6 +376,114 @@ bool KeyboardWin32::handleEvent(const void* event)
return false;
}
+std::list<uint32_t> KeyboardWin32::translateToKeySyms(int systemKeyCode)
+{
+ unsigned vkey;
+ bool extended;
+
+ std::list<uint32_t> keySyms;
+ unsigned mods;
+
+ BYTE state[256];
+
+ uint32_t ks;
+
+ UINT ch;
+
+ extended = systemKeyCode & 0x80;
+ if (extended)
+ systemKeyCode = 0xe0 | (systemKeyCode & 0x7f);
+
+ vkey = MapVirtualKey(systemKeyCode, MAPVK_VSC_TO_VK_EX);
+ if (vkey == 0)
+ return keySyms;
+
+ // Start with no modifiers
+ memset(state, 0, sizeof(state));
+ ks = translateVKey(vkey, extended, state);
+ if (ks != NoSymbol)
+ keySyms.push_back(ks);
+
+ // Next just a single modifier at a time
+ for (mods = 1; mods < 16; mods <<= 1) {
+ std::list<uint32_t>::const_iterator iter;
+
+ memset(state, 0, sizeof(state));
+ if (mods & 0x1)
+ state[VK_CONTROL] = state[VK_LCONTROL] = 0x80;
+ if (mods & 0x2)
+ state[VK_SHIFT] = state[VK_LSHIFT] = 0x80;
+ if (mods & 0x4)
+ state[VK_MENU] = state[VK_LMENU] = 0x80;
+ if (mods & 0x8) {
+ state[VK_CONTROL] = state[VK_LCONTROL] = 0x80;
+ state[VK_MENU] = state[VK_RMENU] = 0x80;
+ }
+
+ ks = translateVKey(vkey, extended, state);
+ if (ks == NoSymbol)
+ continue;
+
+ iter = std::find(keySyms.begin(), keySyms.end(), ks);
+ if (iter != keySyms.end())
+ continue;
+
+ keySyms.push_back(ks);
+ }
+
+ // Finally everything
+ for (mods = 0; mods < 16; mods++) {
+ std::list<uint32_t>::const_iterator iter;
+
+ memset(state, 0, sizeof(state));
+ if (mods & 0x1)
+ state[VK_CONTROL] = state[VK_LCONTROL] = 0x80;
+ if (mods & 0x2)
+ state[VK_SHIFT] = state[VK_LSHIFT] = 0x80;
+ if (mods & 0x4)
+ state[VK_MENU] = state[VK_LMENU] = 0x80;
+ if (mods & 0x8) {
+ state[VK_CONTROL] = state[VK_LCONTROL] = 0x80;
+ state[VK_MENU] = state[VK_RMENU] = 0x80;
+ }
+
+ ks = translateVKey(vkey, extended, state);
+ if (ks == NoSymbol)
+ continue;
+
+ iter = std::find(keySyms.begin(), keySyms.end(), ks);
+ if (iter != keySyms.end())
+ continue;
+
+ keySyms.push_back(ks);
+ }
+
+ // As a final resort we use MapVirtualKey() as that gives us a Latin
+ // character even on non-Latin keyboards, which is useful for
+ // shortcuts
+ //
+ // FIXME: Can this give us anything but ASCII?
+
+ ch = MapVirtualKeyW(vkey, MAPVK_VK_TO_CHAR);
+ if (ch != 0) {
+ if (ch & 0x80000000)
+ ch = ucs2combining(ch & 0xffff);
+ else
+ ch = ch & 0xffff;
+
+ ks = ucs2keysym(ch);
+ if (ks != NoSymbol) {
+ std::list<uint32_t>::const_iterator iter;
+
+ iter = std::find(keySyms.begin(), keySyms.end(), ks);
+ if (iter == keySyms.end())
+ keySyms.push_back(ks);
+ }
+ }
+
+ return keySyms;
+}
+
void KeyboardWin32::reset()
{
altGrArmed = false;
@@ -465,12 +595,12 @@ uint32_t KeyboardWin32::lookupVKeyMap(unsigned vkey, bool extended,
return NoSymbol;
}
-uint32_t KeyboardWin32::translateVKey(unsigned vkey, bool extended)
+uint32_t KeyboardWin32::translateVKey(unsigned vkey, bool extended,
+ const unsigned char state[256])
{
HKL layout;
WORD lang, primary_lang;
- BYTE state[256];
int ret;
WCHAR wstr[10];
@@ -524,25 +654,10 @@ uint32_t KeyboardWin32::translateVKey(unsigned vkey, bool extended)
// does what we want though. Unfortunately it keeps state, so
// we have to be careful around dead characters.
- GetKeyboardState(state);
-
- // Pressing Ctrl wreaks havoc with the symbol lookup, so turn
- // that off. But AltGr shows up as Ctrl+Alt in Windows, so keep
- // Ctrl if Alt is active.
- if (!(state[VK_LCONTROL] & 0x80) || !(state[VK_RMENU] & 0x80))
- state[VK_CONTROL] = state[VK_LCONTROL] = state[VK_RCONTROL] = 0;
-
// FIXME: Multi character results, like U+0644 U+0627
// on Arabic layout
ret = ToUnicode(vkey, 0, state, wstr, sizeof(wstr)/sizeof(wstr[0]), 0);
- if (ret == 0) {
- // Most Ctrl+Alt combinations will fail to produce a symbol, so
- // try it again with Ctrl unconditionally disabled.
- state[VK_CONTROL] = state[VK_LCONTROL] = state[VK_RCONTROL] = 0;
- ret = ToUnicode(vkey, 0, state, wstr, sizeof(wstr)/sizeof(wstr[0]), 0);
- }
-
if (ret == 1)
return ucs2keysym(wstr[0]);
diff --git a/vncviewer/KeyboardWin32.h b/vncviewer/KeyboardWin32.h
index 336fe6da..ecab9268 100644
--- a/vncviewer/KeyboardWin32.h
+++ b/vncviewer/KeyboardWin32.h
@@ -28,6 +28,7 @@ public:
virtual ~KeyboardWin32();
bool handleEvent(const void* event) override;
+ std::list<uint32_t> translateToKeySyms(int systemKeyCode) override;
void reset() override;
@@ -38,7 +39,8 @@ protected:
uint32_t translateSystemKeyCode(int systemKeyCode);
uint32_t lookupVKeyMap(unsigned vkey, bool extended,
const UINT map[][3], size_t size);
- uint32_t translateVKey(unsigned vkey, bool extended);
+ uint32_t translateVKey(unsigned vkey, bool extended,
+ const unsigned char state[256]);
bool hasAltGr();
static void handleAltGrTimeout(void *data);
diff --git a/vncviewer/KeyboardX11.cxx b/vncviewer/KeyboardX11.cxx
index 0ee1d4f6..587d9fc5 100644
--- a/vncviewer/KeyboardX11.cxx
+++ b/vncviewer/KeyboardX11.cxx
@@ -22,12 +22,14 @@
#include <assert.h>
+#include <algorithm>
#include <stdexcept>
#include <X11/XKBlib.h>
#include <FL/x.H>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
+
#include <rfb/ledStates.h>
#include "i18n.h"
@@ -39,7 +41,7 @@ extern const struct _code_map_xkb_to_qnum {
} code_map_xkb_to_qnum[];
extern const unsigned int code_map_xkb_to_qnum_len;
-static rfb::LogWriter vlog("KeyboardX11");
+static core::LogWriter vlog("KeyboardX11");
KeyboardX11::KeyboardX11(KeyboardHandler* handler_)
: Keyboard(handler_)
@@ -86,6 +88,63 @@ KeyboardX11::~KeyboardX11()
{
}
+struct GrabInfo {
+ Window window;
+ bool found;
+};
+
+static Bool is_same_window(Display*, XEvent* event, XPointer arg)
+{
+ GrabInfo* info = (GrabInfo*)arg;
+
+ assert(info);
+
+ // Focus is returned to our window
+ if ((event->type == FocusIn) &&
+ (event->xfocus.window == info->window)) {
+ info->found = true;
+ }
+
+ // Focus got stolen yet again
+ if ((event->type == FocusOut) &&
+ (event->xfocus.window == info->window)) {
+ info->found = false;
+ }
+
+ return False;
+}
+
+bool KeyboardX11::isKeyboardReset(const void* event)
+{
+ const XEvent* xevent = (const XEvent*)event;
+
+ assert(event);
+
+ if (xevent->type == FocusOut) {
+ if (xevent->xfocus.mode == NotifyGrab) {
+ GrabInfo info;
+ XEvent dummy;
+
+ // Something grabbed the keyboard, but we don't know if it was to
+ // ourselves or someone else
+
+ // Make sure we have all the queued events from the X server
+ XSync(fl_display, False);
+
+ // Check if we'll get the focus back right away
+ info.window = xevent->xfocus.window;
+ info.found = false;
+ XCheckIfEvent(fl_display, &dummy, is_same_window, (XPointer)&info);
+ if (info.found)
+ return false;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool KeyboardX11::handleEvent(const void* event)
{
const XEvent *xevent = (const XEvent*)event;
@@ -97,6 +156,10 @@ bool KeyboardX11::handleEvent(const void* event)
char str;
KeySym keysym;
+ // FLTK likes to use this instead of CurrentTime, so we need to keep
+ // it updated now that we steal this event
+ fl_event_time = xevent->xkey.time;
+
keycode = code_map_keycode_to_qnum[xevent->xkey.keycode];
XLookupString((XKeyEvent*)&xevent->xkey, &str, 1, &keysym, nullptr);
@@ -108,6 +171,7 @@ bool KeyboardX11::handleEvent(const void* event)
handler->handleKeyPress(xevent->xkey.keycode, keycode, keysym);
return true;
} else if (xevent->type == KeyRelease) {
+ fl_event_time = xevent->xkey.time;
handler->handleKeyRelease(xevent->xkey.keycode);
return true;
}
@@ -115,6 +179,31 @@ bool KeyboardX11::handleEvent(const void* event)
return false;
}
+std::list<uint32_t> KeyboardX11::translateToKeySyms(int systemKeyCode)
+{
+ Status status;
+ XkbStateRec state;
+ std::list<uint32_t> keySyms;
+ unsigned char group;
+
+ status = XkbGetState(fl_display, XkbUseCoreKbd, &state);
+ if (status != Success)
+ return keySyms;
+
+ // Start with the currently used group
+ translateToKeySyms(systemKeyCode, state.group, &keySyms);
+
+ // Then all other groups
+ for (group = 0; group < XkbNumKbdGroups; group++) {
+ if (group == state.group)
+ continue;
+
+ translateToKeySyms(systemKeyCode, group, &keySyms);
+ }
+
+ return keySyms;
+}
+
unsigned KeyboardX11::getLEDState()
{
unsigned state;
@@ -218,3 +307,40 @@ out:
return mask;
}
+
+void KeyboardX11::translateToKeySyms(int systemKeyCode,
+ unsigned char group,
+ std::list<uint32_t>* keySyms)
+{
+ unsigned int mods;
+
+ // Start with no modifiers
+ translateToKeySyms(systemKeyCode, group, 0, keySyms);
+
+ // Next just a single modifier at a time
+ for (mods = 1; mods < (Mod5Mask+1); mods <<= 1)
+ translateToKeySyms(systemKeyCode, group, mods, keySyms);
+
+ // Finally everything
+ for (mods = 0; mods < (Mod5Mask<<1); mods++)
+ translateToKeySyms(systemKeyCode, group, mods, keySyms);
+}
+
+void KeyboardX11::translateToKeySyms(int systemKeyCode,
+ unsigned char group,
+ unsigned char mods,
+ std::list<uint32_t>* keySyms)
+{
+ KeySym ks;
+ std::list<uint32_t>::const_iterator iter;
+
+ ks = XkbKeycodeToKeysym(fl_display, systemKeyCode, group, mods);
+ if (ks == NoSymbol)
+ return;
+
+ iter = std::find(keySyms->begin(), keySyms->end(), ks);
+ if (iter != keySyms->end())
+ return;
+
+ keySyms->push_back(ks);
+}
diff --git a/vncviewer/KeyboardX11.h b/vncviewer/KeyboardX11.h
index ba9a88f9..b3b8d0a0 100644
--- a/vncviewer/KeyboardX11.h
+++ b/vncviewer/KeyboardX11.h
@@ -27,7 +27,10 @@ public:
KeyboardX11(KeyboardHandler* handler);
virtual ~KeyboardX11();
+ bool isKeyboardReset(const void* event) override;
+
bool handleEvent(const void* event) override;
+ std::list<uint32_t> translateToKeySyms(int systemKeyCode) override;
unsigned getLEDState() override;
void setLEDState(unsigned state) override;
@@ -36,6 +39,13 @@ protected:
unsigned getModifierMask(uint32_t keysym);
private:
+ void translateToKeySyms(int systemKeyCode, unsigned char group,
+ std::list<uint32_t>* keySyms);
+ void translateToKeySyms(int systemKeyCode,
+ unsigned char group, unsigned char mods,
+ std::list<uint32_t>* keySyms);
+
+private:
int code_map_keycode_to_qnum[256];
};
diff --git a/vncviewer/MonitorIndicesParameter.cxx b/vncviewer/MonitorIndicesParameter.cxx
index 957ade06..7f8d6a29 100644
--- a/vncviewer/MonitorIndicesParameter.cxx
+++ b/vncviewer/MonitorIndicesParameter.cxx
@@ -30,22 +30,23 @@
#include <stdexcept>
#include "i18n.h"
+
#include <FL/Fl.H>
-#include <rfb/LogWriter.h>
+
+#include <core/LogWriter.h>
#include "MonitorIndicesParameter.h"
-using namespace rfb;
-static LogWriter vlog("MonitorIndicesParameter");
+static core::LogWriter vlog("MonitorIndicesParameter");
-MonitorIndicesParameter::MonitorIndicesParameter(const char* name_, const char* desc_, const char* v)
-: StringParameter(name_, desc_, v) {}
+MonitorIndicesParameter::MonitorIndicesParameter(const char* name_,
+ const char* desc_,
+ const ListType& v)
+: IntListParameter(name_, desc_, v, 1, INT_MAX) {}
-std::set<int> MonitorIndicesParameter::getParam()
+std::set<int> MonitorIndicesParameter::getMonitors() const
{
- bool valid = false;
std::set<int> indices;
- std::set<int> configIndices;
std::vector<MonitorIndicesParameter::Monitor> monitors = fetchMonitors();
if (monitors.size() <= 0) {
@@ -53,18 +54,9 @@ std::set<int> MonitorIndicesParameter::getParam()
return indices;
}
- valid = parseIndices(value.c_str(), &configIndices);
- if (!valid) {
- return indices;
- }
-
- if (configIndices.size() <= 0) {
- return indices;
- }
-
// Go through the monitors and see what indices are present in the config.
for (int i = 0; i < ((int) monitors.size()); i++) {
- if (std::find(configIndices.begin(), configIndices.end(), i) != configIndices.end())
+ if (std::find(begin(), end(), i+1) != end())
indices.insert(monitors[i].fltkIndex);
}
@@ -73,27 +65,20 @@ std::set<int> MonitorIndicesParameter::getParam()
bool MonitorIndicesParameter::setParam(const char* v)
{
- std::set<int> indices;
-
- if (!parseIndices(v, &indices, true)) {
- vlog.error(_("Invalid configuration specified for %s"), name);
+ if (!IntListParameter::setParam(v))
return false;
- }
- for (int index : indices) {
- index += 1;
+ for (int index : value) {
if (index <= 0 || index > Fl::screen_count())
vlog.error(_("Monitor index %d does not exist"), index);
}
- return StringParameter::setParam(v);
+ return true;
}
-bool MonitorIndicesParameter::setParam(std::set<int> indices)
+void MonitorIndicesParameter::setMonitors(const std::set<int>& indices)
{
- static const int BUF_MAX_LEN = 1024;
- char buf[BUF_MAX_LEN] = {0};
- std::set<int> configIndices;
+ std::list<int> configIndices;
std::vector<MonitorIndicesParameter::Monitor> monitors = fetchMonitors();
if (monitors.size() <= 0) {
@@ -103,88 +88,10 @@ bool MonitorIndicesParameter::setParam(std::set<int> indices)
for (int i = 0; i < ((int) monitors.size()); i++) {
if (std::find(indices.begin(), indices.end(), monitors[i].fltkIndex) != indices.end())
- configIndices.insert(i);
- }
-
- int bytesWritten = 0;
- char const * separator = "";
-
- for (int configIndex : configIndices)
- {
- bytesWritten += snprintf(
- buf+bytesWritten,
- BUF_MAX_LEN-bytesWritten,
- "%s%u",
- separator,
- configIndex+1
- );
-
- separator = ",";
+ configIndices.push_back(i+1);
}
- return setParam(buf);
-}
-
-static bool parseNumber(std::string number, std::set<int> *indices)
-{
- if (number.size() <= 0)
- return false;
-
- int v = strtol(number.c_str(), nullptr, 0);
-
- if (v <= 0)
- return false;
-
- if (v > INT_MAX)
- return false;
-
- indices->insert(v-1);
- return true;
-}
-
-bool MonitorIndicesParameter::parseIndices(const char* value,
- std::set<int> *indices,
- bool complain)
-{
- char d;
- std::string current;
-
- for (size_t i = 0; i < strlen(value); i++) {
- d = value[i];
-
- if (d == ' ')
- continue;
- else if (d >= '0' && d <= '9')
- current.push_back(d);
- else if (d == ',') {
- if (!parseNumber(current, indices)) {
- if (complain)
- vlog.error(_("Invalid monitor index '%s'"),
- current.c_str());
- return false;
- }
-
- current.clear();
- } else {
- if (complain)
- vlog.error(_("Unexpected character '%c'"), d);
- return false;
- }
- }
-
- // If we have nothing left to parse we are in a valid state.
- if (current.size() == 0)
- return true;
-
- // Parsing anything we have left.
- if (!parseNumber(current, indices)) {
- if (complain)
- vlog.error(_("Invalid monitor index '%s'"),
- current.c_str());
- return false;
- }
-
- return true;
+ IntListParameter::setParam(configIndices);
}
std::vector<MonitorIndicesParameter::Monitor> MonitorIndicesParameter::fetchMonitors()
diff --git a/vncviewer/MonitorIndicesParameter.h b/vncviewer/MonitorIndicesParameter.h
index d91c84fe..a4f7171d 100644
--- a/vncviewer/MonitorIndicesParameter.h
+++ b/vncviewer/MonitorIndicesParameter.h
@@ -22,23 +22,22 @@
#include <set>
#include <vector>
-#include <rfb/Configuration.h>
+#include <core/Configuration.h>
-class MonitorIndicesParameter: public rfb::StringParameter {
+class MonitorIndicesParameter: public core::IntListParameter {
public:
- MonitorIndicesParameter(const char* name_, const char* desc_, const char* v);
- std::set<int> getParam();
- bool setParam(std::set<int> indices);
- bool setParam(const char* v) override;
+ MonitorIndicesParameter(const char* name_, const char* desc_,
+ const ListType& v);
+ std::set<int> getMonitors() const;
+ bool setParam(const char* value) override;
+ void setMonitors(const std::set<int>& v);
private:
typedef struct {
int x, y, w, h;
int fltkIndex;
} Monitor;
- static bool parseIndices(const char* value, std::set<int> *indices,
- bool complain=false);
- std::vector<MonitorIndicesParameter::Monitor> fetchMonitors();
+ static std::vector<MonitorIndicesParameter::Monitor> fetchMonitors();
static int compare(const void*, const void*);
};
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
index c5f21b24..3ba6fba1 100644
--- a/vncviewer/OptionsDialog.cxx
+++ b/vncviewer/OptionsDialog.cxx
@@ -1,4 +1,4 @@
-/* Copyright 2011-2021 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2011-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,8 @@
#include <stdlib.h>
#include <list>
+#include <core/string.h>
+
#include <rfb/encodings.h>
#if defined(HAVE_GNUTLS) || defined(HAVE_NETTLE)
@@ -35,8 +37,8 @@
#endif
#include "OptionsDialog.h"
+#include "ShortcutHandler.h"
#include "i18n.h"
-#include "menukey.h"
#include "parameters.h"
#include "fltk/layout.h"
@@ -44,18 +46,21 @@
#include "fltk/Fl_Monitor_Arrangement.h"
#include "fltk/Fl_Navigation.h"
+#ifdef __APPLE__
+#include "cocoa.h"
+#endif
+
#include <FL/Fl.H>
+#include <FL/Fl_Box.H>
#include <FL/Fl_Tabs.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Check_Button.H>
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Round_Button.H>
+#include <FL/Fl_Toggle_Button.H>
#include <FL/Fl_Int_Input.H>
#include <FL/Fl_Choice.H>
-using namespace std;
-using namespace rfb;
-
std::map<OptionsCallback*, void*> OptionsDialog::callbacks;
static std::set<OptionsDialog *> instances;
@@ -85,6 +90,7 @@ OptionsDialog::OptionsDialog()
createCompressionPage(tx, ty, tw, th);
createSecurityPage(tx, ty, tw, th);
createInputPage(tx, ty, tw, th);
+ createShortcutsPage(tx, ty, tw, th);
createDisplayPage(tx, ty, tw, th);
createMiscPage(tx, ty, tw, th);
}
@@ -162,27 +168,18 @@ void OptionsDialog::loadOptions(void)
/* Compression */
autoselectCheckbox->value(autoSelect);
- int encNum = encodingNum(preferredEncoding);
-
- switch (encNum) {
- case encodingTight:
+ if (preferredEncoding == "Tight")
tightButton->setonly();
- break;
- case encodingZRLE:
+ else if (preferredEncoding == "ZRLE")
zrleButton->setonly();
- break;
- case encodingHextile:
+ else if (preferredEncoding == "Hextile")
hextileButton->setonly();
- break;
#ifdef HAVE_H264
- case encodingH264:
+ else if (preferredEncoding == "H.264")
h264Button->setonly();
- break;
#endif
- case encodingRaw:
+ else if (preferredEncoding == "Raw")
rawButton->setonly();
- break;
- }
if (fullColour)
fullcolorCheckbox->setonly();
@@ -215,11 +212,11 @@ void OptionsDialog::loadOptions(void)
#if defined(HAVE_GNUTLS) || defined(HAVE_NETTLE)
/* Security */
- Security security(SecurityClient::secTypes);
+ rfb::Security security(rfb::SecurityClient::secTypes);
- list<uint8_t> secTypes;
+ std::list<uint8_t> secTypes;
- list<uint32_t> secTypesExt;
+ std::list<uint32_t> secTypesExt;
encNoneCheckbox->value(false);
#ifdef HAVE_GNUTLS
@@ -237,11 +234,11 @@ void OptionsDialog::loadOptions(void)
secTypes = security.GetEnabledSecTypes();
for (uint8_t type : secTypes) {
switch (type) {
- case secTypeNone:
+ case rfb::secTypeNone:
encNoneCheckbox->value(true);
authNoneCheckbox->value(true);
break;
- case secTypeVncAuth:
+ case rfb::secTypeVncAuth:
encNoneCheckbox->value(true);
authVncCheckbox->value(true);
break;
@@ -251,49 +248,49 @@ void OptionsDialog::loadOptions(void)
secTypesExt = security.GetEnabledExtSecTypes();
for (uint32_t type : secTypesExt) {
switch (type) {
- case secTypePlain:
+ case rfb::secTypePlain:
encNoneCheckbox->value(true);
authPlainCheckbox->value(true);
break;
#ifdef HAVE_GNUTLS
- case secTypeTLSNone:
+ case rfb::secTypeTLSNone:
encTLSCheckbox->value(true);
authNoneCheckbox->value(true);
break;
- case secTypeTLSVnc:
+ case rfb::secTypeTLSVnc:
encTLSCheckbox->value(true);
authVncCheckbox->value(true);
break;
- case secTypeTLSPlain:
+ case rfb::secTypeTLSPlain:
encTLSCheckbox->value(true);
authPlainCheckbox->value(true);
break;
- case secTypeX509None:
+ case rfb::secTypeX509None:
encX509Checkbox->value(true);
authNoneCheckbox->value(true);
break;
- case secTypeX509Vnc:
+ case rfb::secTypeX509Vnc:
encX509Checkbox->value(true);
authVncCheckbox->value(true);
break;
- case secTypeX509Plain:
+ case rfb::secTypeX509Plain:
encX509Checkbox->value(true);
authPlainCheckbox->value(true);
break;
#endif
#ifdef HAVE_NETTLE
- case secTypeRA2:
- case secTypeRA256:
+ case rfb::secTypeRA2:
+ case rfb::secTypeRA256:
encRSAAESCheckbox->value(true);
authVncCheckbox->value(true);
authPlainCheckbox->value(true);
break;
- case secTypeRA2ne:
- case secTypeRAne256:
+ case rfb::secTypeRA2ne:
+ case rfb::secTypeRAne256:
authVncCheckbox->value(true);
/* fall through */
- case secTypeDH:
- case secTypeMSLogonII:
+ case rfb::secTypeDH:
+ case rfb::secTypeMSLogonII:
encNoneCheckbox->value(true);
authPlainCheckbox->value(true);
break;
@@ -303,16 +300,14 @@ void OptionsDialog::loadOptions(void)
}
#ifdef HAVE_GNUTLS
- caInput->value(CSecurityTLS::X509CA);
- crlInput->value(CSecurityTLS::X509CRL);
+ caInput->value(rfb::CSecurityTLS::X509CA);
+ crlInput->value(rfb::CSecurityTLS::X509CRL);
handleX509(encX509Checkbox, this);
#endif
#endif
/* Input */
- const char *menuKeyBuf;
-
viewOnlyCheckbox->value(viewOnly);
emulateMBCheckbox->value(emulateMiddleButton);
acceptClipboardCheckbox->value(acceptClipboard);
@@ -325,34 +320,48 @@ void OptionsDialog::loadOptions(void)
#endif
systemKeysCheckbox->value(fullscreenSystemKeys);
- menuKeyChoice->value(0);
+ /* Keyboard shortcuts */
+ unsigned modifierMask;
+
+ modifierMask = 0;
+ for (core::EnumListEntry key : shortcutModifiers)
+ modifierMask |= ShortcutHandler::parseModifier(key.getValueStr().c_str());
+
+ ctrlButton->value(modifierMask & ShortcutHandler::Control);
+ shiftButton->value(modifierMask & ShortcutHandler::Shift);
+ altButton->value(modifierMask & ShortcutHandler::Alt);
+ superButton->value(modifierMask & ShortcutHandler::Super);
- menuKeyBuf = menuKey;
- for (int idx = 0; idx < getMenuKeySymbolCount(); idx++)
- if (!strcmp(getMenuKeySymbols()[idx].name, menuKeyBuf))
- menuKeyChoice->value(idx + 1);
+ handleModifier(nullptr, this);
/* Display */
if (!fullScreen) {
windowedButton->setonly();
} else {
- if (!strcasecmp(fullScreenMode, "all")) {
+ if (fullScreenMode == "all") {
allMonitorsButton->setonly();
- } else if (!strcasecmp(fullScreenMode, "selected")) {
+ } else if (fullScreenMode == "selected") {
selectedMonitorsButton->setonly();
} else {
currentMonitorButton->setonly();
}
}
- monitorArrangement->value(fullScreenSelectedMonitors.getParam());
+ monitorArrangement->value(fullScreenSelectedMonitors.getMonitors());
handleFullScreenMode(selectedMonitorsButton, this);
/* Misc. */
sharedCheckbox->value(shared);
reconnectCheckbox->value(reconnectOnError);
- dotCursorCheckbox->value(dotWhenNoCursor);
+ alwaysCursorCheckbox->value(alwaysCursor);
+ if (cursorType == "system") {
+ cursorTypeChoice->value(1);
+ } else {
+ // Default
+ cursorTypeChoice->value(0);
+ }
+ handleAlwaysCursor(alwaysCursorCheckbox, this);
}
@@ -362,17 +371,17 @@ void OptionsDialog::storeOptions(void)
autoSelect.setParam(autoselectCheckbox->value());
if (tightButton->value())
- preferredEncoding.setParam(encodingName(encodingTight));
+ preferredEncoding.setParam(rfb::encodingName(rfb::encodingTight));
else if (zrleButton->value())
- preferredEncoding.setParam(encodingName(encodingZRLE));
+ preferredEncoding.setParam(rfb::encodingName(rfb::encodingZRLE));
else if (hextileButton->value())
- preferredEncoding.setParam(encodingName(encodingHextile));
+ preferredEncoding.setParam(rfb::encodingName(rfb::encodingHextile));
#ifdef HAVE_H264
else if (h264Button->value())
- preferredEncoding.setParam(encodingName(encodingH264));
+ preferredEncoding.setParam(rfb::encodingName(rfb::encodingH264));
#endif
else if (rawButton->value())
- preferredEncoding.setParam(encodingName(encodingRaw));
+ preferredEncoding.setParam(rfb::encodingName(rfb::encodingRaw));
fullColour.setParam(fullcolorCheckbox->value());
if (verylowcolorCheckbox->value())
@@ -389,26 +398,26 @@ void OptionsDialog::storeOptions(void)
#if defined(HAVE_GNUTLS) || defined(HAVE_NETTLE)
/* Security */
- Security security;
+ rfb::Security security;
/* Process security types which don't use encryption */
if (encNoneCheckbox->value()) {
if (authNoneCheckbox->value())
- security.EnableSecType(secTypeNone);
+ security.EnableSecType(rfb::secTypeNone);
if (authVncCheckbox->value()) {
- security.EnableSecType(secTypeVncAuth);
+ security.EnableSecType(rfb::secTypeVncAuth);
#ifdef HAVE_NETTLE
- security.EnableSecType(secTypeRA2ne);
- security.EnableSecType(secTypeRAne256);
+ security.EnableSecType(rfb::secTypeRA2ne);
+ security.EnableSecType(rfb::secTypeRAne256);
#endif
}
if (authPlainCheckbox->value()) {
- security.EnableSecType(secTypePlain);
+ security.EnableSecType(rfb::secTypePlain);
#ifdef HAVE_NETTLE
- security.EnableSecType(secTypeRA2ne);
- security.EnableSecType(secTypeRAne256);
- security.EnableSecType(secTypeDH);
- security.EnableSecType(secTypeMSLogonII);
+ security.EnableSecType(rfb::secTypeRA2ne);
+ security.EnableSecType(rfb::secTypeRAne256);
+ security.EnableSecType(rfb::secTypeDH);
+ security.EnableSecType(rfb::secTypeMSLogonII);
#endif
}
}
@@ -417,34 +426,34 @@ void OptionsDialog::storeOptions(void)
/* Process security types which use TLS encryption */
if (encTLSCheckbox->value()) {
if (authNoneCheckbox->value())
- security.EnableSecType(secTypeTLSNone);
+ security.EnableSecType(rfb::secTypeTLSNone);
if (authVncCheckbox->value())
- security.EnableSecType(secTypeTLSVnc);
+ security.EnableSecType(rfb::secTypeTLSVnc);
if (authPlainCheckbox->value())
- security.EnableSecType(secTypeTLSPlain);
+ security.EnableSecType(rfb::secTypeTLSPlain);
}
/* Process security types which use X509 encryption */
if (encX509Checkbox->value()) {
if (authNoneCheckbox->value())
- security.EnableSecType(secTypeX509None);
+ security.EnableSecType(rfb::secTypeX509None);
if (authVncCheckbox->value())
- security.EnableSecType(secTypeX509Vnc);
+ security.EnableSecType(rfb::secTypeX509Vnc);
if (authPlainCheckbox->value())
- security.EnableSecType(secTypeX509Plain);
+ security.EnableSecType(rfb::secTypeX509Plain);
}
- CSecurityTLS::X509CA.setParam(caInput->value());
- CSecurityTLS::X509CRL.setParam(crlInput->value());
+ rfb::CSecurityTLS::X509CA.setParam(caInput->value());
+ rfb::CSecurityTLS::X509CRL.setParam(crlInput->value());
#endif
#ifdef HAVE_NETTLE
if (encRSAAESCheckbox->value()) {
- security.EnableSecType(secTypeRA2);
- security.EnableSecType(secTypeRA256);
+ security.EnableSecType(rfb::secTypeRA2);
+ security.EnableSecType(rfb::secTypeRA256);
}
#endif
- SecurityClient::secTypes.setParam(security.ToString());
+ rfb::SecurityClient::secTypes.setParam(security.ToString());
#endif
/* Input */
@@ -460,11 +469,23 @@ void OptionsDialog::storeOptions(void)
#endif
fullscreenSystemKeys.setParam(systemKeysCheckbox->value());
- if (menuKeyChoice->value() == 0)
- menuKey.setParam("");
- else {
- menuKey.setParam(menuKeyChoice->text());
- }
+ /* Keyboard shortcuts */
+ std::list<std::string> modifierList;
+
+ if (ctrlButton->value())
+ modifierList.push_back(
+ ShortcutHandler::modifierString(ShortcutHandler::Control));
+ if (shiftButton->value())
+ modifierList.push_back(
+ ShortcutHandler::modifierString(ShortcutHandler::Shift));
+ if (altButton->value())
+ modifierList.push_back(
+ ShortcutHandler::modifierString(ShortcutHandler::Alt));
+ if (superButton->value())
+ modifierList.push_back(
+ ShortcutHandler::modifierString(ShortcutHandler::Super));
+
+ shortcutModifiers.setParam(modifierList);
/* Display */
if (windowedButton->value()) {
@@ -481,12 +502,19 @@ void OptionsDialog::storeOptions(void)
}
}
- fullScreenSelectedMonitors.setParam(monitorArrangement->value());
+ fullScreenSelectedMonitors.setMonitors(monitorArrangement->value());
/* Misc. */
shared.setParam(sharedCheckbox->value());
reconnectOnError.setParam(reconnectCheckbox->value());
- dotWhenNoCursor.setParam(dotCursorCheckbox->value());
+ alwaysCursor.setParam(alwaysCursorCheckbox->value());
+
+ if (cursorTypeChoice->value() == 1) {
+ cursorType.setParam("System");
+ } else {
+ // Default
+ cursorType.setParam("Dot");
+ }
std::map<OptionsCallback*, void*>::const_iterator iter;
@@ -840,11 +868,23 @@ void OptionsDialog::createInputPage(int tx, int ty, int tw, int th)
_("Emulate middle mouse button")));
ty += CHECK_HEIGHT + TIGHT_MARGIN;
- dotCursorCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
- CHECK_MIN_WIDTH,
- CHECK_HEIGHT,
- _("Show dot when no cursor")));
+ alwaysCursorCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
+ CHECK_MIN_WIDTH,
+ CHECK_HEIGHT,
+ _("Show local cursor when not provided by server")));
+ alwaysCursorCheckbox->callback(handleAlwaysCursor, this);
ty += CHECK_HEIGHT + TIGHT_MARGIN;
+
+ /* Cursor type */
+ cursorTypeChoice = new Fl_Choice(LBLLEFT(tx, ty, 150, CHOICE_HEIGHT, _("Cursor type")));
+
+ fltk_menu_add(cursorTypeChoice, _("Dot"), 0, nullptr, nullptr, 0);
+ fltk_menu_add(cursorTypeChoice, _("System"), 0, nullptr, nullptr, 0);
+
+ fltk_adjust_choice(cursorTypeChoice);
+
+ ty += CHOICE_HEIGHT + TIGHT_MARGIN;
+
}
ty -= TIGHT_MARGIN;
@@ -868,19 +908,11 @@ void OptionsDialog::createInputPage(int tx, int ty, int tw, int th)
tx += INDENT;
ty += TIGHT_MARGIN;
- systemKeysCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
- CHECK_MIN_WIDTH,
- CHECK_HEIGHT,
- _("Pass system keys directly to server (full screen)")));
+ systemKeysCheckbox = new Fl_Check_Button(
+ LBLRIGHT(tx, ty, CHECK_MIN_WIDTH, CHECK_HEIGHT,
+ _("Always send all keyboard input in full screen")));
+ systemKeysCheckbox->callback(handleSystemKeys, this);
ty += CHECK_HEIGHT + TIGHT_MARGIN;
-
- menuKeyChoice = new Fl_Choice(LBLLEFT(tx, ty, 150, CHOICE_HEIGHT, _("Menu key")));
-
- fltk_menu_add(menuKeyChoice, _("None"), 0, nullptr, nullptr, FL_MENU_DIVIDER);
- for (int idx = 0; idx < getMenuKeySymbolCount(); idx++)
- fltk_menu_add(menuKeyChoice, getMenuKeySymbols()[idx].name, 0, nullptr, nullptr, 0);
-
- ty += CHOICE_HEIGHT + TIGHT_MARGIN;
}
ty -= TIGHT_MARGIN;
@@ -949,6 +981,76 @@ void OptionsDialog::createInputPage(int tx, int ty, int tw, int th)
}
+void OptionsDialog::createShortcutsPage(int tx, int ty, int tw, int th)
+{
+ Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Keyboard shortcuts"));
+
+ tx += OUTER_MARGIN;
+ ty += OUTER_MARGIN;
+
+ Fl_Box *intro = new Fl_Box(tx, ty, tw - OUTER_MARGIN * 2, INPUT_HEIGHT);
+ intro->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
+ intro->label(_("Modifier keys for keyboard shortcuts:"));
+
+ ty += INPUT_HEIGHT + INNER_MARGIN;
+
+ int width;
+
+ width = (tw - OUTER_MARGIN * 2 - INNER_MARGIN * 3) / 4;
+
+ ctrlButton = new Fl_Toggle_Button(tx, ty,
+ /*
+ * TRANSLATORS: This refers to the
+ * keyboard key
+ * */
+ width, BUTTON_HEIGHT, _("Ctrl"));
+ ctrlButton->selection_color(FL_SELECTION_COLOR);
+ ctrlButton->callback(handleModifier, this);
+ shiftButton = new Fl_Toggle_Button(tx + width + INNER_MARGIN, ty,
+ /*
+ * TRANSLATORS: This refers to the
+ * keyboard key
+ * */
+ width, BUTTON_HEIGHT, _("Shift"));
+ shiftButton->selection_color(FL_SELECTION_COLOR);
+ shiftButton->callback(handleModifier, this);
+ altButton = new Fl_Toggle_Button(tx + width * 2 + INNER_MARGIN * 2, ty,
+ /*
+ * TRANSLATORS: This refers to the
+ * keyboard key
+ * */
+ width, BUTTON_HEIGHT, _("Alt"));
+ altButton->selection_color(FL_SELECTION_COLOR);
+ altButton->callback(handleModifier, this);
+ superButton = new Fl_Toggle_Button(tx + width * 3 + INNER_MARGIN * 3, ty,
+ /*
+ * TRANSLATORS: This refers to the
+ * keyboard key
+ * */
+ width, BUTTON_HEIGHT, _("Win"));
+ superButton->selection_color(FL_SELECTION_COLOR);
+ superButton->callback(handleModifier, this);
+
+#ifdef __APPLE__
+ /* TRANSLATORS: This refers to the keyboard key */
+ ctrlButton->label(_("⌃ Ctrl"));
+ /* TRANSLATORS: This refers to the keyboard key */
+ shiftButton->label(_("⇧ Shift"));
+ /* TRANSLATORS: This refers to the keyboard key */
+ altButton->label(_("⌥ Option"));
+ /* TRANSLATORS: This refers to the keyboard key */
+ superButton->label(_("⌘ Cmd"));
+#endif
+
+ ty += BUTTON_HEIGHT + INNER_MARGIN;
+
+ shortcutsText = new Fl_Box(tx, ty, tw - OUTER_MARGIN * 2, th - ty - OUTER_MARGIN);
+ shortcutsText->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
+
+ group->end();
+}
+
+
void OptionsDialog::createDisplayPage(int tx, int ty, int tw, int th)
{
Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Display"));
@@ -1117,6 +1219,20 @@ void OptionsDialog::handleRSAAES(Fl_Widget* /*widget*/, void *data)
}
+void OptionsDialog::handleSystemKeys(Fl_Widget* /*widget*/, void* data)
+{
+#ifdef __APPLE__
+ OptionsDialog* dialog = (OptionsDialog*)data;
+
+ // Pop up the access dialog if needed
+ if (dialog->systemKeysCheckbox->value())
+ cocoa_is_trusted(true);
+#else
+ (void)data;
+#endif
+}
+
+
void OptionsDialog::handleClipboard(Fl_Widget* /*widget*/, void *data)
{
(void)data;
@@ -1134,6 +1250,61 @@ void OptionsDialog::handleClipboard(Fl_Widget* /*widget*/, void *data)
#endif
}
+void OptionsDialog::handleModifier(Fl_Widget* /*widget*/, void *data)
+{
+ OptionsDialog *dialog = (OptionsDialog*)data;
+ unsigned mask;
+
+ mask = 0;
+ if (dialog->ctrlButton->value())
+ mask |= ShortcutHandler::Control;
+ if (dialog->shiftButton->value())
+ mask |= ShortcutHandler::Shift;
+ if (dialog->altButton->value())
+ mask |= ShortcutHandler::Alt;
+ if (dialog->superButton->value())
+ mask |= ShortcutHandler::Super;
+
+ if (mask == 0) {
+ dialog->shortcutsText->copy_label(
+ _("All keyboard shortcuts are disabled."));
+ } else {
+ char prefix[256];
+ char prefix_noplus[256];
+
+ std::string label;
+
+ strcpy(prefix, ShortcutHandler::modifierPrefix(mask));
+ strcpy(prefix_noplus, ShortcutHandler::modifierPrefix(mask, true));
+
+ label += core::format(
+ _("To release keyboard control from the session, press %s."),
+ prefix_noplus);
+ label += "\n\n";
+
+ label += core::format(
+ _("To pass all keyboard input to the session, press %sG."),
+ prefix);
+ label += "\n\n";
+
+ label += core::format(
+ _("To toggle full-screen mode, press %sEnter."), prefix);
+ label += "\n\n";
+
+ label += core::format(
+ _("To open the session context menu, press %sM."), prefix);
+ label += "\n\n";
+
+ label += core::format(
+ _("To send a key combination that includes %s directly to the "
+ "session, press %sSpace, release the space bar without "
+ "releasing %s, and press the desired key."),
+ prefix_noplus, prefix, prefix_noplus);
+
+ dialog->shortcutsText->copy_label(label.c_str());
+ }
+}
+
void OptionsDialog::handleFullScreenMode(Fl_Widget* /*widget*/, void *data)
{
OptionsDialog *dialog = (OptionsDialog*)data;
@@ -1184,5 +1355,16 @@ void OptionsDialog::handleScreenConfigTimeout(void *data)
assert(self);
- self->monitorArrangement->value(fullScreenSelectedMonitors.getParam());
+ self->monitorArrangement->value(fullScreenSelectedMonitors.getMonitors());
+}
+
+void OptionsDialog::handleAlwaysCursor(Fl_Widget* /*widget*/, void *data)
+{
+ OptionsDialog *dialog = (OptionsDialog*)data;
+
+ if (dialog->alwaysCursorCheckbox->value()) {
+ dialog->cursorTypeChoice->activate();
+ } else {
+ dialog->cursorTypeChoice->deactivate();
+ }
}
diff --git a/vncviewer/OptionsDialog.h b/vncviewer/OptionsDialog.h
index f6ca89b1..daa9f3e8 100644
--- a/vncviewer/OptionsDialog.h
+++ b/vncviewer/OptionsDialog.h
@@ -24,9 +24,11 @@
#include <FL/Fl_Window.H>
class Fl_Widget;
+class Fl_Box;
class Fl_Group;
class Fl_Check_Button;
class Fl_Round_Button;
+class Fl_Toggle_Button;
class Fl_Input;
class Fl_Int_Input;
class Fl_Choice;
@@ -54,18 +56,24 @@ protected:
void createCompressionPage(int tx, int ty, int tw, int th);
void createSecurityPage(int tx, int ty, int tw, int th);
void createInputPage(int tx, int ty, int tw, int th);
+ void createShortcutsPage(int tx, int ty, int tw, int th);
void createDisplayPage(int tx, int ty, int tw, int th);
void createMiscPage(int tx, int ty, int tw, int th);
static void handleAutoselect(Fl_Widget *widget, void *data);
static void handleCompression(Fl_Widget *widget, void *data);
static void handleJpeg(Fl_Widget *widget, void *data);
+ static void handleAlwaysCursor(Fl_Widget *widget, void *data);
static void handleX509(Fl_Widget *widget, void *data);
static void handleRSAAES(Fl_Widget *widget, void *data);
+ static void handleSystemKeys(Fl_Widget *widget, void *data);
+
static void handleClipboard(Fl_Widget *widget, void *data);
+ static void handleModifier(Fl_Widget *widget, void *data);
+
static void handleFullScreenMode(Fl_Widget *widget, void *data);
static void handleCancel(Fl_Widget *widget, void *data);
@@ -115,10 +123,10 @@ protected:
Fl_Check_Button *viewOnlyCheckbox;
Fl_Group *mouseGroup;
Fl_Check_Button *emulateMBCheckbox;
- Fl_Check_Button *dotCursorCheckbox;
+ Fl_Check_Button *alwaysCursorCheckbox;
+ Fl_Choice *cursorTypeChoice;
Fl_Group *keyboardGroup;
Fl_Check_Button *systemKeysCheckbox;
- Fl_Choice *menuKeyChoice;
Fl_Group *clipboardGroup;
Fl_Check_Button *acceptClipboardCheckbox;
#if !defined(WIN32) && !defined(__APPLE__)
@@ -129,6 +137,14 @@ protected:
Fl_Check_Button *sendPrimaryCheckbox;
#endif
+ /* Keyboard shortcuts */
+ Fl_Toggle_Button *ctrlButton;
+ Fl_Toggle_Button *altButton;
+ Fl_Toggle_Button *shiftButton;
+ Fl_Toggle_Button *superButton;
+
+ Fl_Box *shortcutsText;
+
/* Display */
Fl_Group *displayModeGroup;
Fl_Round_Button *windowedButton;
diff --git a/vncviewer/PlatformPixelBuffer.cxx b/vncviewer/PlatformPixelBuffer.cxx
index 0f152e11..6a6d22f1 100644
--- a/vncviewer/PlatformPixelBuffer.cxx
+++ b/vncviewer/PlatformPixelBuffer.cxx
@@ -33,11 +33,11 @@
#include <FL/Fl.H>
#include <FL/x.H>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
#include "PlatformPixelBuffer.h"
-static rfb::LogWriter vlog("PlatformPixelBuffer");
+static core::LogWriter vlog("PlatformPixelBuffer");
PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) :
FullFramePixelBuffer(rfb::PixelFormat(32, 24, false, true,
@@ -91,17 +91,17 @@ PlatformPixelBuffer::~PlatformPixelBuffer()
#endif
}
-void PlatformPixelBuffer::commitBufferRW(const rfb::Rect& r)
+void PlatformPixelBuffer::commitBufferRW(const core::Rect& r)
{
FullFramePixelBuffer::commitBufferRW(r);
mutex.lock();
- damage.assign_union(rfb::Region(r));
+ damage.assign_union(r);
mutex.unlock();
}
-rfb::Rect PlatformPixelBuffer::getDamage(void)
+core::Rect PlatformPixelBuffer::getDamage(void)
{
- rfb::Rect r;
+ core::Rect r;
mutex.lock();
r = damage.get_bounding_rect();
diff --git a/vncviewer/PlatformPixelBuffer.h b/vncviewer/PlatformPixelBuffer.h
index 24763d46..2c8d3957 100644
--- a/vncviewer/PlatformPixelBuffer.h
+++ b/vncviewer/PlatformPixelBuffer.h
@@ -27,11 +27,11 @@
#endif
#include <list>
+#include <mutex>
-#include <os/Mutex.h>
+#include <core/Region.h>
#include <rfb/PixelBuffer.h>
-#include <rfb/Region.h>
#include "Surface.h"
@@ -40,16 +40,16 @@ public:
PlatformPixelBuffer(int width, int height);
~PlatformPixelBuffer();
- void commitBufferRW(const rfb::Rect& r) override;
+ void commitBufferRW(const core::Rect& r) override;
- rfb::Rect getDamage(void);
+ core::Rect getDamage(void);
using rfb::FullFramePixelBuffer::width;
using rfb::FullFramePixelBuffer::height;
protected:
- os::Mutex mutex;
- rfb::Region damage;
+ std::mutex mutex;
+ core::Region damage;
#if !defined(WIN32) && !defined(__APPLE__)
protected:
diff --git a/vncviewer/ServerDialog.cxx b/vncviewer/ServerDialog.cxx
index e9d4e75b..3011e948 100644
--- a/vncviewer/ServerDialog.cxx
+++ b/vncviewer/ServerDialog.cxx
@@ -25,6 +25,11 @@
#include <algorithm>
#include <libgen.h>
+// FIXME: Workaround for FLTK including windows.h
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
#include <FL/Fl.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Input_Choice.H>
@@ -35,13 +40,12 @@
#include <FL/Fl_Box.H>
#include <FL/Fl_File_Chooser.H>
-#include <os/os.h>
-
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+#include <core/xdgdirs.h>
-#include <rfb/Hostname.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+#include <network/TcpSocket.h>
#include "fltk/layout.h"
#include "fltk/util.h"
@@ -51,16 +55,12 @@
#include "vncviewer.h"
#include "parameters.h"
-
-using namespace std;
-using namespace rfb;
-
-static LogWriter vlog("ServerDialog");
+static core::LogWriter vlog("ServerDialog");
const char* SERVER_HISTORY="tigervnc.history";
ServerDialog::ServerDialog()
- : Fl_Window(450, 0, _("VNC viewer: Connection details"))
+ : Fl_Window(450, 0, "TigerVNC")
{
int x, y, x2;
Fl_Button *button;
@@ -139,7 +139,7 @@ void ServerDialog::run(const char* servername, char *newservername)
dialog.loadServerHistory();
dialog.serverName->clear();
- for (const string& entry : dialog.serverHistory)
+ for (const std::string& entry : dialog.serverHistory)
fltk_menu_add(dialog.serverName->menubutton(),
entry.c_str(), 0, nullptr);
} catch (std::exception& e) {
@@ -170,7 +170,7 @@ void ServerDialog::handleLoad(Fl_Widget* /*widget*/, void* data)
ServerDialog *dialog = (ServerDialog*)data;
if (dialog->usedDir.empty())
- dialog->usedDir = os::getuserhomedir();
+ dialog->usedDir = core::getuserhomedir();
Fl_File_Chooser* file_chooser = new Fl_File_Chooser(dialog->usedDir.c_str(),
_("TigerVNC configuration (*.tigervnc)"),
@@ -210,7 +210,7 @@ void ServerDialog::handleSaveAs(Fl_Widget* /*widget*/, void* data)
const char* servername = dialog->serverName->value();
const char* filename;
if (dialog->usedDir.empty())
- dialog->usedDir = os::getuserhomedir();
+ dialog->usedDir = core::getuserhomedir();
Fl_File_Chooser* file_chooser = new Fl_File_Chooser(dialog->usedDir.c_str(),
_("TigerVNC configuration (*.tigervnc)"),
@@ -309,19 +309,20 @@ void ServerDialog::handleConnect(Fl_Widget* /*widget*/, void *data)
}
-static bool same_server(const string& a, const string& b)
+static bool same_server(const std::string& a, const std::string& b)
{
- string hostA, hostB;
+ std::string hostA, hostB;
int portA, portB;
#ifndef WIN32
- if ((a.find("/") != string::npos) || (b.find("/") != string::npos))
+ if ((a.find("/") != std::string::npos) ||
+ (b.find("/") != std::string::npos))
return a == b;
#endif
try {
- getHostAndPort(a.c_str(), &hostA, &portA);
- getHostAndPort(b.c_str(), &hostB, &portB);
+ network::getHostAndPort(a.c_str(), &hostA, &portA);
+ network::getHostAndPort(b.c_str(), &hostB, &portB);
} catch (std::exception& e) {
return false;
}
@@ -338,7 +339,7 @@ static bool same_server(const string& a, const string& b)
void ServerDialog::loadServerHistory()
{
- list<string> rawHistory;
+ std::list<std::string> rawHistory;
serverHistory.clear();
@@ -346,7 +347,7 @@ void ServerDialog::loadServerHistory()
rawHistory = loadHistoryFromRegKey();
#else
- const char* stateDir = os::getvncstatedir();
+ const char* stateDir = core::getvncstatedir();
if (stateDir == nullptr)
throw std::runtime_error(_("Could not determine VNC state directory path"));
@@ -360,8 +361,8 @@ void ServerDialog::loadServerHistory()
// no history file
return;
}
- std::string msg = format(_("Could not open \"%s\""), filepath);
- throw rdr::posix_error(msg.c_str(), errno);
+ throw core::posix_error(
+ core::format(_("Could not open \"%s\""), filepath), errno);
}
int lineNr = 0;
@@ -375,20 +376,21 @@ void ServerDialog::loadServerHistory()
break;
fclose(f);
- std::string msg = format(_("Failed to read line %d in "
- "file \"%s\""), lineNr, filepath);
- throw rdr::posix_error(msg.c_str(), errno);
+ throw core::posix_error(
+ core::format(_("Failed to read line %d in file \"%s\""),
+ lineNr, filepath),
+ errno);
}
int len = strlen(line);
if (len == (sizeof(line) - 1)) {
fclose(f);
- throw std::runtime_error(format("%s: %s",
- format(_("Failed to read line %d "
- "in file %s"),
- lineNr, filepath).c_str(),
- _("Line too long")));
+ std::string msg = core::format(_("Failed to read line %d in "
+ "file \"%s\""),
+ lineNr, filepath);
+ throw std::runtime_error(
+ core::format("%s: %s", msg.c_str(), _("Line too long")));
}
if ((len > 0) && (line[len-1] == '\n')) {
@@ -410,9 +412,11 @@ void ServerDialog::loadServerHistory()
#endif
// Filter out duplicates, even if they have different formats
- for (const string& entry : rawHistory) {
+ for (const std::string& entry : rawHistory) {
if (std::find_if(serverHistory.begin(), serverHistory.end(),
- [&entry](const string& s) { return same_server(s, entry); }) != serverHistory.end())
+ [&entry](const std::string& s) {
+ return same_server(s, entry);
+ }) != serverHistory.end())
continue;
serverHistory.push_back(entry);
}
@@ -425,7 +429,7 @@ void ServerDialog::saveServerHistory()
return;
#endif
- const char* stateDir = os::getvncstatedir();
+ const char* stateDir = core::getvncstatedir();
if (stateDir == nullptr)
throw std::runtime_error(_("Could not determine VNC state directory path"));
@@ -435,13 +439,13 @@ void ServerDialog::saveServerHistory()
/* Write server history to file */
FILE* f = fopen(filepath, "w+");
if (!f) {
- std::string msg = format(_("Could not open \"%s\""), filepath);
- throw rdr::posix_error(msg.c_str(), errno);
+ std::string msg = core::format(_("Could not open \"%s\""), filepath);
+ throw core::posix_error(msg.c_str(), errno);
}
// Save the last X elements to the config file.
size_t count = 0;
- for (const string& entry : serverHistory) {
+ for (const std::string& entry : serverHistory) {
if (++count > SERVER_HISTORY_SIZE)
break;
fprintf(f, "%s\n", entry.c_str());
diff --git a/vncviewer/ShortcutHandler.cxx b/vncviewer/ShortcutHandler.cxx
new file mode 100644
index 00000000..aa17a6d1
--- /dev/null
+++ b/vncviewer/ShortcutHandler.cxx
@@ -0,0 +1,275 @@
+/* Copyright 2021-2025 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define XK_MISCELLANY
+#include <rfb/keysymdef.h>
+
+#include "ShortcutHandler.h"
+#include "i18n.h"
+
+ShortcutHandler::ShortcutHandler() :
+ modifierMask(0), state(Idle)
+{
+}
+
+void ShortcutHandler::setModifiers(unsigned mask)
+{
+ modifierMask = mask;
+ reset();
+}
+
+ShortcutHandler::KeyAction ShortcutHandler::handleKeyPress(int keyCode,
+ uint32_t keySym)
+{
+ unsigned modifier, pressedMask;
+ std::map<int, uint32_t>::const_iterator iter;
+
+ pressedKeys[keyCode] = keySym;
+
+ if (modifierMask == 0)
+ return KeyNormal;
+
+ modifier = keySymToModifier(keySym);
+
+ pressedMask = 0;
+ for (iter = pressedKeys.begin(); iter != pressedKeys.end(); ++iter)
+ pressedMask |= keySymToModifier(iter->second);
+
+ switch (state) {
+ case Idle:
+ case Arming:
+ case Rearming:
+ if (pressedMask == modifierMask) {
+ // All triggering modifier keys are pressed
+ state = Armed;
+ } if (modifier && ((modifier & modifierMask) == modifier)) {
+ // The new key is part of the triggering set
+ if (state == Idle)
+ state = Arming;
+ } else {
+ // The new key was something else
+ state = Wedged;
+ }
+ return KeyNormal;
+ case Armed:
+ if (modifier && ((modifier & modifierMask) == modifier)) {
+ // The new key is part of the triggering set
+ return KeyNormal;
+ } else if (modifier) {
+ // The new key is some other modifier
+ state = Wedged;
+ return KeyNormal;
+ } else {
+ // The new key was something else
+ state = Firing;
+ firedKeys.insert(keyCode);
+ return KeyShortcut;
+ }
+ break;
+ case Firing:
+ if (modifier) {
+ // The new key is a modifier (may or may not be part of the
+ // triggering set)
+ return KeyIgnore;
+ } else {
+ // The new key was something else
+ firedKeys.insert(keyCode);
+ return KeyShortcut;
+ }
+ default:
+ break;
+ }
+
+ return KeyNormal;
+}
+
+ShortcutHandler::KeyAction ShortcutHandler::handleKeyRelease(int keyCode)
+{
+ bool firedKey;
+ unsigned pressedMask;
+ std::map<int, uint32_t>::const_iterator iter;
+ KeyAction action;
+
+ firedKey = firedKeys.count(keyCode) != 0;
+
+ firedKeys.erase(keyCode);
+ pressedKeys.erase(keyCode);
+
+ pressedMask = 0;
+ for (iter = pressedKeys.begin(); iter != pressedKeys.end(); ++iter)
+ pressedMask |= keySymToModifier(iter->second);
+
+ switch (state) {
+ case Arming:
+ action = KeyNormal;
+ break;
+ case Armed:
+ if (pressedKeys.empty())
+ action = KeyUnarm;
+ else if (pressedMask == modifierMask)
+ action = KeyNormal;
+ else {
+ action = KeyNormal;
+ state = Rearming;
+ }
+ break;
+ case Rearming:
+ if (pressedKeys.empty())
+ action = KeyUnarm;
+ else
+ action = KeyNormal;
+ break;
+ case Firing:
+ if (firedKey)
+ action = KeyShortcut;
+ else
+ action = KeyIgnore;
+ break;
+ default:
+ action = KeyNormal;
+ }
+
+ if (pressedKeys.empty())
+ state = Idle;
+
+ return action;
+}
+
+void ShortcutHandler::reset()
+{
+ state = Idle;
+ firedKeys.clear();
+ pressedKeys.clear();
+}
+
+// Keep list of valid values in sync with shortcutModifiers
+unsigned ShortcutHandler::parseModifier(const char* key)
+{
+ if (strcasecmp(key, "Ctrl") == 0)
+ return Control;
+ else if (strcasecmp(key, "Shift") == 0)
+ return Shift;
+ else if (strcasecmp(key, "Alt") == 0)
+ return Alt;
+ else if (strcasecmp(key, "Win") == 0)
+ return Super;
+ else if (strcasecmp(key, "Super") == 0)
+ return Super;
+ else if (strcasecmp(key, "Option") == 0)
+ return Alt;
+ else if (strcasecmp(key, "Cmd") == 0)
+ return Super;
+ else
+ return 0;
+}
+
+const char* ShortcutHandler::modifierString(unsigned key)
+{
+ if (key == Control)
+ return "Ctrl";
+ if (key == Shift)
+ return "Shift";
+ if (key == Alt)
+ return "Alt";
+ if (key == Super)
+ return "Super";
+
+ return "";
+}
+
+const char* ShortcutHandler::modifierPrefix(unsigned mask,
+ bool justPrefix)
+{
+ static char prefix[256];
+
+ prefix[0] = '\0';
+ if (mask & Control) {
+#ifdef __APPLE__
+ strcat(prefix, "⌃");
+#else
+ strcat(prefix, _("Ctrl"));
+ strcat(prefix, "+");
+#endif
+ }
+ if (mask & Shift) {
+#ifdef __APPLE__
+ strcat(prefix, "⇧");
+#else
+ strcat(prefix, _("Shift"));
+ strcat(prefix, "+");
+#endif
+ }
+ if (mask & Alt) {
+#ifdef __APPLE__
+ strcat(prefix, "⌥");
+#else
+ strcat(prefix, _("Alt"));
+ strcat(prefix, "+");
+#endif
+ }
+ if (mask & Super) {
+#ifdef __APPLE__
+ strcat(prefix, "⌘");
+#else
+ strcat(prefix, _("Win"));
+ strcat(prefix, "+");
+#endif
+ }
+
+ if (prefix[0] == '\0')
+ return "";
+
+ if (justPrefix) {
+#ifndef __APPLE__
+ prefix[strlen(prefix)-1] = '\0';
+#endif
+ return prefix;
+ }
+
+#ifdef __APPLE__
+ strcat(prefix, "\xc2\xa0"); // U+00A0 NO-BREAK SPACE
+#endif
+
+ return prefix;
+}
+
+unsigned ShortcutHandler::keySymToModifier(uint32_t keySym)
+{
+ switch (keySym) {
+ case XK_Control_L:
+ case XK_Control_R:
+ return Control;
+ case XK_Shift_L:
+ case XK_Shift_R:
+ return Shift;
+ case XK_Alt_L:
+ case XK_Alt_R:
+ return Alt;
+ case XK_Super_L:
+ case XK_Super_R:
+ case XK_Hyper_L:
+ case XK_Hyper_R:
+ return Super;
+ }
+
+ return 0;
+}
diff --git a/vncviewer/ShortcutHandler.h b/vncviewer/ShortcutHandler.h
new file mode 100644
index 00000000..bb6497a9
--- /dev/null
+++ b/vncviewer/ShortcutHandler.h
@@ -0,0 +1,79 @@
+/* Copyright 2021-2025 Pierre Ossman for Cendio AB
+ *
+ * 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 __SHORTCUTHANDLER__
+#define __SHORTCUTHANDLER__
+
+#include <set>
+#include <map>
+
+#include <stdint.h>
+
+class ShortcutHandler {
+public:
+ ShortcutHandler();
+
+ void setModifiers(unsigned mask);
+
+ enum KeyAction {
+ KeyNormal,
+ KeyUnarm,
+ KeyShortcut,
+ KeyIgnore,
+ };
+
+ KeyAction handleKeyPress(int keyCode, uint32_t keySym);
+ KeyAction handleKeyRelease(int keyCode);
+
+ void reset();
+
+public:
+ enum Modifier {
+ Control = (1<<0),
+ Shift = (1<<1),
+ Alt = (1<<2),
+ Super = (1<<3),
+ };
+
+ static unsigned parseModifier(const char* key);
+ static const char* modifierString(unsigned key);
+
+ static const char* modifierPrefix(unsigned mask,
+ bool justPrefix=false);
+
+private:
+ unsigned keySymToModifier(uint32_t keySym);
+
+private:
+ unsigned modifierMask;
+
+ enum State {
+ Idle,
+ Arming,
+ Armed,
+ Rearming,
+ Firing,
+ Wedged,
+ };
+ State state;
+
+ std::set<int> firedKeys;
+ std::map<int, uint32_t> pressedKeys;
+};
+
+#endif
diff --git a/vncviewer/Surface_Win32.cxx b/vncviewer/Surface_Win32.cxx
index c992dbea..c00cbc06 100644
--- a/vncviewer/Surface_Win32.cxx
+++ b/vncviewer/Surface_Win32.cxx
@@ -25,7 +25,7 @@
#include <FL/Fl_RGB_Image.H>
#include <FL/x.H>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
#include "Surface.h"
@@ -57,10 +57,10 @@ void Surface::draw(int src_x, int src_y, int dst_x, int dst_y,
dc = CreateCompatibleDC(fl_gc);
if (!dc)
- throw rdr::win32_error("CreateCompatibleDC", GetLastError());
+ throw core::win32_error("CreateCompatibleDC", GetLastError());
if (!SelectObject(dc, bitmap))
- throw rdr::win32_error("SelectObject", GetLastError());
+ throw core::win32_error("SelectObject", GetLastError());
if (!BitBlt(fl_gc, dst_x, dst_y, dst_w, dst_h,
dc, src_x, src_y, SRCCOPY)) {
@@ -70,7 +70,7 @@ void Surface::draw(int src_x, int src_y, int dst_x, int dst_y,
// with it. For now, we've only seen this error and for this function
// so only ignore this combination.
if (GetLastError() != ERROR_INVALID_HANDLE)
- throw rdr::win32_error("BitBlt", GetLastError());
+ throw core::win32_error("BitBlt", GetLastError());
}
DeleteDC(dc);
@@ -83,10 +83,10 @@ void Surface::draw(Surface* dst, int src_x, int src_y,
dstdc = CreateCompatibleDC(nullptr);
if (!dstdc)
- throw rdr::win32_error("CreateCompatibleDC", GetLastError());
+ throw core::win32_error("CreateCompatibleDC", GetLastError());
if (!SelectObject(dstdc, dst->bitmap))
- throw rdr::win32_error("SelectObject", GetLastError());
+ throw core::win32_error("SelectObject", GetLastError());
origdc = fl_gc;
fl_gc = dstdc;
@@ -113,15 +113,15 @@ void Surface::blend(Surface* dst, int src_x, int src_y,
dstdc = CreateCompatibleDC(nullptr);
if (!dstdc)
- throw rdr::win32_error("CreateCompatibleDC", GetLastError());
+ throw core::win32_error("CreateCompatibleDC", GetLastError());
srcdc = CreateCompatibleDC(nullptr);
if (!srcdc)
- throw rdr::win32_error("CreateCompatibleDC", GetLastError());
+ throw core::win32_error("CreateCompatibleDC", GetLastError());
if (!SelectObject(dstdc, dst->bitmap))
- throw rdr::win32_error("SelectObject", GetLastError());
+ throw core::win32_error("SelectObject", GetLastError());
if (!SelectObject(srcdc, bitmap))
- throw rdr::win32_error("SelectObject", GetLastError());
+ throw core::win32_error("SelectObject", GetLastError());
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
@@ -136,7 +136,7 @@ void Surface::blend(Surface* dst, int src_x, int src_y,
// with it. For now, we've only seen this error and for this function
// so only ignore this combination.
if (GetLastError() != ERROR_INVALID_HANDLE)
- throw rdr::win32_error("BitBlt", GetLastError());
+ throw core::win32_error("BitBlt", GetLastError());
}
DeleteDC(srcdc);
@@ -161,7 +161,7 @@ void Surface::alloc()
bitmap = CreateDIBSection(nullptr, (BITMAPINFO*)&bih,
DIB_RGB_COLORS, (void**)&data, nullptr, 0);
if (!bitmap)
- throw rdr::win32_error("CreateDIBSection", GetLastError());
+ throw core::win32_error("CreateDIBSection", GetLastError());
}
void Surface::dealloc()
diff --git a/vncviewer/UserDialog.cxx b/vncviewer/UserDialog.cxx
index c6cc02f7..9b7c0b93 100644
--- a/vncviewer/UserDialog.cxx
+++ b/vncviewer/UserDialog.cxx
@@ -36,8 +36,9 @@
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Pixmap.H>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+#include <rfb/CConnection.h>
#include <rfb/Exception.h>
#include <rfb/obfuscate.h>
@@ -54,8 +55,6 @@
#include "../media/insecure.xpm"
#pragma GCC diagnostic pop
-using namespace rfb;
-
static Fl_Pixmap secure_icon(secure);
static Fl_Pixmap insecure_icon(insecure);
@@ -65,8 +64,16 @@ std::string UserDialog::savedPassword;
static long ret_val = 0;
static void button_cb(Fl_Widget *widget, long val) {
+ Fl_Window* win;
+
ret_val = val;
- widget->window()->hide();
+
+ assert(widget != nullptr);
+ win = dynamic_cast<Fl_Window*>(widget);
+ if (win == nullptr)
+ win = widget->window();
+ assert(win != nullptr);
+ win->hide();
}
UserDialog::UserDialog()
@@ -120,12 +127,12 @@ void UserDialog::getUserPasswd(bool secure_, std::string* user,
fp = fopen(passwordFileName, "rb");
if (!fp)
- throw rdr::posix_error(_("Opening password file failed"), errno);
+ throw core::posix_error(_("Opening password file failed"), errno);
obfPwd.resize(fread(obfPwd.data(), 1, obfPwd.size(), fp));
fclose(fp);
- *password = deobfuscate(obfPwd.data(), obfPwd.size());
+ *password = rfb::deobfuscate(obfPwd.data(), obfPwd.size());
return;
}
@@ -141,7 +148,7 @@ void UserDialog::getUserPasswd(bool secure_, std::string* user,
int x, y;
win = new Fl_Window(410, 0, _("VNC authentication"));
- win->callback(button_cb, 0);
+ win->callback(button_cb, 1);
banner = new Fl_Box(0, 0, win->w(), 20);
banner->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE|FL_ALIGN_IMAGE_NEXT_TO_TEXT);
@@ -254,7 +261,8 @@ void UserDialog::getUserPasswd(bool secure_, std::string* user,
throw rfb::auth_cancelled();
}
-bool UserDialog::showMsgBox(MsgBoxFlags flags, const char* title, const char* text)
+bool UserDialog::showMsgBox(rfb::MsgBoxFlags flags,
+ const char* title, const char* text)
{
char buffer[1024];
@@ -267,14 +275,14 @@ bool UserDialog::showMsgBox(MsgBoxFlags flags, const char* title, const char* te
fl_message_title(title);
switch (flags & 0xf) {
- case M_OKCANCEL:
+ case rfb::M_OKCANCEL:
return fl_choice("%s", nullptr, fl_ok, fl_cancel, buffer) == 1;
- case M_YESNO:
+ case rfb::M_YESNO:
return fl_choice("%s", nullptr, fl_yes, fl_no, buffer) == 1;
- case M_OK:
+ case rfb::M_OK:
default:
- if (((flags & 0xf0) == M_ICONERROR) ||
- ((flags & 0xf0) == M_ICONWARNING))
+ if (((flags & 0xf0) == rfb::M_ICONERROR) ||
+ ((flags & 0xf0) == rfb::M_ICONWARNING))
fl_alert("%s", buffer);
else
fl_message("%s", buffer);
diff --git a/vncviewer/UserDialog.h b/vncviewer/UserDialog.h
index ddafbc3c..22799fb9 100644
--- a/vncviewer/UserDialog.h
+++ b/vncviewer/UserDialog.h
@@ -19,8 +19,6 @@
#ifndef __USERDIALOG_H__
#define __USERDIALOG_H__
-#include <rfb/CConnection.h>
-
class UserDialog
{
public:
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 8c3b5dc5..03e6fb09 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011-2021 Pierre Ossman for Cendio AB
+ * Copyright 2011-2025 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,17 +25,27 @@
#include <stdio.h>
#include <string.h>
+#include <stdexcept>
+
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb/CMsgWriter.h>
-#include <rfb/LogWriter.h>
+#include <rfb/Cursor.h>
+#include <rfb/KeysymStr.h>
#include <rfb/ledStates.h>
-#include <rfb/util.h>
// FLTK can pull in the X11 headers on some systems
#ifndef XK_VoidSymbol
+#define XK_LATIN1
#define XK_MISCELLANY
#include <rfb/keysymdef.h>
#endif
+#ifndef NoSymbol
+#define NoSymbol 0
+#endif
+
#include "fltk/layout.h"
#include "fltk/util.h"
#include "Viewport.h"
@@ -44,7 +54,6 @@
#include "DesktopWindow.h"
#include "i18n.h"
#include "parameters.h"
-#include "menukey.h"
#include "vncviewer.h"
#include "PlatformPixelBuffer.h"
@@ -68,14 +77,12 @@
#include "cocoa.h"
#endif
-using namespace rfb;
-
-static rfb::LogWriter vlog("Viewport");
+static core::LogWriter vlog("Viewport");
// Menu constants
enum { ID_DISCONNECT, ID_FULLSCREEN, ID_MINIMIZE, ID_RESIZE,
- ID_CTRL, ID_ALT, ID_MENUKEY, ID_CTRLALTDEL,
+ ID_CTRL, ID_ALT, ID_CTRLALTDEL,
ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT };
// Used for fake key presses from the menu
@@ -86,12 +93,13 @@ static const int FAKE_DEL_KEY_CODE = 0x10003;
// Used for fake key presses for lock key sync
static const int FAKE_KEY_CODE = 0xffff;
-Viewport::Viewport(int w, int h, const rfb::PixelFormat& /*serverPF*/, CConn* cc_)
+Viewport::Viewport(int w, int h, CConn* cc_)
: Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(nullptr),
lastPointerPos(0, 0), lastButtonMask(0),
- keyboard(nullptr),
+ keyboard(nullptr), shortcutBypass(false), shortcutActive(false),
firstLEDState(true), pendingClientClipboard(false),
- menuCtrlKey(false), menuAltKey(false), cursor(nullptr)
+ menuCtrlKey(false), menuAltKey(false), cursor(nullptr),
+ cursorIsBlank(false)
{
#if defined(WIN32)
keyboard = new KeyboardWin32(this);
@@ -106,6 +114,12 @@ Viewport::Viewport(int w, int h, const rfb::PixelFormat& /*serverPF*/, CConn* cc
// We need to intercept keyboard events early
Fl::add_system_handler(handleSystemEvent, this);
+ // FIXME: We should only disable this whilst we have keyboard focus,
+ // but we also need to keep it disabled when we lose focus to
+ // any layout selector so it can properly filter out the
+ // layouts we don't support
+ Fl::disable_im();
+
frameBuffer = new PlatformPixelBuffer(w, h);
assert(frameBuffer);
cc->setFramebuffer(frameBuffer);
@@ -121,12 +135,16 @@ Viewport::Viewport(int w, int h, const rfb::PixelFormat& /*serverPF*/, CConn* cc
// reparenting to the current window works for most cases.
window()->add(contextMenu);
- setMenuKey();
+ unsigned modifierMask = 0;
+ for (core::EnumListEntry key : shortcutModifiers)
+ modifierMask |= ShortcutHandler::parseModifier(key.getValueStr().c_str());
+
+ shortcutHandler.setModifiers(modifierMask);
OptionsDialog::addCallback(handleOptions, this);
// Make sure we have an initial blank cursor set
- setCursor(0, 0, rfb::Point(0, 0), nullptr);
+ setCursor();
}
@@ -149,6 +167,7 @@ Viewport::~Viewport()
}
delete keyboard;
+ Fl::enable_im();
// FLTK automatically deletes all child widgets, so we shouldn't touch
// them ourselves here
@@ -166,7 +185,7 @@ const rfb::PixelFormat &Viewport::getPreferredPF()
void Viewport::updateWindow()
{
- Rect r;
+ core::Rect r;
r = frameBuffer->getDamage();
damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height());
@@ -182,9 +201,12 @@ static const char * dotcursor_xpm[] = {
" ... ",
" "};
-void Viewport::setCursor(int width, int height, const Point& hotspot,
- const uint8_t* data)
+void Viewport::setCursor()
{
+ int width, height;
+ core::Point hotspot;
+ const uint8_t* data;
+
int i;
if (cursor) {
@@ -193,10 +215,20 @@ void Viewport::setCursor(int width, int height, const Point& hotspot,
delete cursor;
}
+ width = cc->server.cursor().width();
+ height = cc->server.cursor().height();
+ hotspot = cc->server.cursor().hotspot();
+ data = cc->server.cursor().getBuffer();
+
for (i = 0; i < width*height; i++)
if (data[i*4 + 3] != 0) break;
- if ((i == width*height) && dotWhenNoCursor) {
+ cursorIsBlank = i == width*height;
+
+ if (cursorIsBlank && alwaysCursor) {
+ // This is the default in case the local cursor should be displayed yet cursorType is invalid.
+ // Since the cursor variable isn't used if the cursorType is system, we can do this without checking the current
+ // type which helps handle changing the type while the viewer is running.
vlog.debug("Cursor is empty, using dot");
Fl_Pixmap pxm(dotcursor_xpm);
@@ -217,16 +249,36 @@ void Viewport::setCursor(int width, int height, const Point& hotspot,
}
if (Fl::belowmouse() == this)
+ showCursor();
+}
+
+void Viewport::showCursor()
+{
+ if (viewOnly) {
+ window()->cursor(FL_CURSOR_DEFAULT);
+ return;
+ }
+
+ if (cursorIsBlank && alwaysCursor && (cursorType == "system")) {
+ window()->cursor(FL_CURSOR_DEFAULT);
+ } else {
window()->cursor(cursor, cursorHotspot.x, cursorHotspot.y);
+ }
}
void Viewport::handleClipboardRequest()
{
+ if (viewOnly)
+ return;
+
Fl::paste(*this, clipboardSource);
}
void Viewport::handleClipboardAnnounce(bool available)
{
+ if (viewOnly)
+ return;
+
if (!acceptClipboard)
return;
@@ -281,6 +333,9 @@ void Viewport::setLEDState(unsigned int ledState)
return;
}
+ if (viewOnly)
+ return;
+
if (!hasFocus())
return;
@@ -291,30 +346,36 @@ void Viewport::pushLEDState()
{
unsigned int ledState;
+ if (viewOnly)
+ return;
+
// Server support?
- if (cc->server.ledState() == ledUnknown)
+ if (cc->server.ledState() == rfb::ledUnknown)
return;
ledState = keyboard->getLEDState();
- if (ledState == ledUnknown)
+ if (ledState == rfb::ledUnknown)
return;
#if defined(__APPLE__)
// No support for Scroll Lock //
- ledState |= (cc->server.ledState() & ledScrollLock);
+ ledState |= (cc->server.ledState() & rfb::ledScrollLock);
#endif
- if ((ledState & ledCapsLock) != (cc->server.ledState() & ledCapsLock)) {
+ if ((ledState & rfb::ledCapsLock) !=
+ (cc->server.ledState() & rfb::ledCapsLock)) {
vlog.debug("Inserting fake CapsLock to get in sync with server");
handleKeyPress(FAKE_KEY_CODE, 0x3a, XK_Caps_Lock);
handleKeyRelease(FAKE_KEY_CODE);
}
- if ((ledState & ledNumLock) != (cc->server.ledState() & ledNumLock)) {
+ if ((ledState & rfb::ledNumLock) !=
+ (cc->server.ledState() & rfb::ledNumLock)) {
vlog.debug("Inserting fake NumLock to get in sync with server");
handleKeyPress(FAKE_KEY_CODE, 0x45, XK_Num_Lock);
handleKeyRelease(FAKE_KEY_CODE);
}
- if ((ledState & ledScrollLock) != (cc->server.ledState() & ledScrollLock)) {
+ if ((ledState & rfb::ledScrollLock) !=
+ (cc->server.ledState() & rfb::ledScrollLock)) {
vlog.debug("Inserting fake ScrollLock to get in sync with server");
handleKeyPress(FAKE_KEY_CODE, 0x46, XK_Scroll_Lock);
handleKeyRelease(FAKE_KEY_CODE);
@@ -370,12 +431,20 @@ int Viewport::handle(int event)
switch (event) {
case FL_PASTE:
- if (!isValidUTF8(Fl::event_text(), Fl::event_length())) {
+ if (!core::isValidUTF8(Fl::event_text(), Fl::event_length())) {
vlog.error("Invalid UTF-8 sequence in system clipboard");
+ // Reset the state as if we don't have any clipboard data at all
+ this->pendingClientClipboard = false;
+ try {
+ this->cc->announceClipboard(false);
+ } catch (std::exception& e) {
+ vlog.error("%s", e.what());
+ abort_connection_with_unexpected_error(e);
+ }
return 1;
}
- filtered = convertLF(Fl::event_text(), Fl::event_length());
+ filtered = core::convertLF(Fl::event_text(), Fl::event_length());
vlog.debug("Sending clipboard data (%d bytes)", (int)filtered.size());
@@ -389,14 +458,14 @@ int Viewport::handle(int event)
return 1;
case FL_ENTER:
- window()->cursor(cursor, cursorHotspot.x, cursorHotspot.y);
+ showCursor();
// Yes, we would like some pointer events please!
return 1;
case FL_LEAVE:
window()->cursor(FL_CURSOR_DEFAULT);
// We want a last move event to help trigger edge stuff
- handlePointerEvent(Point(Fl::event_x() - x(), Fl::event_y() - y()), 0);
+ handlePointerEvent({Fl::event_x() - x(), Fl::event_y() - y()}, 0);
return 1;
case FL_PUSH:
@@ -439,16 +508,14 @@ int Viewport::handle(int event)
// A quick press of the wheel "button", followed by a immediate
// release below
- handlePointerEvent(Point(Fl::event_x() - x(), Fl::event_y() - y()),
+ handlePointerEvent({Fl::event_x() - x(), Fl::event_y() - y()},
buttonMask | wheelMask);
}
- handlePointerEvent(Point(Fl::event_x() - x(), Fl::event_y() - y()), buttonMask);
+ handlePointerEvent({Fl::event_x() - x(), Fl::event_y() - y()}, buttonMask);
return 1;
case FL_FOCUS:
- Fl::disable_im();
-
flushPendingClipboard();
// We may have gotten our lock keys out of sync with the server
@@ -467,8 +534,6 @@ int Viewport::handle(int event)
case FL_UNFOCUS:
// We won't get more key events, so reset our knowledge about keys
resetKeyboard();
-
- Fl::enable_im();
return 1;
case FL_KEYDOWN:
@@ -480,7 +545,8 @@ int Viewport::handle(int event)
return Fl_Widget::handle(event);
}
-void Viewport::sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask)
+void Viewport::sendPointerEvent(const core::Point& pos,
+ uint16_t buttonMask)
{
if (viewOnly)
return;
@@ -518,6 +584,9 @@ void Viewport::handleClipboardChange(int source, void *data)
assert(self);
+ if (viewOnly)
+ return;
+
if (!sendClipboard)
return;
@@ -530,7 +599,12 @@ void Viewport::handleClipboardChange(int source, void *data)
vlog.debug("Got non-plain text in local clipboard, ignoring.");
// Reset the state as if we don't have any clipboard data at all
self->pendingClientClipboard = false;
- self->cc->announceClipboard(false);
+ try {
+ self->cc->announceClipboard(false);
+ } catch (std::exception& e) {
+ vlog.error("%s", e.what());
+ abort_connection_with_unexpected_error(e);
+ }
return;
}
@@ -540,7 +614,12 @@ void Viewport::handleClipboardChange(int source, void *data)
vlog.debug("Local clipboard changed whilst not focused, will notify server later");
self->pendingClientClipboard = true;
// Clear any older client clipboard from the server
- self->cc->announceClipboard(false);
+ try {
+ self->cc->announceClipboard(false);
+ } catch (std::exception& e) {
+ vlog.error("%s", e.what());
+ abort_connection_with_unexpected_error(e);
+ }
return;
}
@@ -570,7 +649,8 @@ void Viewport::flushPendingClipboard()
}
-void Viewport::handlePointerEvent(const rfb::Point& pos, uint16_t buttonMask)
+void Viewport::handlePointerEvent(const core::Point& pos,
+ uint16_t buttonMask)
{
filterPointerEvent(pos, buttonMask);
}
@@ -602,23 +682,122 @@ void Viewport::resetKeyboard()
}
keyboard->reset();
+
+ shortcutHandler.reset();
+ shortcutBypass = false;
+ shortcutActive = false;
+ pressedKeys.clear();
}
void Viewport::handleKeyPress(int systemKeyCode,
uint32_t keyCode, uint32_t keySym)
{
- static bool menuRecursion = false;
-
- // Prevent recursion if the menu wants to send its own
- // activation key.
- if (menuKeySym && (keySym == menuKeySym) && !menuRecursion) {
- menuRecursion = true;
- popupContextMenu();
- menuRecursion = false;
- return;
+ pressedKeys.insert(systemKeyCode);
+
+ // Possible keyboard shortcut?
+
+ if (!shortcutBypass) {
+ ShortcutHandler::KeyAction action;
+
+ action = shortcutHandler.handleKeyPress(systemKeyCode, keySym);
+
+ if (action == ShortcutHandler::KeyIgnore) {
+ vlog.debug("Ignoring key press %d => 0x%02x / XK_%s (0x%04x)",
+ systemKeyCode, keyCode, KeySymName(keySym), keySym);
+ return;
+ }
+
+ if (action == ShortcutHandler::KeyShortcut) {
+ std::list<uint32_t> keySyms;
+ std::list<uint32_t>::const_iterator iter;
+
+ // Modifiers can change the KeySym that's been resolved, so we
+ // need to check all possible KeySyms for this physical key, not
+ // just the current one
+ keySyms = keyboard->translateToKeySyms(systemKeyCode);
+
+ // Then we pick the one that matches first
+ keySym = NoSymbol;
+ for (iter = keySyms.begin(); iter != keySyms.end(); iter++) {
+ bool found;
+
+ switch (*iter) {
+ case XK_space:
+ case XK_G:
+ case XK_g:
+ case XK_M:
+ case XK_m:
+ case XK_KP_Enter:
+ case XK_Return:
+ keySym = *iter;
+ found = true;
+ break;
+ default:
+ found = false;
+ break;
+ }
+
+ if (found)
+ break;
+ }
+
+ vlog.debug("Detected shortcut %d => 0x%02x / XK_%s (0x%04x)",
+ systemKeyCode, keyCode, KeySymName(keySym), keySym);
+
+ // Special case which we need to handle first
+ if (keySym == XK_space) {
+ // If another shortcut has already fired, then we're too late as
+ // we've already released the modifier keys
+ if (!shortcutActive) {
+ shortcutBypass = true;
+ shortcutHandler.reset();
+ }
+ return;
+ }
+
+ shortcutActive = true;
+
+ // The remote session won't see any more keys, so release the ones
+ // currently down
+ try {
+ cc->releaseAllKeys();
+ } catch (std::exception& e) {
+ vlog.error("%s", e.what());
+ abort_connection(_("An unexpected error occurred when communicating "
+ "with the server:\n\n%s"), e.what());
+ }
+
+ switch (keySym) {
+ case XK_G:
+ case XK_g:
+ ((DesktopWindow*)window())->grabKeyboard();
+ break;
+ case XK_M:
+ case XK_m:
+ popupContextMenu();
+ break;
+ case XK_KP_Enter:
+ case XK_Return:
+ if (window()->fullscreen_active()) {
+ fullScreen.setParam(false);
+ window()->fullscreen_off();
+ } else {
+ fullScreen.setParam(true);
+ ((DesktopWindow*)window())->fullscreen_on();
+ }
+ break;
+ default:
+ // Unknown/Unused keyboard shortcut
+ break;
+ }
+
+ return;
+ }
}
+ // Normal key, so send to server...
+
if (viewOnly)
return;
@@ -633,6 +812,54 @@ void Viewport::handleKeyPress(int systemKeyCode,
void Viewport::handleKeyRelease(int systemKeyCode)
{
+ pressedKeys.erase(systemKeyCode);
+
+ if (pressedKeys.empty())
+ shortcutActive = false;
+
+ // Possible keyboard shortcut?
+
+ if (!shortcutBypass) {
+ ShortcutHandler::KeyAction action;
+
+ action = shortcutHandler.handleKeyRelease(systemKeyCode);
+
+ if (action == ShortcutHandler::KeyIgnore) {
+ vlog.debug("Ignoring key release %d", systemKeyCode);
+ return;
+ }
+
+ if (action == ShortcutHandler::KeyShortcut) {
+ vlog.debug("Shortcut release %d", systemKeyCode);
+ return;
+ }
+
+ if (action == ShortcutHandler::KeyUnarm) {
+ DesktopWindow *win;
+
+ vlog.debug("Detected shortcut to release grab");
+
+ try {
+ cc->releaseAllKeys();
+ } catch (std::exception& e) {
+ vlog.error("%s", e.what());
+ abort_connection(_("An unexpected error occurred when communicating "
+ "with the server:\n\n%s"), e.what());
+ }
+
+ win = dynamic_cast<DesktopWindow*>(window());
+ assert(win);
+ win->ungrabKeyboard();
+
+ return;
+ }
+ }
+
+ if (pressedKeys.empty())
+ shortcutBypass = false;
+
+ // Normal key, so send to server...
+
if (viewOnly)
return;
@@ -655,13 +882,11 @@ int Viewport::handleSystemEvent(void *event, void *data)
if (!self->hasFocus())
return 0;
-#ifdef __APPLE__
// Special event that means we temporarily lost some input
- if (KeyboardMacOS::isKeyboardSync(event)) {
+ if (self->keyboard->isKeyboardReset(event)) {
self->resetKeyboard();
return 1;
}
-#endif
consumed = self->keyboard->handleEvent(event);
if (consumed)
@@ -697,15 +922,6 @@ void Viewport::initContextMenu()
0, nullptr, (void*)ID_ALT,
FL_MENU_TOGGLE | (menuAltKey?FL_MENU_VALUE:0));
- if (menuKeySym) {
- char sendMenuKey[64];
- snprintf(sendMenuKey, 64, p_("ContextMenu|", "Send %s"), (const char *)menuKey);
- fltk_menu_add(contextMenu, sendMenuKey, 0, nullptr, (void*)ID_MENUKEY, 0);
- fltk_menu_add(contextMenu, "Secret shortcut menu key",
- menuKeyFLTK, nullptr,
- (void*)ID_MENUKEY, FL_MENU_INVISIBLE);
- }
-
fltk_menu_add(contextMenu, p_("ContextMenu|", "Send Ctrl-Alt-&Del"),
0, nullptr, (void*)ID_CTRLALTDEL, FL_MENU_DIVIDER);
@@ -716,7 +932,7 @@ void Viewport::initContextMenu()
0, nullptr, (void*)ID_OPTIONS, 0);
fltk_menu_add(contextMenu, p_("ContextMenu|", "Connection &info..."),
0, nullptr, (void*)ID_INFO, 0);
- fltk_menu_add(contextMenu, p_("ContextMenu|", "About &TigerVNC viewer..."),
+ fltk_menu_add(contextMenu, p_("ContextMenu|", "About &TigerVNC..."),
0, nullptr, (void*)ID_ABOUT, 0);
}
#pragma GCC diagnostic pop
@@ -739,15 +955,15 @@ void Viewport::popupContextMenu()
window()->cursor(FL_CURSOR_DEFAULT);
// FLTK also doesn't switch focus properly for menus
- handle(FL_UNFOCUS);
+ Fl::handle(FL_UNFOCUS, window());
m = contextMenu->popup();
- handle(FL_FOCUS);
+ Fl::handle(FL_FOCUS, window());
// Back to our proper mouse pointer.
- if (Fl::belowmouse())
- window()->cursor(cursor, cursorHotspot.x, cursorHotspot.y);
+ if (Fl::belowmouse() == this)
+ showCursor();
if (m == nullptr)
return;
@@ -790,10 +1006,6 @@ void Viewport::popupContextMenu()
handleKeyRelease(FAKE_ALT_KEY_CODE);
menuAltKey = !menuAltKey;
break;
- case ID_MENUKEY:
- handleKeyPress(FAKE_KEY_CODE, menuKeyCode, menuKeySym);
- handleKeyRelease(FAKE_KEY_CODE);
- break;
case ID_CTRLALTDEL:
handleKeyPress(FAKE_CTRL_KEY_CODE, 0x1d, XK_Control_L);
handleKeyPress(FAKE_ALT_KEY_CODE, 0x38, XK_Alt_L);
@@ -822,17 +1034,17 @@ void Viewport::popupContextMenu()
}
}
-
-void Viewport::setMenuKey()
-{
- getMenuKey(&menuKeyFLTK, &menuKeyCode, &menuKeySym);
-}
-
-
void Viewport::handleOptions(void *data)
{
Viewport *self = (Viewport*)data;
+ unsigned modifierMask;
+
+ modifierMask = 0;
+ for (core::EnumListEntry key : shortcutModifiers)
+ modifierMask |= ShortcutHandler::parseModifier(key.getValueStr().c_str());
+
+ self->shortcutHandler.setModifiers(modifierMask);
- self->setMenuKey();
- // FIXME: Need to recheck cursor for dotWhenNoCursor
+ if (Fl::belowmouse() == self)
+ self->showCursor();
}
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index 41696d9d..8e3f473e 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -20,12 +20,13 @@
#ifndef __VIEWPORT_H__
#define __VIEWPORT_H__
-#include <rfb/Rect.h>
+#include <core/Rect.h>
#include <FL/Fl_Widget.H>
#include "EmulateMB.h"
#include "Keyboard.h"
+#include "ShortcutHandler.h"
class Fl_Menu_Button;
class Fl_RGB_Image;
@@ -39,7 +40,7 @@ class Viewport : public Fl_Widget, protected EmulateMB,
protected KeyboardHandler {
public:
- Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_);
+ Viewport(int w, int h, CConn* cc_);
~Viewport();
// Most efficient format (from Viewport's point of view)
@@ -49,8 +50,7 @@ public:
void updateWindow();
// New image for the locally rendered cursor
- void setCursor(int width, int height, const rfb::Point& hotspot,
- const uint8_t* data);
+ void setCursor();
// Change client LED state
void setLEDState(unsigned int state);
@@ -71,16 +71,20 @@ public:
int handle(int event) override;
protected:
- void sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask) override;
+ void sendPointerEvent(const core::Point& pos,
+ uint16_t buttonMask) override;
private:
bool hasFocus();
+ // Show the currently set (or system) cursor
+ void showCursor();
+
static void handleClipboardChange(int source, void *data);
void flushPendingClipboard();
- void handlePointerEvent(const rfb::Point& pos, uint16_t buttonMask);
+ void handlePointerEvent(const core::Point& pos, uint16_t buttonMask);
static void handlePointerTimeout(void *data);
void resetKeyboard();
@@ -96,8 +100,6 @@ private:
void initContextMenu();
void popupContextMenu();
- void setMenuKey();
-
static void handleOptions(void *data);
private:
@@ -105,10 +107,14 @@ private:
PlatformPixelBuffer* frameBuffer;
- rfb::Point lastPointerPos;
+ core::Point lastPointerPos;
uint16_t lastButtonMask;
Keyboard* keyboard;
+ ShortcutHandler shortcutHandler;
+ bool shortcutBypass;
+ bool shortcutActive;
+ std::set<int> pressedKeys;
bool firstLEDState;
@@ -116,15 +122,14 @@ private:
int clipboardSource;
- uint32_t menuKeySym;
- int menuKeyCode, menuKeyFLTK;
Fl_Menu_Button *contextMenu;
bool menuCtrlKey;
bool menuAltKey;
Fl_RGB_Image *cursor;
- rfb::Point cursorHotspot;
+ core::Point cursorHotspot;
+ bool cursorIsBlank;
};
#endif
diff --git a/vncviewer/Win32TouchHandler.cxx b/vncviewer/Win32TouchHandler.cxx
index 2be27ede..2777cca2 100644
--- a/vncviewer/Win32TouchHandler.cxx
+++ b/vncviewer/Win32TouchHandler.cxx
@@ -24,14 +24,15 @@
#include <stdexcept>
+#include <core/LogWriter.h>
+
#define XK_MISCELLANY
#include <rfb/keysymdef.h>
-#include <rfb/LogWriter.h>
#include "i18n.h"
#include "Win32TouchHandler.h"
-static rfb::LogWriter vlog("Win32TouchHandler");
+static core::LogWriter vlog("Win32TouchHandler");
static const DWORD MOUSEMOVE_FLAGS = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE |
MOUSEEVENTF_VIRTUALDESK;
@@ -309,6 +310,9 @@ void Win32TouchHandler::fakeButtonEvent(bool press, int button,
LPARAM lParam;
int delta;
+ // Needed to silence false positive that this is used uninitialized
+ delta = 0;
+
switch (button) {
case 1: // left mousebutton
diff --git a/vncviewer/XInputTouchHandler.cxx b/vncviewer/XInputTouchHandler.cxx
index 2b2e02c6..545a097e 100644
--- a/vncviewer/XInputTouchHandler.cxx
+++ b/vncviewer/XInputTouchHandler.cxx
@@ -30,16 +30,17 @@
#include <FL/x.H>
+#include <core/LogWriter.h>
+
#ifndef XK_MISCELLANY
#define XK_MISCELLANY
#include <rfb/keysymdef.h>
#endif
-#include <rfb/LogWriter.h>
#include "i18n.h"
#include "XInputTouchHandler.h"
-static rfb::LogWriter vlog("XInputTouchHandler");
+static core::LogWriter vlog("XInputTouchHandler");
static bool grabbed = false;
diff --git a/vncviewer/cocoa.h b/vncviewer/cocoa.h
index 64acefbf..09db9a45 100644
--- a/vncviewer/cocoa.h
+++ b/vncviewer/cocoa.h
@@ -1,4 +1,4 @@
-/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2011-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,11 +21,12 @@
class Fl_Window;
-int cocoa_get_level(Fl_Window *win);
-void cocoa_set_level(Fl_Window *win, int level);
+void cocoa_prevent_native_fullscreen(Fl_Window *win);
-int cocoa_capture_displays(Fl_Window *win);
-void cocoa_release_displays(Fl_Window *win);
+bool cocoa_is_trusted(bool prompt=false);
+
+bool cocoa_tap_keyboard();
+void cocoa_untap_keyboard();
typedef struct CGColorSpace *CGColorSpaceRef;
diff --git a/vncviewer/cocoa.mm b/vncviewer/cocoa.mm
index 1d63b750..4d9908dd 100644
--- a/vncviewer/cocoa.mm
+++ b/vncviewer/cocoa.mm
@@ -1,4 +1,4 @@
-/* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+/* Copyright 2011-2025 Pierre Ossman <ossman@cendio.se> for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,108 +20,207 @@
#include <config.h>
#endif
-#include <FL/Fl.H>
+#include <assert.h>
+#include <dlfcn.h>
+
#include <FL/Fl_Window.H>
#include <FL/x.H>
#import <Cocoa/Cocoa.h>
+#import <ApplicationServices/ApplicationServices.h>
-#include <rfb/Rect.h>
+#include "cocoa.h"
-static bool captured = false;
+static CFMachPortRef event_tap;
+static CFRunLoopSourceRef tap_source;
-int cocoa_get_level(Fl_Window *win)
+void cocoa_prevent_native_fullscreen(Fl_Window *win)
{
NSWindow *nsw;
nsw = (NSWindow*)fl_xid(win);
- return [nsw level];
+ assert(nsw);
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 100700
+ nsw.collectionBehavior |= NSWindowCollectionBehaviorFullScreenNone;
+#endif
}
-void cocoa_set_level(Fl_Window *win, int level)
+bool cocoa_is_trusted(bool prompt)
{
- NSWindow *nsw;
- nsw = (NSWindow*)fl_xid(win);
- [nsw setLevel:level];
-}
+ CFStringRef keys[1];
+ CFBooleanRef values[1];
+ CFDictionaryRef options;
-int cocoa_capture_displays(Fl_Window *win)
-{
- NSWindow *nsw;
+ Boolean trusted;
- nsw = (NSWindow*)fl_xid(win);
+#if !defined(MAC_OS_X_VERSION_10_9) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+ // FIXME: Raise system requirements so this isn't needed
+ void *lib;
+ typedef Boolean (*AXIsProcessTrustedWithOptionsRef)(CFDictionaryRef);
+ AXIsProcessTrustedWithOptionsRef AXIsProcessTrustedWithOptions;
+ CFStringRef kAXTrustedCheckOptionPrompt;
- CGDisplayCount count;
- CGDirectDisplayID displays[16];
+ lib = dlopen(nullptr, 0);
+ if (lib == nullptr)
+ return false;
- int sx, sy, sw, sh;
- rfb::Rect windows_rect, screen_rect;
+ AXIsProcessTrustedWithOptions =
+ (AXIsProcessTrustedWithOptionsRef)dlsym(lib, "AXIsProcessTrustedWithOptions");
- windows_rect.setXYWH(win->x(), win->y(), win->w(), win->h());
+ dlclose(lib);
- if (CGGetActiveDisplayList(16, displays, &count) != kCGErrorSuccess)
- return 1;
+ if (AXIsProcessTrustedWithOptions == nullptr)
+ return false;
- if (count != (unsigned)Fl::screen_count())
- return 1;
+ kAXTrustedCheckOptionPrompt = CFSTR("AXTrustedCheckOptionPrompt");
+#endif
- for (int i = 0; i < Fl::screen_count(); i++) {
- Fl::screen_xywh(sx, sy, sw, sh, i);
+ keys[0] = kAXTrustedCheckOptionPrompt;
+ values[0] = prompt ? kCFBooleanTrue : kCFBooleanFalse;
+ options = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void**)keys,
+ (const void**)values, 1,
+ &kCFCopyStringDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (options == nullptr)
+ return false;
+
+ trusted = AXIsProcessTrustedWithOptions(options);
+ CFRelease(options);
+
+ // For some reason, the authentication popups isn't set as active and
+ // is hidden behind our window(s). Try to find it and manually switch
+ // to it.
+ if (!trusted && prompt) {
+ long long pid;
+
+ pid = 0;
+ for (int attempt = 0; attempt < 5; attempt++) {
+ CFArrayRef windowList;
+
+ windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly,
+ kCGNullWindowID);
+ for (int i = 0; i < CFArrayGetCount(windowList); i++) {
+ CFDictionaryRef window;
+ CFStringRef owner;
+ CFNumberRef cfpid;
+
+ window = (CFDictionaryRef)CFArrayGetValueAtIndex(windowList, i);
+ assert(window != nullptr);
+ owner = (CFStringRef)CFDictionaryGetValue(window,
+ kCGWindowOwnerName);
+ if (owner == nullptr)
+ continue;
+
+ // FIXME: Unknown how stable this identifier is
+ CFStringRef authOwner = CFSTR("universalAccessAuthWarn");
+ if (CFStringCompare(owner, authOwner, 0) != kCFCompareEqualTo)
+ continue;
+
+ cfpid = (CFNumberRef)CFDictionaryGetValue(window,
+ kCGWindowOwnerPID);
+ if (cfpid == nullptr)
+ continue;
+
+ CFNumberGetValue(cfpid, kCFNumberLongLongType, &pid);
+ break;
+ }
+
+ CFRelease(windowList);
+
+ if (pid != 0)
+ break;
+
+ usleep(100000);
+ }
- screen_rect.setXYWH(sx, sy, sw, sh);
- if (screen_rect.enclosed_by(windows_rect)) {
- if (CGDisplayCapture(displays[i]) != kCGErrorSuccess)
- return 1;
+ if (pid != 0) {
+ NSRunningApplication* authApp;
- } else {
- // A display might have been captured with the previous
- // monitor selection. In that case we don't want to keep
- // it when its no longer inside the window_rect.
- CGDisplayRelease(displays[i]);
+ authApp = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
+ if (authApp != nil) {
+ // Seems to work fine even without yieldActivationToApplication,
+ // or NSApplicationActivateIgnoringOtherApps
+ [authApp activateWithOptions:0];
+ }
}
}
- captured = true;
+ return trusted;
+}
- if ([nsw level] == CGShieldingWindowLevel())
- return 0;
+static CGEventRef cocoa_event_tap(CGEventTapProxy /*proxy*/,
+ CGEventType type, CGEventRef event,
+ void* /*refcon*/)
+{
+ ProcessSerialNumber psn;
+ OSErr err;
+
+ // We should just be getting these events, but just in case
+ if ((type != kCGEventKeyDown) &&
+ (type != kCGEventKeyUp) &&
+ (type != kCGEventFlagsChanged))
+ return event;
+
+ // Redirect the event to us, no matter the original target
+ // (note that this will loop if kCGAnnotatedSessionEventTap is used)
+ err = GetCurrentProcess(&psn);
+ if (err != noErr)
+ return event;
+
+ // FIXME: CGEventPostToPid() in macOS 10.11+
+ CGEventPostToPSN(&psn, event);
+
+ // Stop delivery to original target
+ return nullptr;
+}
- [nsw setLevel:CGShieldingWindowLevel()];
+bool cocoa_tap_keyboard()
+{
+ CGEventMask mask;
- // We're not getting put in front of the shielding window in many
- // cases on macOS 13, despite setLevel: being documented as also
- // pushing the window to the front. So let's explicitly move it.
- [nsw orderFront:nsw];
+ if (event_tap != nullptr)
+ return true;
- return 0;
-}
+ if (!cocoa_is_trusted())
+ return false;
-void cocoa_release_displays(Fl_Window *win)
-{
- NSWindow *nsw;
- int newlevel;
+ mask = CGEventMaskBit(kCGEventKeyDown) |
+ CGEventMaskBit(kCGEventKeyUp) |
+ CGEventMaskBit(kCGEventFlagsChanged);
- if (captured)
- CGReleaseAllDisplays();
+ // Cannot be kCGAnnotatedSessionEventTap as window manager intercepts
+ // before that (e.g. Ctrl+Up)
+ event_tap = CGEventTapCreate(kCGSessionEventTap,
+ kCGHeadInsertEventTap,
+ kCGEventTapOptionDefault,
+ mask, cocoa_event_tap, nullptr);
+ if (event_tap == nullptr)
+ return false;
- captured = false;
+ tap_source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
+ event_tap, 0);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), tap_source,
+ kCFRunLoopCommonModes);
- nsw = (NSWindow*)fl_xid(win);
+ return true;
+}
- // Someone else has already changed the level of this window
- if ([nsw level] != CGShieldingWindowLevel())
+void cocoa_untap_keyboard()
+{
+ if (event_tap == nullptr)
return;
- // FIXME: Store the previous level somewhere so we don't have to hard
- // code a level here.
- if (win->fullscreen_active() && win->contains(Fl::focus()))
- newlevel = NSStatusWindowLevel;
- else
- newlevel = NSNormalWindowLevel;
-
- // Only change if different as the level change also moves the window
- // to the top of that level.
- if ([nsw level] != newlevel)
- [nsw setLevel:newlevel];
+ // Need to explicitly disable the tap first, or we get a short delay
+ // where all events are dropped
+ CGEventTapEnable(event_tap, false);
+
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), tap_source,
+ kCFRunLoopCommonModes);
+ CFRelease(tap_source);
+ tap_source = nullptr;
+
+ CFRelease(event_tap);
+ event_tap = nullptr;
}
CGColorSpaceRef cocoa_win_color_space(Fl_Window *win)
@@ -130,6 +229,7 @@ CGColorSpaceRef cocoa_win_color_space(Fl_Window *win)
NSColorSpace *nscs;
nsw = (NSWindow*)fl_xid(win);
+ assert(nsw);
nscs = [nsw colorSpace];
if (nscs == nil) {
@@ -150,6 +250,7 @@ bool cocoa_win_is_zoomed(Fl_Window *win)
{
NSWindow *nsw;
nsw = (NSWindow*)fl_xid(win);
+ assert(nsw);
return [nsw isZoomed];
}
@@ -157,5 +258,6 @@ void cocoa_win_zoom(Fl_Window *win)
{
NSWindow *nsw;
nsw = (NSWindow*)fl_xid(win);
+ assert(nsw);
[nsw zoom:nsw];
}
diff --git a/vncviewer/fltk/Fl_Navigation.cxx b/vncviewer/fltk/Fl_Navigation.cxx
index d3117aae..be258ce5 100644
--- a/vncviewer/fltk/Fl_Navigation.cxx
+++ b/vncviewer/fltk/Fl_Navigation.cxx
@@ -31,6 +31,7 @@
#include <FL/Fl_Button.H>
#include <FL/Fl_Scroll.H>
+#include <FL/fl_draw.H>
#include "Fl_Navigation.h"
@@ -154,14 +155,21 @@ void Fl_Navigation::update_labels()
for (i = 0;i < pages->children();i++) {
Fl_Widget *page;
Fl_Button *btn;
+ int w, h;
page = pages->child(i);
+ w = labels->w() - page->labelsize() * 2;
+ fl_font(page->labelfont(), page->labelsize());
+ fl_measure(page->label(), w, h);
+ h += page->labelsize() * 2;
+
btn = new Fl_Button(labels->x(), labels->y() + offset,
- labels->w(), page->labelsize() * 3,
+ labels->w(), h,
page->label());
btn->box(FL_FLAT_BOX);
btn->type(FL_RADIO_BUTTON);
+ btn->align(btn->align() | FL_ALIGN_WRAP);
btn->color(FL_BACKGROUND2_COLOR);
btn->selection_color(FL_SELECTION_COLOR);
btn->labelsize(page->labelsize());
@@ -171,7 +179,7 @@ void Fl_Navigation::update_labels()
btn->callback(label_pressed, this);
labels->add(btn);
- offset += page->labelsize() * 3;
+ offset += h;
}
labels->size(labels->w(), offset);
diff --git a/vncviewer/fltk/layout.h b/vncviewer/fltk/layout.h
index 01dc73e6..9a74c234 100644
--- a/vncviewer/fltk/layout.h
+++ b/vncviewer/fltk/layout.h
@@ -24,6 +24,7 @@
#ifndef __FLTK_LAYOUT_H__
#define __FLTK_LAYOUT_H__
+#include <FL/Fl_Choice.H>
#include <FL/fl_draw.H>
/* Calculates the width of a string as printed by FLTK (pixels) */
@@ -38,6 +39,18 @@ static inline int gui_str_len(const char *str)
return (int)(len + 0.5f);
}
+/* Adjusts an Fl_Choice so that all options are visible */
+static inline void fltk_adjust_choice(Fl_Choice *choice)
+{
+ int option_len;
+
+ option_len = 0;
+ for (int i = 0; i < choice->size(); i++)
+ option_len = std::max(option_len, gui_str_len(choice->text(i)));
+
+ choice->size(option_len + 30, choice->h());
+}
+
/**** MARGINS ****/
#define OUTER_MARGIN 15
diff --git a/vncviewer/menukey.cxx b/vncviewer/menukey.cxx
deleted file mode 100644
index c12d8c93..00000000
--- a/vncviewer/menukey.cxx
+++ /dev/null
@@ -1,86 +0,0 @@
-/* Copyright 2011 Martin Koegler <mkoegler@auto.tuwien.ac.at>
- * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <FL/Fl.H>
-
-// FLTK can pull in the X11 headers on some systems
-#ifndef XK_VoidSymbol
-#define XK_MISCELLANY
-#include <rfb/keysymdef.h>
-#endif
-
-#include "menukey.h"
-#include "parameters.h"
-
-static const MenuKeySymbol menuSymbols[] = {
- {"F1", FL_F + 1, 0x3b, XK_F1},
- {"F2", FL_F + 2, 0x3c, XK_F2},
- {"F3", FL_F + 3, 0x3d, XK_F3},
- {"F4", FL_F + 4, 0x3e, XK_F4},
- {"F5", FL_F + 5, 0x3f, XK_F5},
- {"F6", FL_F + 6, 0x40, XK_F6},
- {"F7", FL_F + 7, 0x41, XK_F7},
- {"F8", FL_F + 8, 0x42, XK_F8},
- {"F9", FL_F + 9, 0x43, XK_F9},
- {"F10", FL_F + 10, 0x44, XK_F10},
- {"F11", FL_F + 11, 0x57, XK_F11},
- {"F12", FL_F + 12, 0x58, XK_F12},
- {"Pause", FL_Pause, 0xc6, XK_Pause},
- {"Scroll_Lock", FL_Scroll_Lock, 0x46, XK_Scroll_Lock},
- {"Escape", FL_Escape, 0x01, XK_Escape},
- {"Insert", FL_Insert, 0xd2, XK_Insert},
- {"Delete", FL_Delete, 0xd3, XK_Delete},
- {"Home", FL_Home, 0xc7, XK_Home},
- {"Page_Up", FL_Page_Up, 0xc9, XK_Page_Up},
- {"Page_Down", FL_Page_Down, 0xd1, XK_Page_Down},
-};
-
-int getMenuKeySymbolCount()
-{
- return sizeof(menuSymbols)/sizeof(menuSymbols[0]);
-}
-
-const MenuKeySymbol* getMenuKeySymbols()
-{
- return menuSymbols;
-}
-
-void getMenuKey(int *fltkcode, int *keycode, uint32_t *keysym)
-{
- const char *menuKeyStr;
-
- menuKeyStr = menuKey;
- for(int i = 0; i < getMenuKeySymbolCount(); i++) {
- if (!strcmp(menuSymbols[i].name, menuKeyStr)) {
- *fltkcode = menuSymbols[i].fltkcode;
- *keycode = menuSymbols[i].keycode;
- *keysym = menuSymbols[i].keysym;
- return;
- }
- }
-
- *fltkcode = 0;
- *keycode = 0;
- *keysym = 0;
-}
diff --git a/vncviewer/menukey.h b/vncviewer/menukey.h
deleted file mode 100644
index 50106955..00000000
--- a/vncviewer/menukey.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright 2011 Martin Koegler <mkoegler@auto.tuwien.ac.at>
- *
- * 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 __KEYSYM_H__
-#define __KEYSYM_H__
-
-#include <stdint.h>
-
-typedef struct {
- const char* name;
- int fltkcode;
- int keycode;
- uint32_t keysym;
-} MenuKeySymbol;
-
-void getMenuKey(int *fltkcode, int *keycode, uint32_t *keysym);
-int getMenuKeySymbolCount();
-const MenuKeySymbol* getMenuKeySymbols();
-
-#endif
diff --git a/vncviewer/org.tigervnc.vncviewer.metainfo.xml.in b/vncviewer/org.tigervnc.vncviewer.metainfo.xml.in
index 0a211a51..207f9707 100644
--- a/vncviewer/org.tigervnc.vncviewer.metainfo.xml.in
+++ b/vncviewer/org.tigervnc.vncviewer.metainfo.xml.in
@@ -10,7 +10,7 @@
<id>org.tigervnc.vncviewer</id>
<metadata_license>FSFAP</metadata_license>
<project_license>GPL-2.0-or-later</project_license>
- <name>TigerVNC Viewer</name>
+ <name>TigerVNC</name>
<summary>Connect to VNC server and display remote desktop</summary>
<content_rating type="oars-1.1"/>
<description>
@@ -30,16 +30,22 @@
<launchable type="desktop-id">vncviewer.desktop</launchable>
<screenshots>
<screenshot type="default">
- <caption>TigerVNC viewer connection to a CentOS machine</caption>
+ <caption>TigerVNC connection to a CentOS machine</caption>
<image>https://raw.githubusercontent.com/TigerVNC/tigervnc/741d3edbfab65eda6f033078bc06347fe244ea6a/vncviewer/metainfo/tigervnc-connection-linux.jpg</image>
</screenshot>
<screenshot>
- <caption>TigerVNC viewer connection to a macOS machine</caption>
+ <caption>TigerVNC connection to a macOS machine</caption>
<image>https://raw.githubusercontent.com/TigerVNC/tigervnc/741d3edbfab65eda6f033078bc06347fe244ea6a/vncviewer/metainfo/tigervnc-connection-macos.jpg</image>
</screenshot>
<screenshot>
- <caption>TigerVNC viewer connection to a Windows machine</caption>
+ <caption>TigerVNC connection to a Windows machine</caption>
<image>https://raw.githubusercontent.com/TigerVNC/tigervnc/741d3edbfab65eda6f033078bc06347fe244ea6a/vncviewer/metainfo/tigervnc-connection-windows.jpg</image>
</screenshot>
</screenshots>
+ <!-- developer_name tag deprecated with Appstream 1.0 -->
+ <developer_name>The TigerVNC team</developer_name>
+ <developer id="org.tigervnc">
+ <name>The TigerVNC team</name>
+ </developer>
+ <url type="homepage">https://tigervnc.org</url>
</component>
diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx
index a6229a34..d2000181 100644
--- a/vncviewer/parameters.cxx
+++ b/vncviewer/parameters.cxx
@@ -32,13 +32,12 @@
#include "parameters.h"
-#include <os/os.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+#include <core/xdgdirs.h>
-#include <rdr/Exception.h>
-
-#include <rfb/LogWriter.h>
#include <rfb/SecurityClient.h>
-#include <rfb/util.h>
#include <FL/fl_utf8.h>
@@ -50,123 +49,199 @@
#include "i18n.h"
-using namespace rfb;
-using namespace std;
-
-static LogWriter vlog("Parameters");
-
-
-IntParameter pointerEventInterval("PointerEventInterval",
- "Time in milliseconds to rate-limit"
- " successive pointer events", 17);
-BoolParameter emulateMiddleButton("EmulateMiddleButton",
- "Emulate middle mouse button by pressing "
- "left and right mouse buttons simultaneously",
- false);
-BoolParameter dotWhenNoCursor("DotWhenNoCursor",
- "Show the dot cursor when the server sends an "
- "invisible cursor", false);
-
-BoolParameter alertOnFatalError("AlertOnFatalError",
- "Give a dialog on connection problems rather "
- "than exiting immediately", true);
-
-BoolParameter reconnectOnError("ReconnectOnError",
- "Give a dialog on connection problems rather "
- "than exiting immediately and ask for a reconnect.", true);
-
-StringParameter passwordFile("PasswordFile",
- "Password file for VNC authentication", "");
-AliasParameter passwd("passwd", "Alias for PasswordFile", &passwordFile);
-
-BoolParameter autoSelect("AutoSelect",
- "Auto select pixel format and encoding. "
- "Default if PreferredEncoding and FullColor are not specified.",
- true);
-BoolParameter fullColour("FullColor",
- "Use full color", true);
-AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
-IntParameter lowColourLevel("LowColorLevel",
- "Color level to use on slow connections. "
- "0 = Very Low, 1 = Low, 2 = Medium", 2);
-AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
-StringParameter preferredEncoding("PreferredEncoding",
- "Preferred encoding to use (Tight, ZRLE, Hextile or"
- " Raw)", "Tight");
-BoolParameter customCompressLevel("CustomCompressLevel",
- "Use custom compression level. "
- "Default if CompressLevel is specified.", false);
-IntParameter compressLevel("CompressLevel",
- "Use specified compression level 0 = Low, 9 = High",
- 2);
-BoolParameter noJpeg("NoJPEG",
- "Disable lossy JPEG compression in Tight encoding.",
- false);
-IntParameter qualityLevel("QualityLevel",
- "JPEG quality level. 0 = Low, 9 = High",
- 8);
-
-BoolParameter maximize("Maximize", "Maximize viewer window", false);
-BoolParameter fullScreen("FullScreen", "Enable full screen", false);
-StringParameter fullScreenMode("FullScreenMode", "Specify which monitors to use when in full screen. "
- "Should be either Current, Selected or All",
- "Current");
-BoolParameter fullScreenAllMonitors("FullScreenAllMonitors",
- "[DEPRECATED] Enable full screen over all monitors",
- false);
-MonitorIndicesParameter fullScreenSelectedMonitors("FullScreenSelectedMonitors",
- "Use the given list of monitors in full screen"
- " when -FullScreenMode=Selected.",
- "1");
-StringParameter desktopSize("DesktopSize",
- "Reconfigure desktop size on the server on "
- "connect (if possible)", "");
-StringParameter geometry("geometry",
- "Specify size and position of viewer window", "");
-
-BoolParameter listenMode("listen", "Listen for connections from VNC servers", false);
-
-BoolParameter remoteResize("RemoteResize",
- "Dynamically resize the remote desktop size as "
- "the size of the local client window changes. "
- "(Does not work with all servers)", true);
-
-BoolParameter viewOnly("ViewOnly",
- "Don't send any mouse or keyboard events to the server",
- false);
-BoolParameter shared("Shared",
- "Don't disconnect other viewers upon connection - "
- "share the desktop instead",
- false);
-
-BoolParameter acceptClipboard("AcceptClipboard",
- "Accept clipboard changes from the server",
- true);
-BoolParameter sendClipboard("SendClipboard",
- "Send clipboard changes to the server", true);
+static core::LogWriter vlog("Parameters");
+
+core::IntParameter
+ pointerEventInterval("PointerEventInterval",
+ "Time in milliseconds to rate-limit successive "
+ "pointer events",
+ 17, 0, INT_MAX);
+core::BoolParameter
+ emulateMiddleButton("EmulateMiddleButton",
+ "Emulate middle mouse button by pressing left "
+ "and right mouse buttons simultaneously",
+ false);
+core::BoolParameter
+ dotWhenNoCursor("DotWhenNoCursor",
+ "[DEPRECATED] Show the dot cursor when the server "
+ "sends an invisible cursor",
+ false);
+core::BoolParameter
+ alwaysCursor("AlwaysCursor",
+ "Show the local cursor when the server sends an "
+ "invisible cursor",
+ false);
+core::EnumParameter
+ cursorType("CursorType",
+ "Specify which cursor type the local cursor should be. "
+ "Should be either Dot or System",
+ {"Dot", "System"}, "Dot");
+
+core::BoolParameter
+ alertOnFatalError("AlertOnFatalError",
+ "Give a dialog on connection problems rather than "
+ "exiting immediately",
+ true);
+
+core::BoolParameter
+ reconnectOnError("ReconnectOnError",
+ "Give a dialog on connection problems rather than "
+ "exiting immediately and ask for a reconnect.",
+ true);
+
+core::StringParameter
+ passwordFile("PasswordFile",
+ "Password file for VNC authentication",
+ "");
+core::AliasParameter
+ passwd("passwd", "Alias for PasswordFile", &passwordFile);
+
+core::BoolParameter
+ autoSelect("AutoSelect",
+ "Auto select pixel format and encoding. Default if "
+ "PreferredEncoding and FullColor are not specified.",
+ true);
+core::BoolParameter
+ fullColour("FullColor", "Use full color", true);
+core::AliasParameter
+ fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
+core::IntParameter
+ lowColourLevel("LowColorLevel",
+ "Color level to use on slow connections. "
+ "0 = Very Low, 1 = Low, 2 = Medium",
+ 2, 0, 2);
+core::AliasParameter
+ lowColourLevelAlias("LowColourLevel",
+ "Alias for LowColorLevel", &lowColourLevel);
+core::EnumParameter
+ preferredEncoding("PreferredEncoding",
+ "Preferred encoding to use (Tight, ZRLE, Hextile, "
+#ifdef HAVE_H264
+ "H.264, "
+#endif
+ "or Raw)",
+ {"Tight", "ZRLE", "Hextile",
+#ifdef HAVE_H264
+ "H.264",
+#endif
+ "Raw"},
+ "Tight");
+core::BoolParameter
+ customCompressLevel("CustomCompressLevel",
+ "Use custom compression level. Default if "
+ "CompressLevel is specified.",
+ false);
+core::IntParameter
+ compressLevel("CompressLevel",
+ "Use specified compression level 0 = Low, 9 = High",
+ 2, 0, 9);
+core::BoolParameter
+ noJpeg("NoJPEG",
+ "Disable lossy JPEG compression in Tight encoding.",
+ false);
+core::IntParameter
+ qualityLevel("QualityLevel",
+ "JPEG quality level. 0 = Low, 9 = High",
+ 8, 0, 9);
+
+core::BoolParameter
+ maximize("Maximize", "Maximize viewer window", false);
+core::BoolParameter
+ fullScreen("FullScreen", "Enable full screen", false);
+core::EnumParameter
+ fullScreenMode("FullScreenMode",
+ "Specify which monitors to use when in full screen. "
+ "Should be either Current, Selected or All",
+ {"Current", "Selected", "All"}, "Current");
+
+core::BoolParameter
+ fullScreenAllMonitors("FullScreenAllMonitors",
+ "[DEPRECATED] Enable full screen over all "
+ "monitors",
+ false);
+MonitorIndicesParameter
+ fullScreenSelectedMonitors("FullScreenSelectedMonitors",
+ "Use the given list of monitors in full "
+ "screen when -FullScreenMode=Selected.",
+ {1});
+core::StringParameter
+ desktopSize("DesktopSize",
+ "Reconfigure desktop size on the server on connect (if "
+ "possible)",
+ "");
+core::StringParameter
+ geometry("geometry",
+ "Specify size and position of viewer window",
+ "");
+
+core::BoolParameter
+ listenMode("listen",
+ "Listen for connections from VNC servers",
+ false);
+
+core::BoolParameter
+ remoteResize("RemoteResize",
+ "Dynamically resize the remote desktop size as the size "
+ "of the local client window changes. (Does not work "
+ "with all servers)",
+ true);
+
+core::BoolParameter
+ viewOnly("ViewOnly",
+ "Don't send any mouse or keyboard events to the server",
+ false);
+core::BoolParameter
+ shared("Shared",
+ "Don't disconnect other viewers upon connection - "
+ "share the desktop instead",
+ false);
+
+core::BoolParameter
+ acceptClipboard("AcceptClipboard",
+ "Accept clipboard changes from the server",
+ true);
+core::BoolParameter
+ sendClipboard("SendClipboard",
+ "Send clipboard changes to the server",
+ true);
#if !defined(WIN32) && !defined(__APPLE__)
-BoolParameter setPrimary("SetPrimary",
- "Set the primary selection as well as the "
- "clipboard selection", true);
-BoolParameter sendPrimary("SendPrimary",
- "Send the primary selection to the "
- "server as well as the clipboard selection",
- true);
-StringParameter display("display",
- "Specifies the X display on which the VNC viewer window should appear.",
- "");
+core::BoolParameter
+ setPrimary("SetPrimary",
+ "Set the primary selection as well as the clipboard "
+ "selection",
+ true);
+core::BoolParameter
+ sendPrimary("SendPrimary",
+ "Send the primary selection to the server as well as the "
+ "clipboard selection",
+ true);
+core::StringParameter
+ display("display",
+ "Specifies the X display on which the TigerVNC window "
+ "should appear.",
+ "");
#endif
-StringParameter menuKey("MenuKey", "The key which brings up the popup menu",
- "F8");
-
-BoolParameter fullscreenSystemKeys("FullscreenSystemKeys",
- "Pass special keys (like Alt+Tab) directly "
- "to the server when in full-screen mode.",
- true);
+// Keep list of valid values in sync with ShortcutHandler
+core::EnumListParameter
+ shortcutModifiers("ShortcutModifiers",
+ "The combination of modifier keys that triggers "
+ "special actions in the viewer instead of being "
+ "sent to the remote session. Possible values are a "
+ "combination of Ctrl, Shift, Alt, and Super.",
+ {"Ctrl", "Shift", "Alt", "Super",
+ "Win", "Option", "Cmd"},
+ {"Ctrl", "Alt"});
+
+core::BoolParameter
+ fullscreenSystemKeys("FullscreenSystemKeys",
+ "Pass special keys (like Alt+Tab) directly to "
+ "the server when in full-screen mode.",
+ true);
#ifndef WIN32
-StringParameter via("via", "Gateway to tunnel via", "");
+core::StringParameter
+ via("via", "Gateway to tunnel via", "");
#endif
static const char* IDENTIFIER_STRING = "TigerVNC Configuration file Version 1.0";
@@ -175,13 +250,13 @@ static const char* IDENTIFIER_STRING = "TigerVNC Configuration file Version 1.0"
* We only save the sub set of parameters that can be modified from
* the graphical user interface
*/
-static VoidParameter* parameterArray[] = {
+static core::VoidParameter* parameterArray[] = {
/* Security */
#ifdef HAVE_GNUTLS
- &CSecurityTLS::X509CA,
- &CSecurityTLS::X509CRL,
+ &rfb::CSecurityTLS::X509CA,
+ &rfb::CSecurityTLS::X509CRL,
#endif // HAVE_GNUTLS
- &SecurityClient::secTypes,
+ &rfb::SecurityClient::secTypes,
/* Misc. */
&reconnectOnError,
&shared,
@@ -201,19 +276,22 @@ static VoidParameter* parameterArray[] = {
/* Input */
&viewOnly,
&emulateMiddleButton,
- &dotWhenNoCursor,
+ &alwaysCursor,
+ &cursorType,
&acceptClipboard,
&sendClipboard,
#if !defined(WIN32) && !defined(__APPLE__)
&sendPrimary,
&setPrimary,
#endif
- &menuKey,
- &fullscreenSystemKeys
+ &fullscreenSystemKeys,
+ /* Keyboard shortcuts */
+ &shortcutModifiers,
};
-static VoidParameter* readOnlyParameterArray[] = {
- &fullScreenAllMonitors
+static core::VoidParameter* readOnlyParameterArray[] = {
+ &fullScreenAllMonitors,
+ &dotWhenNoCursor
};
// Encoding Table
@@ -320,7 +398,7 @@ static void setKeyString(const char *_name, const char *_value, HKEY* hKey) {
LONG res = RegSetValueExW(*hKey, name, 0, REG_SZ, (BYTE*)&value, (wcslen(value)+1)*2);
if (res != ERROR_SUCCESS)
- throw rdr::win32_error("RegSetValueExW", res);
+ throw core::win32_error("RegSetValueExW", res);
}
@@ -336,7 +414,7 @@ static void setKeyInt(const char *_name, const int _value, HKEY* hKey) {
LONG res = RegSetValueExW(*hKey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(DWORD));
if (res != ERROR_SUCCESS)
- throw rdr::win32_error("RegSetValueExW", res);
+ throw core::win32_error("RegSetValueExW", res);
}
@@ -357,7 +435,7 @@ static bool getKeyString(const char* _name, char* dest, size_t destSize, HKEY* h
if (res != ERROR_SUCCESS){
delete [] value;
if (res != ERROR_FILE_NOT_FOUND)
- throw rdr::win32_error("RegQueryValueExW", res);
+ throw core::win32_error("RegQueryValueExW", res);
// The value does not exist, defaults will be used.
return false;
}
@@ -394,7 +472,7 @@ static bool getKeyInt(const char* _name, int* dest, HKEY* hKey) {
LONG res = RegQueryValueExW(*hKey, name, nullptr, nullptr, (LPBYTE)&value, &dwordsize);
if (res != ERROR_SUCCESS){
if (res != ERROR_FILE_NOT_FOUND)
- throw rdr::win32_error("RegQueryValueExW", res);
+ throw core::win32_error("RegQueryValueExW", res);
// The value does not exist, defaults will be used.
return false;
}
@@ -414,13 +492,14 @@ static void removeValue(const char* _name, HKEY* hKey) {
LONG res = RegDeleteValueW(*hKey, name);
if (res != ERROR_SUCCESS) {
if (res != ERROR_FILE_NOT_FOUND)
- throw rdr::win32_error("RegDeleteValueW", res);
+ throw core::win32_error("RegDeleteValueW", res);
// The value does not exist, no need to remove it.
return;
}
}
-void saveHistoryToRegKey(const list<string>& serverHistory) {
+void saveHistoryToRegKey(const std::list<std::string>& serverHistory)
+{
HKEY hKey;
LONG res = RegCreateKeyExW(HKEY_CURRENT_USER,
L"Software\\TigerVNC\\vncviewer\\history", 0, nullptr,
@@ -428,14 +507,14 @@ void saveHistoryToRegKey(const list<string>& serverHistory) {
&hKey, nullptr);
if (res != ERROR_SUCCESS)
- throw rdr::win32_error(_("Failed to create registry key"), res);
+ throw core::win32_error(_("Failed to create registry key"), res);
unsigned index = 0;
assert(SERVER_HISTORY_SIZE < 100);
char indexString[3];
try {
- for (const string& entry : serverHistory) {
+ for (const std::string& entry : serverHistory) {
if (index > SERVER_HISTORY_SIZE)
break;
snprintf(indexString, 3, "%d", index);
@@ -449,7 +528,7 @@ void saveHistoryToRegKey(const list<string>& serverHistory) {
res = RegCloseKey(hKey);
if (res != ERROR_SUCCESS)
- throw rdr::win32_error(_("Failed to close registry key"), res);
+ throw core::win32_error(_("Failed to close registry key"), res);
}
static void saveToReg(const char* servername) {
@@ -461,57 +540,74 @@ static void saveToReg(const char* servername) {
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr,
&hKey, nullptr);
if (res != ERROR_SUCCESS)
- throw rdr::win32_error(_("Failed to create registry key"), res);
+ throw core::win32_error(_("Failed to create registry key"), res);
try {
setKeyString("ServerName", servername, &hKey);
} catch (std::exception& e) {
RegCloseKey(hKey);
- throw std::runtime_error(format(_("Failed to save \"%s\": %s"),
- "ServerName", e.what()));
+ throw std::runtime_error(core::format(
+ _("Failed to save \"%s\": %s"), "ServerName", e.what()));
}
- for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
+ for (core::VoidParameter* param : parameterArray) {
+ core::IntParameter* iparam;
+ core::BoolParameter* bparam;
+
+ if (param->isDefault()) {
+ try {
+ removeValue(param->getName(), &hKey);
+ } catch (std::exception& e) {
+ RegCloseKey(hKey);
+ throw std::runtime_error(
+ core::format(_("Failed to remove \"%s\": %s"),
+ param->getName(), e.what()));
+ }
+ continue;
+ }
+
+ iparam = dynamic_cast<core::IntParameter*>(param);
+ bparam = dynamic_cast<core::BoolParameter*>(param);
+
try {
- if (dynamic_cast<StringParameter*>(parameterArray[i]) != nullptr) {
- setKeyString(parameterArray[i]->getName(), *(StringParameter*)parameterArray[i], &hKey);
- } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != nullptr) {
- setKeyInt(parameterArray[i]->getName(), (int)*(IntParameter*)parameterArray[i], &hKey);
- } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != nullptr) {
- setKeyInt(parameterArray[i]->getName(), (int)*(BoolParameter*)parameterArray[i], &hKey);
+ if (iparam != nullptr) {
+ setKeyInt(iparam->getName(), (int)*(iparam), &hKey);
+ } else if (bparam != nullptr) {
+ setKeyInt(bparam->getName(), (int)*(bparam), &hKey);
} else {
- throw std::logic_error(_("Unknown parameter type"));
+ setKeyString(param->getName(), param->getValueStr().c_str(), &hKey);
}
} catch (std::exception& e) {
RegCloseKey(hKey);
- throw std::runtime_error(format(_("Failed to save \"%s\": %s"),
- parameterArray[i]->getName(),
- e.what()));
+ throw std::runtime_error(
+ core::format(_("Failed to save \"%s\": %s"),
+ param->getName(), e.what()));
}
}
// Remove read-only parameters to replicate the behaviour of Linux/macOS when they
// store a config to disk. If the parameter hasn't been migrated at this point it
// will be lost.
- for (size_t i = 0; i < sizeof(readOnlyParameterArray)/sizeof(VoidParameter*); i++) {
+ for (core::VoidParameter* param : readOnlyParameterArray) {
try {
- removeValue(readOnlyParameterArray[i]->getName(), &hKey);
+ removeValue(param->getName(), &hKey);
} catch (std::exception& e) {
RegCloseKey(hKey);
- throw std::runtime_error(format(_("Failed to remove \"%s\": %s"),
- readOnlyParameterArray[i]->getName(),
- e.what()));
+ throw std::runtime_error(
+ core::format(_("Failed to remove \"%s\": %s"),
+ param->getName(), e.what()));
}
}
res = RegCloseKey(hKey);
if (res != ERROR_SUCCESS)
- throw rdr::win32_error(_("Failed to close registry key"), res);
+ throw core::win32_error(_("Failed to close registry key"), res);
}
-list<string> loadHistoryFromRegKey() {
+std::list<std::string> loadHistoryFromRegKey()
+{
HKEY hKey;
- list<string> serverHistory;
+ std::list<std::string> serverHistory;
LONG res = RegOpenKeyExW(HKEY_CURRENT_USER,
L"Software\\TigerVNC\\vncviewer\\history", 0,
@@ -522,7 +618,7 @@ list<string> loadHistoryFromRegKey() {
return serverHistory;
}
- throw rdr::win32_error(_("Failed to open registry key"), res);
+ throw core::win32_error(_("Failed to open registry key"), res);
}
unsigned index;
@@ -549,31 +645,35 @@ list<string> loadHistoryFromRegKey() {
res = RegCloseKey(hKey);
if (res != ERROR_SUCCESS)
- throw rdr::win32_error(_("Failed to close registry key"), res);
+ throw core::win32_error(_("Failed to close registry key"), res);
return serverHistory;
}
-static void getParametersFromReg(VoidParameter* parameters[],
+static void getParametersFromReg(core::VoidParameter* parameters[],
size_t parameters_len, HKEY* hKey)
{
const size_t buffersize = 256;
int intValue = 0;
char stringValue[buffersize];
- for (size_t i = 0; i < parameters_len/sizeof(VoidParameter*); i++) {
+ for (size_t i = 0; i < parameters_len; i++) {
+ core::IntParameter* iparam;
+ core::BoolParameter* bparam;
+
+ iparam = dynamic_cast<core::IntParameter*>(parameters[i]);
+ bparam = dynamic_cast<core::BoolParameter*>(parameters[i]);
+
try {
- if (dynamic_cast<StringParameter*>(parameters[i]) != nullptr) {
+ if (iparam != nullptr) {
+ if (getKeyInt(iparam->getName(), &intValue, hKey))
+ iparam->setParam(intValue);
+ } else if (bparam != nullptr) {
+ if (getKeyInt(bparam->getName(), &intValue, hKey))
+ bparam->setParam(intValue);
+ } else {
if (getKeyString(parameters[i]->getName(), stringValue, buffersize, hKey))
parameters[i]->setParam(stringValue);
- } else if (dynamic_cast<IntParameter*>(parameters[i]) != nullptr) {
- if (getKeyInt(parameters[i]->getName(), &intValue, hKey))
- ((IntParameter*)parameters[i])->setParam(intValue);
- } else if (dynamic_cast<BoolParameter*>(parameters[i]) != nullptr) {
- if (getKeyInt(parameters[i]->getName(), &intValue, hKey))
- ((BoolParameter*)parameters[i])->setParam(intValue);
- } else {
- throw std::logic_error(_("Unknown parameter type"));
}
} catch(std::exception& e) {
// Just ignore this entry and continue with the rest
@@ -596,7 +696,7 @@ static char* loadFromReg() {
return nullptr;
}
- throw rdr::win32_error(_("Failed to open registry key"), res);
+ throw core::win32_error(_("Failed to open registry key"), res);
}
const size_t buffersize = 256;
@@ -612,13 +712,18 @@ static char* loadFromReg() {
strcpy(servername, "");
}
- getParametersFromReg(parameterArray, sizeof(parameterArray), &hKey);
+ getParametersFromReg(parameterArray,
+ sizeof(parameterArray) /
+ sizeof(core::VoidParameter*),
+ &hKey);
getParametersFromReg(readOnlyParameterArray,
- sizeof(readOnlyParameterArray), &hKey);
+ sizeof(readOnlyParameterArray) /
+ sizeof(core::VoidParameter*),
+ &hKey);
res = RegCloseKey(hKey);
if (res != ERROR_SUCCESS)
- throw rdr::win32_error(_("Failed to close registry key"), res);
+ throw core::win32_error(_("Failed to close registry key"), res);
return servername;
}
@@ -639,7 +744,7 @@ void saveViewerParameters(const char *filename, const char *servername) {
return;
#endif
- const char* configDir = os::getvncconfigdir();
+ const char* configDir = core::getvncconfigdir();
if (configDir == nullptr)
throw std::runtime_error(_("Could not determine VNC config directory path"));
@@ -650,78 +755,50 @@ void saveViewerParameters(const char *filename, const char *servername) {
/* Write parameters to file */
FILE* f = fopen(filepath, "w+");
- if (!f) {
- std::string msg = format(_("Could not open \"%s\""), filepath);
- throw rdr::posix_error(msg.c_str(), errno);
- }
+ if (!f)
+ throw core::posix_error(
+ core::format(_("Could not open \"%s\""), filepath), errno);
fprintf(f, "%s\n", IDENTIFIER_STRING);
fprintf(f, "\n");
if (!encodeValue(servername, encodingBuffer, buffersize)) {
fclose(f);
- throw std::runtime_error(format(_("Failed to save \"%s\": %s"),
- "ServerName",
- _("Could not encode parameter")));
+ throw std::runtime_error(
+ core::format(_("Failed to save \"%s\": %s"), "ServerName",
+ _("Could not encode parameter")));
}
fprintf(f, "ServerName=%s\n", encodingBuffer);
- for (VoidParameter* param : parameterArray) {
- if (dynamic_cast<StringParameter*>(param) != nullptr) {
- if (!encodeValue(*(StringParameter*)param,
- encodingBuffer, buffersize)) {
- fclose(f);
- throw std::runtime_error(format(_("Failed to save \"%s\": %s"),
- param->getName(),
- _("Could not encode parameter")));
- }
- fprintf(f, "%s=%s\n", ((StringParameter*)param)->getName(), encodingBuffer);
- } else if (dynamic_cast<IntParameter*>(param) != nullptr) {
- fprintf(f, "%s=%d\n", ((IntParameter*)param)->getName(), (int)*(IntParameter*)param);
- } else if (dynamic_cast<BoolParameter*>(param) != nullptr) {
- fprintf(f, "%s=%d\n", ((BoolParameter*)param)->getName(), (int)*(BoolParameter*)param);
- } else {
+ for (core::VoidParameter* param : parameterArray) {
+ if (param->isDefault())
+ continue;
+ if (!encodeValue(param->getValueStr().c_str(),
+ encodingBuffer, buffersize)) {
fclose(f);
- throw std::logic_error(format(_("Failed to save \"%s\": %s"),
- param->getName(),
- _("Unknown parameter type")));
+ throw std::runtime_error(
+ core::format(_("Failed to save \"%s\": %s"), param->getName(),
+ _("Could not encode parameter")));
}
+ fprintf(f, "%s=%s\n", param->getName(), encodingBuffer);
}
fclose(f);
}
static bool findAndSetViewerParameterFromValue(
- VoidParameter* parameters[], size_t parameters_len,
+ core::VoidParameter* parameters[], size_t parameters_len,
char* value, char* line)
{
const size_t buffersize = 256;
char decodingBuffer[buffersize];
// Find and set the correct parameter
- for (size_t i = 0; i < parameters_len/sizeof(VoidParameter*); i++) {
-
- if (dynamic_cast<StringParameter*>(parameters[i]) != nullptr) {
- if (strcasecmp(line, ((StringParameter*)parameters[i])->getName()) == 0) {
- if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer)))
- throw std::runtime_error(_("Invalid format or too large value"));
- ((StringParameter*)parameters[i])->setParam(decodingBuffer);
- return false;
- }
-
- } else if (dynamic_cast<IntParameter*>(parameters[i]) != nullptr) {
- if (strcasecmp(line, ((IntParameter*)parameters[i])->getName()) == 0) {
- ((IntParameter*)parameters[i])->setParam(atoi(value));
- return false;
- }
-
- } else if (dynamic_cast<BoolParameter*>(parameters[i]) != nullptr) {
- if (strcasecmp(line, ((BoolParameter*)parameters[i])->getName()) == 0) {
- ((BoolParameter*)parameters[i])->setParam(atoi(value));
- return false;
- }
-
- } else {
- throw std::logic_error(_("Unknown parameter type"));
+ for (size_t i = 0; i < parameters_len; i++) {
+ if (strcasecmp(line, parameters[i]->getName()) == 0) {
+ if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer)))
+ throw std::runtime_error(_("Invalid format or too large value"));
+ parameters[i]->setParam(decodingBuffer);
+ return false;
}
}
@@ -745,7 +822,7 @@ char* loadViewerParameters(const char *filename) {
return loadFromReg();
#endif
- const char* configDir = os::getvncconfigdir();
+ const char* configDir = core::getvncconfigdir();
if (configDir == nullptr)
throw std::runtime_error(_("Could not determine VNC config directory path"));
@@ -759,10 +836,10 @@ char* loadViewerParameters(const char *filename) {
if (!f) {
if (!filename)
return nullptr; // Use defaults.
- std::string msg = format(_("Could not open \"%s\""), filepath);
- throw rdr::posix_error(msg.c_str(), errno);
+ throw core::posix_error(
+ core::format(_("Could not open \"%s\""), filepath), errno);
}
-
+
int lineNr = 0;
while (!feof(f)) {
@@ -773,18 +850,19 @@ char* loadViewerParameters(const char *filename) {
break;
fclose(f);
- std::string msg = format(_("Failed to read line %d in "
- "file \"%s\""), lineNr, filepath);
- throw rdr::posix_error(msg.c_str(), errno);
+ throw core::posix_error(
+ core::format(_("Failed to read line %d in file \"%s\""),
+ lineNr, filepath),
+ errno);
}
if (strlen(line) == (sizeof(line) - 1)) {
fclose(f);
- throw std::runtime_error(format("%s: %s",
- format(_("Failed to read line %d "
- "in file \"%s\""),
- lineNr, filepath).c_str(),
- _("Line too long")));
+ std::string msg = core::format(_("Failed to read line %d in "
+ "file \"%s\""),
+ lineNr, filepath);
+ throw std::runtime_error(
+ core::format("%s: %s", msg.c_str(), _("Line too long")));
}
// Make sure that the first line of the file has the file identifier string
@@ -793,11 +871,10 @@ char* loadViewerParameters(const char *filename) {
continue;
fclose(f);
- throw std::runtime_error(format(_("Configuration file %s is in "
- "an invalid format"),
- filepath));
+ throw std::runtime_error(core::format(
+ _("Configuration file %s is in an invalid format"), filepath));
}
-
+
// Skip empty lines and comments
if ((line[0] == '\n') || (line[0] == '#') || (line[0] == '\r'))
continue;
@@ -815,8 +892,10 @@ char* loadViewerParameters(const char *filename) {
// Find the parameter value
char *value = strchr(line, '=');
if (value == nullptr) {
- vlog.error(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, _("Invalid format"));
+ std::string msg = core::format(_("Failed to read line %d in "
+ "file \"%s\""),
+ lineNr, filepath);
+ vlog.error("%s: %s", msg.c_str(), _("Invalid format"));
continue;
}
*value = '\0'; // line only contains the parameter name below.
@@ -834,24 +913,34 @@ char* loadViewerParameters(const char *filename) {
invalidParameterName = false;
} else {
- invalidParameterName = findAndSetViewerParameterFromValue(parameterArray, sizeof(parameterArray),
- value, line);
+ invalidParameterName = findAndSetViewerParameterFromValue(
+ parameterArray,
+ sizeof(parameterArray) / sizeof(core::VoidParameter *),
+ value, line);
if (invalidParameterName) {
- invalidParameterName = findAndSetViewerParameterFromValue(readOnlyParameterArray, sizeof(readOnlyParameterArray),
- value, line);
+ invalidParameterName = findAndSetViewerParameterFromValue(
+ readOnlyParameterArray,
+ sizeof(readOnlyParameterArray) /
+ sizeof(core::VoidParameter *),
+ value, line);
}
}
} catch(std::exception& e) {
// Just ignore this entry and continue with the rest
- vlog.error(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, e.what());
+ std::string msg = core::format(_("Failed to read line %d in "
+ "file \"%s\""),
+ lineNr, filepath);
+ vlog.error("%s: %s", msg.c_str(), e.what());
continue;
}
- if (invalidParameterName)
- vlog.error(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, _("Unknown parameter"));
+ if (invalidParameterName) {
+ std::string msg = core::format(_("Failed to read line %d in "
+ "file \"%s\""),
+ lineNr, filepath);
+ vlog.error("%s: %s", msg.c_str(), _("Unknown parameter"));
+ }
}
fclose(f);
f = nullptr;
diff --git a/vncviewer/parameters.h b/vncviewer/parameters.h
index a25c932d..4dc30db6 100644
--- a/vncviewer/parameters.h
+++ b/vncviewer/parameters.h
@@ -20,7 +20,8 @@
#ifndef __PARAMETERS_H__
#define __PARAMETERS_H__
-#include <rfb/Configuration.h>
+#include <core/Configuration.h>
+
#include "MonitorIndicesParameter.h"
#ifdef _WIN32
@@ -31,53 +32,55 @@
#define SERVER_HISTORY_SIZE 20
-extern rfb::IntParameter pointerEventInterval;
-extern rfb::BoolParameter emulateMiddleButton;
-extern rfb::BoolParameter dotWhenNoCursor;
-
-extern rfb::StringParameter passwordFile;
-
-extern rfb::BoolParameter autoSelect;
-extern rfb::BoolParameter fullColour;
-extern rfb::AliasParameter fullColourAlias;
-extern rfb::IntParameter lowColourLevel;
-extern rfb::AliasParameter lowColourLevelAlias;
-extern rfb::StringParameter preferredEncoding;
-extern rfb::BoolParameter customCompressLevel;
-extern rfb::IntParameter compressLevel;
-extern rfb::BoolParameter noJpeg;
-extern rfb::IntParameter qualityLevel;
-
-extern rfb::BoolParameter maximize;
-extern rfb::BoolParameter fullScreen;
-extern rfb::StringParameter fullScreenMode;
-extern rfb::BoolParameter fullScreenAllMonitors; // deprecated
+extern core::IntParameter pointerEventInterval;
+extern core::BoolParameter emulateMiddleButton;
+extern core::BoolParameter dotWhenNoCursor; // deprecated
+extern core::BoolParameter alwaysCursor;
+extern core::EnumParameter cursorType;
+
+extern core::StringParameter passwordFile;
+
+extern core::BoolParameter autoSelect;
+extern core::BoolParameter fullColour;
+extern core::AliasParameter fullColourAlias;
+extern core::IntParameter lowColourLevel;
+extern core::AliasParameter lowColourLevelAlias;
+extern core::EnumParameter preferredEncoding;
+extern core::BoolParameter customCompressLevel;
+extern core::IntParameter compressLevel;
+extern core::BoolParameter noJpeg;
+extern core::IntParameter qualityLevel;
+
+extern core::BoolParameter maximize;
+extern core::BoolParameter fullScreen;
+extern core::EnumParameter fullScreenMode;
+extern core::BoolParameter fullScreenAllMonitors; // deprecated
extern MonitorIndicesParameter fullScreenSelectedMonitors;
-extern rfb::StringParameter desktopSize;
-extern rfb::StringParameter geometry;
-extern rfb::BoolParameter remoteResize;
+extern core::StringParameter desktopSize;
+extern core::StringParameter geometry;
+extern core::BoolParameter remoteResize;
-extern rfb::BoolParameter listenMode;
+extern core::BoolParameter listenMode;
-extern rfb::BoolParameter viewOnly;
-extern rfb::BoolParameter shared;
+extern core::BoolParameter viewOnly;
+extern core::BoolParameter shared;
-extern rfb::BoolParameter acceptClipboard;
-extern rfb::BoolParameter setPrimary;
-extern rfb::BoolParameter sendClipboard;
+extern core::BoolParameter acceptClipboard;
+extern core::BoolParameter setPrimary;
+extern core::BoolParameter sendClipboard;
#if !defined(WIN32) && !defined(__APPLE__)
-extern rfb::BoolParameter sendPrimary;
-extern rfb::StringParameter display;
+extern core::BoolParameter sendPrimary;
+extern core::StringParameter display;
#endif
-extern rfb::StringParameter menuKey;
+extern core::EnumListParameter shortcutModifiers;
-extern rfb::BoolParameter fullscreenSystemKeys;
-extern rfb::BoolParameter alertOnFatalError;
-extern rfb::BoolParameter reconnectOnError;
+extern core::BoolParameter fullscreenSystemKeys;
+extern core::BoolParameter alertOnFatalError;
+extern core::BoolParameter reconnectOnError;
#ifndef WIN32
-extern rfb::StringParameter via;
+extern core::StringParameter via;
#endif
void saveViewerParameters(const char *filename, const char *servername=nullptr);
diff --git a/vncviewer/touch.cxx b/vncviewer/touch.cxx
index 572e726e..8b998425 100644
--- a/vncviewer/touch.cxx
+++ b/vncviewer/touch.cxx
@@ -36,7 +36,7 @@
#include <FL/Fl.H>
#include <FL/x.H>
-#include <rfb/LogWriter.h>
+#include <core/LogWriter.h>
#include "i18n.h"
#include "vncviewer.h"
@@ -49,7 +49,7 @@
#include "touch.h"
-static rfb::LogWriter vlog("Touch");
+static core::LogWriter vlog("Touch");
#if !defined(WIN32) && !defined(__APPLE__)
static int xi_major;
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index 4efe6e93..324ec632 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -35,7 +35,7 @@
#include <sys/stat.h>
#ifdef WIN32
-#include <os/winerrno.h>
+#include <core/winerrno.h>
#include <direct.h>
#endif
@@ -48,16 +48,18 @@
#include <X11/XKBlib.h>
#endif
-#include <rfb/Logger_stdio.h>
+#include <core/Exception.h>
+#include <core/Logger_stdio.h>
+#include <core/LogWriter.h>
+#include <core/Timer.h>
+
#ifdef HAVE_GNUTLS
#include <rfb/CSecurityTLS.h>
#endif
-#include <rfb/Hostname.h>
-#include <rfb/LogWriter.h>
-#include <rfb/Timer.h>
-#include <rdr/Exception.h>
+
+#include <core/xdgdirs.h>
+
#include <network/TcpSocket.h>
-#include <os/os.h>
#include <FL/Fl_PNG_Image.H>
#include <FL/Fl_Sys_Menu_Bar.H>
@@ -79,10 +81,7 @@
#include "win32.h"
#endif
-static rfb::LogWriter vlog("main");
-
-using namespace network;
-using namespace rfb;
+static core::LogWriter vlog("main");
char vncServerName[VNCSERVERNAMELEN] = { '\0' };
@@ -101,11 +100,11 @@ static const char *about_text()
// encodings, so we need to make sure we get a fresh string every
// time.
snprintf(buffer, sizeof(buffer),
- _("TigerVNC viewer v%s\n"
+ _("TigerVNC v%s\n"
"Built on: %s\n"
"Copyright (C) 1999-%d TigerVNC team and many others (see README.rst)\n"
"See https://www.tigervnc.org for information on TigerVNC."),
- PACKAGE_VERSION, BUILD_TIMESTAMP, 2024);
+ PACKAGE_VERSION, BUILD_TIMESTAMP, 2025);
return buffer;
}
@@ -171,7 +170,7 @@ bool should_disconnect()
void about_vncviewer()
{
- fl_message_title(_("About TigerVNC Viewer"));
+ fl_message_title(_("About TigerVNC"));
fl_message("%s", about_text());
}
@@ -182,12 +181,13 @@ static void mainloop(const char* vncserver, network::Socket* sock)
exitMainloop = false;
- cc = new CConn(vncserver, sock);
+ cc = new CConn();
+ cc->connect(vncserver, sock);
while (!exitMainloop) {
int next_timer;
- next_timer = Timer::checkTimeouts();
+ next_timer = core::Timer::checkTimeouts();
if (next_timer < 0)
next_timer = INT_MAX;
@@ -242,7 +242,7 @@ static void new_connection_cb(Fl_Widget* /*widget*/, void* /*data*/)
pid = fork();
if (pid == -1) {
- vlog.error(_("Error starting new TigerVNC Viewer: %s"), strerror(errno));
+ vlog.error(_("Error starting new connection: %s"), strerror(errno));
return;
}
@@ -254,7 +254,7 @@ static void new_connection_cb(Fl_Widget* /*widget*/, void* /*data*/)
execvp(argv[0], (char * const *)argv);
- vlog.error(_("Error starting new TigerVNC Viewer: %s"), strerror(errno));
+ vlog.error(_("Error starting new connection: %s"), strerror(errno));
_exit(1);
}
#endif
@@ -263,7 +263,7 @@ static void CleanupSignalHandler(int sig)
{
// CleanupSignalHandler allows C++ object cleanup to happen because it calls
// exit() rather than the default which is to abort.
- vlog.info(_("Termination signal %d has been received. TigerVNC viewer will now exit."), sig);
+ vlog.info(_("Termination signal %d has been received. TigerVNC will now exit."), sig);
exit(1);
}
@@ -388,7 +388,7 @@ static void init_fltk()
fl_message_hotspot(false);
// Avoid empty titles for popups
- fl_message_title_default(_("TigerVNC viewer"));
+ fl_message_title_default("TigerVNC");
// FLTK exposes these so that we can translate them.
fl_no = _("No");
@@ -446,7 +446,7 @@ static void usage(const char *programName)
}
#endif
- fprintf(stderr,
+ fprintf(stderr, _(
"\n"
"Usage: %s [parameters] [host][:displayNum]\n"
" %s [parameters] [host][::port]\n"
@@ -454,7 +454,7 @@ static void usage(const char *programName)
" %s [parameters] [unix socket]\n"
#endif
" %s [parameters] -listen [port]\n"
- " %s [parameters] [.tigervnc file]\n",
+ " %s [parameters] [.tigervnc file]\n"),
programName, programName,
#ifndef WIN32
programName,
@@ -462,21 +462,21 @@ static void usage(const char *programName)
programName, programName);
#if !defined(WIN32) && !defined(__APPLE__)
- fprintf(stderr,"\n"
+ fprintf(stderr, _("\n"
"Options:\n\n"
" -display Xdisplay - Specifies the X display for the viewer window\n"
- " -geometry geometry - Initial position of the main VNC viewer window. See the\n"
- " man page for details.\n");
+ " -geometry geometry - Initial position of the main TigerVNC window. See the\n"
+ " man page for details.\n"));
#endif
- fprintf(stderr,"\n"
+ fprintf(stderr, _("\n"
"Parameters can be turned on with -<param> or off with -<param>=0\n"
"Parameters which take a value can be specified as "
"-<param> <value>\n"
"Other valid forms are <param>=<value> -<param>=<value> "
"--<param>=<value>\n"
- "Parameter names are case-insensitive. The parameters are:\n\n");
- Configuration::listParams(79, 14);
+ "Parameter names are case-insensitive. The parameters are:\n\n"));
+ core::Configuration::listParams(79, 14);
#ifdef WIN32
// Just wait for the user to kill the console window
@@ -528,6 +528,12 @@ migrateDeprecatedOptions()
fullScreenMode.setParam("all");
}
+ if (dotWhenNoCursor) {
+ vlog.info(_("DotWhenNoCursor is deprecated, set AlwaysCursor to 1 and CursorType to 'Dot' instead"));
+
+ alwaysCursor.setParam(true);
+ cursorType.setParam("Dot");
+ }
}
static void
@@ -535,7 +541,7 @@ create_base_dirs()
{
const char *dir;
- dir = os::getvncconfigdir();
+ dir = core::getvncconfigdir();
if (dir == nullptr) {
vlog.error(_("Could not determine VNC config directory path"));
return;
@@ -551,31 +557,31 @@ create_base_dirs()
vlog.info(_("%%APPDATA%%\\vnc is deprecated, please switch to the %%APPDATA%%\\TigerVNC location."));
#endif
- if (os::mkdir_p(dir, 0755) == -1) {
+ if (core::mkdir_p(dir, 0755) == -1) {
if (errno != EEXIST)
vlog.error(_("Could not create VNC config directory \"%s\": %s"),
dir, strerror(errno));
}
- dir = os::getvncdatadir();
+ dir = core::getvncdatadir();
if (dir == nullptr) {
vlog.error(_("Could not determine VNC data directory path"));
return;
}
- if (os::mkdir_p(dir, 0755) == -1) {
+ if (core::mkdir_p(dir, 0755) == -1) {
if (errno != EEXIST)
vlog.error(_("Could not create VNC data directory \"%s\": %s"),
dir, strerror(errno));
}
- dir = os::getvncstatedir();
+ dir = core::getvncstatedir();
if (dir == nullptr) {
vlog.error(_("Could not determine VNC state directory path"));
return;
}
- if (os::mkdir_p(dir, 0755) == -1) {
+ if (core::mkdir_p(dir, 0755) == -1) {
if (errno != EEXIST)
vlog.error(_("Could not create VNC state directory \"%s\": %s"),
dir, strerror(errno));
@@ -602,7 +608,9 @@ createTunnel(const char *gatewayHost, const char *remoteHost,
cmd2 = strdup(cmd);
while ((percent = strchr(cmd2, '%')) != nullptr)
*percent = '$';
- system(cmd2);
+ int res = system(cmd2);
+ if (res != 0)
+ fprintf(stderr, "Failed to create tunnel: '%s' returned %d\n", cmd2, res);
free(cmd2);
}
@@ -610,10 +618,10 @@ static void mktunnel()
{
const char *gatewayHost;
std::string remoteHost;
- int localPort = findFreeTcpPort();
+ int localPort = network::findFreeTcpPort();
int remotePort;
- getHostAndPort(vncServerName, &remoteHost, &remotePort);
+ network::getHostAndPort(vncServerName, &remoteHost, &remotePort);
snprintf(vncServerName, VNCSERVERNAMELEN, "localhost::%d", localPort);
vncServerName[VNCSERVERNAMELEN - 1] = '\0';
gatewayHost = (const char*)via;
@@ -645,13 +653,13 @@ int main(int argc, char** argv)
bind_textdomain_codeset(PACKAGE_NAME, "UTF-8");
bind_textdomain_codeset("libc", "UTF-8");
- rfb::initStdIOLoggers();
+ core::initStdIOLoggers();
#ifdef WIN32
- rfb::initFileLogger("C:\\temp\\vncviewer.log");
+ core::initFileLogger("C:\\temp\\vncviewer.log");
#else
- rfb::initFileLogger("/tmp/vncviewer.log");
+ core::initFileLogger("/tmp/vncviewer.log");
#endif
- rfb::LogWriter::setLogParams("*:stderr:30");
+ core::LogWriter::setLogParams("*:stderr:30");
#ifdef SIGHUP
signal(SIGHUP, CleanupSignalHandler);
@@ -659,8 +667,6 @@ int main(int argc, char** argv)
signal(SIGINT, CleanupSignalHandler);
signal(SIGTERM, CleanupSignalHandler);
- Configuration::enableViewerParams();
-
/* Load the default parameter settings */
char defaultServerName[VNCSERVERNAMELEN] = "";
try {
@@ -675,40 +681,40 @@ int main(int argc, char** argv)
}
for (int i = 1; i < argc;) {
- /* We need to resolve an ambiguity for booleans */
- if (argv[i][0] == '-' && i+1 < argc) {
- VoidParameter *param;
-
- param = Configuration::getParam(&argv[i][1]);
- if ((param != nullptr) &&
- (dynamic_cast<BoolParameter*>(param) != nullptr)) {
- if ((strcasecmp(argv[i+1], "0") == 0) ||
- (strcasecmp(argv[i+1], "1") == 0) ||
- (strcasecmp(argv[i+1], "true") == 0) ||
- (strcasecmp(argv[i+1], "false") == 0) ||
- (strcasecmp(argv[i+1], "yes") == 0) ||
- (strcasecmp(argv[i+1], "no") == 0)) {
- param->setParam(argv[i+1]);
- i += 2;
- continue;
- }
- }
- }
+ int ret;
- if (Configuration::setParam(argv[i])) {
- i++;
+ ret = core::Configuration::handleParamArg(argc, argv, i);
+ if (ret > 0) {
+ i += ret;
continue;
}
+ if (strcmp(argv[i], "-h") == 0 ||
+ strcmp(argv[i], "--help") == 0) {
+ usage(argv[0]);
+ }
+
+ if (strcmp(argv[i], "-v") == 0 ||
+ strcmp(argv[i], "--version") == 0) {
+ /* We already print version on every start */
+ return 0;
+ }
+
if (argv[i][0] == '-') {
- if (i+1 < argc) {
- if (Configuration::setParam(&argv[i][1], argv[i+1])) {
- i += 2;
- continue;
- }
- }
+ fprintf(stderr, "\n");
+ fprintf(stderr, _("%s: Unrecognized option '%s'\n"),
+ argv[0], argv[i]);
+ fprintf(stderr, _("See '%s --help' for more information.\n"),
+ argv[0]);
+ exit(1);
+ }
- usage(argv[0]);
+ if (vncServerName[0] != '\0') {
+ fprintf(stderr, "\n");
+ fprintf(stderr, _("%s: Extra argument '%s'\n"), argv[0], argv[i]);
+ fprintf(stderr, _("See '%s --help' for more information.\n"),
+ argv[0]);
+ exit(0);
}
strncpy(vncServerName, argv[i], VNCSERVERNAMELEN);
@@ -734,7 +740,7 @@ int main(int argc, char** argv)
create_base_dirs();
- Socket *sock = nullptr;
+ network::Socket* sock = nullptr;
#ifndef WIN32
/* Specifying -via and -listen together is nonsense */
@@ -748,7 +754,7 @@ int main(int argc, char** argv)
#endif
if (listenMode) {
- std::list<SocketListener*> listeners;
+ std::list<network::SocketListener*> listeners;
try {
int port = 5500;
if (isdigit(vncServerName[0]))
@@ -764,7 +770,7 @@ int main(int argc, char** argv)
while (sock == nullptr) {
fd_set rfds;
FD_ZERO(&rfds);
- for (SocketListener* listener : listeners)
+ for (network::SocketListener* listener : listeners)
FD_SET(listener->getFd(), &rfds);
int n = select(FD_SETSIZE, &rfds, nullptr, nullptr, nullptr);
@@ -773,11 +779,11 @@ int main(int argc, char** argv)
vlog.debug("Interrupted select() system call");
continue;
} else {
- throw rdr::socket_error("select", errno);
+ throw core::socket_error("select", errno);
}
}
- for (SocketListener* listener : listeners)
+ for (network::SocketListener* listener : listeners)
if (FD_ISSET(listener->getFd(), &rfds)) {
sock = listener->accept();
if (sock)
diff --git a/vncviewer/vncviewer.desktop.in.in b/vncviewer/vncviewer.desktop.in.in
index 1a91755c..705845d9 100644
--- a/vncviewer/vncviewer.desktop.in.in
+++ b/vncviewer/vncviewer.desktop.in.in
@@ -1,5 +1,5 @@
[Desktop Entry]
-Name=TigerVNC viewer
+Name=TigerVNC
GenericName=Remote desktop viewer
Comment=Connect to VNC server and display remote desktop
Exec=@CMAKE_INSTALL_FULL_BINDIR@/vncviewer
diff --git a/vncviewer/vncviewer.man b/vncviewer/vncviewer.man
index ade45b78..9a8ad001 100644
--- a/vncviewer/vncviewer.man
+++ b/vncviewer/vncviewer.man
@@ -77,24 +77,40 @@ safely.
Automatic selection can be turned off by setting the
\fBAutoSelect\fP parameter to false, or from the options dialog.
-.SH POPUP MENU
-The viewer has a popup menu containing entries which perform various actions.
-It is usually brought up by pressing F8, but this can be configured with the
-MenuKey parameter. Actions which the popup menu can perform include:
-.RS 2
-.IP * 2
-switching in and out of full-screen mode
-.IP *
-quitting the viewer
-.IP *
-generating key events, e.g. sending ctrl-alt-del
-.IP *
-accessing the options dialog and various other dialogs
-.RE
-.PP
-By default, key presses in the popup menu get sent to the VNC server and
-dismiss the popup. So to get an F8 through to the VNC server simply press it
-twice.
+.SH KEYBOARD SHORTCUTS
+
+The viewer can be controlled using certain key combinations, invoking
+special actions instead of passing the keyboard events on to the remote
+session. By default pressing Ctrl+Alt and something else will be
+interpreted as a keyboard shortcut for the viewer, but this can be
+changed witht the \fBShortcutModifiers\fP parameter.
+
+The possible keyboard shortcuts are:
+
+.TP
+Ctrl+Alt
+Releases control of the keyboard and allows system keys to be used
+locally.
+.
+.TP
+Ctrl+Alt+G
+Grabs control of the keyboard and allows system keys (like Alt+Tab) to
+be sent to the remote session.
+.
+.TP
+Ctrl+Alt+Enter
+Toggles full-screen mode.
+.
+.TP
+Ctrl+Alt+M
+Opens a popup menu that can perform various extra actions, such as
+quitting the viewer or opening the options dialog.
+.
+.TP
+Ctrl+Alt+Space
+Temporarily bypasses the keyboard shortcuts, allowing the same key
+combinations to be sent to the remote session.
+.
.SH FULL-SCREEN MODE
A full-screen mode is supported. This is particularly useful when connecting
@@ -115,94 +131,62 @@ This can be accessed from the popup menu or from the "Connection details"
dialog box.
.TP
-.B \-display \fIXdisplay\fP
-Specifies the X display on which the VNC viewer window should appear.
-.
-.TP
-.B \-geometry \fIgeometry\fP
-Initial position of the main VNC viewer window. The format is
-.B \fIwidth\fPx\fIheight\fP+\fIxoffset\fP+\fIyoffset\fP
-, where `+' signs can be replaced with `\-' signs to specify offsets from the
-right and/or from the bottom of the screen. Offsets are optional and the
-window will be placed by the window manager by default.
-.
-.TP
-.B \-listen \fI[port]\fP
-Causes vncviewer to listen on the given port (default 5500) for reverse
-connections from a VNC server. WinVNC supports reverse connections initiated
-using the 'Add new client' menu option or the '\-connect' command-line option.
-Xvnc supports reverse connections with a helper program called
-.B vncconfig.
-.
-.TP
-.B \-SecurityTypes \fIsec-types\fP
-Specify which security schemes to attempt to use when authenticating with
-the server. Valid values are a comma separated list of \fBNone\fP,
-\fBVncAuth\fP, \fBPlain\fP, \fBTLSNone\fP, \fBTLSVnc\fP, \fBTLSPlain\fP,
-\fBX509None\fP, \fBX509Vnc\fP, \fBX509Plain\fP, \fBRA2\fP, \fBRA2ne\fP,
-\fBRA2_256\fP and \fBRA2ne_256\fP. Default is to attempt
-every supported scheme.
+.B \-AcceptClipboard
+Accept clipboard changes from the server. Default is on.
.
.TP
-.B \-passwd, \-PasswordFile \fIpassword-file\fP
-If you are on a filesystem which gives you access to the password file used by
-the server, you can specify it here to avoid typing it in. It will usually be
-\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP, or \fI~/.config/tigervnc/passwd\fP
-if the former is unset.
+.B \-AlertOnFatalError
+Display a dialog with any fatal error before exiting. Default is on.
.
.TP
-.B \-X509CA \fIpath\fP
-Path to CA certificate to use when authenticating remote servers using any
-of the X509 security schemes (X509None, X509Vnc, etc.). Must be in PEM
-format. Default is \fI$XDG_CONFIG_HOME/tigervnc/x509_ca.pem\fP, or
-\fI~/.config/tigervnc/x509_ca.pem\fP.
+.B \-AlwaysCursor
+Show a local cursor when the server sends an invisible cursor. Default is off.
.
.TP
-.B \-X509CRL \fIpath\fP
-Path to certificate revocation list to use in conjunction with
-\fB-X509CA\fP. Must also be in PEM format. Default is
-\fI$XDG_CONFIG_HOME/tigervnc/x509_crl.pem\fP, or
-\fI~/.config/tigervnc/x509_crl.pem\fP.
+.B \-AutoSelect
+Use automatic selection of encoding and pixel format (default is on). Normally
+the viewer tests the speed of the connection to the server and chooses the
+encoding and pixel format appropriately. Turn it off with \fB-AutoSelect=0\fP.
.
.TP
-.B \-Shared
-When you make a connection to a VNC server, all other existing connections are
-normally closed. This option requests that they be left open, allowing you to
-share the desktop with someone already using it.
+.B \-CompressLevel \fIlevel\fP
+Use specified lossless compression level. 0 = Low, 9 = High. Default is 2.
.
.TP
-.B \-ViewOnly
-Specifies that no keyboard or mouse events should be sent to the server.
-Useful if you want to view a desktop without interfering; often needs to be
-combined with
-.B \-Shared.
+.B \-CursorType \fItype\fP
+Specify which cursor type to use when a local cursor is shown. It should be
+either "Dot", or "System". Ignored if AlwaysCursor is off.
+The default is "Dot".
.
.TP
-.B \-AcceptClipboard
-Accept clipboard changes from the server. Default is on.
+.B \-CustomCompressLevel
+Use custom compression level as specified by \fBCompressLevel\fP. Default is
+off.
.
.TP
-.B \-SetPrimary
-Set the primary selection as well as the clipboard selection.
-Default is on.
+.B \-DesktopSize \fIwidth\fPx\fIheight\fP
+Instead of keeping the existing remote screen size, the client will attempt to
+switch to the specified since when connecting. If the server does not support
+the SetDesktopSize message then the screen will retain the original size.
.
.TP
-.B \-MaxCutText \fIbytes\fP
-The maximum size of a clipboard update that will be accepted from a server.
-Default is \fB262144\fP.
+.B \-display \fIXdisplay\fP
+Specifies the X display on which the TigerVNC window should appear.
.
.TP
-.B \-SendClipboard
-Send clipboard changes to the server. Default is on.
+.B \-DotWhenNoCursor (DEPRECATED)
+Show the dot cursor when the server sends an invisible cursor. Replaced by
+\fB-AlwaysCursor\fP and \fB-CursorType=Dot\fP
.
.TP
-.B \-SendPrimary
-Send the primary selection to the server as well as the clipboard
-selection. Default is on.
+.B \-EmulateMiddleButton
+Emulate middle mouse button by pressing left and right mouse buttons
+simultaneously. Default is off.
.
.TP
-.B \-Maximize
-Maximize viewer window.
+.B \-FullColor, \-FullColour
+Tells the VNC server to send full-color pixels in the best format for this
+display. This is default.
.
.TP
.B \-FullScreen
@@ -216,7 +200,7 @@ full-screen mode. Replaced by \fB-FullScreenMode=all\fP
.TP
.B \-FullScreenMode \fImode\fP
Specify which monitors to use when in full screen. It should be either "Current",
-"Selected" (specified by \fB-FullScreenSelectedMonitors\fP) or "All".
+"Selected" (specified by \fB-FullScreenSelectedMonitors\fP) or "All".
The default is "Current".
.
.TP
@@ -229,30 +213,37 @@ The default is "1".
.
.TP
.B \-FullscreenSystemKeys
-Pass special keys (like Alt+Tab) directly to the server when in full-screen
-mode.
+Automatically grab all input from the keyboard when entering full-screen
+and pass special keys (like Alt+Tab) directly to the server.
.
.TP
-.B \-DesktopSize \fIwidth\fPx\fIheight\fP
-Instead of keeping the existing remote screen size, the client will attempt to
-switch to the specified since when connecting. If the server does not support
-the SetDesktopSize message then the screen will retain the original size.
+.B \-geometry \fIgeometry\fP
+Initial position of the main TigerVNC window. The format is
+.B \fIwidth\fPx\fIheight\fP+\fIxoffset\fP+\fIyoffset\fP
+, where `+' signs can be replaced with `\-' signs to specify offsets from the
+right and/or from the bottom of the screen. Offsets are optional and the
+window will be placed by the window manager by default.
.
.TP
-.B \-RemoteResize
-Dynamically resize the remote desktop size as the size of the local client
-window changes. Note that this may not work with all VNC servers.
+.B \-GnuTLSPriority \fIpriority\fP
+GnuTLS priority string that controls the TLS session’s handshake algorithms.
+See the GnuTLS manual for possible values. Default is \fBNORMAL\fP.
.
.TP
-.B \-AutoSelect
-Use automatic selection of encoding and pixel format (default is on). Normally
-the viewer tests the speed of the connection to the server and chooses the
-encoding and pixel format appropriately. Turn it off with \fB-AutoSelect=0\fP.
+.B \-listen \fI[port]\fP
+Causes vncviewer to listen on the given port (default 5500) for reverse
+connections from a VNC server. WinVNC supports reverse connections initiated
+using the 'Add new client' menu option or the '\-connect' command-line option.
+Xvnc supports reverse connections with a helper program called
+.B vncconfig.
.
.TP
-.B \-FullColor, \-FullColour
-Tells the VNC server to send full-color pixels in the best format for this
-display. This is default.
+.B \-Log \fIlogname\fP:\fIdest\fP:\fIlevel\fP[, ...]
+Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP or
+\fBstdout\fP, and \fIlevel\fP is between 0 and 100, 100 meaning most verbose
+output. \fIlogname\fP is usually \fB*\fP meaning all, but you can target a
+specific source file if you know the name of its "LogWriter". Default is
+\fB*:stderr:30\fP.
.
.TP
.B \-LowColorLevel, \-LowColourLevel \fIlevel\fP
@@ -263,54 +254,94 @@ vncviewer. If you would like to force vncviewer to use reduced color level
use \fB-AutoSelect=0\fP parameter.
.
.TP
-.B \-PreferredEncoding \fIencoding\fP
-This option specifies the preferred encoding to use from one of "Tight", "ZRLE",
-"hextile" or "raw".
+.B \-MaxCutText \fIbytes\fP
+The maximum size of a clipboard update that will be accepted from a server.
+Default is \fB262144\fP.
+.
+.TP
+.B \-Maximize
+Maximize viewer window.
.
.TP
.B \-NoJpeg
Disable lossy JPEG compression in Tight encoding. Default is off.
.
.TP
+.B \-passwd, \-PasswordFile \fIpassword-file\fP
+If you are on a filesystem which gives you access to the password file used by
+the server, you can specify it here to avoid typing it in. It will usually be
+\fI$XDG_CONFIG_HOME/tigervnc/passwd\fP, or \fI~/.config/tigervnc/passwd\fP
+if the former is unset.
+.
+.TP
+.B \-PointerEventInterval \fItime\fP
+Time in milliseconds to rate-limit successive pointer events. Default is
+17 ms (60 Hz).
+.
+.TP
+.B \-PreferredEncoding \fIencoding\fP
+This option specifies the preferred encoding to use from one of "Tight",
+"ZRLE", "Hextile", "H.264", or "Raw".
+.
+.TP
.B \-QualityLevel \fIlevel\fP
JPEG quality level. 0 = Low, 9 = High. May be adjusted automatically if
\fB-AutoSelect\fP is turned on. Default is 8.
.
.TP
-.B \-CompressLevel \fIlevel\fP
-Use specified lossless compression level. 0 = Low, 9 = High. Default is 2.
+.B \-ReconnectOnError
+Display a dialog with any error and offer the possibility to retry
+establishing the connection. In case this is off no dialog to
+re-connect will be offered. Default is on.
.
.TP
-.B \-CustomCompressLevel
-Use custom compression level. Default if \fBCompressLevel\fP is specified.
+.B \-RemoteResize
+Dynamically resize the remote desktop size as the size of the local client
+window changes. Note that this may not work with all VNC servers.
.
.TP
-.B \-DotWhenNoCursor
-Show the dot cursor when the server sends an invisible cursor. Default is off.
+.B \-SecurityTypes \fIsec-types\fP
+Specify which security schemes to attempt to use when authenticating with
+the server. Valid values are a comma separated list of \fBNone\fP,
+\fBVncAuth\fP, \fBPlain\fP, \fBTLSNone\fP, \fBTLSVnc\fP, \fBTLSPlain\fP,
+\fBX509None\fP, \fBX509Vnc\fP, \fBX509Plain\fP, \fBRA2\fP, \fBRA2ne\fP,
+\fBRA2_256\fP and \fBRA2ne_256\fP. Default is to attempt
+every supported scheme.
.
.TP
-.B \-PointerEventInterval \fItime\fP
-Time in milliseconds to rate-limit successive pointer events. Default is
-17 ms (60 Hz).
+.B \-SendClipboard
+Send clipboard changes to the server. Default is on.
.
.TP
-.B \-EmulateMiddleButton
-Emulate middle mouse button by pressing left and right mouse buttons
-simultaneously. Default is off.
+.B \-SendPrimary
+Send the primary selection to the server as well as the clipboard
+selection. Default is on.
.
.TP
-.B \-Log \fIlogname\fP:\fIdest\fP:\fIlevel\fP
-Configures the debug log settings. \fIdest\fP can currently be \fBstderr\fP or
-\fBstdout\fP, and \fIlevel\fP is between 0 and 100, 100 meaning most verbose
-output. \fIlogname\fP is usually \fB*\fP meaning all, but you can target a
-specific source file if you know the name of its "LogWriter". Default is
-\fB*:stderr:30\fP.
+.B \-SetPrimary
+Set the primary selection as well as the clipboard selection.
+Default is on.
+.
+.TP
+.B \-Shared
+When you make a connection to a VNC server, all other existing connections are
+normally closed. This option requests that they be left open, allowing you to
+share the desktop with someone already using it.
.
.TP
-.B \-MenuKey \fIkeysym-name\fP
-This option specifies the key which brings up the popup menu. The currently
-supported list is: F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, Pause,
-Scroll_Lock, Escape, Insert, Delete, Home, Page_Up, Page_Down). Default is F8.
+.B \-ShortcutModifiers \fIkeys\fP
+The combination of modifier keys that triggers special actions in the
+viewer instead of being sent to the remote session. Possible values are
+a combination of \fBCtrl\fP, \fBShift\fP, \fBAlt\fP, and \fBSuper\fP.
+Default is \fBCtrl,Alt\fP.
+.
+.TP
+.B \-UseIPv4
+Use IPv4 for incoming and outgoing connections. Default is on.
+.
+.TP
+.B \-UseIPv6
+Use IPv6 for incoming and outgoing connections. Default is on.
.
.TP
\fB\-via\fR \fIgateway\fR
@@ -319,25 +350,36 @@ before connection, connect to the \fIhost\fR through that tunnel
(TigerVNC\-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.
+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. The environment variable \fIVNC_VIA_CMD\fR can override
the default tunnel command of
-\fB/usr/bin/ssh\ -f\ -L\ "$L":"$H":"$R"\ "$G"\ sleep\ 20\fR. The tunnel
+\fB/usr/bin/ssh\ \-f\ \-L\ "$L":"$H":"$R"\ "$G"\ sleep\ 20\fR. The tunnel
command is executed with the environment variables \fIL\fR, \fIH\fR,
\fIR\fR, and \fIG\fR taking the values of the local port number, the remote
host, the port number on the remote host, and the gateway machine
respectively.
.
.TP
-.B \-AlertOnFatalError
-Display a dialog with any fatal error before exiting. Default is on.
+.B \-ViewOnly
+Specifies that no keyboard or mouse events should be sent to the server.
+Useful if you want to view a desktop without interfering; often needs to be
+combined with
+.B \-Shared.
.
.TP
-.B \-ReconnectOnError
-Display a dialog with any error and offer the possibility to retry
-establishing the connection. In case this is off no dialog to
-re-connect will be offered. Default is on.
+.B \-X509CA \fIpath\fP
+Path to CA certificate to use when authenticating remote servers using any
+of the X509 security schemes (X509None, X509Vnc, etc.). Must be in PEM
+format. Default is \fI$XDG_CONFIG_HOME/tigervnc/x509_ca.pem\fP, or
+\fI~/.config/tigervnc/x509_ca.pem\fP.
+.
+.TP
+.B \-X509CRL \fIpath\fP
+Path to certificate revocation list to use in conjunction with
+\fB-X509CA\fP. Must also be in PEM format. Default is
+\fI$XDG_CONFIG_HOME/tigervnc/x509_crl.pem\fP, or
+\fI~/.config/tigervnc/x509_crl.pem\fP.
.SH FILES
.TP
diff --git a/vncviewer/vncviewer.rc.in b/vncviewer/vncviewer.rc.in
index a186ee95..375da7af 100644
--- a/vncviewer/vncviewer.rc.in
+++ b/vncviewer/vncviewer.rc.in
@@ -42,12 +42,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "Comments", "\0"
- VALUE "CompanyName", "TigerVNC project\0"
- VALUE "FileDescription", "TigerVNC client\0"
- VALUE "ProductName", "TigerVNC client\0"
+ VALUE "CompanyName", "TigerVNC team\0"
+ VALUE "FileDescription", "TigerVNC\0"
+ VALUE "ProductName", "TigerVNC\0"
VALUE "FileVersion", "@RCVERSION@\0"
VALUE "InternalName", "vncviewer\0"
- VALUE "LegalCopyright", "Copyright (C) 1999-2024 TigerVNC Team and many others (see README.rst)\0"
+ VALUE "LegalCopyright", "Copyright (C) 1999-2025 TigerVNC team and many others (see README.rst)\0"
VALUE "LegalTrademarks", "TigerVNC\0"
VALUE "OriginalFilename", "vncviewer.exe\0"
VALUE "PrivateBuild", "\0"
diff --git a/vncviewer/win32.c b/vncviewer/win32.c
index b0a3813c..c649f783 100644
--- a/vncviewer/win32.c
+++ b/vncviewer/win32.c
@@ -27,39 +27,50 @@ static HANDLE thread;
static DWORD thread_id;
static HHOOK hook = 0;
+static BYTE kbd_state[256];
static HWND target_wnd = 0;
-static int is_system_hotkey(int vkCode) {
- switch (vkCode) {
- case VK_LWIN:
- case VK_RWIN:
- case VK_SNAPSHOT:
- return 1;
- case VK_TAB:
- if (GetAsyncKeyState(VK_MENU) & 0x8000)
- return 1;
- break;
- case VK_ESCAPE:
- if (GetAsyncKeyState(VK_MENU) & 0x8000)
- return 1;
- if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
- return 1;
- break;
- }
- return 0;
-}
-
static LRESULT CALLBACK keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0) {
KBDLLHOOKSTRUCT* msgInfo = (KBDLLHOOKSTRUCT*)lParam;
- // Grabbing everything seems to mess up some keyboard state that
- // FLTK relies on, so just grab the keys that we normally cannot.
- if (is_system_hotkey(msgInfo->vkCode)) {
- PostMessage(target_wnd, wParam, msgInfo->vkCode,
- (msgInfo->scanCode & 0xff) << 16 |
- (msgInfo->flags & 0xff) << 24);
+ BYTE vkey;
+ BYTE scanCode;
+ BYTE flags;
+
+ vkey = msgInfo->vkCode;
+ scanCode = msgInfo->scanCode;
+ flags = msgInfo->flags;
+
+ // We get the low level vkeys here, but the application code
+ // expects this to have been translated to the generic ones
+ switch (vkey) {
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ vkey = VK_SHIFT;
+ // The extended bit is also always missing for right shift
+ flags &= ~0x01;
+ break;
+ case VK_LCONTROL:
+ case VK_RCONTROL:
+ vkey = VK_CONTROL;
+ break;
+ case VK_LMENU:
+ case VK_RMENU:
+ vkey = VK_MENU;
+ break;
+ }
+
+ // If the key was pressed before the grab was activated, then we
+ // need to avoid intercepting the release event or Windows will get
+ // confused about the state of the key
+ if (((wParam == WM_KEYUP) || (wParam == WM_SYSKEYUP)) &&
+ (kbd_state[msgInfo->vkCode] & 0x80)) {
+ kbd_state[msgInfo->vkCode] &= ~0x80;
+ } else {
+ PostMessage(target_wnd, wParam, vkey,
+ scanCode << 16 | flags << 24);
return 1;
}
}
@@ -76,6 +87,9 @@ static DWORD WINAPI keyboard_thread(LPVOID data)
// Make sure a message queue is created
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD);
+ // We need to know which keys are currently pressed
+ GetKeyboardState(kbd_state);
+
hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook, GetModuleHandle(0), 0);
// If something goes wrong then there is not much we can do.
// Just sit around and wait for WM_QUIT...
diff --git a/win/rfb_win32/AboutDialog.cxx b/win/rfb_win32/AboutDialog.cxx
index a41ceefd..ce876fe5 100644
--- a/win/rfb_win32/AboutDialog.cxx
+++ b/win/rfb_win32/AboutDialog.cxx
@@ -20,14 +20,15 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
#include <rfb_win32/AboutDialog.h>
#include <rfb_win32/Win32Util.h>
-#include <rfb/LogWriter.h>
using namespace rfb;
using namespace rfb::win32;
-static LogWriter vlog("AboutDialog");
+static core::LogWriter vlog("AboutDialog");
AboutDialog AboutDialog::instance;
diff --git a/win/rfb_win32/CleanDesktop.cxx b/win/rfb_win32/CleanDesktop.cxx
index 9713b2cd..5205ed2e 100644
--- a/win/rfb_win32/CleanDesktop.cxx
+++ b/win/rfb_win32/CleanDesktop.cxx
@@ -25,18 +25,20 @@
#include <windows.h>
#include <wininet.h>
#include <shlobj.h>
+
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/CleanDesktop.h>
#include <rfb_win32/CurrentUser.h>
#include <rfb_win32/Registry.h>
-#include <rfb/LogWriter.h>
-#include <rdr/Exception.h>
-#include <os/os.h>
+
#include <set>
using namespace rfb;
using namespace rfb::win32;
-static LogWriter vlog("CleanDesktop");
+static core::LogWriter vlog("CleanDesktop");
struct ActiveDesktop {
@@ -45,7 +47,7 @@ struct ActiveDesktop {
HRESULT result = CoCreateInstance(CLSID_ActiveDesktop, nullptr, CLSCTX_INPROC_SERVER,
IID_IActiveDesktop, (PVOID*)&handle);
if (result != S_OK)
- throw rdr::win32_error("Failed to contact Active Desktop", HRESULT_CODE(result));
+ throw core::win32_error("Failed to contact Active Desktop", HRESULT_CODE(result));
}
~ActiveDesktop() {
if (handle)
diff --git a/win/rfb_win32/Clipboard.cxx b/win/rfb_win32/Clipboard.cxx
index 8fdc79c8..faff6e3d 100644
--- a/win/rfb_win32/Clipboard.cxx
+++ b/win/rfb_win32/Clipboard.cxx
@@ -23,14 +23,15 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
+#include <core/Exception.h>
#include <rfb_win32/Clipboard.h>
#include <rfb_win32/WMShatter.h>
-#include <rfb/util.h>
-
-#include <rfb/LogWriter.h>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -129,7 +130,7 @@ Clipboard::setClipText(const char* text) {
// - Firstly, we must open the clipboard
if (!OpenClipboard(getHandle()))
- throw rdr::win32_error("Unable to open Win32 clipboard", GetLastError());
+ throw core::win32_error("Unable to open Win32 clipboard", GetLastError());
// - Convert the supplied clipboard text into UTF-16 format with CRLF
std::string filtered(convertCRLF(text));
@@ -144,11 +145,11 @@ Clipboard::setClipText(const char* text) {
// - Next, we must clear out any existing data
if (!EmptyClipboard())
- throw rdr::win32_error("Unable to empty Win32 clipboard", GetLastError());
+ throw core::win32_error("Unable to empty Win32 clipboard", GetLastError());
// - Set the new clipboard data
if (!SetClipboardData(CF_UNICODETEXT, clip_handle))
- throw rdr::win32_error("Unable to set Win32 clipboard", GetLastError());
+ throw core::win32_error("Unable to set Win32 clipboard", GetLastError());
clip_handle = nullptr;
vlog.debug("Set clipboard");
diff --git a/win/rfb_win32/CompatibleBitmap.h b/win/rfb_win32/CompatibleBitmap.h
index c8fdf829..4e00a35f 100644
--- a/win/rfb_win32/CompatibleBitmap.h
+++ b/win/rfb_win32/CompatibleBitmap.h
@@ -20,7 +20,7 @@
#define __RFB_WIN32_COMPAT_BITMAP_H__
#include <windows.h>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
namespace rfb {
namespace win32 {
@@ -30,7 +30,7 @@ namespace rfb {
CompatibleBitmap(HDC hdc, int width, int height) {
hbmp = CreateCompatibleBitmap(hdc, width, height);
if (!hbmp)
- throw rdr::win32_error("CreateCompatibleBitmap() failed", GetLastError());
+ throw core::win32_error("CreateCompatibleBitmap() failed", GetLastError());
}
virtual ~CompatibleBitmap() {
if (hbmp) DeleteObject(hbmp);
diff --git a/win/rfb_win32/CurrentUser.cxx b/win/rfb_win32/CurrentUser.cxx
index a9404c94..753967cb 100644
--- a/win/rfb_win32/CurrentUser.cxx
+++ b/win/rfb_win32/CurrentUser.cxx
@@ -23,16 +23,19 @@
#endif
#include <stdlib.h>
-#include <rfb/LogWriter.h>
+
+#include <core/LogWriter.h>
+
#include <rfb_win32/CurrentUser.h>
#include <rfb_win32/Service.h>
+
#include <lmcons.h>
#include <wtsapi32.h>
using namespace rfb;
using namespace win32;
-static LogWriter vlog("CurrentUser");
+static core::LogWriter vlog("CurrentUser");
const char* shellIconClass = "Shell_TrayWnd";
@@ -80,7 +83,7 @@ CurrentUserToken::CurrentUserToken() {
if (!OpenProcessToken(GetCurrentProcess(), GENERIC_ALL, &h)) {
DWORD err = GetLastError();
if (err != ERROR_CALL_NOT_IMPLEMENTED)
- throw rdr::win32_error("OpenProcessToken failed", err);
+ throw core::win32_error("OpenProcessToken failed", err);
h = INVALID_HANDLE_VALUE;
}
}
@@ -96,7 +99,7 @@ ImpersonateCurrentUser::ImpersonateCurrentUser() {
if (!ImpersonateLoggedOnUser(token)) {
DWORD err = GetLastError();
if (err != ERROR_CALL_NOT_IMPLEMENTED)
- throw rdr::win32_error("Failed to impersonate user", GetLastError());
+ throw core::win32_error("Failed to impersonate user", GetLastError());
}
}
@@ -114,7 +117,7 @@ UserName::UserName() {
char buf[UNLEN+1];
DWORD len = UNLEN+1;
if (!GetUserName(buf, &len))
- throw rdr::win32_error("GetUserName failed", GetLastError());
+ throw core::win32_error("GetUserName failed", GetLastError());
assign(buf);
}
diff --git a/win/rfb_win32/DIBSectionBuffer.cxx b/win/rfb_win32/DIBSectionBuffer.cxx
index 3ce99809..e706dd00 100644
--- a/win/rfb_win32/DIBSectionBuffer.cxx
+++ b/win/rfb_win32/DIBSectionBuffer.cxx
@@ -21,17 +21,17 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
#include <rfb_win32/DIBSectionBuffer.h>
#include <rfb_win32/DeviceContext.h>
#include <rfb_win32/BitmapInfo.h>
-#include <rfb/LogWriter.h>
using namespace rfb;
using namespace win32;
-static LogWriter vlog("DIBSectionBuffer");
+static core::LogWriter vlog("DIBSectionBuffer");
DIBSectionBuffer::DIBSectionBuffer(HWND window_)
@@ -87,7 +87,7 @@ void DIBSectionBuffer::initBuffer(const PixelFormat& pf, int w, int h) {
if (!new_bitmap) {
int err = GetLastError();
- throw rdr::win32_error("Unable to create DIB section", err);
+ throw core::win32_error("Unable to create DIB section", err);
}
vlog.debug("recreateBuffer()");
@@ -130,7 +130,7 @@ void DIBSectionBuffer::initBuffer(const PixelFormat& pf, int w, int h) {
// Determine the *actual* DIBSection format
DIBSECTION ds;
if (!GetObject(bitmap, sizeof(ds), &ds))
- throw rdr::win32_error("GetObject", GetLastError());
+ throw core::win32_error("GetObject", GetLastError());
// Correct the "stride" of the DIB
// *** This code DWORD aligns each row - is that right???
diff --git a/win/rfb_win32/DIBSectionBuffer.h b/win/rfb_win32/DIBSectionBuffer.h
index 2f099f39..fa40c02f 100644
--- a/win/rfb_win32/DIBSectionBuffer.h
+++ b/win/rfb_win32/DIBSectionBuffer.h
@@ -26,8 +26,10 @@
#define __RFB_WIN32_DIB_SECTION_BUFFER_H__
#include <windows.h>
+
+#include <core/Region.h>
+
#include <rfb/PixelBuffer.h>
-#include <rfb/Region.h>
#include <rfb/Exception.h>
namespace rfb {
diff --git a/win/rfb_win32/DeviceContext.cxx b/win/rfb_win32/DeviceContext.cxx
index 092279fb..212e3bf1 100644
--- a/win/rfb_win32/DeviceContext.cxx
+++ b/win/rfb_win32/DeviceContext.cxx
@@ -21,12 +21,14 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/DeviceContext.h>
#include <rfb_win32/CompatibleBitmap.h>
#include <rfb_win32/BitmapInfo.h>
-#include <rdr/Exception.h>
-#include <rfb/LogWriter.h>
+using namespace core;
using namespace rfb;
using namespace win32;
@@ -51,10 +53,10 @@ PixelFormat DeviceContext::getPF(HDC dc) {
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biBitCount = 0;
if (!::GetDIBits(dc, bitmap, 0, 1, nullptr, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
- throw rdr::win32_error("Unable to determine device pixel format", GetLastError());
+ throw core::win32_error("Unable to determine device pixel format", GetLastError());
}
if (!::GetDIBits(dc, bitmap, 0, 1, nullptr, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
- throw rdr::win32_error("Unable to determine pixel shifts/palette", GetLastError());
+ throw core::win32_error("Unable to determine pixel shifts/palette", GetLastError());
}
// Set the initial format information
@@ -151,15 +153,15 @@ Rect DeviceContext::getClipBox(HDC dc) {
// Get the display dimensions
RECT cr;
if (!GetClipBox(dc, &cr))
- throw rdr::win32_error("GetClipBox", GetLastError());
- return Rect(cr.left, cr.top, cr.right, cr.bottom);
+ throw core::win32_error("GetClipBox", GetLastError());
+ return {cr.left, cr.top, cr.right, cr.bottom};
}
DeviceDC::DeviceDC(const char* deviceName) {
dc = ::CreateDC("DISPLAY", deviceName, nullptr, nullptr);
if (!dc)
- throw rdr::win32_error("Failed to create DeviceDC", GetLastError());
+ throw core::win32_error("Failed to create DeviceDC", GetLastError());
}
DeviceDC::~DeviceDC() {
@@ -171,7 +173,7 @@ DeviceDC::~DeviceDC() {
WindowDC::WindowDC(HWND wnd) : hwnd(wnd) {
dc = GetDC(wnd);
if (!dc)
- throw rdr::win32_error("GetDC failed", GetLastError());
+ throw core::win32_error("GetDC failed", GetLastError());
}
WindowDC::~WindowDC() {
@@ -183,7 +185,7 @@ WindowDC::~WindowDC() {
CompatibleDC::CompatibleDC(HDC existing) {
dc = CreateCompatibleDC(existing);
if (!dc)
- throw rdr::win32_error("CreateCompatibleDC failed", GetLastError());
+ throw core::win32_error("CreateCompatibleDC failed", GetLastError());
}
CompatibleDC::~CompatibleDC() {
@@ -195,7 +197,7 @@ CompatibleDC::~CompatibleDC() {
BitmapDC::BitmapDC(HDC hdc, HBITMAP hbitmap) : CompatibleDC(hdc){
oldBitmap = (HBITMAP)SelectObject(dc, hbitmap);
if (!oldBitmap)
- throw rdr::win32_error("SelectObject to CompatibleDC failed",
+ throw core::win32_error("SelectObject to CompatibleDC failed",
GetLastError());
}
diff --git a/win/rfb_win32/DeviceContext.h b/win/rfb_win32/DeviceContext.h
index 7e89723c..a04c80a0 100644
--- a/win/rfb_win32/DeviceContext.h
+++ b/win/rfb_win32/DeviceContext.h
@@ -24,8 +24,10 @@
#define __RFB_WIN32_DEVICECONTEXT_H__
#include <windows.h>
+
+#include <core/Rect.h>
+
#include <rfb/PixelFormat.h>
-#include <rfb/Rect.h>
namespace rfb {
@@ -40,8 +42,8 @@ namespace rfb {
operator HDC() const {return dc;}
PixelFormat getPF() const;
static PixelFormat getPF(HDC dc);
- Rect getClipBox() const;
- static Rect getClipBox(HDC dc);
+ core::Rect getClipBox() const;
+ static core::Rect getClipBox(HDC dc);
protected:
HDC dc;
};
diff --git a/win/rfb_win32/DeviceFrameBuffer.cxx b/win/rfb_win32/DeviceFrameBuffer.cxx
index 9d215041..8a7d50f9 100644
--- a/win/rfb_win32/DeviceFrameBuffer.cxx
+++ b/win/rfb_win32/DeviceFrameBuffer.cxx
@@ -27,12 +27,16 @@
#endif
#include <vector>
+
+#include <core/LogWriter.h>
+
#include <rfb_win32/DeviceFrameBuffer.h>
#include <rfb_win32/DeviceContext.h>
#include <rfb_win32/IconInfo.h>
+
#include <rfb/VNCServer.h>
-#include <rfb/LogWriter.h>
+using namespace core;
using namespace rfb;
using namespace win32;
@@ -102,7 +106,7 @@ DeviceFrameBuffer::grabRect(const Rect &rect) {
if (ignoreGrabErrors)
vlog.error("BitBlt failed:%ld", GetLastError());
else
- throw rdr::win32_error("BitBlt failed", GetLastError());
+ throw core::win32_error("BitBlt failed", GetLastError());
}
}
@@ -123,7 +127,7 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
// - If hCursor is null then there is no cursor - clear the old one
if (hCursor == nullptr) {
- server->setCursor(0, 0, Point(), nullptr);
+ server->setCursor(0, 0, {}, nullptr);
return;
}
@@ -138,7 +142,7 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
BITMAP maskInfo;
if (!GetObject(iconInfo.hbmMask, sizeof(BITMAP), &maskInfo))
- throw rdr::win32_error("GetObject() failed", GetLastError());
+ throw core::win32_error("GetObject() failed", GetLastError());
if (maskInfo.bmPlanes != 1)
throw std::invalid_argument("Unsupported multi-plane cursor");
if (maskInfo.bmBitsPixel != 1)
@@ -151,7 +155,7 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
buffer.resize(width * height * 4);
- Point hotspot = Point(iconInfo.xHotspot, iconInfo.yHotspot);
+ Point hotspot(iconInfo.xHotspot, iconInfo.yHotspot);
if (iconInfo.hbmColor) {
// Colour cursor
@@ -174,7 +178,7 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
if (!GetDIBits(dc, iconInfo.hbmColor, 0, height,
buffer.data(), (LPBITMAPINFO)&bi, DIB_RGB_COLORS))
- throw rdr::win32_error("GetDIBits", GetLastError());
+ throw core::win32_error("GetDIBits", GetLastError());
// We may not get the RGBA order we want, so shuffle things around
int ridx, gidx, bidx, aidx;
@@ -217,7 +221,7 @@ void DeviceFrameBuffer::setCursor(HCURSOR hCursor, VNCServer* server)
if (!GetBitmapBits(iconInfo.hbmMask,
maskInfo.bmWidthBytes * maskInfo.bmHeight, mask.data()))
- throw rdr::win32_error("GetBitmapBits", GetLastError());
+ throw core::win32_error("GetBitmapBits", GetLastError());
bool doOutline = false;
uint8_t* rwbuffer = buffer.data();
diff --git a/win/rfb_win32/DeviceFrameBuffer.h b/win/rfb_win32/DeviceFrameBuffer.h
index e9f06cb0..67b1cd87 100644
--- a/win/rfb_win32/DeviceFrameBuffer.h
+++ b/win/rfb_win32/DeviceFrameBuffer.h
@@ -27,11 +27,14 @@
#define __RFB_WIN32_DEVICE_FRAME_BUFFER_H__
#include <windows.h>
+
+#include <core/Configuration.h>
+#include <core/Region.h>
+
#include <rfb_win32/DIBSectionBuffer.h>
+
#include <rfb/Cursor.h>
-#include <rfb/Region.h>
#include <rfb/Exception.h>
-#include <rfb/Configuration.h>
namespace rfb {
@@ -63,13 +66,13 @@ namespace rfb {
class DeviceFrameBuffer : public DIBSectionBuffer {
public:
- DeviceFrameBuffer(HDC deviceContext, const Rect& area_=Rect());
+ DeviceFrameBuffer(HDC deviceContext, const core::Rect& area_={});
virtual ~DeviceFrameBuffer();
// - FrameBuffer overrides
- virtual void grabRect(const Rect &rect);
- void grabRegion(const Region &region) override;
+ virtual void grabRect(const core::Rect& rect);
+ void grabRegion(const core::Region& region) override;
// - DeviceFrameBuffer specific methods
@@ -79,15 +82,15 @@ namespace rfb {
// Only set this if you are sure you'll capture the errors some other way!
void setIgnoreGrabErrors(bool ie) {ignoreGrabErrors=ie;}
- static BoolParameter useCaptureBlt;
+ static core::BoolParameter useCaptureBlt;
protected:
// Translate supplied Desktop coordinates into Device-relative coordinates
// This translation may have been affected at start-time by the supplied sub-rect.
- Point desktopToDevice(const Point p) const {return p.translate(deviceCoords.tl);}
+ core::Point desktopToDevice(const core::Point p) const {return p.translate(deviceCoords.tl);}
HDC device;
- Rect deviceCoords;
+ core::Rect deviceCoords;
bool ignoreGrabErrors;
};
diff --git a/win/rfb_win32/Dialog.cxx b/win/rfb_win32/Dialog.cxx
index cf8b2475..264db3f8 100644
--- a/win/rfb_win32/Dialog.cxx
+++ b/win/rfb_win32/Dialog.cxx
@@ -25,9 +25,10 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/Dialog.h>
-#include <rfb/LogWriter.h>
-#include <rdr/Exception.h>
#include <rfb_win32/Win32Util.h>
#ifdef _DIALOG_CAPTURE
@@ -43,8 +44,8 @@
using namespace rfb;
using namespace rfb::win32;
-static LogWriter dlog("Dialog");
-static LogWriter plog("PropSheet");
+static core::LogWriter dlog("Dialog");
+static core::LogWriter plog("PropSheet");
Dialog::Dialog(HINSTANCE inst_)
@@ -65,7 +66,7 @@ bool Dialog::showDialog(const char* resource, HWND owner)
INT_PTR result = DialogBoxParam(inst, resource, owner,
staticDialogProc, (LPARAM)this);
if (result<0)
- throw rdr::win32_error("DialogBoxParam failed", GetLastError());
+ throw core::win32_error("DialogBoxParam failed", GetLastError());
alreadyShowing = false;
return (result == 1);
}
@@ -275,7 +276,7 @@ bool PropSheet::showPropSheet(HWND owner_, bool showApply, bool showCtxtHelp, bo
handle = (HWND)PropertySheet(&header);
if ((handle == nullptr) || (handle == (HWND)-1))
- throw rdr::win32_error("PropertySheet failed", GetLastError());
+ throw core::win32_error("PropertySheet failed", GetLastError());
centerWindow(handle, owner_);
plog.info("Created %p", handle);
diff --git a/win/rfb_win32/EventManager.cxx b/win/rfb_win32/EventManager.cxx
index 995c4fe2..6f45a35c 100644
--- a/win/rfb_win32/EventManager.cxx
+++ b/win/rfb_win32/EventManager.cxx
@@ -25,8 +25,11 @@
#include <stdexcept>
#include <rfb_win32/EventManager.h>
-#include <rfb/LogWriter.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
diff --git a/win/rfb_win32/IconInfo.h b/win/rfb_win32/IconInfo.h
index 991a5a13..6348e7b2 100644
--- a/win/rfb_win32/IconInfo.h
+++ b/win/rfb_win32/IconInfo.h
@@ -20,7 +20,7 @@
#define __RFB_WIN32_ICONINFO_H__
#include <windows.h>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
namespace rfb {
namespace win32 {
@@ -28,7 +28,7 @@ namespace rfb {
struct IconInfo : public ICONINFO {
IconInfo(HICON icon) {
if (!GetIconInfo(icon, this))
- throw rdr::win32_error("GetIconInfo() failed", GetLastError());
+ throw core::win32_error("GetIconInfo() failed", GetLastError());
}
~IconInfo() {
if (hbmColor)
diff --git a/win/rfb_win32/IntervalTimer.h b/win/rfb_win32/IntervalTimer.h
index b62040b3..2e15821c 100644
--- a/win/rfb_win32/IntervalTimer.h
+++ b/win/rfb_win32/IntervalTimer.h
@@ -23,6 +23,8 @@
#ifndef __RFB_WIN32_INTERVAL_TIMER_H__
#define __RFB_WIN32_INTERVAL_TIMER_H__
+#include <core/Exception.h>
+
namespace rfb {
namespace win32 {
@@ -41,7 +43,7 @@ namespace rfb {
if (!active || interval_ != interval) {
interval = interval_;
if (!SetTimer(hwnd, id, interval, nullptr))
- throw rdr::win32_error("SetTimer", GetLastError());
+ throw core::win32_error("SetTimer", GetLastError());
active = true;
}
}
diff --git a/win/rfb_win32/LaunchProcess.cxx b/win/rfb_win32/LaunchProcess.cxx
index 93bd21fe..a9e43fa6 100644
--- a/win/rfb_win32/LaunchProcess.cxx
+++ b/win/rfb_win32/LaunchProcess.cxx
@@ -22,10 +22,12 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+
#include <rfb_win32/LaunchProcess.h>
#include <rfb_win32/ModuleFileName.h>
#include <rfb_win32/Win32Util.h>
-#include <rdr/Exception.h>
+
#include <stdio.h>
using namespace rfb;
@@ -53,7 +55,7 @@ void LaunchProcess::start(HANDLE userToken, bool createConsole) {
char buf[256];
HDESK desktop = GetThreadDesktop(GetCurrentThreadId());
if (!GetUserObjectInformation(desktop, UOI_NAME, buf, 256, &size))
- throw rdr::win32_error("Unable to launch process", GetLastError());
+ throw core::win32_error("Unable to launch process", GetLastError());
snprintf(desktopName, 256, "WinSta0\\%s", buf);
@@ -95,7 +97,7 @@ void LaunchProcess::start(HANDLE userToken, bool createConsole) {
flags, nullptr, nullptr,
&sinfo, &procInfo);
if (!success)
- throw rdr::win32_error("Unable to launch process", GetLastError());
+ throw core::win32_error("Unable to launch process", GetLastError());
// Wait for it to finish initialising
WaitForInputIdle(procInfo.hProcess, 15000);
@@ -119,7 +121,7 @@ bool LaunchProcess::await(DWORD timeoutMs) {
detach();
return true;
} else if (result == WAIT_FAILED) {
- throw rdr::win32_error("await() failed", GetLastError());
+ throw core::win32_error("await() failed", GetLastError());
}
return false;
}
diff --git a/win/rfb_win32/LocalMem.h b/win/rfb_win32/LocalMem.h
index 5280dea3..54ac896b 100644
--- a/win/rfb_win32/LocalMem.h
+++ b/win/rfb_win32/LocalMem.h
@@ -20,7 +20,7 @@
#define __RFB_WIN32_LOCALMEM_H__
#include <windows.h>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
namespace rfb {
namespace win32 {
@@ -28,7 +28,7 @@ namespace rfb {
// Allocate and/or manage LocalAlloc memory.
struct LocalMem {
LocalMem(int size) : ptr(LocalAlloc(LMEM_FIXED, size)) {
- if (!ptr) throw rdr::win32_error("LocalAlloc", GetLastError());
+ if (!ptr) throw core::win32_error("LocalAlloc", GetLastError());
}
LocalMem(void* p) : ptr(p) {}
~LocalMem() {LocalFree(ptr);}
diff --git a/win/rfb_win32/MonitorInfo.cxx b/win/rfb_win32/MonitorInfo.cxx
index 5d715ef6..5b1f5533 100644
--- a/win/rfb_win32/MonitorInfo.cxx
+++ b/win/rfb_win32/MonitorInfo.cxx
@@ -20,10 +20,11 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/Win32Util.h>
-#include <rdr/Exception.h>
-#include <rfb/LogWriter.h>
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
@@ -33,6 +34,7 @@
#define max(a,b) ((a)>(b)?(a):(b))
#endif
+using namespace core;
using namespace rfb;
using namespace win32;
@@ -44,7 +46,7 @@ static void fillMonitorInfo(HMONITOR monitor, MONITORINFOEXA* mi) {
memset(mi, 0, sizeof(MONITORINFOEXA));
mi->cbSize = sizeof(MONITORINFOEXA);
if (!GetMonitorInfo(monitor, mi))
- throw rdr::win32_error("Failed to GetMonitorInfo", GetLastError());
+ throw core::win32_error("Failed to GetMonitorInfo", GetLastError());
vlog.debug("Monitor is %ld,%ld-%ld,%ld", mi->rcMonitor.left, mi->rcMonitor.top, mi->rcMonitor.right, mi->rcMonitor.bottom);
vlog.debug("Work area is %ld,%ld-%ld,%ld", mi->rcWork.left, mi->rcWork.top, mi->rcWork.right, mi->rcWork.bottom);
vlog.debug("Device is \"%s\"", mi->szDevice);
@@ -57,7 +59,7 @@ MonitorInfo::MonitorInfo(HWND window) {
HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST);
if (!monitor)
- throw rdr::win32_error("Failed to get monitor", GetLastError());
+ throw core::win32_error("Failed to get monitor", GetLastError());
fillMonitorInfo(monitor, this);
}
@@ -67,7 +69,7 @@ MonitorInfo::MonitorInfo(const RECT& r) {
HMONITOR monitor = MonitorFromRect(&r, MONITOR_DEFAULTTONEAREST);
if (!monitor)
- throw rdr::win32_error("Failed to get monitor", GetLastError());
+ throw core::win32_error("Failed to get monitor", GetLastError());
fillMonitorInfo(monitor, this);
}
diff --git a/win/rfb_win32/MsgWindow.cxx b/win/rfb_win32/MsgWindow.cxx
index c89db851..4b20dc88 100644
--- a/win/rfb_win32/MsgWindow.cxx
+++ b/win/rfb_win32/MsgWindow.cxx
@@ -23,16 +23,18 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/MsgWindow.h>
#include <rfb_win32/WMShatter.h>
-#include <rfb/LogWriter.h>
-#include <rdr/Exception.h>
+
#include <malloc.h>
using namespace rfb;
using namespace rfb::win32;
-static LogWriter vlog("MsgWindow");
+static core::LogWriter vlog("MsgWindow");
//
// -=- MsgWindowClass
@@ -82,7 +84,7 @@ MsgWindowClass::MsgWindowClass() : classAtom(0) {
wndClass.lpszClassName = "rfb::win32::MsgWindowClass";
classAtom = RegisterClass(&wndClass);
if (!classAtom) {
- throw rdr::win32_error("Unable to register MsgWindow window class", GetLastError());
+ throw core::win32_error("Unable to register MsgWindow window class", GetLastError());
}
}
@@ -104,7 +106,7 @@ MsgWindow::MsgWindow(const char* name_) : name(name_), handle(nullptr) {
name.c_str(), WS_OVERLAPPED, 0, 0, 10, 10,
nullptr, nullptr, baseClass.instance, this);
if (!handle) {
- throw rdr::win32_error("Unable to create WMNotifier window instance", GetLastError());
+ throw core::win32_error("Unable to create WMNotifier window instance", GetLastError());
}
vlog.debug("Created window \"%s\" (%p)", name.c_str(), handle);
}
diff --git a/win/rfb_win32/RegConfig.cxx b/win/rfb_win32/RegConfig.cxx
index d9835201..057882b9 100644
--- a/win/rfb_win32/RegConfig.cxx
+++ b/win/rfb_win32/RegConfig.cxx
@@ -24,15 +24,17 @@
#include <malloc.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/RegConfig.h>
-#include <rfb/LogWriter.h>
+
//#include <rdr/HexOutStream.h>
using namespace rfb;
using namespace rfb::win32;
-static LogWriter vlog("RegConfig");
+static core::LogWriter vlog("RegConfig");
RegConfig::RegConfig(EventManager* em)
@@ -66,10 +68,10 @@ void RegConfig::loadRegistryConfig(RegKey& key) {
const char *name = key.getValueName(i++);
if (!name) break;
std::string value = key.getRepresentation(name);
- if (!Configuration::setParam(name, value.c_str()))
+ if (!core::Configuration::setParam(name, value.c_str()))
vlog.info("Unable to process %s", name);
}
- } catch (rdr::win32_error& e) {
+ } catch (core::win32_error& e) {
if (e.err != ERROR_INVALID_HANDLE)
vlog.error("%s", e.what());
}
@@ -91,17 +93,21 @@ void RegConfig::processEvent(HANDLE /*event*/) {
}
-RegConfigThread::RegConfigThread() : config(&eventMgr), thread_id(-1) {
+RegConfigThread::RegConfigThread() : config(&eventMgr), thread(nullptr),
+ thread_id(-1) {
}
RegConfigThread::~RegConfigThread() {
PostThreadMessage(thread_id, WM_QUIT, 0, 0);
- wait();
+ if (thread != nullptr) {
+ thread->join();
+ delete thread;
+ }
}
bool RegConfigThread::start(const HKEY rootKey, const char* keyname) {
if (config.setKey(rootKey, keyname)) {
- Thread::start();
+ thread = new std::thread(&RegConfigThread::worker, this);
while (thread_id == (DWORD)-1)
Sleep(0);
return true;
@@ -115,5 +121,5 @@ void RegConfigThread::worker() {
thread_id = GetCurrentThreadId();
while ((result = eventMgr.getMessage(&msg, nullptr, 0, 0)) > 0) {}
if (result < 0)
- throw rdr::win32_error("RegConfigThread failed", GetLastError());
+ throw core::win32_error("RegConfigThread failed", GetLastError());
}
diff --git a/win/rfb_win32/RegConfig.h b/win/rfb_win32/RegConfig.h
index 401cb148..4a2f8ca8 100644
--- a/win/rfb_win32/RegConfig.h
+++ b/win/rfb_win32/RegConfig.h
@@ -24,9 +24,8 @@
#ifndef __RFB_WIN32_REG_CONFIG_H__
#define __RFB_WIN32_REG_CONFIG_H__
-#include <os/Thread.h>
+#include <thread>
-#include <rfb/Configuration.h>
#include <rfb_win32/Registry.h>
#include <rfb_win32/EventManager.h>
#include <rfb_win32/Handle.h>
@@ -64,7 +63,7 @@ namespace rfb {
RegKey key;
};
- class RegConfigThread : os::Thread {
+ class RegConfigThread {
public:
RegConfigThread();
~RegConfigThread();
@@ -72,9 +71,10 @@ namespace rfb {
// Start the thread, reading from the specified key
bool start(const HKEY rootkey, const char* keyname);
protected:
- void worker() override;
+ void worker();
EventManager eventMgr;
RegConfig config;
+ std::thread* thread;
DWORD thread_id;
};
diff --git a/win/rfb_win32/Registry.cxx b/win/rfb_win32/Registry.cxx
index d40c9016..aef15a1b 100644
--- a/win/rfb_win32/Registry.cxx
+++ b/win/rfb_win32/Registry.cxx
@@ -22,14 +22,17 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb_win32/Registry.h>
#include <rfb_win32/Security.h>
+
#include <rdr/MemOutStream.h>
#include <rdr/HexOutStream.h>
#include <rdr/HexInStream.h>
+
#include <stdlib.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
// These flags are required to control access control inheritance,
// but are not defined by VC6's headers. These definitions comes
@@ -42,6 +45,7 @@
#endif
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -54,7 +58,7 @@ RegKey::RegKey() : key(nullptr), freeKey(false), valueName(nullptr), valueNameBu
RegKey::RegKey(const HKEY k) : key(nullptr), freeKey(false), valueName(nullptr), valueNameBufLen(0) {
LONG result = RegOpenKeyEx(k, nullptr, 0, KEY_ALL_ACCESS, &key);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegOpenKeyEx(HKEY)", result);
+ throw core::win32_error("RegOpenKeyEx(HKEY)", result);
vlog.debug("Duplicated %p to %p", k, key);
freeKey = true;
}
@@ -62,7 +66,7 @@ RegKey::RegKey(const HKEY k) : key(nullptr), freeKey(false), valueName(nullptr),
RegKey::RegKey(const RegKey& k) : key(nullptr), freeKey(false), valueName(nullptr), valueNameBufLen(0) {
LONG result = RegOpenKeyEx(k.key, nullptr, 0, KEY_ALL_ACCESS, &key);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegOpenKeyEx(RegKey&)", result);
+ throw core::win32_error("RegOpenKeyEx(RegKey&)", result);
vlog.debug("Duplicated %p to %p", k.key, key);
freeKey = true;
}
@@ -86,7 +90,7 @@ bool RegKey::createKey(const RegKey& root, const char* name) {
LONG result = RegCreateKey(root.key, name, &key);
if (result != ERROR_SUCCESS) {
vlog.error("RegCreateKey(%p, %s): %lx", root.key, name, result);
- throw rdr::win32_error("RegCreateKeyEx", result);
+ throw core::win32_error("RegCreateKeyEx", result);
}
vlog.debug("createKey(%p,%s) = %p", root.key, name, key);
freeKey = true;
@@ -97,7 +101,7 @@ void RegKey::openKey(const RegKey& root, const char* name, bool readOnly) {
close();
LONG result = RegOpenKeyEx(root.key, name, 0, readOnly ? KEY_READ : KEY_ALL_ACCESS, &key);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegOpenKeyEx (open)", result);
+ throw core::win32_error("RegOpenKeyEx (open)", result);
vlog.debug("openKey(%p,%s,%s) = %p", root.key, name,
readOnly ? "ro" : "rw", key);
freeKey = true;
@@ -109,7 +113,7 @@ void RegKey::setDACL(const PACL acl, bool inherit) {
DACL_SECURITY_INFORMATION |
(inherit ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION),
nullptr, nullptr, acl, nullptr)) != ERROR_SUCCESS)
- throw rdr::win32_error("RegKey::setDACL failed", result);
+ throw core::win32_error("RegKey::setDACL failed", result);
}
void RegKey::close() {
@@ -123,19 +127,19 @@ void RegKey::close() {
void RegKey::deleteKey(const char* name) const {
LONG result = RegDeleteKey(key, name);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegDeleteKey", result);
+ throw core::win32_error("RegDeleteKey", result);
}
void RegKey::deleteValue(const char* name) const {
LONG result = RegDeleteValue(key, name);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegDeleteValue", result);
+ throw core::win32_error("RegDeleteValue", result);
}
void RegKey::awaitChange(bool watchSubTree, DWORD filter, HANDLE event) const {
LONG result = RegNotifyChangeKeyValue(key, watchSubTree, filter, event, event != nullptr);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegNotifyChangeKeyValue", result);
+ throw core::win32_error("RegNotifyChangeKeyValue", result);
}
@@ -144,22 +148,22 @@ RegKey::operator HKEY() const {return key;}
void RegKey::setExpandString(const char* valname, const char* value) const {
LONG result = RegSetValueEx(key, valname, 0, REG_EXPAND_SZ, (const BYTE*)value, (strlen(value)+1)*sizeof(char));
- if (result != ERROR_SUCCESS) throw rdr::win32_error("setExpandString", result);
+ if (result != ERROR_SUCCESS) throw core::win32_error("setExpandString", result);
}
void RegKey::setString(const char* valname, const char* value) const {
LONG result = RegSetValueEx(key, valname, 0, REG_SZ, (const BYTE*)value, (strlen(value)+1)*sizeof(char));
- if (result != ERROR_SUCCESS) throw rdr::win32_error("setString", result);
+ if (result != ERROR_SUCCESS) throw core::win32_error("setString", result);
}
void RegKey::setBinary(const char* valname, const void* value, size_t length) const {
LONG result = RegSetValueEx(key, valname, 0, REG_BINARY, (const BYTE*)value, length);
- if (result != ERROR_SUCCESS) throw rdr::win32_error("setBinary", result);
+ if (result != ERROR_SUCCESS) throw core::win32_error("setBinary", result);
}
void RegKey::setInt(const char* valname, int value) const {
LONG result = RegSetValueEx(key, valname, 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
- if (result != ERROR_SUCCESS) throw rdr::win32_error("setInt", result);
+ if (result != ERROR_SUCCESS) throw core::win32_error("setInt", result);
}
void RegKey::setBool(const char* valname, bool value) const {
@@ -214,11 +218,11 @@ std::string RegKey::getRepresentation(const char* valname) const {
DWORD type, length;
LONG result = RegQueryValueEx(key, valname, nullptr, &type, nullptr, &length);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("Get registry value length", result);
+ throw core::win32_error("Get registry value length", result);
std::vector<uint8_t> data(length);
result = RegQueryValueEx(key, valname, nullptr, &type, (BYTE*)data.data(), &length);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("Get registry value", result);
+ throw core::win32_error("Get registry value", result);
switch (type) {
case REG_BINARY:
@@ -243,7 +247,7 @@ std::string RegKey::getRepresentation(const char* valname) const {
std::string str((char*)data.data(), length);
DWORD required = ExpandEnvironmentStrings(str.c_str(), nullptr, 0);
if (required==0)
- throw rdr::win32_error("ExpandEnvironmentStrings", GetLastError());
+ throw core::win32_error("ExpandEnvironmentStrings", GetLastError());
std::vector<char> expanded(required);
length = ExpandEnvironmentStrings(str.c_str(), expanded.data(), required);
if (required<length)
@@ -271,7 +275,7 @@ const char* RegKey::getValueName(int i) {
DWORD maxValueNameLen;
LONG result = RegQueryInfoKey(key, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &maxValueNameLen, nullptr, nullptr, nullptr);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegQueryInfoKey", result);
+ throw core::win32_error("RegQueryInfoKey", result);
if (valueNameBufLen < maxValueNameLen + 1) {
valueNameBufLen = maxValueNameLen + 1;
delete [] valueName;
@@ -281,7 +285,7 @@ const char* RegKey::getValueName(int i) {
result = RegEnumValue(key, i, valueName, &length, nullptr, nullptr, nullptr, nullptr);
if (result == ERROR_NO_MORE_ITEMS) return nullptr;
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegEnumValue", result);
+ throw core::win32_error("RegEnumValue", result);
return valueName;
}
@@ -289,7 +293,7 @@ const char* RegKey::getKeyName(int i) {
DWORD maxValueNameLen;
LONG result = RegQueryInfoKey(key, nullptr, nullptr, nullptr, nullptr, &maxValueNameLen, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegQueryInfoKey", result);
+ throw core::win32_error("RegQueryInfoKey", result);
if (valueNameBufLen < maxValueNameLen + 1) {
valueNameBufLen = maxValueNameLen + 1;
delete [] valueName;
@@ -299,6 +303,6 @@ const char* RegKey::getKeyName(int i) {
result = RegEnumKeyEx(key, i, valueName, &length, nullptr, nullptr, nullptr, nullptr);
if (result == ERROR_NO_MORE_ITEMS) return nullptr;
if (result != ERROR_SUCCESS)
- throw rdr::win32_error("RegEnumKey", result);
+ throw core::win32_error("RegEnumKey", result);
return valueName;
}
diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
index b930328f..de986ead 100644
--- a/win/rfb_win32/SDisplay.cxx
+++ b/win/rfb_win32/SDisplay.cxx
@@ -27,6 +27,8 @@
#include <assert.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/SDisplay.h>
#include <rfb_win32/Service.h>
#include <rfb_win32/TsSessions.h>
@@ -35,10 +37,11 @@
#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/SDisplayCorePolling.h>
#include <rfb_win32/SDisplayCoreWMHooks.h>
-#include <rfb/LogWriter.h>
+#include <rfb/VNCServer.h>
#include <rfb/ledStates.h>
+using namespace core;
using namespace rdr;
using namespace rfb;
using namespace rfb::win32;
@@ -48,11 +51,13 @@ static LogWriter vlog("SDisplay");
// - SDisplay-specific configuration options
IntParameter rfb::win32::SDisplay::updateMethod("UpdateMethod",
- "How to discover desktop updates; 0 - Polling, 1 - Application hooking, 2 - Driver hooking.", 0);
+ "How to discover desktop updates; 0 - Polling, 1 - Application hooking, 2 - Driver hooking.",
+ 0, 0, 2);
BoolParameter rfb::win32::SDisplay::disableLocalInputs("DisableLocalInputs",
"Disable local keyboard and pointer input while the server is in use", false);
-StringParameter rfb::win32::SDisplay::disconnectAction("DisconnectAction",
- "Action to perform when all clients have disconnected. (None, Lock, Logoff)", "None");
+EnumParameter rfb::win32::SDisplay::disconnectAction("DisconnectAction",
+ "Action to perform when all clients have disconnected. (None, Lock, Logoff)",
+ {"None", "Lock", "Logoff"}, "None");
StringParameter displayDevice("DisplayDevice",
"Display device name of the monitor to be remoted, or empty to export the whole desktop.", "");
BoolParameter rfb::win32::SDisplay::removeWallpaper("RemoveWallpaper",
@@ -123,12 +128,12 @@ void SDisplay::stop()
// If we successfully start()ed then perform the DisconnectAction
if (core) {
CurrentUserToken cut;
- if (stricmp(disconnectAction, "Logoff") == 0) {
+ if (disconnectAction == "Logoff") {
if (!cut.h)
vlog.info("Ignoring DisconnectAction=Logoff - no current user");
else
ExitWindowsEx(EWX_LOGOFF, 0);
- } else if (stricmp(disconnectAction, "Lock") == 0) {
+ } else if (disconnectAction == "Lock") {
if (!cut.h) {
vlog.info("Ignoring DisconnectAction=Lock - no current user");
} else {
@@ -460,8 +465,8 @@ SDisplay::recreatePixelBuffer(bool force) {
Rect newScreenRect;
if (strlen(displayDevice) > 0) {
MonitorInfo info(displayDevice);
- newScreenRect = Rect(info.rcMonitor.left, info.rcMonitor.top,
- info.rcMonitor.right, info.rcMonitor.bottom);
+ newScreenRect = {info.rcMonitor.left, info.rcMonitor.top,
+ info.rcMonitor.right, info.rcMonitor.bottom};
} else {
newScreenRect = new_device->getClipBox();
}
diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h
index aa1a69e5..e116b483 100644
--- a/win/rfb_win32/SDisplay.h
+++ b/win/rfb_win32/SDisplay.h
@@ -24,9 +24,11 @@
#ifndef __RFB_SDISPLAY_H__
#define __RFB_SDISPLAY_H__
+#include <core/Configuration.h>
+
#include <rfb/SDesktop.h>
#include <rfb/UpdateTracker.h>
-#include <rfb/Configuration.h>
+
#include <rfb_win32/Handle.h>
#include <rfb_win32/EventManager.h>
#include <rfb_win32/SInput.h>
@@ -48,7 +50,7 @@ namespace rfb {
class SDisplayCore {
public:
virtual ~SDisplayCore() {};
- virtual void setScreenRect(const Rect& screenRect_) = 0;
+ virtual void setScreenRect(const core::Rect& screenRect_) = 0;
virtual void flushUpdates() = 0;
virtual const char* methodName() const = 0;
};
@@ -80,7 +82,8 @@ namespace rfb {
void handleClipboardRequest() override;
void handleClipboardAnnounce(bool available) override;
void handleClipboardData(const char* data) override;
- void pointerEvent(const Point& pos, uint16_t buttonmask) override;
+ void pointerEvent(const core::Point& pos,
+ uint16_t buttonmask) override;
void keyEvent(uint32_t keysym, uint32_t keycode, bool down) override;
// -=- Clipboard events
@@ -107,11 +110,11 @@ namespace rfb {
queryConnectionHandler = qch;
}
- static IntParameter updateMethod;
- static BoolParameter disableLocalInputs;
- static StringParameter disconnectAction;
- static BoolParameter removeWallpaper;
- static BoolParameter disableEffects;
+ static core::IntParameter updateMethod;
+ static core::BoolParameter disableLocalInputs;
+ static core::EnumParameter disconnectAction;
+ static core::BoolParameter removeWallpaper;
+ static core::BoolParameter disableEffects;
// -=- Use by VNC Config to determine whether hooks are available
static bool areHooksAvailable();
@@ -133,7 +136,7 @@ namespace rfb {
DeviceContext* device;
// -=- The coordinates of Window's entire virtual Screen
- Rect screenRect;
+ core::Rect screenRect;
// -=- All changes are collected in UN-CLIPPED Display coords and merged
// When they are to be flushed to the VNCServer, they are changed
@@ -162,8 +165,8 @@ namespace rfb {
// Cursor
WMCursor* cursor;
WMCursor::Info old_cursor;
- Region old_cursor_region;
- Point cursor_renderpos;
+ core::Region old_cursor_region;
+ core::Point cursor_renderpos;
// -=- Event signalled to trigger an update to be flushed
Handle updateEvent;
diff --git a/win/rfb_win32/SDisplayCorePolling.cxx b/win/rfb_win32/SDisplayCorePolling.cxx
index bd8883e6..0a600c97 100644
--- a/win/rfb_win32/SDisplayCorePolling.cxx
+++ b/win/rfb_win32/SDisplayCorePolling.cxx
@@ -22,9 +22,11 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
#include <rfb_win32/SDisplayCorePolling.h>
-#include <rfb/LogWriter.h>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -37,7 +39,9 @@ const unsigned int SDisplayCorePolling::pollTimerId = 1;
SDisplayCorePolling::SDisplayCorePolling(SDisplay* d, UpdateTracker* ut, int pollInterval_)
: MsgWindow("rfb::win32::SDisplayCorePolling"),
pollTimer(getHandle(), pollTimerId), pollNextStrip(false), display(d), updateTracker(ut) {
- pollInterval = __rfbmax(10, (pollInterval_ / POLLING_SEGMENTS));
+ pollInterval = pollInterval_ / POLLING_SEGMENTS;
+ if (pollInterval < 10)
+ pollInterval = 10;
copyrect.setUpdateTracker(ut);
}
@@ -78,7 +82,8 @@ void SDisplayCorePolling::flushUpdates() {
// No. Poll the next section
pollrect.tl.y = pollNextY;
pollNextY += pollIncrementY;
- pollrect.br.y = __rfbmin(pollNextY, pollrect.br.y);
+ if (pollrect.br.y > pollNextY)
+ pollrect.br.y = pollNextY;
updateTracker->add_changed(pollrect);
}
}
diff --git a/win/rfb_win32/SDisplayCorePolling.h b/win/rfb_win32/SDisplayCorePolling.h
index 00de2d40..bfd72d74 100644
--- a/win/rfb_win32/SDisplayCorePolling.h
+++ b/win/rfb_win32/SDisplayCorePolling.h
@@ -40,7 +40,7 @@ namespace rfb {
~SDisplayCorePolling();
// - Called by SDisplay to inform Core of the screen size
- void setScreenRect(const Rect& screenRect_) override;
+ void setScreenRect(const core::Rect& screenRect_) override;
// - Called by SDisplay to flush updates to the specified tracker
void flushUpdates() override;
@@ -58,7 +58,7 @@ namespace rfb {
// - Background full screen polling fields
IntervalTimer pollTimer;
static const unsigned int pollTimerId;
- Rect screenRect;
+ core::Rect screenRect;
int pollInterval;
int pollNextY;
int pollIncrementY;
diff --git a/win/rfb_win32/SDisplayCoreWMHooks.cxx b/win/rfb_win32/SDisplayCoreWMHooks.cxx
index 056ff4cb..62ab8f75 100644
--- a/win/rfb_win32/SDisplayCoreWMHooks.cxx
+++ b/win/rfb_win32/SDisplayCoreWMHooks.cxx
@@ -22,9 +22,11 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
#include <rfb_win32/SDisplayCoreWMHooks.h>
-#include <rfb/LogWriter.h>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
diff --git a/win/rfb_win32/SInput.cxx b/win/rfb_win32/SInput.cxx
index 13ac9f26..2a772fe8 100644
--- a/win/rfb_win32/SInput.cxx
+++ b/win/rfb_win32/SInput.cxx
@@ -30,13 +30,15 @@
#define XK_CURRENCY
#include <rfb/keysymdef.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/SInput.h>
#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/Service.h>
#include <rfb_win32/keymap.h>
-#include <rdr/Exception.h>
-#include <rfb/LogWriter.h>
+using namespace core;
using namespace rfb;
static LogWriter vlog("SInput");
@@ -126,7 +128,7 @@ win32::SPointer::pointerEvent(const Point& pos, uint16_t buttonmask)
evt.mi.mouseData = data;
evt.mi.time = 0;
if (SendInput(1, &evt, sizeof(evt)) != 1)
- throw rdr::win32_error("SendInput", GetLastError());
+ throw core::win32_error("SendInput", GetLastError());
}
}
diff --git a/win/rfb_win32/SInput.h b/win/rfb_win32/SInput.h
index 018bec55..6f1341ee 100644
--- a/win/rfb_win32/SInput.h
+++ b/win/rfb_win32/SInput.h
@@ -24,8 +24,8 @@
#ifndef __RFB_WIN32_INPUT_H__
#define __RFB_WIN32_INPUT_H__
-#include <rfb/Rect.h>
-#include <rfb/Configuration.h>
+#include <core/Configuration.h>
+#include <core/Rect.h>
#include <map>
#include <vector>
@@ -44,9 +44,9 @@ namespace rfb {
// - Create a pointer event at a the given coordinates, with the
// specified button state. The event must be specified using
// Screen coordinates.
- void pointerEvent(const Point& pos, uint16_t buttonmask);
+ void pointerEvent(const core::Point& pos, uint16_t buttonmask);
protected:
- Point last_position;
+ core::Point last_position;
uint16_t last_buttonmask;
};
@@ -56,8 +56,8 @@ namespace rfb {
public:
SKeyboard();
void keyEvent(uint32_t keysym, uint32_t keycode, bool down);
- static BoolParameter deadKeyAware;
- static BoolParameter rawKeyboard;
+ static core::BoolParameter deadKeyAware;
+ static core::BoolParameter rawKeyboard;
private:
std::map<uint32_t,uint8_t> vkMap;
std::map<uint32_t,bool> extendedMap;
diff --git a/win/rfb_win32/Security.cxx b/win/rfb_win32/Security.cxx
index 8f000e1b..eededb6a 100644
--- a/win/rfb_win32/Security.cxx
+++ b/win/rfb_win32/Security.cxx
@@ -22,13 +22,15 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
#include <rfb_win32/Security.h>
-#include <rfb/LogWriter.h>
#include <lmcons.h>
#include <accctrl.h>
#include <list>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -99,7 +101,7 @@ PSID Sid::copySID(const PSID sid) {
throw std::invalid_argument("Invalid SID in copyPSID");
PSID buf = (PSID)new uint8_t[GetLengthSid(sid)];
if (!CopySid(GetLengthSid(sid), buf, sid))
- throw rdr::win32_error("CopySid failed", GetLastError());
+ throw core::win32_error("CopySid failed", GetLastError());
return buf;
}
@@ -108,7 +110,7 @@ void Sid::setSID(const PSID sid) {
throw std::invalid_argument("Invalid SID in copyPSID");
resize(GetLengthSid(sid));
if (!CopySid(GetLengthSid(sid), data(), sid))
- throw rdr::win32_error("CopySid failed", GetLastError());
+ throw core::win32_error("CopySid failed", GetLastError());
}
void Sid::getUserNameAndDomain(char** name, char** domain) {
@@ -117,12 +119,12 @@ void Sid::getUserNameAndDomain(char** name, char** domain) {
SID_NAME_USE use;
LookupAccountSid(nullptr, (PSID)*this, nullptr, &nameLen, nullptr, &domainLen, &use);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- throw rdr::win32_error("Unable to determine SID name lengths", GetLastError());
+ throw core::win32_error("Unable to determine SID name lengths", GetLastError());
vlog.info("nameLen=%lu, domainLen=%lu, use=%d", nameLen, domainLen, use);
*name = new char[nameLen];
*domain = new char[domainLen];
if (!LookupAccountSid(nullptr, (PSID)*this, *name, &nameLen, *domain, &domainLen, &use))
- throw rdr::win32_error("Unable to lookup account SID", GetLastError());
+ throw core::win32_error("Unable to lookup account SID", GetLastError());
}
@@ -133,7 +135,7 @@ Sid::Administrators::Administrators() {
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &sid))
- throw rdr::win32_error("Sid::Administrators", GetLastError());
+ throw core::win32_error("Sid::Administrators", GetLastError());
setSID(sid);
FreeSid(sid);
}
@@ -144,7 +146,7 @@ Sid::SYSTEM::SYSTEM() {
if (!AllocateAndInitializeSid(&ntAuth, 1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &sid))
- throw rdr::win32_error("Sid::SYSTEM", GetLastError());
+ throw core::win32_error("Sid::SYSTEM", GetLastError());
setSID(sid);
FreeSid(sid);
}
@@ -154,7 +156,7 @@ Sid::FromToken::FromToken(HANDLE h) {
GetTokenInformation(h, TokenUser, nullptr, 0, &required);
std::vector<uint8_t> tmp(required);
if (!GetTokenInformation(h, TokenUser, tmp.data(), tmp.size(), &required))
- throw rdr::win32_error("GetTokenInformation", GetLastError());
+ throw core::win32_error("GetTokenInformation", GetLastError());
TOKEN_USER* tokenUser = (TOKEN_USER*)tmp.data();
setSID(tokenUser->User.Sid);
}
@@ -164,7 +166,7 @@ PACL rfb::win32::CreateACL(const AccessEntries& ae, PACL existing_acl) {
PACL new_dacl;
DWORD result;
if ((result = SetEntriesInAcl(ae.entry_count, ae.entries, existing_acl, &new_dacl)) != ERROR_SUCCESS)
- throw rdr::win32_error("SetEntriesInAcl", result);
+ throw core::win32_error("SetEntriesInAcl", result);
return new_dacl;
}
@@ -172,18 +174,18 @@ PACL rfb::win32::CreateACL(const AccessEntries& ae, PACL existing_acl) {
PSECURITY_DESCRIPTOR rfb::win32::CreateSdWithDacl(const PACL dacl) {
SECURITY_DESCRIPTOR absSD;
if (!InitializeSecurityDescriptor(&absSD, SECURITY_DESCRIPTOR_REVISION))
- throw rdr::win32_error("InitializeSecurityDescriptor", GetLastError());
+ throw core::win32_error("InitializeSecurityDescriptor", GetLastError());
Sid::SYSTEM owner;
if (!SetSecurityDescriptorOwner(&absSD, owner, FALSE))
- throw rdr::win32_error("SetSecurityDescriptorOwner", GetLastError());
+ throw core::win32_error("SetSecurityDescriptorOwner", GetLastError());
Sid::Administrators group;
if (!SetSecurityDescriptorGroup(&absSD, group, FALSE))
- throw rdr::win32_error("SetSecurityDescriptorGroupp", GetLastError());
+ throw core::win32_error("SetSecurityDescriptorGroupp", GetLastError());
if (!SetSecurityDescriptorDacl(&absSD, TRUE, dacl, FALSE))
- throw rdr::win32_error("SetSecurityDescriptorDacl", GetLastError());
+ throw core::win32_error("SetSecurityDescriptorDacl", GetLastError());
DWORD sdSize = GetSecurityDescriptorLength(&absSD);
SecurityDescriptorPtr sd(sdSize);
if (!MakeSelfRelativeSD(&absSD, (PSECURITY_DESCRIPTOR)sd.ptr, &sdSize))
- throw rdr::win32_error("MakeSelfRelativeSD", GetLastError());
+ throw core::win32_error("MakeSelfRelativeSD", GetLastError());
return sd.takeSD();
}
diff --git a/win/rfb_win32/SecurityPage.cxx b/win/rfb_win32/SecurityPage.cxx
index a6f026cf..94a88492 100644
--- a/win/rfb_win32/SecurityPage.cxx
+++ b/win/rfb_win32/SecurityPage.cxx
@@ -21,9 +21,8 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
+#include <core/LogWriter.h>
-#include <rfb/LogWriter.h>
#include <rfb/Security.h>
#include <rfb_win32/resource.h>
@@ -31,7 +30,7 @@
#include <list>
-using namespace rdr;
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
using namespace std;
@@ -124,9 +123,6 @@ SecurityPage::onOk() {
bool vnc_loaded = false;
list<uint32_t> secTypes;
- /* Keep same priorities as in common/rfb/SecurityClient::secTypes */
- secTypes.push_back(secTypeVeNCrypt);
-
#ifdef HAVE_GNUTLS
/* X509Plain */
if (authMethodEnabled(IDC_ENC_X509, IDC_AUTH_PLAIN)) {
diff --git a/win/rfb_win32/Service.cxx b/win/rfb_win32/Service.cxx
index bc9875e5..d28fdb75 100644
--- a/win/rfb_win32/Service.cxx
+++ b/win/rfb_win32/Service.cxx
@@ -22,18 +22,19 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb_win32/Service.h>
#include <rfb_win32/MsgWindow.h>
#include <rfb_win32/ModuleFileName.h>
#include <rfb_win32/Registry.h>
#include <rfb_win32/Handle.h>
-#include <logmessages/messages.h>
-#include <rdr/Exception.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+#include <logmessages/messages.h>
-using namespace rdr;
+using namespace core;
using namespace rfb;
using namespace win32;
@@ -335,7 +336,7 @@ bool rfb::win32::registerService(const char* name,
// - Open the SCM
ServiceHandle scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE);
if (!scm)
- throw rdr::win32_error("Unable to open Service Control Manager", GetLastError());
+ throw core::win32_error("Unable to open Service Control Manager", GetLastError());
// - Add the service
ServiceHandle handle = CreateService(scm,
@@ -344,7 +345,7 @@ bool rfb::win32::registerService(const char* name,
SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
cmdline.c_str(), nullptr, nullptr, nullptr, nullptr, nullptr);
if (!handle)
- throw rdr::win32_error("Unable to create service", GetLastError());
+ throw core::win32_error("Unable to create service", GetLastError());
// - Set a description
SERVICE_DESCRIPTION sdesc = {(LPTSTR)desc};
@@ -380,14 +381,14 @@ bool rfb::win32::unregisterService(const char* name) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE);
if (!scm)
- throw rdr::win32_error("Unable to open Service Control Manager", GetLastError());
+ throw core::win32_error("Unable to open Service Control Manager", GetLastError());
// - Create the service
ServiceHandle handle = OpenService(scm, name, SC_MANAGER_ALL_ACCESS);
if (!handle)
- throw rdr::win32_error("Unable to locate the service", GetLastError());
+ throw core::win32_error("Unable to locate the service", GetLastError());
if (!DeleteService(handle))
- throw rdr::win32_error("Unable to remove the service", GetLastError());
+ throw core::win32_error("Unable to remove the service", GetLastError());
// - Register the event log source
RegKey hk;
@@ -407,16 +408,16 @@ bool rfb::win32::startService(const char* name) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
if (!scm)
- throw rdr::win32_error("Unable to open Service Control Manager", GetLastError());
+ throw core::win32_error("Unable to open Service Control Manager", GetLastError());
// - Locate the service
ServiceHandle handle = OpenService(scm, name, SERVICE_START);
if (!handle)
- throw rdr::win32_error("Unable to open the service", GetLastError());
+ throw core::win32_error("Unable to open the service", GetLastError());
// - Start the service
if (!StartService(handle, 0, nullptr))
- throw rdr::win32_error("Unable to start the service", GetLastError());
+ throw core::win32_error("Unable to start the service", GetLastError());
Sleep(500);
@@ -427,17 +428,17 @@ bool rfb::win32::stopService(const char* name) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
if (!scm)
- throw rdr::win32_error("Unable to open Service Control Manager", GetLastError());
+ throw core::win32_error("Unable to open Service Control Manager", GetLastError());
// - Locate the service
ServiceHandle handle = OpenService(scm, name, SERVICE_STOP);
if (!handle)
- throw rdr::win32_error("Unable to open the service", GetLastError());
+ throw core::win32_error("Unable to open the service", GetLastError());
// - Start the service
SERVICE_STATUS status;
if (!ControlService(handle, SERVICE_CONTROL_STOP, &status))
- throw rdr::win32_error("Unable to stop the service", GetLastError());
+ throw core::win32_error("Unable to stop the service", GetLastError());
Sleep(500);
@@ -448,17 +449,17 @@ DWORD rfb::win32::getServiceState(const char* name) {
// - Open the SCM
ServiceHandle scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
if (!scm)
- throw rdr::win32_error("Unable to open Service Control Manager", GetLastError());
+ throw core::win32_error("Unable to open Service Control Manager", GetLastError());
// - Locate the service
ServiceHandle handle = OpenService(scm, name, SERVICE_INTERROGATE);
if (!handle)
- throw rdr::win32_error("Unable to open the service", GetLastError());
+ throw core::win32_error("Unable to open the service", GetLastError());
// - Get the service status
SERVICE_STATUS status;
if (!ControlService(handle, SERVICE_CONTROL_INTERROGATE, (SERVICE_STATUS*)&status))
- throw rdr::win32_error("Unable to query the service", GetLastError());
+ throw core::win32_error("Unable to query the service", GetLastError());
return status.dwCurrentState;
}
diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx
index 7f6d1773..9a22ee14 100644
--- a/win/rfb_win32/SocketManager.cxx
+++ b/win/rfb_win32/SocketManager.cxx
@@ -25,16 +25,19 @@
#include <winsock2.h>
#include <list>
-#include <rdr/Exception.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+#include <core/Timer.h>
+#include <core/time.h>
+
+#include <rdr/FdOutStream.h>
#include <network/Socket.h>
-#include <rfb/LogWriter.h>
-#include <rfb/Timer.h>
#include <rfb/VNCServer.h>
-#include <rfb/util.h>
#include <rfb_win32/SocketManager.h>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -69,7 +72,7 @@ void SocketManager::addListener(network::SocketListener* sock_,
flags |= FD_ADDRESS_LIST_CHANGE;
try {
if (event && (WSAEventSelect(sock_->getFd(), event, flags) == SOCKET_ERROR))
- throw rdr::socket_error("Unable to select on listener", WSAGetLastError());
+ throw core::socket_error("Unable to select on listener", WSAGetLastError());
// requestAddressChangeEvents MUST happen after WSAEventSelect, so that the socket is non-blocking
if (acn)
@@ -186,7 +189,7 @@ int SocketManager::checkTimeouts() {
if (j->second.sock->outStream().hasBufferedData())
eventMask |= FD_WRITE;
if (WSAEventSelect(j->second.sock->getFd(), j->first, eventMask) == SOCKET_ERROR)
- throw rdr::socket_error("unable to adjust WSAEventSelect:%u", WSAGetLastError());
+ throw core::socket_error("unable to adjust WSAEventSelect:%u", WSAGetLastError());
}
}
@@ -236,11 +239,11 @@ void SocketManager::processEvent(HANDLE event) {
// Fetch why this event notification triggered
if (WSAEnumNetworkEvents(ci.sock->getFd(), event, &network_events) == SOCKET_ERROR)
- throw rdr::socket_error("Unable to get WSAEnumNetworkEvents:%u", WSAGetLastError());
+ throw core::socket_error("Unable to get WSAEnumNetworkEvents:%u", WSAGetLastError());
// Cancel event notification for this socket
if (WSAEventSelect(ci.sock->getFd(), event, 0) == SOCKET_ERROR)
- throw rdr::socket_error("unable to disable WSAEventSelect:%u", WSAGetLastError());
+ throw core::socket_error("unable to disable WSAEventSelect:%u", WSAGetLastError());
// Reset the event object
WSAResetEvent(event);
@@ -268,7 +271,7 @@ void SocketManager::processEvent(HANDLE event) {
if (ci.sock->outStream().hasBufferedData())
eventMask |= FD_WRITE;
if (WSAEventSelect(ci.sock->getFd(), event, eventMask) == SOCKET_ERROR)
- throw rdr::socket_error("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
+ throw core::socket_error("unable to re-enable WSAEventSelect:%u", WSAGetLastError());
} catch (std::exception& e) {
vlog.error("%s", e.what());
remSocket(ci.sock);
diff --git a/win/rfb_win32/TrayIcon.h b/win/rfb_win32/TrayIcon.h
index b4e75ea5..9eccc937 100644
--- a/win/rfb_win32/TrayIcon.h
+++ b/win/rfb_win32/TrayIcon.h
@@ -25,8 +25,8 @@
#include <windows.h>
#include <shellapi.h>
+
#include <rfb_win32/MsgWindow.h>
-#include <rdr/Exception.h>
namespace rfb {
diff --git a/win/rfb_win32/TsSessions.cxx b/win/rfb_win32/TsSessions.cxx
index faf83e89..77d6cc52 100644
--- a/win/rfb_win32/TsSessions.cxx
+++ b/win/rfb_win32/TsSessions.cxx
@@ -20,12 +20,14 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/TsSessions.h>
-#include <rfb/LogWriter.h>
-#include <rdr/Exception.h>
+
#include <wtsapi32.h>
-static rfb::LogWriter vlog("TsSessions");
+static core::LogWriter vlog("TsSessions");
namespace rfb {
namespace win32 {
@@ -35,7 +37,7 @@ namespace win32 {
if (processId == (DWORD)-1)
processId = GetCurrentProcessId();
if (!ProcessIdToSessionId(GetCurrentProcessId(), &id))
- throw rdr::win32_error("ProcessIdToSessionId", GetLastError());
+ throw core::win32_error("ProcessIdToSessionId", GetLastError());
}
ProcessSessionId mySessionId;
@@ -57,7 +59,7 @@ namespace win32 {
ConsoleSessionId console;
vlog.info("Console session is %lu", console.id);
if (!WTSConnectSession(sessionId, console.id, (PTSTR)"", 0))
- throw rdr::win32_error("Unable to connect session to Console", GetLastError());
+ throw core::win32_error("Unable to connect session to Console", GetLastError());
// Lock the newly connected session, for security
LockWorkStation();
diff --git a/win/rfb_win32/WMCursor.cxx b/win/rfb_win32/WMCursor.cxx
index 65d7a9d7..4481f3f7 100644
--- a/win/rfb_win32/WMCursor.cxx
+++ b/win/rfb_win32/WMCursor.cxx
@@ -22,11 +22,14 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/WMCursor.h>
+
#include <rfb/Exception.h>
-#include <rfb/LogWriter.h>
-using namespace rdr;
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -45,9 +48,9 @@ WMCursor::getCursorInfo() {
CURSORINFO info;
info.cbSize = sizeof(CURSORINFO);
if (!GetCursorInfo(&info))
- throw rdr::win32_error("GetCursorInfo failed", GetLastError());
+ throw core::win32_error("GetCursorInfo failed", GetLastError());
result.cursor = info.hCursor;
- result.position = Point(info.ptScreenPos.x, info.ptScreenPos.y);
+ result.position = {info.ptScreenPos.x, info.ptScreenPos.y};
result.visible = info.flags & CURSOR_SHOWING;
return result;
}
diff --git a/win/rfb_win32/WMCursor.h b/win/rfb_win32/WMCursor.h
index 465331de..1df50741 100644
--- a/win/rfb_win32/WMCursor.h
+++ b/win/rfb_win32/WMCursor.h
@@ -38,7 +38,7 @@ namespace rfb {
struct Info {
HCURSOR cursor;
- Point position;
+ core::Point position;
bool visible;
Info() : cursor(nullptr), visible(false) {}
bool operator!=(const Info& info) {
diff --git a/win/rfb_win32/WMHooks.cxx b/win/rfb_win32/WMHooks.cxx
index e1840eef..e3285948 100644
--- a/win/rfb_win32/WMHooks.cxx
+++ b/win/rfb_win32/WMHooks.cxx
@@ -22,17 +22,19 @@
#include <config.h>
#endif
-#include <os/Mutex.h>
-#include <os/Thread.h>
+#include <mutex>
+#include <thread>
+
+#include <core/LogWriter.h>
#include <rfb_win32/WMHooks.h>
#include <rfb_win32/Service.h>
#include <rfb_win32/MsgWindow.h>
#include <rfb_win32/IntervalTimer.h>
-#include <rfb/LogWriter.h>
#include <list>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -114,21 +116,23 @@ error:
}
-class WMHooksThread : public os::Thread {
+class WMHooksThread {
public:
- WMHooksThread() : active(true), thread_id(-1) { }
+ WMHooksThread() : active(true), thread(WMHooksThread::worker, this),
+ thread_id(-1) { }
void stop();
DWORD getThreadId() { return thread_id; }
protected:
- void worker() override;
+ void worker();
protected:
bool active;
+ std::thread thread;
DWORD thread_id;
};
static WMHooksThread* hook_mgr = nullptr;
static std::list<WMHooks*> hooks;
-static os::Mutex hook_mgr_lock;
+static std::mutex hook_mgr_lock;
static bool StartHookThread() {
@@ -138,7 +142,6 @@ static bool StartHookThread() {
return false;
vlog.debug("Creating thread");
hook_mgr = new WMHooksThread();
- hook_mgr->start();
while (hook_mgr->getThreadId() == (DWORD)-1)
Sleep(0);
vlog.debug("Installing hooks");
@@ -166,7 +169,7 @@ static void StopHookThread() {
static bool AddHook(WMHooks* hook) {
vlog.debug("Adding hook");
- os::AutoMutex a(&hook_mgr_lock);
+ const std::lock_guard<std::mutex> lock(hook_mgr_lock);
if (!StartHookThread())
return false;
hooks.push_back(hook);
@@ -176,7 +179,7 @@ static bool AddHook(WMHooks* hook) {
static bool RemHook(WMHooks* hook) {
{
vlog.debug("Removing hook");
- os::AutoMutex a(&hook_mgr_lock);
+ const std::lock_guard<std::mutex> lock(hook_mgr_lock);
hooks.remove(hook);
}
StopHookThread();
@@ -184,7 +187,7 @@ static bool RemHook(WMHooks* hook) {
}
static void NotifyHooksRegion(const Region& r) {
- os::AutoMutex a(&hook_mgr_lock);
+ const std::lock_guard<std::mutex> lock(hook_mgr_lock);
std::list<WMHooks*>::iterator i;
for (i=hooks.begin(); i!=hooks.end(); i++)
(*i)->NotifyHooksRegion(r);
@@ -236,8 +239,8 @@ WMHooksThread::worker() {
hwnd = (HWND) msg.lParam;
if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
GetWindowRect(hwnd, &wrect) && !IsRectEmpty(&wrect)) {
- updates[activeRgn].assign_union(Rect(wrect.left, wrect.top,
- wrect.right, wrect.bottom));
+ updates[activeRgn].assign_union({{wrect.left, wrect.top,
+ wrect.right, wrect.bottom}});
updateDelayTimer.start(updateDelayMs);
}
@@ -249,8 +252,8 @@ WMHooksThread::worker() {
{
POINT pt = {0,0};
if (ClientToScreen(hwnd, &pt)) {
- updates[activeRgn].assign_union(Rect(wrect.left+pt.x, wrect.top+pt.y,
- wrect.right+pt.x, wrect.bottom+pt.y));
+ updates[activeRgn].assign_union({{wrect.left+pt.x, wrect.top+pt.y,
+ wrect.right+pt.x, wrect.bottom+pt.y}});
updateDelayTimer.start(updateDelayMs);
}
}
@@ -260,14 +263,14 @@ WMHooksThread::worker() {
if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) &&
GetWindowRect(hwnd, &wrect) && !IsRectEmpty(&wrect))
{
- Region changed(Rect(wrect.left, wrect.top, wrect.right, wrect.bottom));
+ Region changed({wrect.left, wrect.top, wrect.right, wrect.bottom});
RECT crect;
POINT pt = {0,0};
if (GetClientRect(hwnd, &crect) && ClientToScreen(hwnd, &pt) &&
!IsRectEmpty(&crect))
{
- changed.assign_subtract(Rect(crect.left+pt.x, crect.top+pt.y,
- crect.right+pt.x, crect.bottom+pt.y));
+ changed.assign_subtract({{crect.left+pt.x, crect.top+pt.y,
+ crect.right+pt.x, crect.bottom+pt.y}});
}
if (!changed.is_empty()) {
updates[activeRgn].assign_union(changed);
@@ -275,8 +278,8 @@ WMHooksThread::worker() {
}
}
} else if (msg.message == rectangleMsg) {
- Rect r = Rect(LOWORD(msg.wParam), HIWORD(msg.wParam),
- LOWORD(msg.lParam), HIWORD(msg.lParam));
+ Rect r(LOWORD(msg.wParam), HIWORD(msg.wParam),
+ LOWORD(msg.lParam), HIWORD(msg.lParam));
if (!r.is_empty()) {
updates[activeRgn].assign_union(r);
updateDelayTimer.start(updateDelayMs);
@@ -301,7 +304,7 @@ WMHooksThread::stop() {
active = false;
PostThreadMessage(thread_id, WM_QUIT, 0, 0);
vlog.debug("Waiting for WMHooks thread");
- wait();
+ thread.join();
}
// -=- WMHooks class
@@ -323,7 +326,7 @@ bool rfb::win32::WMHooks::setEvent(HANDLE ue) {
bool rfb::win32::WMHooks::getUpdates(UpdateTracker* ut) {
if (!updatesReady) return false;
- os::AutoMutex a(&hook_mgr_lock);
+ const std::lock_guard<std::mutex> lock(hook_mgr_lock);
updates.copyTo(ut);
updates.clear();
updatesReady = false;
@@ -375,12 +378,12 @@ static bool blockRealInputs(bool block_) {
return block_ == blocking;
}
-static os::Mutex blockMutex;
+static std::mutex blockMutex;
static int blockCount = 0;
bool rfb::win32::WMBlockInput::blockInputs(bool on) {
if (active == on) return true;
- os::AutoMutex a(&blockMutex);
+ const std::lock_guard<std::mutex> lock(blockMutex);
int newCount = on ? blockCount+1 : blockCount-1;
if (!blockRealInputs(newCount > 0))
return false;
diff --git a/win/rfb_win32/WMHooks.h b/win/rfb_win32/WMHooks.h
index c1dbd5f3..0a729239 100644
--- a/win/rfb_win32/WMHooks.h
+++ b/win/rfb_win32/WMHooks.h
@@ -22,8 +22,9 @@
#define __RFB_WIN32_WM_HOOKS_H__
#include <windows.h>
+
#include <rfb/UpdateTracker.h>
-#include <rdr/Exception.h>
+
#include <rfb_win32/Win32Util.h>
namespace rfb {
@@ -53,7 +54,7 @@ namespace rfb {
#endif
// * INTERNAL NOTIFICATION FUNCTION *
- void NotifyHooksRegion(const Region& r);
+ void NotifyHooksRegion(const core::Region& r);
protected:
HANDLE updateEvent;
bool updatesReady;
diff --git a/win/rfb_win32/WMNotifier.cxx b/win/rfb_win32/WMNotifier.cxx
index 894add1c..3fda81e7 100644
--- a/win/rfb_win32/WMNotifier.cxx
+++ b/win/rfb_win32/WMNotifier.cxx
@@ -22,12 +22,13 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
#include <rfb_win32/WMNotifier.h>
#include <rfb_win32/WMShatter.h>
#include <rfb_win32/MsgWindow.h>
-#include <rfb/LogWriter.h>
-
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
diff --git a/win/rfb_win32/WMPoller.cxx b/win/rfb_win32/WMPoller.cxx
index e2ff0ac6..e1efc447 100644
--- a/win/rfb_win32/WMPoller.cxx
+++ b/win/rfb_win32/WMPoller.cxx
@@ -22,12 +22,13 @@
#include <config.h>
#endif
-#include <rdr/Exception.h>
+#include <core/Configuration.h>
+#include <core/Exception.h>
+#include <core/LogWriter.h>
#include <rfb_win32/WMPoller.h>
-#include <rfb/LogWriter.h>
-#include <rfb/Configuration.h>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -58,7 +59,7 @@ bool
rfb::win32::WMPoller::checkPollWindow(HWND w) {
char buffer[128];
if (!GetClassName(w, buffer, 128))
- throw rdr::win32_error("Unable to get window class:%u", GetLastError());
+ throw core::win32_error("Unable to get window class:%u", GetLastError());
if ((strcmp(buffer, "tty") != 0) &&
(strcmp(buffer, "ConsoleWindowClass") != 0)) {
return false;
@@ -71,7 +72,7 @@ rfb::win32::WMPoller::pollWindow(HWND w, PollInfo* i) {
RECT r;
if (IsWindowVisible(w) && GetWindowRect(w, &r)) {
if (IsRectEmpty(&r)) return;
- Region wrgn(Rect(r.left, r.top, r.right, r.bottom));
+ Region wrgn({r.left, r.top, r.right, r.bottom});
if (checkPollWindow(w)) {
wrgn.assign_subtract(i->poll_exclude);
i->poll_include.assign_union(wrgn);
diff --git a/win/rfb_win32/WMPoller.h b/win/rfb_win32/WMPoller.h
index 0783e4ff..7fa896f0 100644
--- a/win/rfb_win32/WMPoller.h
+++ b/win/rfb_win32/WMPoller.h
@@ -29,8 +29,10 @@
#define __RFB_WIN32_WM_POLLER_H__
#include <windows.h>
+
+#include <core/Configuration.h>
+
#include <rfb/UpdateTracker.h>
-#include <rfb/Configuration.h>
namespace rfb {
@@ -43,11 +45,11 @@ namespace rfb {
bool processEvent();
bool setUpdateTracker(UpdateTracker* ut);
- static BoolParameter poll_console_windows;
+ static core::BoolParameter poll_console_windows;
protected:
struct PollInfo {
- Region poll_include;
- Region poll_exclude;
+ core::Region poll_include;
+ core::Region poll_exclude;
};
static bool checkPollWindow(HWND w);
static void pollWindow(HWND w, PollInfo* info);
diff --git a/win/rfb_win32/WMShatter.cxx b/win/rfb_win32/WMShatter.cxx
index ede80e91..0965da86 100644
--- a/win/rfb_win32/WMShatter.cxx
+++ b/win/rfb_win32/WMShatter.cxx
@@ -22,10 +22,11 @@
#include <config.h>
#endif
-#include <rfb_win32/WMShatter.h>
+#include <core/LogWriter.h>
-#include <rfb/LogWriter.h>
+#include <rfb_win32/WMShatter.h>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
diff --git a/win/rfb_win32/WMWindowCopyRect.cxx b/win/rfb_win32/WMWindowCopyRect.cxx
index ec6e1fdc..d64c0e31 100644
--- a/win/rfb_win32/WMWindowCopyRect.cxx
+++ b/win/rfb_win32/WMWindowCopyRect.cxx
@@ -22,10 +22,13 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
#include <rfb_win32/WMWindowCopyRect.h>
-#include <rfb/LogWriter.h>
+
#include <windows.h>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -49,8 +52,8 @@ rfb::win32::WMCopyRect::processEvent() {
// Window has moved - mark both the previous and new position as changed
// (we can't use add_copied() here because we aren't that properly synced
// with the actual state of the framebuffer)
- ut->add_changed(Region(winrect));
- ut->add_changed(Region(fg_window_rect));
+ ut->add_changed(winrect);
+ ut->add_changed(fg_window_rect);
}
}
fg_window = window;
diff --git a/win/rfb_win32/WMWindowCopyRect.h b/win/rfb_win32/WMWindowCopyRect.h
index 5a0e876d..d3ed7881 100644
--- a/win/rfb_win32/WMWindowCopyRect.h
+++ b/win/rfb_win32/WMWindowCopyRect.h
@@ -43,7 +43,7 @@ namespace rfb {
protected:
UpdateTracker* ut;
void* fg_window;
- Rect fg_window_rect;
+ core::Rect fg_window_rect;
};
};
diff --git a/win/rfb_win32/Win32Util.cxx b/win/rfb_win32/Win32Util.cxx
index b35bf629..f4220e32 100644
--- a/win/rfb_win32/Win32Util.cxx
+++ b/win/rfb_win32/Win32Util.cxx
@@ -22,15 +22,20 @@
#include <config.h>
#endif
+#include <core/Exception.h>
+#include <core/string.h>
+
#include <rfb_win32/ModuleFileName.h>
#include <rfb_win32/Win32Util.h>
#include <rfb_win32/MonitorInfo.h>
#include <rfb_win32/Handle.h>
+
#include <rdr/HexOutStream.h>
-#include <rdr/Exception.h>
-#include <rfb/util.h>
+
#include <stdio.h>
+using namespace core;
+
namespace rfb {
namespace win32 {
@@ -46,19 +51,19 @@ FileVersionInfo::FileVersionInfo(const char* filename) {
{
Handle file(CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
if (file.h == INVALID_HANDLE_VALUE)
- throw rdr::win32_error("Failed to open file", GetLastError());
+ throw core::win32_error("Failed to open file", GetLastError());
}
// Get version info size
DWORD handle;
int size = GetFileVersionInfoSize((char*)filename, &handle);
if (!size)
- throw rdr::win32_error("GetVersionInfoSize failed", GetLastError());
+ throw core::win32_error("GetVersionInfoSize failed", GetLastError());
// Get version info
buf = new char[size];
if (!GetFileVersionInfo((char*)filename, handle, size, buf))
- throw rdr::win32_error("GetVersionInfo failed", GetLastError());
+ throw core::win32_error("GetVersionInfo failed", GetLastError());
}
FileVersionInfo::~FileVersionInfo() {
diff --git a/win/vncconfig/Authentication.h b/win/vncconfig/Authentication.h
index 1123678f..2bf44dee 100644
--- a/win/vncconfig/Authentication.h
+++ b/win/vncconfig/Authentication.h
@@ -33,7 +33,7 @@
#include <rfb/SSecurityTLS.h>
#endif
-static rfb::BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn",
+static core::BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn",
"Only prompt for a local user to accept incoming connections if there is a user logged on", false);
namespace rfb {
diff --git a/win/vncconfig/Connections.h b/win/vncconfig/Connections.h
index 9ec78c07..17c685ea 100644
--- a/win/vncconfig/Connections.h
+++ b/win/vncconfig/Connections.h
@@ -20,19 +20,23 @@
#include <vector>
+#include <core/Configuration.h>
+#include <core/string.h>
+
#include <rfb_win32/Registry.h>
#include <rfb_win32/Dialog.h>
#include <rfb_win32/ModuleFileName.h>
-#include <rfb/Configuration.h>
+
#include <rfb/Blacklist.h>
-#include <rfb/util.h>
+
#include <network/TcpSocket.h>
-static rfb::IntParameter port_number("PortNumber",
- "TCP/IP port on which the server will accept connections", 5900);
-static rfb::StringParameter hosts("Hosts",
+static core::IntParameter port_number("PortNumber",
+ "TCP/IP port on which the server will accept connections",
+ 5900, 0, 65535);
+static core::StringParameter hosts("Hosts",
"Filter describing which hosts are allowed access to this server", "+");
-static rfb::BoolParameter localHost("LocalHost",
+static core::BoolParameter localHost("LocalHost",
"Only accept connections from via the local loop-back network interface", false);
namespace rfb {
@@ -100,7 +104,7 @@ namespace rfb {
SendMessage(listBox, LB_DELETESTRING, 0, 0);
std::vector<std::string> hostv;
- hostv = split(hosts, ',');
+ hostv = core::split(hosts, ',');
for (size_t i = 0; i < hostv.size(); i++) {
if (!hostv[i].empty())
SendMessage(listBox, LB_ADDSTRING, 0, (LPARAM)hostv[i].c_str());
diff --git a/win/vncconfig/Desktop.h b/win/vncconfig/Desktop.h
index a5058389..c7b97533 100644
--- a/win/vncconfig/Desktop.h
+++ b/win/vncconfig/Desktop.h
@@ -31,9 +31,8 @@ namespace rfb {
DesktopPage(const RegKey& rk)
: PropSheetPage(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_DESKTOP)), regKey(rk) {}
void initDialog() override {
- const char *action(rfb::win32::SDisplay::disconnectAction);
- bool disconnectLock = stricmp(action, "Lock") == 0;
- bool disconnectLogoff = stricmp(action, "Logoff") == 0;
+ bool disconnectLock = rfb::win32::SDisplay::disconnectAction == "Lock";
+ bool disconnectLogoff = rfb::win32::SDisplay::disconnectAction == "Logoff";
setItemChecked(IDC_DISCONNECT_LOGOFF, disconnectLogoff);
setItemChecked(IDC_DISCONNECT_LOCK, disconnectLock);
setItemChecked(IDC_DISCONNECT_NONE, !disconnectLock && !disconnectLogoff);
@@ -47,9 +46,8 @@ namespace rfb {
case IDC_DISCONNECT_NONE:
case IDC_REMOVE_WALLPAPER:
case IDC_DISABLE_EFFECTS:
- const char *action(rfb::win32::SDisplay::disconnectAction);
- bool disconnectLock = stricmp(action, "Lock") == 0;
- bool disconnectLogoff = stricmp(action, "Logoff") == 0;
+ bool disconnectLock = rfb::win32::SDisplay::disconnectAction == "Lock";
+ bool disconnectLogoff = rfb::win32::SDisplay::disconnectAction == "Logoff";
setChanged((disconnectLogoff != isItemChecked(IDC_DISCONNECT_LOGOFF)) ||
(disconnectLock != isItemChecked(IDC_DISCONNECT_LOCK)) ||
(isItemChecked(IDC_REMOVE_WALLPAPER) != rfb::win32::SDisplay::removeWallpaper) ||
diff --git a/win/vncconfig/Legacy.cxx b/win/vncconfig/Legacy.cxx
index 3280eaef..bf073fd7 100644
--- a/win/vncconfig/Legacy.cxx
+++ b/win/vncconfig/Legacy.cxx
@@ -18,10 +18,12 @@
#include <vncconfig/Legacy.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb_win32/CurrentUser.h>
+using namespace core;
using namespace rfb;
using namespace win32;
@@ -42,7 +44,7 @@ void LegacyPage::LoadPrefs()
std::string username;
try {
username = UserName();
- } catch (rdr::win32_error& e) {
+ } catch (core::win32_error& e) {
if (e.err != ERROR_NOT_LOGGED_ON)
throw;
}
@@ -70,7 +72,7 @@ void LegacyPage::LoadPrefs()
try {
// Split the AuthHosts string into patterns to match
std::vector<std::string> patterns;
- patterns = rfb::split(authHosts.c_str(), ':');
+ patterns = split(authHosts.c_str(), ':');
for (size_t i = 0; i < patterns.size(); i++) {
if (!patterns[i].empty()) {
int bits = 0;
@@ -80,7 +82,7 @@ void LegacyPage::LoadPrefs()
// Split the pattern into IP address parts and process
std::vector<std::string> parts;
- parts = rfb::split(&patterns[i][1], '.');
+ parts = split(&patterns[i][1], '.');
for (size_t j = 0; j < parts.size(); j++) {
if (bits)
strcat(pattern, ".");
diff --git a/win/vncconfig/vncconfig.cxx b/win/vncconfig/vncconfig.cxx
index fffdea18..da594435 100644
--- a/win/vncconfig/vncconfig.cxx
+++ b/win/vncconfig/vncconfig.cxx
@@ -22,12 +22,15 @@
#include <string.h>
#include "resource.h"
-#include <rfb/Logger_stdio.h>
-#include <rfb/LogWriter.h>
+
+#include <core/Logger_stdio.h>
+#include <core/LogWriter.h>
+
#include <rfb_win32/Dialog.h>
#include <rfb_win32/RegConfig.h>
#include <rfb_win32/CurrentUser.h>
+using namespace core;
using namespace rfb;
using namespace rfb::win32;
@@ -61,15 +64,12 @@ processParams(int argc, char* argv[]) {
} else if (strcasecmp(argv[i], "-user") == 0) {
configKey = HKEY_CURRENT_USER;
} else {
- // Try to process <option>=<value>, or -<bool>
- if (Configuration::setParam(argv[i], true))
+ int ret;
+
+ ret = Configuration::handleParamArg(argc, argv, i);
+ if (ret > 0) {
+ i += ret - 1;
continue;
- // Try to process -<option> <value>
- if ((argv[i][0] == '-') && (i+1 < argc)) {
- if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
- i++;
- continue;
- }
}
}
}
@@ -90,8 +90,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE /*prev*/, char* /*cmdLine*/, int /*
vlog.info("Starting vncconfig applet");
#endif
- Configuration::enableServerParams();
-
try {
try {
// Process command-line args
@@ -125,7 +123,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE /*prev*/, char* /*cmdLine*/, int /*
// Set the DACL, and don't allow the key to inherit its parent's DACL
rootKey.setDACL(acl, false);
- } catch (rdr::win32_error& e) {
+ } catch (core::win32_error& e) {
// Something weird happens on NT 4.0 SP5 but I can't reproduce it on other
// NT 4.0 service pack revisions.
if (e.err == ERROR_INVALID_PARAMETER) {
@@ -169,7 +167,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE /*prev*/, char* /*cmdLine*/, int /*
#else
sheet.showPropSheet(nullptr, true, false);
#endif
- } catch (rdr::win32_error& e) {
+ } catch (core::win32_error& e) {
switch (e.err) {
case ERROR_ACCESS_DENIED:
MsgBox(nullptr, "You do not have sufficient access rights to run the VNC Configuration applet",
diff --git a/win/vncconfig/vncconfig.rc b/win/vncconfig/vncconfig.rc
index ca188bcf..e8b50ed1 100644
--- a/win/vncconfig/vncconfig.rc
+++ b/win/vncconfig/vncconfig.rc
@@ -459,7 +459,7 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "Comments", "\0"
- VALUE "CompanyName", "TigerVNC project\0"
+ VALUE "CompanyName", "TigerVNC team\0"
#ifdef WIN64
VALUE "FileDescription", "TigerVNC server configuration applet for Win64\0"
VALUE "ProductName", "TigerVNC server configuration applet for Win64\0"
@@ -469,7 +469,7 @@ BEGIN
#endif
VALUE "FileVersion", __RCVERSIONSTR
VALUE "InternalName", "vncconfig\0"
- VALUE "LegalCopyright", "Copyright (C) 1999-2024 TigerVNC team and many others (see README.rst)\0"
+ VALUE "LegalCopyright", "Copyright (C) 1999-2025 TigerVNC team and many others (see README.rst)\0"
VALUE "LegalTrademarks", "TigerVNC\0"
VALUE "OriginalFilename", "vncconfig.exe\0"
VALUE "PrivateBuild", "\0"
diff --git a/win/winvnc/ControlPanel.cxx b/win/winvnc/ControlPanel.cxx
index 6c593c45..9041d81f 100644
--- a/win/winvnc/ControlPanel.cxx
+++ b/win/winvnc/ControlPanel.cxx
@@ -31,9 +31,9 @@ void ControlPanel::initDialog()
SendCommand(4, -1);
}
-bool ControlPanel::onCommand(int cmd)
+bool ControlPanel::onCommand(int item, int /*cmd*/)
{
- switch (cmd) {
+ switch (item) {
case IDC_PROPERTIES:
SendMessage(m_hSTIcon, WM_COMMAND, ID_OPTIONS, 0);
return false;
@@ -122,7 +122,7 @@ BOOL ControlPanel::dialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM /*lPara
EndDialog(hwnd, 0);
return TRUE;
default:
- return onCommand(LOWORD(wParam));
+ return onCommand(LOWORD(wParam), HIWORD(wParam));
}
}
return FALSE;
diff --git a/win/winvnc/ControlPanel.h b/win/winvnc/ControlPanel.h
index 23aff0a5..3b994a59 100644
--- a/win/winvnc/ControlPanel.h
+++ b/win/winvnc/ControlPanel.h
@@ -26,7 +26,7 @@ namespace winvnc {
};
virtual bool showDialog();
void initDialog() override;
- virtual bool onCommand(int cmd);
+ bool onCommand(int item, int cmd) override;
void UpdateListView(ListConnInfo* LCInfo);
HWND GetHandle() {return handle;};
void SendCommand(DWORD command, int data);
diff --git a/win/winvnc/ManagedListener.cxx b/win/winvnc/ManagedListener.cxx
index 6690f364..7362b57c 100644
--- a/win/winvnc/ManagedListener.cxx
+++ b/win/winvnc/ManagedListener.cxx
@@ -20,10 +20,12 @@
#include <config.h>
#endif
+#include <core/LogWriter.h>
+
#include <winvnc/ManagedListener.h>
-#include <rfb/LogWriter.h>
using namespace winvnc;
+using namespace core;
using namespace rfb;
using namespace win32;
diff --git a/win/winvnc/QueryConnectDialog.cxx b/win/winvnc/QueryConnectDialog.cxx
index e1df584d..1b03af5d 100644
--- a/win/winvnc/QueryConnectDialog.cxx
+++ b/win/winvnc/QueryConnectDialog.cxx
@@ -23,10 +23,13 @@
#include <winvnc/VNCServerWin32.h>
#include <winvnc/QueryConnectDialog.h>
#include <winvnc/resource.h>
+
+#include <core/LogWriter.h>
+
#include <rfb_win32/Win32Util.h>
#include <rfb_win32/Service.h>
-#include <rfb/LogWriter.h>
+using namespace core;
using namespace rfb;
using namespace win32;
using namespace winvnc;
@@ -36,7 +39,7 @@ static LogWriter vlog("QueryConnectDialog");
static IntParameter timeout("QueryConnectTimeout",
"Number of seconds to show the Accept connection dialog before "
"rejecting the connection",
- 10);
+ 10, 0, INT_MAX);
// - Visible methods
@@ -45,12 +48,21 @@ QueryConnectDialog::QueryConnectDialog(network::Socket* sock_,
const char* userName_,
VNCServerWin32* s)
: Dialog(GetModuleHandle(nullptr)),
- sock(sock_), peerIp(sock->getPeerAddress()), userName(userName_),
+ thread(nullptr), sock(sock_), peerIp(sock->getPeerAddress()),
+ userName(userName_?userName_:""),
approve(false), server(s) {
}
+QueryConnectDialog::~QueryConnectDialog()
+{
+ if (thread != nullptr) {
+ thread->join();
+ delete thread;
+ }
+}
+
void QueryConnectDialog::startDialog() {
- start();
+ thread = new std::thread(&QueryConnectDialog::worker, this);
}
@@ -74,7 +86,7 @@ void QueryConnectDialog::worker() {
void QueryConnectDialog::initDialog() {
if (!SetTimer(handle, 1, 1000, nullptr))
- throw rdr::win32_error("SetTimer", GetLastError());
+ throw core::win32_error("SetTimer", GetLastError());
setItemString(IDC_QUERY_HOST, peerIp.c_str());
if (userName.empty())
userName = "(anonymous)";
diff --git a/win/winvnc/QueryConnectDialog.h b/win/winvnc/QueryConnectDialog.h
index 332e7439..102199af 100644
--- a/win/winvnc/QueryConnectDialog.h
+++ b/win/winvnc/QueryConnectDialog.h
@@ -21,9 +21,9 @@
#ifndef __WINVNC_QUERY_CONNECT_DIALOG_H__
#define __WINVNC_QUERY_CONNECT_DIALOG_H__
-#include <rfb_win32/Dialog.h>
+#include <thread>
-namespace os { class Thread; }
+#include <rfb_win32/Dialog.h>
namespace network { class Socket; }
@@ -31,15 +31,16 @@ namespace winvnc {
class VNCServerWin32;
- class QueryConnectDialog : public os::Thread, rfb::win32::Dialog {
+ class QueryConnectDialog : rfb::win32::Dialog {
public:
QueryConnectDialog(network::Socket* sock, const char* userName, VNCServerWin32* s);
+ ~QueryConnectDialog();
virtual void startDialog();
network::Socket* getSock() {return sock;}
bool isAccepted() const {return approve;}
protected:
// Thread methods
- void worker() override;
+ void worker();
// Dialog methods (protected)
void initDialog() override;
@@ -48,6 +49,7 @@ namespace winvnc {
// Custom internal methods
void setCountdownLabel();
+ std::thread* thread;
int countdown;
network::Socket* sock;
std::string peerIp;
diff --git a/win/winvnc/STrayIcon.cxx b/win/winvnc/STrayIcon.cxx
index b64634b3..fc079e76 100644
--- a/win/winvnc/STrayIcon.cxx
+++ b/win/winvnc/STrayIcon.cxx
@@ -26,11 +26,8 @@
#include <winvnc/VNCServerService.h>
#include <winvnc/resource.h>
-#include <os/Mutex.h>
-#include <os/Thread.h>
-
-#include <rfb/LogWriter.h>
-#include <rfb/Configuration.h>
+#include <core/Configuration.h>
+#include <core/LogWriter.h>
#include <rfb_win32/LaunchProcess.h>
#include <rfb_win32/TrayIcon.h>
@@ -41,6 +38,7 @@
#include <winvnc/ControlPanel.h>
+using namespace core;
using namespace rfb;
using namespace win32;
using namespace winvnc;
@@ -217,7 +215,7 @@ public:
case WM_SET_TOOLTIP:
{
- os::AutoMutex a(thread.lock);
+ const std::lock_guard<std::mutex> a(thread.lock);
if (!thread.toolTip.empty())
setToolTip(thread.toolTip.c_str());
}
@@ -239,12 +237,11 @@ protected:
STrayIconThread::STrayIconThread(VNCServerWin32& sm, UINT inactiveIcon_, UINT activeIcon_,
UINT dis_inactiveIcon_, UINT dis_activeIcon_, UINT menu_)
-: thread_id(-1), windowHandle(nullptr), server(sm),
+: thread(&STrayIconThread::worker, this), thread_id(-1),
+ windowHandle(nullptr), server(sm),
inactiveIcon(inactiveIcon_), activeIcon(activeIcon_),
dis_inactiveIcon(dis_inactiveIcon_), dis_activeIcon(dis_activeIcon_),
menu(menu_), runTrayIcon(true) {
- lock = new os::Mutex;
- start();
while (thread_id == (DWORD)-1)
Sleep(0);
}
@@ -252,7 +249,7 @@ STrayIconThread::STrayIconThread(VNCServerWin32& sm, UINT inactiveIcon_, UINT ac
STrayIconThread::~STrayIconThread() {
runTrayIcon = false;
PostThreadMessage(thread_id, WM_QUIT, 0, 0);
- delete lock;
+ thread.join();
}
void STrayIconThread::worker() {
@@ -277,7 +274,7 @@ void STrayIconThread::worker() {
void STrayIconThread::setToolTip(const char* text) {
if (!windowHandle) return;
- os::AutoMutex a(lock);
+ const std::lock_guard<std::mutex> a(lock);
toolTip = text;
PostMessage(windowHandle, WM_SET_TOOLTIP, 0, 0);
}
diff --git a/win/winvnc/STrayIcon.h b/win/winvnc/STrayIcon.h
index 1aa7bfbc..0398757c 100644
--- a/win/winvnc/STrayIcon.h
+++ b/win/winvnc/STrayIcon.h
@@ -19,17 +19,16 @@
#ifndef WINVNC_TRAYICON_H
#define WINVNC_TRAYICON_H
+#include <mutex>
+#include <thread>
+
#include <winvnc/VNCServerWin32.h>
-#include <rfb/Configuration.h>
-namespace os {
- class Mutex;
- class Thread;
-}
+#include <core/Configuration.h>
namespace winvnc {
- class STrayIconThread : os::Thread {
+ class STrayIconThread {
public:
STrayIconThread(VNCServerWin32& sm, UINT inactiveIcon,
UINT activeIcon, UINT dis_inactiveIcon, UINT dis_activeIcon, UINT menu);
@@ -37,14 +36,15 @@ namespace winvnc {
void setToolTip(const char* text);
- static rfb::BoolParameter disableOptions;
- static rfb::BoolParameter disableClose;
+ static core::BoolParameter disableOptions;
+ static core::BoolParameter disableClose;
friend class STrayIcon;
protected:
- void worker() override;
+ void worker();
- os::Mutex* lock;
+ std::mutex lock;
+ std::thread thread;
DWORD thread_id;
HWND windowHandle;
std::string toolTip;
diff --git a/win/winvnc/VNCServerService.cxx b/win/winvnc/VNCServerService.cxx
index 8ae4b747..4da0a5dc 100644
--- a/win/winvnc/VNCServerService.cxx
+++ b/win/winvnc/VNCServerService.cxx
@@ -23,15 +23,19 @@
#endif
#include <winvnc/VNCServerService.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb_win32/TsSessions.h>
#include <rfb_win32/ModuleFileName.h>
+
#include <windows.h>
#include <wtsapi32.h>
#include <tlhelp32.h>
using namespace winvnc;
+using namespace core;
using namespace rfb;
using namespace win32;
diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx
index ee6c60a7..b09b6706 100644
--- a/win/winvnc/VNCServerWin32.cxx
+++ b/win/winvnc/VNCServerWin32.cxx
@@ -27,15 +27,17 @@
#include <winvnc/ListConnInfo.h>
#include <winvnc/STrayIcon.h>
-#include <os/Mutex.h>
+#include <core/LogWriter.h>
+
+#include <network/TcpSocket.h>
#include <rfb_win32/ComputerName.h>
#include <rfb_win32/CurrentUser.h>
#include <rfb_win32/Service.h>
-#include <rfb/Hostname.h>
-#include <rfb/LogWriter.h>
+#include <rfb/SConnection.h>
+using namespace core;
using namespace rfb;
using namespace win32;
using namespace winvnc;
@@ -48,7 +50,8 @@ const char* winvnc::VNCServerWin32::RegConfigPath = "Software\\TigerVNC\\WinVNC4
static IntParameter port_number("PortNumber",
- "TCP/IP port on which the server will accept connections", 5900);
+ "TCP/IP port on which the server will accept connections",
+ 5900, 0, 65535);
static StringParameter hosts("Hosts",
"Filter describing which hosts are allowed access to this server", "+");
static BoolParameter localHost("LocalHost",
@@ -69,11 +72,6 @@ VNCServerWin32::VNCServerWin32()
config(&sockMgr), rfbSock(&sockMgr), trayIcon(nullptr),
queryConnectDialog(nullptr)
{
- commandLock = new os::Mutex;
- commandSig = new os::Condition(commandLock);
-
- runLock = new os::Mutex;
-
// Initialise the desktop
desktop.setStatusLocation(&isDesktopStarted);
desktop.setQueryConnectionHandler(this);
@@ -95,15 +93,8 @@ VNCServerWin32::~VNCServerWin32() {
desktop.setStatusLocation(nullptr);
// Join the Accept/Reject dialog thread
- if (queryConnectDialog) {
- queryConnectDialog->wait();
+ if (queryConnectDialog)
delete queryConnectDialog;
- }
-
- delete runLock;
-
- delete commandSig;
- delete commandLock;
}
@@ -158,7 +149,7 @@ void VNCServerWin32::regConfigChanged() {
int VNCServerWin32::run() {
{
- os::AutoMutex a(runLock);
+ const std::lock_guard<std::mutex> a(runLock);
thread_id = GetCurrentThreadId();
runServer = true;
}
@@ -188,7 +179,7 @@ int VNCServerWin32::run() {
while (runServer) {
result = sockMgr.getMessage(&msg, nullptr, 0, 0);
if (result < 0)
- throw rdr::win32_error("getMessage", GetLastError());
+ throw core::win32_error("getMessage", GetLastError());
if (!isServiceProcess() && (result == 0))
break;
TranslateMessage(&msg);
@@ -196,7 +187,7 @@ int VNCServerWin32::run() {
}
vlog.debug("Server exited cleanly");
- } catch (rdr::win32_error &s) {
+ } catch (core::win32_error &s) {
vlog.error("%s", s.what());
result = s.err;
} catch (std::exception &e) {
@@ -204,7 +195,7 @@ int VNCServerWin32::run() {
}
{
- os::AutoMutex a(runLock);
+ const std::lock_guard<std::mutex> a(runLock);
runServer = false;
thread_id = (DWORD)-1;
}
@@ -213,7 +204,7 @@ int VNCServerWin32::run() {
}
void VNCServerWin32::stop() {
- os::AutoMutex a(runLock);
+ const std::lock_guard<std::mutex> a(runLock);
runServer = false;
if (thread_id != (DWORD)-1)
PostThreadMessage(thread_id, WM_QUIT, 0, 0);
@@ -270,17 +261,17 @@ void VNCServerWin32::queryConnectionComplete() {
bool VNCServerWin32::queueCommand(Command cmd, const void* data, int len, bool wait) {
- os::AutoMutex a(commandLock);
+ std::unique_lock<std::mutex> lock(commandLock);
while (command != NoCommand)
- commandSig->wait();
+ commandSig.wait(lock);
command = cmd;
commandData = data;
commandDataLen = len;
SetEvent(commandEvent);
if (wait) {
while (command != NoCommand)
- commandSig->wait();
- commandSig->signal();
+ commandSig.wait(lock);
+ commandSig.notify_one();
}
return true;
}
@@ -291,7 +282,7 @@ void VNCServerWin32::processEvent(HANDLE event_) {
if (event_ == commandEvent.h) {
// If there is no command queued then return immediately
{
- os::AutoMutex a(commandLock);
+ const std::lock_guard<std::mutex> a(commandLock);
if (command == NoCommand)
return;
}
@@ -321,7 +312,6 @@ void VNCServerWin32::processEvent(HANDLE event_) {
vncServer.approveConnection(queryConnectDialog->getSock(),
queryConnectDialog->isAccepted(),
"Connection rejected by user");
- queryConnectDialog->wait();
delete queryConnectDialog;
queryConnectDialog = nullptr;
break;
@@ -332,9 +322,9 @@ void VNCServerWin32::processEvent(HANDLE event_) {
// Clear the command and signal completion
{
- os::AutoMutex a(commandLock);
+ std::unique_lock<std::mutex> lock(commandLock);
command = NoCommand;
- commandSig->signal();
+ commandSig.notify_one();
}
} else if ((event_ == sessionEvent.h) ||
(event_ == desktop.getTerminateEvent())) {
diff --git a/win/winvnc/VNCServerWin32.h b/win/winvnc/VNCServerWin32.h
index 4fcc66d5..656e2cfa 100644
--- a/win/winvnc/VNCServerWin32.h
+++ b/win/winvnc/VNCServerWin32.h
@@ -19,6 +19,9 @@
#ifndef __VNCSERVER_WIN32_H__
#define __VNCSERVER_WIN32_H__
+#include <condition_variable>
+#include <mutex>
+
#include <winsock2.h>
#include <network/TcpSocket.h>
#include <rfb/VNCServerST.h>
@@ -28,9 +31,7 @@
#include <winvnc/QueryConnectDialog.h>
#include <winvnc/ManagedListener.h>
-namespace os {
- class Mutex;
- class Condition;
+namespace core {
class Thread;
}
@@ -106,15 +107,15 @@ namespace winvnc {
Command command;
const void* commandData;
int commandDataLen;
- os::Mutex* commandLock;
- os::Condition* commandSig;
+ std::mutex commandLock;
+ std::condition_variable commandSig;
rfb::win32::Handle commandEvent;
rfb::win32::Handle sessionEvent;
// VNCServerWin32 Server-internal state
rfb::win32::SDisplay desktop;
rfb::VNCServerST vncServer;
- os::Mutex* runLock;
+ std::mutex runLock;
DWORD thread_id;
bool runServer;
bool isDesktopStarted;
diff --git a/win/winvnc/winvnc.cxx b/win/winvnc/winvnc.cxx
index 299e1fa1..58665005 100644
--- a/win/winvnc/winvnc.cxx
+++ b/win/winvnc/winvnc.cxx
@@ -28,15 +28,18 @@
#include <winvnc/VNCServerService.h>
#include <winvnc/AddNewClientDialog.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/Logger_file.h>
-#include <rfb/LogWriter.h>
-#include <rfb/util.h>
+#include <core/Logger_file.h>
+#include <core/Logger_stdio.h>
+#include <core/LogWriter.h>
+#include <core/string.h>
+
#include <rfb_win32/AboutDialog.h>
#include <rfb_win32/MsgBox.h>
+
#include <network/TcpSocket.h>
using namespace winvnc;
+using namespace core;
using namespace rfb;
using namespace win32;
@@ -177,13 +180,13 @@ static void processParams(int argc, char** argv) {
// Try to clean up earlier services we've had
try {
rfb::win32::unregisterService("WinVNC4");
- } catch (rdr::win32_error&) {
+ } catch (core::win32_error&) {
// Do nothing as we might fail simply because there was no
// service to remove
}
try {
rfb::win32::unregisterService("TigerVNC Server");
- } catch (rdr::win32_error&) {
+ } catch (core::win32_error&) {
}
if (rfb::win32::registerService(VNCServerService::Name,
@@ -212,16 +215,14 @@ static void processParams(int argc, char** argv) {
break;
} else {
- // Try to process <option>=<value>, or -<bool>
- if (Configuration::setParam(argv[i], true))
+ int ret;
+
+ ret = Configuration::handleParamArg(argc, argv, i);
+ if (ret > 0) {
+ i += ret - 1;
continue;
- // Try to process -<option> <value>
- if ((argv[i][0] == '-') && (i+1 < argc)) {
- if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
- i++;
- continue;
- }
}
+
// Nope. Show them usage and don't run the server
runServer = false;
programUsage();
@@ -260,8 +261,6 @@ int WINAPI WinMain(HINSTANCE /*inst*/, HINSTANCE /*prevInst*/, char* /*cmdLine*/
#endif
rfb::win32::initEventLogLogger(VNCServerService::Name);
- Configuration::enableServerParams();
-
// - By default, just log errors to stderr
diff --git a/win/winvnc/winvnc.rc b/win/winvnc/winvnc.rc
index 807114d0..acaa0dbd 100644
--- a/win/winvnc/winvnc.rc
+++ b/win/winvnc/winvnc.rc
@@ -76,12 +76,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "Comments", "\0"
- VALUE "CompanyName", "TigerVNC project\0"
+ VALUE "CompanyName", "TigerVNC team\0"
VALUE "FileDescription", "TigerVNC server\0"
VALUE "ProductName", "TigerVNC server\0"
VALUE "FileVersion", __RCVERSIONSTR
VALUE "InternalName", "winvnc\0"
- VALUE "LegalCopyright", "Copyright (C) 1999-2024 TigerVNC Team and many others (see README.rst)\0"
+ VALUE "LegalCopyright", "Copyright (C) 1999-2025 TigerVNC team and many others (see README.rst)\0"
VALUE "LegalTrademarks", "TigerVNC\0"
VALUE "OriginalFilename", "winvnc4.exe\0"
VALUE "PrivateBuild", "\0"
diff --git a/win/wm_hooks/wm_hooks.cxx b/win/wm_hooks/wm_hooks.cxx
index a48a1738..2f04b851 100644
--- a/win/wm_hooks/wm_hooks.cxx
+++ b/win/wm_hooks/wm_hooks.cxx
@@ -25,7 +25,6 @@
#endif
#include <wm_hooks/wm_hooks.h>
-#include <os/os.h>
#define SHARED __attribute__((section ("shared"), shared))
diff --git a/win/wm_hooks/wm_hooks.rc b/win/wm_hooks/wm_hooks.rc
index ae56b314..2bf38f3d 100644
--- a/win/wm_hooks/wm_hooks.rc
+++ b/win/wm_hooks/wm_hooks.rc
@@ -72,12 +72,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "Comments", "\0"
- VALUE "CompanyName", "TigerVNC project\0"
+ VALUE "CompanyName", "TigerVNC team\0"
VALUE "FileDescription", "TigerVNC server hooking DLL\0"
VALUE "ProductName", "TigerVNC server hooking DLL\0"
VALUE "FileVersion", __RCVERSIONSTR
VALUE "InternalName", "\0"
- VALUE "LegalCopyright", "Copyright (C) 1999-2005 [many holders]\0"
+ VALUE "LegalCopyright", "Copyright (C) 1999-2025 TigerVNC team and many others (see README.rst)\0"
VALUE "LegalTrademarks", "TigerVNC\0"
VALUE "OriginalFilename", "wm_hooks.dll\0"
VALUE "PrivateBuild", "\0"