├── .krazy ├── logo.png ├── AUTHORS ├── doc ├── connection.png ├── screenshot.png ├── configuration_network.png ├── configuration_security.png └── CMakeLists.txt ├── icons ├── 48-apps-krfb.png ├── sc-apps-krfb.svgz └── CMakeLists.txt ├── krfb ├── krfbconfig.kcfgc ├── Messages.sh ├── krfbui.rc ├── krfb.qrc ├── config-krfb.h.cmake ├── rfb.h ├── eventsplugin.cpp ├── framebufferplugin.cpp ├── sockethelpers.h ├── events.cpp ├── eventsplugin.h ├── trayicon.h ├── framebufferplugin.h ├── invitationsrfbclient.h ├── eventsmanager.h ├── events.h ├── framebuffermanager.h ├── mainwindow.h ├── ui │ ├── configsecurity.ui │ ├── configframebuffer.ui │ ├── configtcp.ui │ └── connectionwidget.ui ├── framebuffer.h ├── connectiondialog.h ├── rfbservermanager.h ├── framebuffer.cpp ├── invitationsrfbserver.h ├── krfb.kcfg ├── eventsmanager.cpp ├── rfbserver.h ├── connectiondialog.cpp ├── sockethelpers.cpp ├── org.kde.krfb.virtualmonitor.desktop.cmake ├── framebuffermanager.cpp ├── rfbclient.h ├── invitationsrfbclient.cpp ├── trayicon.cpp ├── CMakeLists.txt ├── org.kde.krfb.desktop ├── main.cpp ├── main-virtualmonitor.cpp ├── rfbservermanager.cpp ├── rfbclient.cpp ├── invitationsrfbserver.cpp └── rfbserver.cpp ├── .flatpak-manifest.json.license ├── po ├── de │ └── docs │ │ └── krfb │ │ ├── connection.png │ │ ├── screenshot.png │ │ ├── email_invitation.png │ │ ├── personal_invitation.png │ │ ├── configuration_network.png │ │ └── configuration_security.png ├── fr │ └── docs │ │ └── krfb │ │ ├── connection.png │ │ ├── screenshot.png │ │ ├── email_invitation.png │ │ ├── personal_invitation.png │ │ ├── configuration_network.png │ │ └── configuration_security.png ├── sv │ └── docs │ │ └── krfb │ │ ├── connection.png │ │ ├── screenshot.png │ │ ├── email_invitation.png │ │ ├── personal_invitation.png │ │ ├── configuration_access.png │ │ ├── configuration_network.png │ │ ├── configuration_session.png │ │ └── invitation_management.png └── sr │ └── docs │ └── krfb │ └── l10n-track ├── framebuffers ├── xcb │ ├── xcb.json │ ├── xcb_framebufferplugin.cpp │ ├── xcb_framebufferplugin.h │ ├── xcb_framebuffer.h │ └── CMakeLists.txt ├── pipewire │ ├── pipewire.json │ ├── pw_framebufferplugin.h │ ├── pw_framebufferplugin.cpp │ ├── screencasting.h │ ├── pw_framebuffer.h │ ├── CMakeLists.txt │ └── screencasting.cpp └── CMakeLists.txt ├── CMakePresets.json.license ├── Mainpage.dox ├── events ├── CMakeLists.txt ├── xdp │ ├── xdpevents.h │ ├── xdpeventsplugin.cpp │ ├── xdpeventsplugin.h │ ├── CMakeLists.txt │ └── xdpevents.cpp └── x11 │ ├── CMakeLists.txt │ ├── x11events.h │ ├── x11eventsplugin.h │ ├── x11eventsplugin.cpp │ └── x11events.cpp ├── .gitignore ├── .gitlab-ci.yml ├── README ├── LICENSES ├── LicenseRef-KDE-Accepted-LGPL.txt ├── BSD-3-Clause.txt ├── CC0-1.0.txt └── LGPL-3.0-only.txt ├── .kde-ci.yml ├── TODO ├── cmake └── modules │ ├── COPYING-CMAKE-SCRIPTS │ └── Findgbm.cmake ├── NOTES ├── .flatpak-manifest.json ├── CMakeLists.txt ├── CMakePresets.json ├── snapcraft.yaml └── dbus └── xdp_dbus_screencast_interface.xml /.krazy: -------------------------------------------------------------------------------- 1 | SKIP /kinetd/ 2 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/logo.png -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Tim Jansen 2 | Ian Reinhart Geiser -------------------------------------------------------------------------------- /doc/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/doc/connection.png -------------------------------------------------------------------------------- /doc/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/doc/screenshot.png -------------------------------------------------------------------------------- /icons/48-apps-krfb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/icons/48-apps-krfb.png -------------------------------------------------------------------------------- /krfb/krfbconfig.kcfgc: -------------------------------------------------------------------------------- 1 | File=krfb.kcfg 2 | ClassName=KrfbConfig 3 | Singleton=true 4 | -------------------------------------------------------------------------------- /icons/sc-apps-krfb.svgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/icons/sc-apps-krfb.svgz -------------------------------------------------------------------------------- /doc/configuration_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/doc/configuration_network.png -------------------------------------------------------------------------------- /.flatpak-manifest.json.license: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: None 2 | # SPDX-License-Identifier: CC0-1.0 3 | -------------------------------------------------------------------------------- /doc/configuration_security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/doc/configuration_security.png -------------------------------------------------------------------------------- /po/de/docs/krfb/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/de/docs/krfb/connection.png -------------------------------------------------------------------------------- /po/de/docs/krfb/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/de/docs/krfb/screenshot.png -------------------------------------------------------------------------------- /po/fr/docs/krfb/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/fr/docs/krfb/connection.png -------------------------------------------------------------------------------- /po/fr/docs/krfb/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/fr/docs/krfb/screenshot.png -------------------------------------------------------------------------------- /po/sv/docs/krfb/connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/sv/docs/krfb/connection.png -------------------------------------------------------------------------------- /po/sv/docs/krfb/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/sv/docs/krfb/screenshot.png -------------------------------------------------------------------------------- /framebuffers/xcb/xcb.json: -------------------------------------------------------------------------------- 1 | { 2 | "X-KDE-OnlyShowOnQtPlatforms": [ 3 | "xcb" 4 | ] 5 | } 6 | 7 | -------------------------------------------------------------------------------- /krfb/Messages.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | $EXTRACTRC ui/*.ui *.kcfg >> rc.cpp 3 | $XGETTEXT *.cpp -o $podir/krfb.pot 4 | -------------------------------------------------------------------------------- /po/de/docs/krfb/email_invitation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/de/docs/krfb/email_invitation.png -------------------------------------------------------------------------------- /po/fr/docs/krfb/email_invitation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/fr/docs/krfb/email_invitation.png -------------------------------------------------------------------------------- /po/sv/docs/krfb/email_invitation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/sv/docs/krfb/email_invitation.png -------------------------------------------------------------------------------- /framebuffers/pipewire/pipewire.json: -------------------------------------------------------------------------------- 1 | { 2 | "X-KDE-OnlyShowOnQtPlatforms": [ 3 | "wayland" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /po/de/docs/krfb/personal_invitation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/de/docs/krfb/personal_invitation.png -------------------------------------------------------------------------------- /po/fr/docs/krfb/personal_invitation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/fr/docs/krfb/personal_invitation.png -------------------------------------------------------------------------------- /po/sv/docs/krfb/personal_invitation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/sv/docs/krfb/personal_invitation.png -------------------------------------------------------------------------------- /po/de/docs/krfb/configuration_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/de/docs/krfb/configuration_network.png -------------------------------------------------------------------------------- /po/de/docs/krfb/configuration_security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/de/docs/krfb/configuration_security.png -------------------------------------------------------------------------------- /po/fr/docs/krfb/configuration_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/fr/docs/krfb/configuration_network.png -------------------------------------------------------------------------------- /po/fr/docs/krfb/configuration_security.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/fr/docs/krfb/configuration_security.png -------------------------------------------------------------------------------- /po/sv/docs/krfb/configuration_access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/sv/docs/krfb/configuration_access.png -------------------------------------------------------------------------------- /po/sv/docs/krfb/configuration_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/sv/docs/krfb/configuration_network.png -------------------------------------------------------------------------------- /po/sv/docs/krfb/configuration_session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/sv/docs/krfb/configuration_session.png -------------------------------------------------------------------------------- /po/sv/docs/krfb/invitation_management.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KDE/krfb/HEAD/po/sv/docs/krfb/invitation_management.png -------------------------------------------------------------------------------- /CMakePresets.json.license: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 Laurent Montel 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | -------------------------------------------------------------------------------- /Mainpage.dox: -------------------------------------------------------------------------------- 1 | /** @mainpage Krfb API Reference 2 | * 3 | * Krfb provides a VNC-compatible server to share KDE desktops. 4 | * 5 | */ 6 | -------------------------------------------------------------------------------- /krfb/krfbui.rc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /icons/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ecm_install_icons(ICONS 2 | sc-apps-krfb.svgz 3 | 48-apps-krfb.png 4 | DESTINATION ${KDE_INSTALL_ICONDIR} THEME hicolor ) 5 | -------------------------------------------------------------------------------- /krfb/krfb.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | krfbui.rc 5 | 6 | 7 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ########### install files ############### 2 | kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR krfb) 3 | -------------------------------------------------------------------------------- /events/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(x11) 2 | 3 | # Makes sense to use only when PW framebuffer is used 4 | if (TARGET K::KPipeWire) 5 | add_subdirectory(xdp) 6 | endif() 7 | -------------------------------------------------------------------------------- /framebuffers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (${XCB_DAMAGE_FOUND} AND ${XCB_SHM_FOUND} AND ${XCB_IMAGE_FOUND}) 2 | add_subdirectory (xcb) 3 | endif() 4 | 5 | if (TARGET K::KPipeWire) 6 | add_subdirectory(pipewire) 7 | endif() 8 | -------------------------------------------------------------------------------- /krfb/config-krfb.h.cmake: -------------------------------------------------------------------------------- 1 | /* Define to 1 if you have the `getifaddrs' function. */ 2 | #cmakedefine HAVE_GETIFADDRS 1 3 | 4 | /* Define if SLP is available */ 5 | #cmakedefine HAVE_SLP 1 6 | 7 | /* Define if XDamage is available */ 8 | #cmakedefine HAVE_XDAMAGE 1 9 | 10 | /* Define if XShm is available */ 11 | #cmakedefine HAVE_XSHM 1 12 | -------------------------------------------------------------------------------- /krfb/rfb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This file should always be included instead of because otherwise it's redefinition 3 | * of TRUE and FALSE plays havoc with other things. 4 | */ 5 | 6 | #ifndef KRFB_RFB_H 7 | #define KRFB_RFB_H 8 | 9 | #include "rfb/rfb.h" 10 | 11 | #ifdef max 12 | #undef max 13 | #endif 14 | 15 | #undef TRUE 16 | #undef FALSE 17 | 18 | #endif // Header guard 19 | 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore the following files 2 | *~ 3 | *.[oa] 4 | *.diff 5 | *.kate-swp 6 | *.kdev4 7 | .kdev_include_paths 8 | *.kdevelop.pcs 9 | *.moc 10 | *.moc.cpp 11 | *.orig 12 | *.user 13 | .*.swp 14 | .swp.* 15 | Doxyfile 16 | Makefile 17 | /build*/ 18 | .cmake/ 19 | CMakeLists.txt.user* 20 | *.unc-backup* 21 | .clang-format 22 | /compile_commands.json 23 | .clangd 24 | .cache 25 | .idea 26 | /cmake-build* 27 | -------------------------------------------------------------------------------- /krfb/eventsplugin.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* This file is part of the KDE project 3 | SPDX-FileCopyrightText: 2016 Oleg Chernovskiy 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #include "eventsplugin.h" 9 | 10 | #include "events.h" 11 | 12 | EventsPlugin::EventsPlugin(QObject *parent, const QVariantList &) 13 | : QObject(parent) 14 | { 15 | } 16 | 17 | EventsPlugin::~EventsPlugin() 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: None 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | include: 5 | - project: sysadmin/ci-utilities 6 | file: 7 | - /gitlab-templates/linux-qt6.yml 8 | - /gitlab-templates/linux-qt6-next.yml 9 | - /gitlab-templates/freebsd-qt6.yml 10 | - /gitlab-templates/flatpak.yml 11 | - /gitlab-templates/xml-lint.yml 12 | - /gitlab-templates/yaml-lint.yml 13 | - /gitlab-templates/documentation.yml 14 | -------------------------------------------------------------------------------- /krfb/framebufferplugin.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #include "framebufferplugin.h" 9 | 10 | #include "framebuffer.h" 11 | 12 | FrameBufferPlugin::FrameBufferPlugin(QObject *parent, const QVariantList &) 13 | : QObject(parent) 14 | { 15 | } 16 | 17 | FrameBufferPlugin::~FrameBufferPlugin() 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /po/sr/docs/krfb/l10n-track: -------------------------------------------------------------------------------- 1 | # Do not edit manually, except to remove complete lines. 2 | 3 | missing ¦configuration_network.png¦ eb78c8413a453310d740cc3fcb970501 518176 4 | missing ¦configuration_security.png¦ 361accc1633088e9ee06e50d0383e200 1140837 5 | missing ¦connection.png¦ 6a679b0c5cd21544a8563e3b20d42e0a 518176 6 | missing ¦email_invitation.png¦ 3c1a8e68101b265ba9800497313652c4 518176 7 | missing ¦personal_invitation.png¦ e7c748afa5fcd5e24cc0ed539730eea1 518176 8 | missing ¦screenshot.png¦ 40f2117205d70ae32c834008f7caa44b 518176 9 | 10 | -------------------------------------------------------------------------------- /events/xdp/xdpevents.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | 4 | SPDX-FileCopyrightText: 2018-2019 Jan Grulich 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #ifndef EVENTS_XDPEVENTS_H 10 | #define EVENTS_XDPEVENTS_H 11 | 12 | #include "../../krfb/events.h" 13 | 14 | class XdpEventHandler : public EventHandler 15 | { 16 | Q_OBJECT 17 | public: 18 | void handleKeyboard(bool down, rfbKeySym key) override; 19 | void handlePointer(int buttonMask, int x, int y) override; 20 | }; 21 | 22 | #endif 23 | 24 | 25 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | KDE Desktop Sharing (krfb) 2 | ========================== 3 | 4 | KDE Desktop Sharing (krfb) is a small server for the RFB protocol, better 5 | known as VNC. Unlike most other Unix/Linux RFB servers, KRfb allows you to 6 | share your X11 session instead of creating a new X11 session. 7 | It was originally based on x0rfbserver 8 | (ttp://www.hexonet.de/software/x0rfbserver/), but there is not much code of 9 | x0rfbserver left. Since version 0.6 it uses libvncserver 10 | (http://libvncserver.sf.net) as backend. 11 | 12 | 13 | Guide to documentation: 14 | TODO - things to be done 15 | NOTES - reasons for various decisions 16 | -------------------------------------------------------------------------------- /events/x11/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories (${CMAKE_CURRENT_SOURCE_DIR} 2 | ${CMAKE_CURRENT_BINARY_DIR} 3 | ) 4 | 5 | set (krfb_events_x11_SRCS 6 | x11events.cpp 7 | x11eventsplugin.cpp 8 | ) 9 | 10 | add_library (krfb_events_x11 MODULE ${krfb_events_x11_SRCS}) 11 | 12 | target_link_libraries (krfb_events_x11 13 | ${X11_XTest_LIB} 14 | KF6::CoreAddons 15 | krfbprivate 16 | ) 17 | set_target_properties(krfb_events_x11 PROPERTIES OUTPUT_NAME x11) 18 | 19 | install (TARGETS krfb_events_x11 DESTINATION ${KDE_INSTALL_PLUGINDIR}/krfb/events) 20 | -------------------------------------------------------------------------------- /krfb/sockethelpers.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 5 | SPDX-FileCopyrightText: 2001-2003 Tim Jansen 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #ifndef SOCKETHELPERS_H 11 | #define SOCKETHELPERS_H 12 | 13 | #include 14 | 15 | QString peerAddress(int sock); 16 | unsigned short peerPort(int sock); 17 | 18 | QString localAddress(int sock); 19 | unsigned short localPort(int sock); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /events/x11/x11events.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | 4 | SPDX-FileCopyrightText: 2016 Oleg Chernovskiy 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #ifndef EVENTS_X11EVENTS_H 10 | #define EVENTS_X11EVENTS_H 11 | 12 | #include "../../krfb/events.h" 13 | 14 | class X11EventHandler : public EventHandler 15 | { 16 | Q_OBJECT 17 | public: 18 | explicit X11EventHandler(QObject *parent = nullptr) 19 | : EventHandler(parent) 20 | { 21 | }; 22 | 23 | void handleKeyboard(bool down, rfbKeySym key) override; 24 | void handlePointer(int buttonMask, int x, int y) override; 25 | }; 26 | 27 | #endif 28 | 29 | -------------------------------------------------------------------------------- /events/xdp/xdpeventsplugin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | 4 | SPDX-FileCopyrightText: 2018-2019 Jan Grulich 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #include "xdpeventsplugin.h" 10 | 11 | #include "xdpevents.h" 12 | 13 | #include 14 | 15 | K_PLUGIN_CLASS(XdpEventsPlugin) 16 | 17 | XdpEventsPlugin::XdpEventsPlugin(QObject *parent, const QVariantList &args) 18 | : EventsPlugin(parent, args) 19 | { 20 | } 21 | 22 | EventHandler *XdpEventsPlugin::eventHandler() 23 | { 24 | // works only under Wayland 25 | return new XdpEventHandler(); 26 | } 27 | 28 | #include "xdpeventsplugin.moc" 29 | 30 | -------------------------------------------------------------------------------- /events/x11/x11eventsplugin.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2016 Oleg Chernovskiy 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef KRFB_EVENTS_X11_X11EVENTSPLUGIN_H 8 | #define KRFB_EVENTS_X11_X11EVENTSPLUGIN_H 9 | 10 | #include "eventsplugin.h" 11 | 12 | #include 13 | 14 | class EventHandler; 15 | 16 | class X11EventsPlugin : public EventsPlugin 17 | { 18 | Q_OBJECT 19 | public: 20 | X11EventsPlugin(QObject *parent, const QVariantList &args); 21 | 22 | EventHandler *eventHandler() override; 23 | 24 | private: 25 | Q_DISABLE_COPY(X11EventsPlugin) 26 | }; 27 | 28 | 29 | #endif // Header guard 30 | -------------------------------------------------------------------------------- /events/xdp/xdpeventsplugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | 4 | SPDX-FileCopyrightText: 2018-2019 Jan Grulich 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #ifndef KRFB_EVENTS_XDP_XDPEVENTSPLUGIN_H 10 | #define KRFB_EVENTS_XDP_XDPEVENTSPLUGIN_H 11 | 12 | #include "eventsplugin.h" 13 | 14 | #include 15 | 16 | class EventHandler; 17 | 18 | class XdpEventsPlugin : public EventsPlugin 19 | { 20 | Q_OBJECT 21 | public: 22 | XdpEventsPlugin(QObject *parent, const QVariantList &args); 23 | 24 | EventHandler *eventHandler() override; 25 | 26 | private: 27 | Q_DISABLE_COPY(XdpEventsPlugin) 28 | }; 29 | 30 | 31 | #endif // Header guard 32 | 33 | -------------------------------------------------------------------------------- /LICENSES/LicenseRef-KDE-Accepted-LGPL.txt: -------------------------------------------------------------------------------- 1 | This library is free software; you can redistribute it and/or 2 | modify it under the terms of the GNU Lesser General Public 3 | License as published by the Free Software Foundation; either 4 | version 3 of the license or (at your option) any later version 5 | that is accepted by the membership of KDE e.V. (or its successor 6 | approved by the membership of KDE e.V.), which shall act as a 7 | proxy as defined in Section 6 of version 3 of the license. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | -------------------------------------------------------------------------------- /framebuffers/xcb/xcb_framebufferplugin.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2017 Alexey Min 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | 8 | #include "xcb_framebufferplugin.h" 9 | #include "xcb_framebuffer.h" 10 | #include 11 | 12 | K_PLUGIN_CLASS_WITH_JSON(XCBFrameBufferPlugin, "xcb.json") 13 | 14 | XCBFrameBufferPlugin::XCBFrameBufferPlugin(QObject *parent, const QVariantList &args) 15 | : FrameBufferPlugin(parent, args) 16 | { 17 | } 18 | 19 | FrameBuffer *XCBFrameBufferPlugin::frameBuffer(const QVariantMap &args) 20 | { 21 | Q_UNUSED(args); 22 | return new XCBFrameBuffer; 23 | } 24 | 25 | #include "xcb_framebufferplugin.moc" 26 | 27 | -------------------------------------------------------------------------------- /framebuffers/pipewire/pw_framebufferplugin.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2018 Oleg Chernovskiy 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #ifndef KRFB_FRAMEBUFFER_PW_PWFRAMEBUFFERPLUGIN_H 8 | #define KRFB_FRAMEBUFFER_PW_PWFRAMEBUFFERPLUGIN_H 9 | 10 | 11 | #include "framebufferplugin.h" 12 | 13 | class FrameBuffer; 14 | 15 | class PWFrameBufferPlugin: public FrameBufferPlugin 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | PWFrameBufferPlugin(QObject *parent, const QVariantList &args); 21 | 22 | FrameBuffer *frameBuffer(const QVariantMap &args) override; 23 | 24 | private: 25 | Q_DISABLE_COPY(PWFrameBufferPlugin) 26 | }; 27 | 28 | 29 | #endif // Header guard 30 | -------------------------------------------------------------------------------- /krfb/events.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | 4 | SPDX-FileCopyrightText: 2010 Collabora Ltd. 5 | SPDX-FileContributor: George Kiagiadakis 6 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 7 | SPDX-FileCopyrightText: 2001-2003 Tim Jansen 8 | 9 | SPDX-License-Identifier: GPL-2.0-or-later 10 | */ 11 | 12 | #include "events.h" 13 | 14 | EventHandler::EventHandler(QObject *parent) 15 | : QObject(parent) 16 | { 17 | } 18 | 19 | void EventHandler::setFrameBufferPlugin(const QSharedPointer &frameBuffer) 20 | { 21 | fb = frameBuffer; 22 | } 23 | 24 | QSharedPointer EventHandler::frameBuffer() 25 | { 26 | return fb; 27 | } 28 | -------------------------------------------------------------------------------- /framebuffers/xcb/xcb_framebufferplugin.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: Alexey Min 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef KRFB_FRAMEBUFFER_XCB_XCBFRAMEBUFFERPLUGIN_H 8 | #define KRFB_FRAMEBUFFER_XCB_XCBFRAMEBUFFERPLUGIN_H 9 | 10 | 11 | #include "framebufferplugin.h" 12 | #include 13 | 14 | 15 | class FrameBuffer; 16 | 17 | class XCBFrameBufferPlugin: public FrameBufferPlugin 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | XCBFrameBufferPlugin(QObject *parent, const QVariantList &args); 23 | 24 | FrameBuffer *frameBuffer(const QVariantMap &args) override; 25 | 26 | private: 27 | Q_DISABLE_COPY(XCBFrameBufferPlugin) 28 | }; 29 | 30 | 31 | #endif // Header guard 32 | -------------------------------------------------------------------------------- /krfb/eventsplugin.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #ifndef LIB_KRFB_EVENTSPLUGIN_H 9 | #define LIB_KRFB_EVENTSPLUGIN_H 10 | 11 | #include "krfbprivate_export.h" 12 | 13 | #include 14 | #include 15 | 16 | class EventHandler; 17 | 18 | class KRFBPRIVATE_EXPORT EventsPlugin : public QObject 19 | { 20 | Q_OBJECT 21 | public: 22 | EventsPlugin(QObject *parent, const QVariantList &args); 23 | ~EventsPlugin() override; 24 | 25 | virtual EventHandler *eventHandler() = 0; 26 | }; 27 | 28 | #endif // Header guard 29 | 30 | -------------------------------------------------------------------------------- /events/x11/x11eventsplugin.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2016 Oleg Chernovskiy 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include "x11eventsplugin.h" 8 | 9 | #include "x11events.h" 10 | 11 | #include 12 | 13 | #include 14 | 15 | K_PLUGIN_CLASS(X11EventsPlugin) 16 | 17 | X11EventsPlugin::X11EventsPlugin(QObject *parent, const QVariantList &args) 18 | : EventsPlugin(parent, args) 19 | { 20 | } 21 | 22 | EventHandler *X11EventsPlugin::eventHandler() 23 | { 24 | // works only under X11 25 | if(!QX11Info::isPlatformX11()) 26 | return nullptr; 27 | 28 | return new X11EventHandler(); 29 | } 30 | 31 | #include "x11eventsplugin.moc" 32 | 33 | -------------------------------------------------------------------------------- /krfb/trayicon.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2001-2002 Tim Jansen 3 | SPDX-License-Identifier: GPL-2.0-or-later 4 | */ 5 | 6 | #ifndef TRAYICON_H 7 | #define TRAYICON_H 8 | 9 | #include 10 | 11 | #include 12 | 13 | class RfbClient; 14 | class ClientActions; 15 | 16 | /** 17 | * Implements the trayicon. 18 | * @author Tim Jansen 19 | */ 20 | 21 | class TrayIcon : public KStatusNotifierItem 22 | { 23 | Q_OBJECT 24 | public: 25 | explicit TrayIcon(QWidget *mainWindow); 26 | 27 | public Q_SLOTS: 28 | void onClientConnected(RfbClient *client); 29 | void onClientDisconnected(RfbClient *client); 30 | void showAbout(); 31 | 32 | private: 33 | QAction *m_aboutAction; 34 | QHash m_clientActions; 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /krfb/framebufferplugin.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #ifndef LIB_KRFB_FRAMEBUFFERPLUGIN_H 9 | #define LIB_KRFB_FRAMEBUFFERPLUGIN_H 10 | 11 | #include "krfbprivate_export.h" 12 | 13 | #include 14 | #include 15 | 16 | 17 | class FrameBuffer; 18 | 19 | class KRFBPRIVATE_EXPORT FrameBufferPlugin : public QObject 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit FrameBufferPlugin(QObject *parent, const QVariantList &args); 25 | ~FrameBufferPlugin() override; 26 | 27 | virtual FrameBuffer *frameBuffer(const QVariantMap &args) = 0; 28 | }; 29 | 30 | #endif // Header guard 31 | 32 | -------------------------------------------------------------------------------- /events/xdp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories (${CMAKE_CURRENT_SOURCE_DIR} 2 | ${CMAKE_CURRENT_BINARY_DIR} 3 | ) 4 | 5 | set (krfb_events_xdp_SRCS 6 | xdpevents.cpp 7 | xdpeventsplugin.cpp 8 | ) 9 | 10 | qt_add_dbus_interface( 11 | krfb_events_xdp_SRCS 12 | ${CMAKE_SOURCE_DIR}/dbus/xdp_dbus_remotedesktop_interface.xml 13 | xdp_dbus_remotedesktop_interface 14 | ) 15 | 16 | add_library (krfb_events_xdp MODULE ${krfb_events_xdp_SRCS}) 17 | 18 | target_link_libraries (krfb_events_xdp 19 | KF6::CoreAddons 20 | KF6::I18n 21 | Qt::DBus 22 | krfbprivate 23 | ) 24 | set_target_properties(krfb_events_xdp PROPERTIES OUTPUT_NAME xdp) 25 | 26 | install (TARGETS krfb_events_xdp 27 | DESTINATION ${KDE_INSTALL_PLUGINDIR}/krfb/events 28 | ) 29 | -------------------------------------------------------------------------------- /.kde-ci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: None 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | Dependencies: 5 | - 'on': ['@all'] 6 | 'require': 7 | 'frameworks/extra-cmake-modules': '@latest-kf6' 8 | 'frameworks/ki18n': '@latest-kf6' 9 | 'frameworks/kconfig': '@latest-kf6' 10 | 'frameworks/kcoreaddons': '@latest-kf6' 11 | 'frameworks/kdbusaddons': '@latest-kf6' 12 | 'frameworks/kdnssd': '@latest-kf6' 13 | 'frameworks/kdoctools': '@latest-kf6' 14 | 'frameworks/knotifications': '@latest-kf6' 15 | 'frameworks/kwallet': '@latest-kf6' 16 | 'frameworks/kwidgetsaddons': '@latest-kf6' 17 | 'frameworks/kwindowsystem': '@latest-kf6' 18 | 'frameworks/kxmlgui': '@latest-kf6' 19 | 'frameworks/kcrash': '@latest-kf6' 20 | 'frameworks/kstatusnotifieritem': '@latest-kf6' 21 | 'libraries/plasma-wayland-protocols': '@latest-kf6' 22 | 'plasma/kwayland': '@latest-kf6' 23 | 'plasma/kpipewire': '@latest-kf6' 24 | 25 | Options: 26 | require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows'] 27 | -------------------------------------------------------------------------------- /krfb/invitationsrfbclient.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2010 Collabora Ltd 3 | SPDX-FileContributor: George Kiagiadakis 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | #ifndef INVITATIONSRFBCLIENT_H 8 | #define INVITATIONSRFBCLIENT_H 9 | 10 | #include "rfbclient.h" 11 | 12 | class InvitationsRfbClient : public RfbClient 13 | { 14 | public: 15 | explicit InvitationsRfbClient(rfbClientPtr client, QObject* parent = nullptr) 16 | : RfbClient(client, parent) {} 17 | }; 18 | 19 | 20 | class PendingInvitationsRfbClient : public PendingRfbClient 21 | { 22 | Q_OBJECT 23 | public: 24 | explicit PendingInvitationsRfbClient(rfbClientPtr client, QObject *parent = nullptr); 25 | ~PendingInvitationsRfbClient() override; 26 | 27 | protected Q_SLOTS: 28 | void processNewClient() override; 29 | bool checkPassword(const QByteArray & encryptedPassword) override; 30 | 31 | private Q_SLOTS: 32 | void dialogAccepted(); 33 | 34 | private: 35 | struct Private; 36 | Private* const d; 37 | }; 38 | 39 | #endif // INVITATIONSRFBCLIENT_H 40 | -------------------------------------------------------------------------------- /krfb/eventsmanager.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #ifndef KRFB_EVENTSMANAGER_H 9 | #define KRFB_EVENTSMANAGER_H 10 | 11 | #include "events.h" 12 | 13 | #include "krfbprivate_export.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | class EventsPlugin; 23 | class KPluginFactory; 24 | 25 | class KRFBPRIVATE_EXPORT EventsManager : public QObject 26 | { 27 | Q_OBJECT 28 | friend class EventsManagerStatic; 29 | 30 | public: 31 | static EventsManager *instance(); 32 | 33 | ~EventsManager() override; 34 | 35 | QSharedPointer eventHandler(); 36 | 37 | private: 38 | Q_DISABLE_COPY(EventsManager) 39 | 40 | EventsManager(); 41 | 42 | QMap m_plugins; 43 | QList > m_eventHandlers; 44 | }; 45 | 46 | 47 | #endif // Header guard 48 | -------------------------------------------------------------------------------- /framebuffers/xcb/xcb_framebuffer.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2017 Alexey Min 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef KRFB_FRAMEBUFFER_XCB_XCB_FRAMEBUFFER_H 7 | #define KRFB_FRAMEBUFFER_XCB_XCB_FRAMEBUFFER_H 8 | 9 | #include "framebuffer.h" 10 | #include 11 | #include 12 | 13 | 14 | 15 | /** 16 | @author Alexey Min 17 | */ 18 | class XCBFrameBuffer: public FrameBuffer 19 | { 20 | Q_OBJECT 21 | public: 22 | explicit XCBFrameBuffer(QObject *parent = nullptr); 23 | ~XCBFrameBuffer() override; 24 | 25 | public: 26 | QList modifiedTiles() override; 27 | int depth() override; 28 | int height() override; 29 | int width() override; 30 | int paddedWidth() override; 31 | void getServerFormat(rfbPixelFormat &format) override; 32 | void startMonitor() override; 33 | void stopMonitor() override; 34 | 35 | public: 36 | void handleXDamageNotify(xcb_generic_event_t *xevent); 37 | 38 | private: 39 | void cleanupRects(); 40 | 41 | class P; 42 | P *const d; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /krfb/events.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | 4 | SPDX-FileCopyrightText: 2010 Collabora Ltd. 5 | SPDX-FileContributor: George Kiagiadakis 6 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 7 | SPDX-FileCopyrightText: 2001-2003 Tim Jansen 8 | 9 | SPDX-License-Identifier: GPL-2.0-or-later 10 | */ 11 | 12 | #ifndef EVENTS_H 13 | #define EVENTS_H 14 | 15 | #include "framebuffer.h" 16 | #include "rfb.h" 17 | #include "krfbprivate_export.h" 18 | 19 | #include 20 | 21 | class KRFBPRIVATE_EXPORT EventHandler : public QObject 22 | { 23 | Q_OBJECT 24 | public: 25 | explicit EventHandler(QObject *parent = nullptr); 26 | ~EventHandler() override = default; 27 | virtual void handleKeyboard(bool down, rfbKeySym key) = 0; 28 | virtual void handlePointer(int buttonMask, int x, int y) = 0; 29 | 30 | void setFrameBufferPlugin(const QSharedPointer &frameBuffer); 31 | QSharedPointer frameBuffer(); 32 | private: 33 | // Used to track framebuffer plugin which we need for xdp event plugin 34 | QSharedPointer fb; 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /krfb/framebuffermanager.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #ifndef KRFB_FRAMEBUFFERMANAGER_H 9 | #define KRFB_FRAMEBUFFERMANAGER_H 10 | 11 | #include "framebuffer.h" 12 | 13 | #include "krfbprivate_export.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | class FrameBufferPlugin; 23 | class KPluginFactory; 24 | 25 | class KRFBPRIVATE_EXPORT FrameBufferManager : public QObject 26 | { 27 | Q_OBJECT 28 | friend class FrameBufferManagerStatic; 29 | 30 | public: 31 | static FrameBufferManager *instance(); 32 | 33 | ~FrameBufferManager() override; 34 | 35 | QSharedPointer frameBuffer(WId id, const QVariantMap &args); 36 | 37 | private: 38 | Q_DISABLE_COPY(FrameBufferManager) 39 | 40 | FrameBufferManager(); 41 | 42 | QMap m_plugins; 43 | QMap > m_frameBuffers; 44 | }; 45 | 46 | 47 | #endif // Header guard 48 | 49 | -------------------------------------------------------------------------------- /framebuffers/xcb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories (${CMAKE_CURRENT_SOURCE_DIR} 2 | ${CMAKE_CURRENT_BINARY_DIR} 3 | ) 4 | 5 | set (krfb_framebuffer_xcb_SRCS 6 | xcb_framebufferplugin.cpp 7 | xcb_framebuffer.cpp 8 | ) 9 | 10 | ecm_qt_declare_logging_category(krfb_framebuffer_xcb_SRCS 11 | HEADER krfb_fb_xcb_debug.h 12 | IDENTIFIER KRFB_FB_XCB 13 | CATEGORY_NAME krfb.framebuffer.xcb 14 | DESCRIPTION "KRFB XCB framebuffer plugin" 15 | EXPORT KRFB 16 | ) 17 | 18 | add_library(krfb_framebuffer_xcb MODULE ${krfb_framebuffer_xcb_SRCS}) 19 | 20 | target_link_libraries (krfb_framebuffer_xcb 21 | Qt::Core 22 | Qt::Gui 23 | Qt::GuiPrivate 24 | XCB::XCB 25 | XCB::RENDER 26 | XCB::SHAPE 27 | XCB::XFIXES 28 | XCB::DAMAGE 29 | XCB::SHM 30 | XCB::IMAGE 31 | KF6::CoreAddons 32 | krfbprivate 33 | ) 34 | 35 | set_target_properties(krfb_framebuffer_xcb PROPERTIES OUTPUT_NAME xcb) 36 | install (TARGETS krfb_framebuffer_xcb 37 | DESTINATION ${KDE_INSTALL_PLUGINDIR}/krfb/framebuffer 38 | ) 39 | -------------------------------------------------------------------------------- /krfb/mainwindow.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 3 | SPDX-FileCopyrightText: 2013 Amandeep Singh 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #ifndef KRFB_MAINWINDOW_H 9 | #define KRFB_MAINWINDOW_H 10 | 11 | #include "ui_mainwidget.h" 12 | 13 | #include 14 | 15 | class QLineEdit; 16 | 17 | class MainWindow : public KXmlGuiWindow 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit MainWindow(QWidget *parent = nullptr); 23 | ~MainWindow() override; 24 | 25 | public Q_SLOTS: 26 | void showConfiguration(); 27 | 28 | protected: 29 | void readProperties(const KConfigGroup & group) override; 30 | void saveProperties(KConfigGroup & group) override; 31 | 32 | private Q_SLOTS: 33 | void editPassword(); 34 | void editUnattendedPassword(); 35 | void toggleDesktopSharing(bool enable); 36 | void passwordChanged(const QString&); 37 | void aboutConnectionAddress(); 38 | void aboutUnattendedMode(); 39 | 40 | private: 41 | Ui::MainWidget m_ui; 42 | bool m_passwordEditable; 43 | QLineEdit *m_passwordLineEdit = nullptr; 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | For 3.2: 3 | - write SLP service template for remote desktop protocols 4 | (documentation) 5 | - enhance RFB with SASL authentication (Kerberos) 6 | - encrypted connections (using SASL and/or SSL/TLS) 7 | - with kerberos/ssl: display name of remote user in connection dialog, 8 | kpassivepopup and systray (if name is available) 9 | - mention that invitations are one-time on personal invitation dialog 10 | 11 | Todo (unscheduled features): 12 | - when krfb is started with URL arguments and without connection 13 | quality, add some kind of smart algorithm to determine whether the 14 | other host is local (maybe using SLP to announce the connectivity 15 | of a LAN) 16 | - NAT traversal support if I can find an acceptable implementation 17 | (probably using TURN, as soon as there is a server and newer spec for that) 18 | - when OpenSLP supports this, allow scope configuration 19 | - split krfb into 2 separate programs (server and invitation) 20 | - look into adding an extension to xfree to improve speed (get noticed of 21 | screen updates) 22 | - cut & paste support 23 | 24 | Known bugs/problems: 25 | - the IP address sent in invitation may be wrong on multi-homed machines, 26 | and it is always incorrect behind a NAT. Right now it is not possible 27 | to solve these problems. 28 | 29 | -------------------------------------------------------------------------------- /krfb/ui/configsecurity.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Security 4 | 5 | 6 | 7 | 0 8 | 0 9 | 507 10 | 201 11 | 12 | 13 | 14 | 15 | 16 | 17 | Allow remote connections to control your desktop 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | Do not store passwords using KDE wallet 28 | 29 | 30 | 31 | 32 | 33 | 34 | Qt::Vertical 35 | 36 | 37 | 38 | 20 39 | 40 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /framebuffers/pipewire/pw_framebufferplugin.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2018 Oleg Chernovskiy 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | 8 | #include "pw_framebufferplugin.h" 9 | #include "pw_framebuffer.h" 10 | #include 11 | 12 | K_PLUGIN_CLASS_WITH_JSON(PWFrameBufferPlugin, "pipewire.json") 13 | 14 | PWFrameBufferPlugin::PWFrameBufferPlugin(QObject *parent, const QVariantList &args) 15 | : FrameBufferPlugin(parent, args) 16 | { 17 | } 18 | 19 | 20 | FrameBuffer *PWFrameBufferPlugin::frameBuffer(const QVariantMap &args) 21 | { 22 | auto pwfb = new PWFrameBuffer; 23 | if (args.contains(QLatin1String("name"))) { 24 | pwfb->startVirtualMonitor(args[QStringLiteral("name")].toString(), args[QStringLiteral("resolution")].toSize(), args[QStringLiteral("scale")].toDouble()); 25 | } else { 26 | // D-Bus is most important in XDG-Desktop-Portals init chain, no toys for us if something is wrong with XDP 27 | // PipeWire connectivity is initialized after D-Bus session is started 28 | pwfb->initDBus(); 29 | } 30 | 31 | // sanity check for dbus/wayland/pipewire errors 32 | if (!pwfb->isValid()) { 33 | delete pwfb; 34 | return nullptr; 35 | } 36 | 37 | return pwfb; 38 | } 39 | 40 | #include "pw_framebufferplugin.moc" 41 | -------------------------------------------------------------------------------- /krfb/framebuffer.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef FRAMEBUFFER_H 8 | #define FRAMEBUFFER_H 9 | 10 | #include "rfb.h" 11 | 12 | #include "krfbprivate_export.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | class FrameBuffer; 22 | /** 23 | @author Alessandro Praduroux 24 | */ 25 | class KRFBPRIVATE_EXPORT FrameBuffer : public QObject 26 | { 27 | Q_OBJECT 28 | public: 29 | explicit FrameBuffer(QObject *parent = nullptr); 30 | 31 | ~FrameBuffer() override; 32 | 33 | char *data(); 34 | 35 | virtual QList modifiedTiles(); 36 | virtual int paddedWidth(); 37 | virtual int width(); 38 | virtual int height(); 39 | virtual int depth(); 40 | virtual void startMonitor(); 41 | virtual void stopMonitor(); 42 | virtual QPoint cursorPosition(); 43 | 44 | virtual void getServerFormat(rfbPixelFormat &format); 45 | 46 | virtual QVariant customProperty(const QString &property) const; 47 | 48 | Q_SIGNALS: 49 | void frameBufferChanged(); 50 | 51 | protected: 52 | char *fb = nullptr; 53 | QList tiles; 54 | 55 | private: 56 | Q_DISABLE_COPY(FrameBuffer) 57 | 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /cmake/modules/COPYING-CMAKE-SCRIPTS: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions 3 | are met: 4 | 5 | 1. Redistributions of source code must retain the copyright 6 | notice, this list of conditions and the following disclaimer. 7 | 2. Redistributions in binary form must reproduce the copyright 8 | notice, this list of conditions and the following disclaimer in the 9 | documentation and/or other materials provided with the distribution. 10 | 3. The name of the author may not be used to endorse or promote products 11 | derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /krfb/connectiondialog.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2010 Collabora Ltd 3 | SPDX-FileContributor: George Kiagiadakis 4 | SPDX-FileCopyrightText: 2004 Nadeem Hasan 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #ifndef CONNECTIONDIALOG_H 10 | #define CONNECTIONDIALOG_H 11 | 12 | #include "ui_connectionwidget.h" 13 | #include 14 | 15 | template 16 | class ConnectionDialog : public QDialog 17 | { 18 | public: 19 | explicit ConnectionDialog(QWidget *parent); 20 | ~ConnectionDialog() override {}; 21 | 22 | void setAllowRemoteControl(bool b); 23 | bool allowRemoteControl(); 24 | 25 | protected: 26 | QWidget *m_connectWidget; 27 | UI m_ui; 28 | }; 29 | 30 | template 31 | void ConnectionDialog::setAllowRemoteControl(bool b) 32 | { 33 | m_ui.cbAllowRemoteControl->setChecked(b); 34 | m_ui.cbAllowRemoteControl->setVisible(b); 35 | } 36 | 37 | template 38 | bool ConnectionDialog::allowRemoteControl() 39 | { 40 | return m_ui.cbAllowRemoteControl->isChecked(); 41 | } 42 | 43 | //********* 44 | 45 | class InvitationsConnectionDialog : public ConnectionDialog 46 | { 47 | Q_OBJECT 48 | public: 49 | explicit InvitationsConnectionDialog(QWidget *parent); 50 | void setRemoteHost(const QString & host); 51 | }; 52 | 53 | //********* 54 | 55 | #endif // CONNECTIONDIALOG_H 56 | 57 | -------------------------------------------------------------------------------- /NOTES: -------------------------------------------------------------------------------- 1 | Comments on various aspects of KRfb: 2 | 3 | - KRfb has been designed for three use cases: 4 | * a user who needs help from an administrator or friend. The administrator can 5 | connect to the user and change settings and so on while both are talking 6 | on the telephone or using VoIP. 7 | * a user who wants to show something to a friend, so he lets his friend 8 | connect to his computer 9 | * (advanced use case) somebody with several computers, that are running 10 | GUIs, wants to control them. 11 | - cases 1&2 are probably more mainstream and more important for novice users, 12 | so KRfb is pre-configured for them. Case 3 is for advanced users and 13 | therefore a little bit more difficult to configure. 14 | - design goal of KRfb is to make it as easy to use as possible. I tried to 15 | limit functionality wherever possible. 16 | - the new-connection-dialog is extra large and has the pixmap on the left 17 | side to capture the attention of the user before allowing a connection. 18 | - the RFBController class is a mess. The interactions between the threaded, 19 | callback-using libvncserver and the event-driven, single thread qt GUI are 20 | quite complicated and I can only hope that it works. 21 | - most limitations and problems of KRfb are caused either by limitations of 22 | Rfb (for example no proper authentication of users, no encryption) or 23 | by lack of a framework in Linux in general (no way to connect through a 24 | NAT device). In the next months I am going to concentrate on improving the 25 | latter. 26 | 27 | tim@tjansen.de 28 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) . All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 26 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /krfb/rfbservermanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | #ifndef RFBSERVERMANAGER_H 10 | #define RFBSERVERMANAGER_H 11 | 12 | #include "rfb.h" 13 | #include "framebuffer.h" 14 | #include 15 | #include 16 | 17 | class RfbClient; 18 | struct RfbServerManagerStatic; 19 | class RfbServer; 20 | 21 | class RfbServerManager : public QObject 22 | { 23 | Q_OBJECT 24 | public: 25 | static RfbServerManager *instance(); 26 | 27 | QSharedPointer framebuffer() const; 28 | static QVariantMap s_pluginArgs; 29 | Q_SIGNALS: 30 | void clientConnected(RfbClient *cc); 31 | void clientDisconnected(RfbClient *cc); 32 | 33 | private Q_SLOTS: 34 | void init(); 35 | void updateFrameBuffer(); 36 | void updateScreens(); 37 | void cleanup(); 38 | 39 | private: 40 | void registerServer(RfbServer *server); 41 | void unregisterServer(RfbServer *server); 42 | 43 | rfbScreenInfoPtr newScreen(); 44 | 45 | void addClient(RfbClient *cc); 46 | void removeClient(RfbClient *cc); 47 | 48 | RfbServerManager(); 49 | ~RfbServerManager() override; 50 | Q_DISABLE_COPY(RfbServerManager) 51 | 52 | friend class RfbServer; 53 | friend struct RfbServerManagerStatic; 54 | 55 | struct Private; 56 | Private *const d; 57 | }; 58 | 59 | #endif // RFBSERVERMANAGER_H 60 | -------------------------------------------------------------------------------- /krfb/framebuffer.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 3 | 4 | SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include "framebuffer.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | FrameBuffer::FrameBuffer(QObject *parent) 16 | : QObject(parent) 17 | { 18 | } 19 | 20 | FrameBuffer::~FrameBuffer() 21 | { 22 | delete fb; 23 | } 24 | 25 | char *FrameBuffer::data() 26 | { 27 | return fb; 28 | } 29 | 30 | QList< QRect > FrameBuffer::modifiedTiles() 31 | { 32 | QList ret = tiles; 33 | tiles.clear(); 34 | return ret; 35 | } 36 | 37 | int FrameBuffer::width() 38 | { 39 | return 0; 40 | } 41 | 42 | int FrameBuffer::height() 43 | { 44 | return 0; 45 | } 46 | 47 | void FrameBuffer::getServerFormat(rfbPixelFormat &) 48 | { 49 | } 50 | 51 | QVariant FrameBuffer::customProperty(const QString &property) const 52 | { 53 | Q_UNUSED(property) 54 | return QVariant(); 55 | } 56 | 57 | int FrameBuffer::depth() 58 | { 59 | return 32; 60 | } 61 | 62 | int FrameBuffer::paddedWidth() 63 | { 64 | return width() * depth() / 8; 65 | } 66 | 67 | void FrameBuffer::startMonitor() 68 | { 69 | } 70 | 71 | void FrameBuffer::stopMonitor() 72 | { 73 | } 74 | 75 | QPoint FrameBuffer::cursorPosition() 76 | { 77 | QPoint cursorPos = QCursor::pos(); 78 | QScreen *primaryScreen = QGuiApplication::primaryScreen(); 79 | if (primaryScreen) { 80 | qreal scaleFactor = primaryScreen->devicePixelRatio(); 81 | cursorPos.setX(qRound(cursorPos.x() * scaleFactor)); 82 | cursorPos.setY(qRound(cursorPos.y() * scaleFactor)); 83 | } else { 84 | qWarning() << "cursorPosition: ERROR: Failed to get application's primary screen info!"; 85 | } 86 | return cursorPos; 87 | } 88 | -------------------------------------------------------------------------------- /framebuffers/pipewire/screencasting.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez 3 | 4 | SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | struct zkde_screencast_unstable_v1; 15 | 16 | namespace KWayland 17 | { 18 | namespace Client 19 | { 20 | class PlasmaWindow; 21 | class Registry; 22 | class Output; 23 | } 24 | } 25 | 26 | class ScreencastingPrivate; 27 | class ScreencastingSourcePrivate; 28 | class ScreencastingStreamPrivate; 29 | class ScreencastingStream : public QObject 30 | { 31 | Q_OBJECT 32 | public: 33 | ScreencastingStream(QObject *parent); 34 | ~ScreencastingStream() override; 35 | 36 | quint32 nodeId() const; 37 | 38 | Q_SIGNALS: 39 | void created(quint32 nodeid); 40 | void failed(const QString &error); 41 | void closed(); 42 | 43 | private: 44 | friend class Screencasting; 45 | QScopedPointer d; 46 | }; 47 | 48 | class Screencasting : public QObject 49 | { 50 | Q_OBJECT 51 | public: 52 | explicit Screencasting(QObject *parent = nullptr); 53 | explicit Screencasting(KWayland::Client::Registry *registry, int id, int version, QObject *parent = nullptr); 54 | ~Screencasting() override; 55 | 56 | enum CursorMode { 57 | Hidden = 1, 58 | Embedded = 2, 59 | Metadata = 4, 60 | }; 61 | Q_ENUM(CursorMode) 62 | 63 | ScreencastingStream *createVirtualMonitorStream(const QString &name, const QSize &resolution, qreal dpr, CursorMode mode); 64 | 65 | void setup(zkde_screencast_unstable_v1 *screencasting); 66 | void destroy(); 67 | 68 | Q_SIGNALS: 69 | void initialized(); 70 | void removed(); 71 | void sourcesChanged(); 72 | 73 | private: 74 | QScopedPointer d; 75 | }; 76 | -------------------------------------------------------------------------------- /krfb/invitationsrfbserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | #ifndef INVITATIONSRFBSERVER_H 10 | #define INVITATIONSRFBSERVER_H 11 | 12 | #include "rfbserver.h" 13 | 14 | namespace KWallet { 15 | class Wallet; 16 | } 17 | 18 | namespace KDNSSD { 19 | class PublicService; 20 | } 21 | 22 | class InvitationsRfbServer : public RfbServer 23 | { 24 | Q_OBJECT 25 | public: 26 | static InvitationsRfbServer *instance; 27 | static void init(); 28 | 29 | const QString& desktopPassword() const; 30 | void setDesktopPassword(const QString&); 31 | const QString& unattendedPassword() const; 32 | void setUnattendedPassword(const QString&); 33 | bool allowUnattendedAccess() const; 34 | 35 | Q_SIGNALS: 36 | void passwordChanged(const QString&); 37 | 38 | public Q_SLOTS: 39 | bool start() override; 40 | void stop() override; 41 | void toggleUnattendedAccess(bool allow); 42 | void openKWallet(); 43 | void closeKWallet(); 44 | void saveSecuritySettings(); 45 | 46 | protected: 47 | InvitationsRfbServer(); 48 | ~InvitationsRfbServer() override; 49 | PendingRfbClient* newClient(rfbClientPtr client) override; 50 | 51 | private Q_SLOTS: 52 | void walletOpened(bool); 53 | 54 | private: 55 | KDNSSD::PublicService *m_publicService = nullptr; 56 | bool m_allowUnattendedAccess; 57 | QString m_desktopPassword; 58 | QString m_unattendedPassword; 59 | KWallet::Wallet *m_wallet = nullptr; 60 | 61 | QString readableRandomString(int); 62 | void readPasswordFromConfig(); 63 | Q_DISABLE_COPY(InvitationsRfbServer) 64 | }; 65 | 66 | #endif // INVITATIONSRFBSERVER_H 67 | -------------------------------------------------------------------------------- /framebuffers/pipewire/pw_framebuffer.h: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2018 Oleg Chernovskiy 3 | SPDX-FileCopyrightText: 2018-2020 Jan Grulich 4 | 5 | SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | #ifndef KRFB_FRAMEBUFFER_XCB_XCB_FRAMEBUFFER_H 8 | #define KRFB_FRAMEBUFFER_XCB_XCB_FRAMEBUFFER_H 9 | 10 | #include "framebuffer.h" 11 | #include 12 | #include 13 | 14 | /** 15 | * @brief The PWFrameBuffer class - framebuffer implementation based on XDG Desktop Portal ScreenCast interface. 16 | * The design relies heavily on a presence of XDG D-Bus service and PipeWire daemon. 17 | * 18 | * @author Oleg Chernovskiy 19 | */ 20 | class PWFrameBuffer: public FrameBuffer 21 | { 22 | Q_OBJECT 23 | public: 24 | using Stream = struct { 25 | uint nodeId; 26 | QVariantMap map; 27 | }; 28 | using Streams = QList; 29 | 30 | PWFrameBuffer(QObject *parent = nullptr); 31 | virtual ~PWFrameBuffer() override; 32 | 33 | void initDBus(); 34 | void startVirtualMonitor(const QString &name, const QSize &resolution, qreal dpr); 35 | 36 | int depth() override; 37 | int height() override; 38 | int width() override; 39 | int paddedWidth() override; 40 | void getServerFormat(rfbPixelFormat &format) override; 41 | void startMonitor() override; 42 | void stopMonitor() override; 43 | QPoint cursorPosition() override; 44 | 45 | QVariant customProperty(const QString &property) const override; 46 | 47 | bool isValid() const; 48 | 49 | private Q_SLOTS: 50 | void handleXdpSessionCreated(quint32 code, const QVariantMap &results); 51 | void handleXdpDevicesSelected(quint32 code, const QVariantMap &results); 52 | void handleXdpSourcesSelected(quint32 code, const QVariantMap &results); 53 | void handleXdpRemoteDesktopStarted(quint32 code, const QVariantMap &results); 54 | 55 | private: 56 | class Private; 57 | const QScopedPointer d; 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /krfb/krfb.kcfg: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | false 11 | 12 | 13 | 14 | 15 | 16 | true 17 | 18 | 19 | 20 | 5900 21 | 22 | 23 | 24 | true 25 | 26 | 27 | 28 | 29 | 30 | false 31 | 32 | 33 | 34 | true 35 | 36 | 37 | 38 | false 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | xcb 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /krfb/eventsmanager.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #include "eventsmanager.h" 9 | 10 | #include "eventsplugin.h" 11 | #include "krfbconfig.h" 12 | #include "rfbservermanager.h" 13 | #include "krfbdebug.h" 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | 21 | class EventsManagerStatic 22 | { 23 | public: 24 | EventsManager instance; 25 | }; 26 | 27 | Q_GLOBAL_STATIC(EventsManagerStatic, eventsManagerStatic) 28 | 29 | EventsManager::EventsManager() 30 | { 31 | const QList plugins = KPluginMetaData::findPlugins(QStringLiteral("krfb/events"), {}, KPluginMetaData::AllowEmptyMetaData); 32 | for (const KPluginMetaData &data : plugins) { 33 | const KPluginFactory::Result result = KPluginFactory::instantiatePlugin(data); 34 | if (result.plugin) { 35 | m_plugins.insert(data.pluginId(), result.plugin); 36 | qCDebug(KRFB) << "Loaded plugin with name " << data.pluginId(); 37 | } else { 38 | qCDebug(KRFB) << "unable to load plugin for " << data.fileName() << result.errorString; 39 | } 40 | } 41 | } 42 | 43 | EventsManager::~EventsManager() = default; 44 | 45 | EventsManager *EventsManager::instance() 46 | { 47 | return &eventsManagerStatic->instance; 48 | } 49 | 50 | QSharedPointer EventsManager::eventHandler() 51 | { 52 | for (auto it = m_plugins.cbegin(); it != m_plugins.constEnd(); it++) { 53 | QSharedPointer eventHandler(it.value()->eventHandler()); 54 | if (eventHandler) { 55 | eventHandler->setFrameBufferPlugin(RfbServerManager::instance()->framebuffer()); 56 | return eventHandler; 57 | } 58 | } 59 | 60 | // No valid events plugin found. 61 | qCDebug(KRFB) << "No valid event handlers found. returning null."; 62 | return QSharedPointer(); 63 | } 64 | -------------------------------------------------------------------------------- /krfb/rfbserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | #ifndef RFBSERVER_H 10 | #define RFBSERVER_H 11 | 12 | #include "rfb.h" 13 | #include "rfbclient.h" 14 | #include 15 | 16 | class RfbServer : public QObject 17 | { 18 | Q_OBJECT 19 | public: 20 | explicit RfbServer(QObject *parent = nullptr); 21 | ~RfbServer() override; 22 | 23 | QByteArray listeningAddress() const; 24 | int listeningPort() const; 25 | bool passwordRequired() const; 26 | 27 | void setListeningAddress(const QByteArray & address); 28 | void setListeningPort(int port); 29 | void setPasswordRequired(bool passwordRequired); 30 | 31 | public Q_SLOTS: 32 | virtual bool start(); 33 | virtual void stop(); 34 | 35 | void updateFrameBuffer(char *fb, int width, int height, int depth); 36 | void updateScreen(const QList & modifiedTiles); 37 | void updateCursorPosition(const QPoint & position); 38 | 39 | private Q_SLOTS: 40 | void krfbSendServerCutText(); 41 | void onListenSocketActivated(); 42 | void pendingClientFinished(RfbClient *client); 43 | 44 | protected: 45 | virtual PendingRfbClient *newClient(rfbClientPtr client) = 0; 46 | 47 | private: 48 | static rfbNewClientAction newClientHook(rfbClientPtr cl); 49 | static void clientGoneHook(rfbClientPtr cl); 50 | 51 | static rfbBool passwordCheck(rfbClientPtr cl, const char *encryptedPassword, int len); 52 | static void keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl); 53 | static void pointerHook(int bm, int x, int y, rfbClientPtr cl); 54 | static void clipboardHook(char *str, int len, rfbClientPtr cl); 55 | static void clipboardHookUtf8(char *str, int len, rfbClientPtr cl); 56 | 57 | Q_DISABLE_COPY(RfbServer) 58 | 59 | struct Private; 60 | Private *const d; 61 | }; 62 | 63 | #endif // RFBSERVER_H 64 | -------------------------------------------------------------------------------- /krfb/connectiondialog.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2010 Collabora Ltd 3 | SPDX-FileContributor: George Kiagiadakis 4 | SPDX-FileCopyrightText: 2004 Nadeem Hasan 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #include "connectiondialog.h" 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | template 23 | ConnectionDialog::ConnectionDialog(QWidget *parent) 24 | : QDialog(parent) 25 | { 26 | setWindowTitle(i18n("New Connection")); 27 | auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); 28 | auto mainWidget = new QWidget(this); 29 | auto mainLayout = new QVBoxLayout; 30 | setLayout(mainLayout); 31 | mainLayout->addWidget(mainWidget); 32 | QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); 33 | okButton->setDefault(true); 34 | okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 35 | connect(buttonBox, &QDialogButtonBox::accepted, this, &ConnectionDialog::accept); 36 | connect(buttonBox, &QDialogButtonBox::rejected, this, &ConnectionDialog::reject); 37 | buttonBox->button(QDialogButtonBox::Cancel)->setDefault(true); 38 | setModal(true); 39 | 40 | setMinimumSize(500, 200); 41 | 42 | m_connectWidget = new QWidget(this); 43 | m_ui.setupUi(m_connectWidget); 44 | 45 | m_ui.pixmapLabel->setPixmap(QIcon::fromTheme(QStringLiteral("krfb")).pixmap(128)); 46 | 47 | KGuiItem accept = KStandardGuiItem::ok(); 48 | accept.setText(i18n("Accept Connection")); 49 | KGuiItem::assign(okButton, accept); 50 | 51 | KGuiItem refuse = KStandardGuiItem::cancel(); 52 | refuse.setText(i18n("Refuse Connection")); 53 | KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), refuse); 54 | 55 | mainLayout->addWidget(m_connectWidget); 56 | mainLayout->addWidget(buttonBox); 57 | } 58 | 59 | //********** 60 | 61 | InvitationsConnectionDialog::InvitationsConnectionDialog(QWidget *parent) 62 | : ConnectionDialog(parent) 63 | { 64 | } 65 | 66 | void InvitationsConnectionDialog::setRemoteHost(const QString &host) 67 | { 68 | m_ui.remoteHost->setText(host); 69 | } 70 | -------------------------------------------------------------------------------- /framebuffers/pipewire/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories (${CMAKE_CURRENT_SOURCE_DIR} 2 | ${CMAKE_CURRENT_BINARY_DIR} 3 | ) 4 | 5 | set (krfb_framebuffer_pw_SRCS 6 | pw_framebuffer.cpp 7 | pw_framebufferplugin.cpp 8 | 9 | screencasting.cpp 10 | ) 11 | 12 | ecm_qt_declare_logging_category(krfb_framebuffer_pw_SRCS 13 | HEADER krfb_fb_pipewire_debug.h 14 | IDENTIFIER KRFB_FB_PIPEWIRE 15 | CATEGORY_NAME krfb.framebuffer.pipewire 16 | DESCRIPTION "KRFB PipeWire framebuffer plugin" 17 | EXPORT KRFB 18 | ) 19 | 20 | qt_add_dbus_interface( 21 | krfb_framebuffer_pw_SRCS 22 | ${CMAKE_SOURCE_DIR}/dbus/xdp_dbus_screencast_interface.xml 23 | xdp_dbus_screencast_interface 24 | ) 25 | 26 | qt_add_dbus_interface( 27 | krfb_framebuffer_pw_SRCS 28 | ${CMAKE_SOURCE_DIR}/dbus/xdp_dbus_remotedesktop_interface.xml 29 | xdp_dbus_remotedesktop_interface 30 | ) 31 | 32 | add_library(krfb_framebuffer_pw 33 | MODULE 34 | ${krfb_framebuffer_pw_SRCS} 35 | ) 36 | 37 | if (Qt6_VERSION VERSION_LESS "6.7.1") 38 | ecm_add_qtwayland_client_protocol(krfb_framebuffer_pw 39 | PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/screencast.xml 40 | BASENAME zkde-screencast-unstable-v1 41 | ) 42 | else() 43 | if (Qt6_VERSION VERSION_GREATER_EQUAL "6.8.0") 44 | set(private_code_option "PRIVATE_CODE") 45 | endif() 46 | qt6_generate_wayland_protocol_client_sources(krfb_framebuffer_pw 47 | ${private_code_option} 48 | FILES ${PLASMA_WAYLAND_PROTOCOLS_DIR}/screencast.xml 49 | ) 50 | endif() 51 | 52 | if (KPipeWire_VERSION VERSION_LESS "6.0.80") 53 | target_compile_definitions(krfb_framebuffer_pw PRIVATE -DKPIPEWIRE60=1) 54 | else() 55 | target_compile_definitions(krfb_framebuffer_pw PRIVATE -DKPIPEWIRE60=0) 56 | endif() 57 | set_property(TARGET krfb_framebuffer_pw PROPERTY C_STANDARD 99) 58 | 59 | target_link_libraries(krfb_framebuffer_pw 60 | Qt::Core 61 | Qt::Gui 62 | Qt::DBus 63 | KF6::CoreAddons 64 | KF6::ConfigCore 65 | PkgConfig::PipeWire 66 | Plasma::KWaylandClient 67 | Wayland::Client 68 | krfbprivate 69 | K::KPipeWire 70 | K::KPipeWireDmaBuf 71 | ) 72 | 73 | set_target_properties(krfb_framebuffer_pw PROPERTIES OUTPUT_NAME pw) 74 | install (TARGETS krfb_framebuffer_pw 75 | DESTINATION ${KDE_INSTALL_PLUGINDIR}/krfb/framebuffer 76 | ) 77 | -------------------------------------------------------------------------------- /krfb/sockethelpers.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 5 | SPDX-FileCopyrightText: 2001-2003 Tim Jansen 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | 10 | #include "sockethelpers.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | QString peerAddress(int sock) 17 | { 18 | const int ADDR_SIZE = 50; 19 | struct sockaddr sa = {}; 20 | socklen_t salen = sizeof(struct sockaddr); 21 | 22 | if (getpeername(sock, &sa, &salen) == 0) { 23 | if (sa.sa_family == AF_INET) { 24 | auto si = (struct sockaddr_in *)&sa; 25 | return QString::fromLatin1(inet_ntoa(si->sin_addr)); 26 | } 27 | 28 | if (sa.sa_family == AF_INET6) { 29 | char inetbuf[ADDR_SIZE]; 30 | inet_ntop(sa.sa_family, &sa, inetbuf, ADDR_SIZE); 31 | return QString::fromLatin1(inetbuf); 32 | } 33 | 34 | return QStringLiteral("not a network address"); 35 | } 36 | 37 | return QStringLiteral("unable to determine..."); 38 | } 39 | 40 | unsigned short peerPort(int sock) 41 | { 42 | struct sockaddr sa = {}; 43 | socklen_t salen = sizeof(struct sockaddr); 44 | 45 | if (getpeername(sock, &sa, &salen) == 0) { 46 | auto si = (struct sockaddr_in *)&sa; 47 | return ntohs(si->sin_port); 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | QString localAddress(int sock) 54 | { 55 | const int ADDR_SIZE = 50; 56 | struct sockaddr sa = {}; 57 | socklen_t salen = sizeof(struct sockaddr); 58 | 59 | if (getsockname(sock, &sa, &salen) == 0) { 60 | if (sa.sa_family == AF_INET) { 61 | auto si = (struct sockaddr_in *)&sa; 62 | return QString::fromLatin1(inet_ntoa(si->sin_addr)); 63 | } 64 | 65 | if (sa.sa_family == AF_INET6) { 66 | char inetbuf[ADDR_SIZE]; 67 | inet_ntop(sa.sa_family, &sa, inetbuf, ADDR_SIZE); 68 | return QString::fromLatin1(inetbuf); 69 | } 70 | 71 | return QStringLiteral("not a network address"); 72 | } 73 | 74 | return QStringLiteral("unable to determine..."); 75 | } 76 | 77 | unsigned short localPort(int sock) 78 | { 79 | struct sockaddr sa = {}; 80 | socklen_t salen = sizeof(struct sockaddr); 81 | 82 | if (getsockname(sock, &sa, &salen) == 0) { 83 | auto si = (struct sockaddr_in *)&sa; 84 | return ntohs(si->sin_port); 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /krfb/ui/configframebuffer.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Framebuffer 4 | 5 | 6 | 7 | 0 8 | 0 9 | 418 10 | 186 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Preferred frameb&uffer plugin: 20 | 21 | 22 | cb_preferredFrameBufferPlugin 23 | 24 | 25 | 26 | 27 | 28 | 29 | false 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | true 42 | 43 | 44 | <html><head/><body><p>When using x11, <span style=" font-weight:600;">xcb</span> plugin should be preferred, because it is more performant.<br/><span style=" font-weight:600;">qt</span> plugin is a safe fallback, if for some reason others don't work. But also it is very slow.</p></body></html> 45 | 46 | 47 | Qt::RichText 48 | 49 | 50 | false 51 | 52 | 53 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 54 | 55 | 56 | true 57 | 58 | 59 | 5 60 | 61 | 62 | Qt::NoTextInteraction 63 | 64 | 65 | 66 | 67 | 68 | 69 | Qt::Vertical 70 | 71 | 72 | 73 | 20 74 | 63 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | cb_preferredFrameBufferPlugin 83 | kcfg_preferredFrameBufferPlugin 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /krfb/ui/configtcp.ui: -------------------------------------------------------------------------------- 1 | 2 | TCP 3 | 4 | 5 | 6 | 0 7 | 0 8 | 400 9 | 169 10 | 11 | 12 | 13 | 14 | 15 | 16 | Announce the service on the local network 17 | 18 | 19 | true 20 | 21 | 22 | 23 | 24 | 25 | 26 | Use default port 27 | 28 | 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | 0 37 | 38 | 39 | 0 40 | 41 | 42 | 0 43 | 44 | 45 | 0 46 | 47 | 48 | 49 | 50 | Listening port: 51 | 52 | 53 | kcfg_port 54 | 55 | 56 | 57 | 58 | 59 | 60 | false 61 | 62 | 63 | 65535 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Qt::Vertical 73 | 74 | 75 | 76 | 20 77 | 40 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | kcfg_useDefaultPort 86 | kcfg_port 87 | 88 | 89 | 90 | 91 | kcfg_useDefaultPort 92 | toggled(bool) 93 | kcfg_port 94 | setDisabled(bool) 95 | 96 | 97 | 120 98 | 53 99 | 100 | 101 | 277 102 | 122 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /krfb/org.kde.krfb.virtualmonitor.desktop.cmake: -------------------------------------------------------------------------------- 1 | # KDE Config File 2 | [Desktop Entry] 3 | Type=Application 4 | Exec=@CMAKE_INSTALL_PREFIX@/bin/krfb-virtualmonitor 5 | Icon=krfb 6 | Terminal=false 7 | Name=KRFBs Virtual Monitor 8 | Name[ar]=شاشة افتراضية لكرفب 9 | Name[bg]=Виртуален монитор на KRFB 10 | Name[ca]=Monitor virtual del Krfb 11 | Name[ca@valencia]=Monitor virtual de Krfb 12 | Name[cs]=Virtuální monitor KRFB 13 | Name[el]=Εικονική οθόνη του KRFB 14 | Name[en_GB]=KRFBs Virtual Monitor 15 | Name[eo]=Virtuala Monitoro de KRFB 16 | Name[es]=Monitor virtual de KRFB 17 | Name[eu]=KRFBren alegiazko monitorea 18 | Name[fi]=KRFB:n virtuaalinäyttö 19 | Name[fr]=Moniteur virtuel « Krfb » 20 | Name[gl]=Monitor virtual de KRFB 21 | Name[he]=הצג הווירטואלי של KRFB 22 | Name[hu]=KRFB virtuális monitor 23 | Name[ia]=Virtual Monitor de KRFB 24 | Name[it]=Monitor virtuale di KRFB 25 | Name[ka]=KRFB-ის ვირტუალური ეკრანი 26 | Name[ko]=KRFBs 가상 모니터 27 | Name[lt]=KRFBs virtualus monitorius 28 | Name[lv]=KRFB virtuālais monitors 29 | Name[nl]=Virtuele monitor van KRFB 30 | Name[nn]=KRFBs virtuell skjerm 31 | Name[pl]=Monitor wirtualny KRFB 32 | Name[pt]=Monitor Virtual do KRFB 33 | Name[pt_BR]=Monitor virtual do KRFB 34 | Name[ro]=Monitor virtual KRFB 35 | Name[ru]=Виртуальный монитор KRFB 36 | Name[sa]=KRFBs वर्चुअल मॉनिटर 37 | Name[sk]=Virtuálny monitor KRFB 38 | Name[sl]=Navidezni monitor KRFB 39 | Name[sv]=Krfb:s virtuella bildskärm 40 | Name[tr]=KRFB Sanal Monitörü 41 | Name[uk]=Віртуальний монітор KRFB 42 | Name[zh_CN]=KRBs 虚拟监视器 43 | Name[zh_TW]=KRFBs 虛擬螢幕 44 | Comment=Remote Virtual Monitor 45 | Comment[ar]=شاشة افتراضية بعيدة 46 | Comment[bg]=Отдалечен виртуален монитор 47 | Comment[ca]=Monitor virtual remot 48 | Comment[ca@valencia]=Monitor virtual remot 49 | Comment[cs]=Vzdálený virtuální monitor 50 | Comment[el]=Απομακρυσμένη εικονική οθόνη 51 | Comment[en_GB]=Remote Virtual Monitor 52 | Comment[eo]=Fora Virtuala Monitoro 53 | Comment[es]=Monitor virtual remoto 54 | Comment[eu]=Urruneko alegiazko monitorea 55 | Comment[fi]=Virtuaalinen etänäyttö 56 | Comment[fr]=Moniteur virtuel distant 57 | Comment[gl]=Monitor virtual remoto 58 | Comment[he]=צג וירטואלי מרוחק 59 | Comment[hu]=Távoli virtuális monitor 60 | Comment[ia]=Monitor Virtual Remote 61 | Comment[it]=Monitor virtuale remoto 62 | Comment[ka]=დაშორებული ვირტუალური ეკრანი 63 | Comment[ko]=원격 가상 모니터 64 | Comment[lt]=Nuotolinis virtualus monitorius 65 | Comment[lv]=Attālais virtuālais monitors 66 | Comment[nl]=Virtual Monitor op afstand 67 | Comment[nn]=Virtuell skjerm for ekstern ressurs 68 | Comment[pl]=Zdalny monitor wirtualny 69 | Comment[pt]=Monitor Virtual Remoto 70 | Comment[pt_BR]=Monitor virtual remoto 71 | Comment[ro]=Monitor virtual distant 72 | Comment[ru]=Удалённый виртуальный монитор 73 | Comment[sa]=दूरस्थ आभासी निरीक्षक 74 | Comment[sk]=Vzdialený virtuálny monitor 75 | Comment[sl]=Oddaljeni navidezni monitor 76 | Comment[sv]=Virtuell fjärrbildskärm 77 | Comment[tr]=Uzak Sanal Monitör 78 | Comment[uk]=Віддалений віртуальний монітор 79 | Comment[zh_CN]=远程虚拟监视器 80 | Comment[zh_TW]=遠端虛擬螢幕 81 | NoDisplay=true 82 | X-KDE-Wayland-Interfaces=zkde_screencast_unstable_v1 83 | -------------------------------------------------------------------------------- /framebuffers/pipewire/screencasting.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez 3 | 4 | SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 5 | */ 6 | 7 | #include "screencasting.h" 8 | #if QT_VERSION < QT_VERSION_CHECK(6, 7, 1) 9 | #include "qwayland-zkde-screencast-unstable-v1.h" 10 | #else 11 | #include "qwayland-screencast.h" 12 | #endif 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace KWayland::Client; 19 | 20 | class ScreencastingStreamPrivate : public QtWayland::zkde_screencast_stream_unstable_v1 21 | { 22 | public: 23 | ScreencastingStreamPrivate(ScreencastingStream *q) 24 | : q(q) 25 | { 26 | } 27 | ~ScreencastingStreamPrivate() override 28 | { 29 | close(); 30 | q->deleteLater(); 31 | } 32 | 33 | void zkde_screencast_stream_unstable_v1_created(uint32_t node) override 34 | { 35 | m_nodeId = node; 36 | Q_EMIT q->created(node); 37 | } 38 | 39 | void zkde_screencast_stream_unstable_v1_closed() override 40 | { 41 | Q_EMIT q->closed(); 42 | } 43 | 44 | void zkde_screencast_stream_unstable_v1_failed(const QString &error) override 45 | { 46 | Q_EMIT q->failed(error); 47 | } 48 | 49 | uint m_nodeId = 0; 50 | QPointer q; 51 | }; 52 | 53 | ScreencastingStream::ScreencastingStream(QObject *parent) 54 | : QObject(parent) 55 | , d(new ScreencastingStreamPrivate(this)) 56 | { 57 | } 58 | 59 | ScreencastingStream::~ScreencastingStream() = default; 60 | 61 | quint32 ScreencastingStream::nodeId() const 62 | { 63 | return d->m_nodeId; 64 | } 65 | 66 | class ScreencastingPrivate : public QtWayland::zkde_screencast_unstable_v1 67 | { 68 | public: 69 | ScreencastingPrivate(Registry *registry, int id, int version, Screencasting *q) 70 | : QtWayland::zkde_screencast_unstable_v1(*registry, id, version) 71 | , q(q) 72 | { 73 | } 74 | 75 | ScreencastingPrivate(::zkde_screencast_unstable_v1 *screencasting, Screencasting *q) 76 | : QtWayland::zkde_screencast_unstable_v1(screencasting) 77 | , q(q) 78 | { 79 | } 80 | 81 | ~ScreencastingPrivate() override 82 | { 83 | destroy(); 84 | } 85 | 86 | Screencasting *const q; 87 | }; 88 | 89 | Screencasting::Screencasting(QObject *parent) 90 | : QObject(parent) 91 | { 92 | } 93 | 94 | Screencasting::Screencasting(Registry *registry, int id, int version, QObject *parent) 95 | : QObject(parent) 96 | , d(new ScreencastingPrivate(registry, id, version, this)) 97 | { 98 | } 99 | 100 | Screencasting::~Screencasting() = default; 101 | 102 | ScreencastingStream * Screencasting::createVirtualMonitorStream(const QString& name, const QSize& resolution, qreal dpr, Screencasting::CursorMode mode) 103 | { 104 | auto stream = new ScreencastingStream(this); 105 | stream->d->init(d->stream_virtual_output(name, resolution.width(), resolution.height(), wl_fixed_from_double(dpr), mode)); 106 | return stream; 107 | } 108 | 109 | void Screencasting::setup(::zkde_screencast_unstable_v1 *screencasting) 110 | { 111 | d.reset(new ScreencastingPrivate(screencasting, this)); 112 | } 113 | 114 | void Screencasting::destroy() 115 | { 116 | d.reset(nullptr); 117 | } 118 | -------------------------------------------------------------------------------- /krfb/framebuffermanager.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2009 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | 5 | SPDX-License-Identifier: GPL-2.0-or-later 6 | */ 7 | 8 | #include "framebuffermanager.h" 9 | 10 | #include "framebufferplugin.h" 11 | #include "krfbconfig.h" 12 | #include "krfbdebug.h" 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | 21 | class FrameBufferManagerStatic 22 | { 23 | public: 24 | FrameBufferManager instance; 25 | }; 26 | 27 | Q_GLOBAL_STATIC(FrameBufferManagerStatic, frameBufferManagerStatic) 28 | 29 | FrameBufferManager::FrameBufferManager() 30 | { 31 | const auto platformFilter = [] (const KPluginMetaData &pluginData) { 32 | return pluginData.value(QStringLiteral("X-KDE-OnlyShowOnQtPlatforms"), QStringList()).contains(QGuiApplication::platformName()); 33 | }; 34 | const QList plugins = KPluginMetaData::findPlugins(QStringLiteral("krfb/framebuffer"), platformFilter, KPluginMetaData::AllowEmptyMetaData); 35 | for (const KPluginMetaData &data : plugins) { 36 | const KPluginFactory::Result result = KPluginFactory::instantiatePlugin(data); 37 | if (result.plugin) { 38 | m_plugins.insert(data.pluginId(), result.plugin); 39 | qCDebug(KRFB) << "Loaded plugin with name " << data.pluginId(); 40 | } else { 41 | qCDebug(KRFB) << "unable to load plugin for " << data.fileName() << result.errorString; 42 | } 43 | } 44 | } 45 | 46 | FrameBufferManager::~FrameBufferManager() 47 | { 48 | } 49 | 50 | FrameBufferManager *FrameBufferManager::instance() 51 | { 52 | return &frameBufferManagerStatic->instance; 53 | } 54 | 55 | QSharedPointer FrameBufferManager::frameBuffer(WId id, const QVariantMap &args) 56 | { 57 | // See if there is still an existing framebuffer to this WId. 58 | if (m_frameBuffers.contains(id)) { 59 | QWeakPointer weakFrameBuffer = m_frameBuffers.value(id); 60 | 61 | if (weakFrameBuffer) { 62 | //qDebug() << "Found cached frame buffer."; 63 | return weakFrameBuffer.toStrongRef(); 64 | } else { 65 | //qDebug() << "Found deleted cached frame buffer. Don't use."; 66 | m_frameBuffers.remove(id); 67 | } 68 | } 69 | 70 | if (auto preferredPlugin = m_plugins.value(KrfbConfig::preferredFrameBufferPlugin())) { 71 | if (auto frameBuffer = QSharedPointer(preferredPlugin->frameBuffer(args))) { 72 | qCDebug(KRFB) << "Using FrameBuffer:" << KrfbConfig::preferredFrameBufferPlugin(); 73 | m_frameBuffers.insert(id, frameBuffer.toWeakRef()); 74 | return frameBuffer; 75 | } 76 | } 77 | 78 | // We don't already have that frame buffer. 79 | for (auto it = m_plugins.cbegin(); it != m_plugins.constEnd(); it++) { 80 | QSharedPointer frameBuffer(it.value()->frameBuffer(args)); 81 | if (frameBuffer) { 82 | qCDebug(KRFB) << "Using FrameBuffer:" << it.key(); 83 | m_frameBuffers.insert(id, frameBuffer.toWeakRef()); 84 | return frameBuffer; 85 | } 86 | } 87 | 88 | // No valid framebuffer plugin found. 89 | qCDebug(KRFB) << "No valid framebuffer found. returning null."; 90 | return QSharedPointer(); 91 | } 92 | -------------------------------------------------------------------------------- /.flatpak-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "org.kde.krfb", 3 | "branch": "master", 4 | "runtime": "org.kde.Platform", 5 | "runtime-version": "6.10", 6 | "sdk": "org.kde.Sdk", 7 | "command": "krfb", 8 | "tags": [ 9 | "nightly" 10 | ], 11 | "desktop-file-name-suffix": " (Nightly)", 12 | "finish-args": [ 13 | "--share=ipc", 14 | "--socket=fallback-x11", 15 | "--socket=wayland" 16 | ], 17 | "rename-icon": "krfb", 18 | "modules": [ 19 | { 20 | "name": "libgpg-error", 21 | "sources": [ 22 | { 23 | "type": "archive", 24 | "url": "https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.56.tar.bz2", 25 | "sha256": "82c3d2deb4ad96ad3925d6f9f124fe7205716055ab50e291116ef27975d169c0", 26 | "x-checker-data": { 27 | "type": "anitya", 28 | "project-id": 1628, 29 | "stable-only": true, 30 | "url-template": "https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-${version}.tar.bz2" 31 | } 32 | } 33 | ], 34 | "cleanup": [ 35 | "/lib/libgpg-error.la" 36 | ] 37 | }, 38 | { 39 | "name": "libgcrypt", 40 | "config-opts": [ 41 | "--disable-doc" 42 | ], 43 | "sources": [ 44 | { 45 | "type": "git", 46 | "url": "https://dev.gnupg.org/source/libgcrypt.git", 47 | "tag": "libgcrypt-1.11.2", 48 | "commit": "737cc63600146f196738a6768679eb016cf866e9", 49 | "x-checker-data": { 50 | "type": "anitya", 51 | "project-id": 1623, 52 | "stable-only": true, 53 | "tag-template": "libgcrypt-$version" 54 | } 55 | } 56 | ] 57 | }, 58 | { 59 | "name": "libvncserver", 60 | "buildsystem": "cmake-ninja", 61 | "config-opts": [ 62 | "-DCMAKE_POLICY_VERSION_MINIMUM=3.5" 63 | ], 64 | "sources": [ 65 | { 66 | "type": "git", 67 | "url": "https://github.com/LibVNC/libvncserver", 68 | "branch": "LibVNCServer-0.9.14" 69 | } 70 | ] 71 | }, 72 | { 73 | "name": "kpipewire", 74 | "buildsystem": "cmake-ninja", 75 | "config-opts": [ 76 | "-DBUILD_TESTING=OFF" 77 | ], 78 | "sources": [ 79 | { 80 | "type": "git", 81 | "url": "https://invent.kde.org/plasma/kpipewire.git", 82 | "branch": "master" 83 | } 84 | ] 85 | }, 86 | { 87 | "name": "krfb", 88 | "buildsystem": "cmake-ninja", 89 | "config-opts": [ 90 | "-DCMAKE_BUILD_TYPE=debug", 91 | "-DPLASMA_ENABLED=OFF" 92 | ], 93 | "sources": [ 94 | { 95 | "type": "dir", 96 | "path": "." 97 | } 98 | ] 99 | } 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /cmake/modules/Findgbm.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # Findgbm 3 | # ------- 4 | # 5 | # Try to find gbm on a Unix system. 6 | # 7 | # This will define the following variables: 8 | # 9 | # ``gbm_FOUND`` 10 | # True if (the requested version of) gbm is available 11 | # ``gbm_VERSION`` 12 | # The version of gbm 13 | # ``gbm_LIBRARIES`` 14 | # This can be passed to target_link_libraries() instead of the ``gbm::gbm`` 15 | # target 16 | # ``gbm_INCLUDE_DIRS`` 17 | # This should be passed to target_include_directories() if the target is not 18 | # used for linking 19 | # ``gbm_DEFINITIONS`` 20 | # This should be passed to target_compile_options() if the target is not 21 | # used for linking 22 | # 23 | # If ``gbm_FOUND`` is TRUE, it will also define the following imported target: 24 | # 25 | # ``gbm::gbm`` 26 | # The gbm library 27 | # 28 | # In general we recommend using the imported target, as it is easier to use. 29 | # Bear in mind, however, that if the target is in the link interface of an 30 | # exported library, it must be made available by the package config file. 31 | 32 | #============================================================================= 33 | # SPDX-FileCopyrightText: 2014 Alex Merry 34 | # SPDX-FileCopyrightText: 2014 Martin Gräßlin 35 | # 36 | # SPDX-License-Identifier: BSD-3-Clause 37 | #============================================================================= 38 | 39 | if(CMAKE_VERSION VERSION_LESS 2.8.12) 40 | message(FATAL_ERROR "CMake 2.8.12 is required by Findgbm.cmake") 41 | endif() 42 | if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) 43 | message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Findgbm.cmake") 44 | endif() 45 | 46 | if(NOT WIN32) 47 | # Use pkg-config to get the directories and then use these values 48 | # in the FIND_PATH() and FIND_LIBRARY() calls 49 | find_package(PkgConfig) 50 | pkg_check_modules(PKG_gbm QUIET gbm) 51 | 52 | set(gbm_DEFINITIONS ${PKG_gbm_CFLAGS_OTHER}) 53 | set(gbm_VERSION ${PKG_gbm_VERSION}) 54 | 55 | find_path(gbm_INCLUDE_DIR 56 | NAMES 57 | gbm.h 58 | HINTS 59 | ${PKG_gbm_INCLUDE_DIRS} 60 | ) 61 | find_library(gbm_LIBRARY 62 | NAMES 63 | gbm 64 | HINTS 65 | ${PKG_gbm_LIBRARY_DIRS} 66 | ) 67 | 68 | include(FindPackageHandleStandardArgs) 69 | find_package_handle_standard_args(gbm 70 | FOUND_VAR 71 | gbm_FOUND 72 | REQUIRED_VARS 73 | gbm_LIBRARY 74 | gbm_INCLUDE_DIR 75 | VERSION_VAR 76 | gbm_VERSION 77 | ) 78 | 79 | if(gbm_FOUND AND NOT TARGET gbm::gbm) 80 | add_library(gbm::gbm UNKNOWN IMPORTED) 81 | set_target_properties(gbm::gbm PROPERTIES 82 | IMPORTED_LOCATION "${gbm_LIBRARY}" 83 | INTERFACE_COMPILE_OPTIONS "${gbm_DEFINITIONS}" 84 | INTERFACE_INCLUDE_DIRECTORIES "${gbm_INCLUDE_DIR}" 85 | ) 86 | endif() 87 | 88 | mark_as_advanced(gbm_LIBRARY gbm_INCLUDE_DIR) 89 | 90 | # compatibility variables 91 | set(gbm_LIBRARIES ${gbm_LIBRARY}) 92 | set(gbm_INCLUDE_DIRS ${gbm_INCLUDE_DIR}) 93 | set(gbm_VERSION_STRING ${gbm_VERSION}) 94 | 95 | else() 96 | message(STATUS "Findgbm.cmake cannot find gbm on Windows systems.") 97 | set(gbm_FOUND FALSE) 98 | endif() 99 | 100 | include(FeatureSummary) 101 | set_package_properties(gbm PROPERTIES 102 | URL "https://www.mesa3d.org" 103 | DESCRIPTION "Mesa gbm library." 104 | ) 105 | -------------------------------------------------------------------------------- /krfb/rfbclient.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | #ifndef RFBCLIENT_H 10 | #define RFBCLIENT_H 11 | 12 | #include "rfb.h" 13 | #include 14 | 15 | class QSocketNotifier; 16 | 17 | class RfbClient : public QObject 18 | { 19 | Q_OBJECT 20 | Q_PROPERTY(bool controlEnabled READ controlEnabled WRITE setControlEnabled NOTIFY controlEnabledChanged) 21 | Q_PROPERTY(bool onHold READ isOnHold WRITE setOnHold NOTIFY holdStatusChanged) 22 | public: 23 | explicit RfbClient(rfbClientPtr client, QObject *parent = nullptr); 24 | ~RfbClient() override; 25 | 26 | /** Returns a name for the client, to be shown to the user */ 27 | virtual QString name() const; 28 | 29 | static bool controlCanBeEnabled(); 30 | bool controlEnabled() const; 31 | bool isOnHold() const; 32 | 33 | public Q_SLOTS: 34 | void setControlEnabled(bool enabled); 35 | void setOnHold(bool onHold); 36 | void closeConnection(); 37 | 38 | Q_SIGNALS: 39 | void controlEnabledChanged(bool enabled); 40 | void holdStatusChanged(bool onHold); 41 | 42 | protected: 43 | friend class RfbServer; //the following event handling methods are called by RfbServer 44 | 45 | rfbClientPtr getRfbClientPtr(); 46 | virtual void handleKeyboardEvent(bool down, rfbKeySym keySym); 47 | virtual void handleMouseEvent(int buttonMask, int x, int y); 48 | 49 | private Q_SLOTS: 50 | void onSocketActivated(); 51 | 52 | private: 53 | ///called by RfbServerManager to send framebuffer updates 54 | ///and check for possible disconnection 55 | void update(); 56 | friend class RfbServerManager; 57 | 58 | struct Private; 59 | Private *const d; 60 | }; 61 | 62 | 63 | class PendingRfbClient : public QObject 64 | { 65 | Q_OBJECT 66 | public: 67 | explicit PendingRfbClient(rfbClientPtr client, QObject *parent = nullptr); 68 | ~PendingRfbClient() override; 69 | 70 | Q_SIGNALS: 71 | void finished(RfbClient *client); 72 | 73 | protected Q_SLOTS: 74 | virtual void processNewClient() = 0; 75 | 76 | void accept(RfbClient *newClient); 77 | void reject(); 78 | 79 | protected: 80 | 81 | friend class RfbServer; //Following two methods are handled by RfbServer 82 | 83 | /** This method is supposed to check if the provided \a encryptedPassword 84 | * matches the criteria for authenticating the client. 85 | * The default implementation returns false if a password is required. 86 | * Reimplement to do more useful stuff. 87 | */ 88 | virtual bool checkPassword(const QByteArray & encryptedPassword); 89 | 90 | /** This method checks if the \a encryptedPassword that was sent from the remote 91 | * user matches the \a password that you have specified locally to be the password 92 | * for this connection. This assumes that the standard VNC authentication mechanism 93 | * is used. Returns true if the password matches or false otherwise. 94 | */ 95 | bool vncAuthCheckPassword(const QByteArray & password, const QByteArray & encryptedPassword) const; 96 | 97 | rfbClientPtr m_rfbClient; 98 | 99 | private: 100 | void onSocketActivated(); 101 | 102 | QSocketNotifier *const m_notifier; 103 | }; 104 | 105 | #endif // RFBCLIENT_H 106 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | # KDE Application Version, managed by release script 4 | set (RELEASE_SERVICE_VERSION_MAJOR "26") 5 | set (RELEASE_SERVICE_VERSION_MINOR "03") 6 | set (RELEASE_SERVICE_VERSION_MICRO "70") 7 | set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") 8 | 9 | project(krfb VERSION ${RELEASE_SERVICE_VERSION}) 10 | 11 | set(QT_MIN_VERSION 6.5.0) 12 | set(KF6_MIN_VERSION 6.2.0) 13 | 14 | find_package(ECM ${KF6_MIN_VERSION} NO_MODULE REQUIRED) 15 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ${ECM_MODULE_PATH}) 16 | 17 | include(KDEInstallDirs) 18 | include(KDECMakeSettings) 19 | include(KDECompilerSettings NO_POLICY_SCOPE) 20 | include(ECMInstallIcons) 21 | include(ECMAddAppIcon) 22 | include(ECMSetupVersion) 23 | include(ECMQtDeclareLoggingCategory) 24 | include(ECMDeprecationSettings) 25 | include(FeatureSummary) 26 | include(CheckIncludeFile) 27 | 28 | check_include_file("linux/input.h" HAVE_LINUX_INPUT_H) 29 | 30 | find_package(Qt6 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core DBus Widgets) 31 | if (Qt6Gui_VERSION VERSION_GREATER_EQUAL "6.10.0") 32 | find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) 33 | endif() 34 | find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS 35 | I18n 36 | Config 37 | CoreAddons 38 | DBusAddons 39 | DNSSD 40 | DocTools 41 | Notifications 42 | Wallet 43 | WidgetsAddons 44 | WindowSystem 45 | XmlGui 46 | StatusNotifierItem 47 | Crash 48 | ) 49 | 50 | find_package(X11 REQUIRED) 51 | 52 | find_package(XCB REQUIRED COMPONENTS 53 | XCB 54 | RENDER 55 | SHAPE 56 | XFIXES 57 | DAMAGE 58 | SHM 59 | IMAGE 60 | ) 61 | 62 | if(WIN32) 63 | set(CMAKE_REQUIRED_LIBRARIES ${KDEWIN32_LIBRARIES}) 64 | set(CMAKE_REQUIRED_INCLUDES ${KDEWIN32_INCLUDES}) 65 | endif(WIN32) 66 | 67 | ecm_set_disabled_deprecation_versions( 68 | QT 6.7.0 69 | KF 6.5.0 70 | ) 71 | 72 | include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ) 73 | 74 | find_package(LibVNCServer 0.9.14 REQUIRED) 75 | 76 | 77 | option(DISABLE_PIPEWIRE "Disable PipeWire support." OFF) 78 | if(NOT DISABLE_PIPEWIRE) 79 | find_package(KPipeWire CONFIG REQUIRED) 80 | pkg_check_modules(PipeWire IMPORTED_TARGET libpipewire-0.3) 81 | add_feature_info(PipeWire PipeWire_FOUND "Required for pipewire screencast plugin") 82 | endif() 83 | 84 | find_package(PlasmaWaylandProtocols 1.5.0) 85 | 86 | if(KPipeWire_FOUND AND PipeWire_FOUND AND PlasmaWaylandProtocols_FOUND) 87 | find_package(KWayland REQUIRED) 88 | find_package(QtWaylandScanner REQUIRED) 89 | find_package(Qt6WaylandClient) 90 | find_package(Wayland REQUIRED COMPONENTS Client) 91 | endif() 92 | 93 | ecm_setup_version(PROJECT 94 | VARIABLE_PREFIX KRFB 95 | VERSION_HEADER "krfb_version.h") 96 | 97 | include_directories ("${CMAKE_CURRENT_BINARY_DIR}/krfb" 98 | "${CMAKE_CURRENT_SOURCE_DIR}/krfb" 99 | "${CMAKE_CURRENT_SOURCE_DIR}/krfb/ui" 100 | ) 101 | 102 | add_subdirectory(events) 103 | add_subdirectory(krfb) 104 | add_subdirectory(framebuffers) 105 | add_subdirectory(doc) 106 | add_subdirectory(icons) 107 | 108 | ki18n_install(po) 109 | kdoctools_install(po) 110 | 111 | ecm_qt_install_logging_categories( 112 | EXPORT KRFB 113 | FILE krfb.categories 114 | DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} 115 | ) 116 | 117 | feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) 118 | -------------------------------------------------------------------------------- /krfb/invitationsrfbclient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | SPDX-FileCopyrightText: 2001-2003 Tim Jansen 7 | 8 | SPDX-License-Identifier: GPL-2.0-or-later 9 | */ 10 | #include "rfb.h" 11 | #include "invitationsrfbclient.h" 12 | #include "invitationsrfbserver.h" 13 | #include "krfbconfig.h" 14 | #include "sockethelpers.h" 15 | #include "connectiondialog.h" 16 | #include "krfbdebug.h" 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | struct PendingInvitationsRfbClient::Private 26 | { 27 | Private(rfbClientPtr client) : 28 | client(client), 29 | askOnConnect(true) 30 | {} 31 | 32 | rfbClientPtr client; 33 | QSocketNotifier *notifier = nullptr; 34 | bool askOnConnect; 35 | }; 36 | 37 | static void clientGoneHookNoop(rfbClientPtr cl) { Q_UNUSED(cl); } 38 | 39 | PendingInvitationsRfbClient::PendingInvitationsRfbClient(rfbClientPtr client, QObject *parent) : 40 | PendingRfbClient(client, parent), 41 | d(new Private(client)) 42 | { 43 | d->client->clientGoneHook = clientGoneHookNoop; 44 | } 45 | 46 | PendingInvitationsRfbClient::~PendingInvitationsRfbClient() 47 | { 48 | delete d; 49 | } 50 | 51 | void PendingInvitationsRfbClient::processNewClient() 52 | { 53 | QString host = peerAddress(m_rfbClient->sock) + QLatin1Char(':') + QString::number(peerPort(m_rfbClient->sock)); 54 | 55 | if (d->askOnConnect == false) { 56 | 57 | KNotification::event(QStringLiteral("NewConnectionAutoAccepted"), 58 | i18n("Accepted connection from %1", host)); 59 | accept(new InvitationsRfbClient(m_rfbClient, parent())); 60 | 61 | } else { 62 | 63 | KNotification::event(QStringLiteral("NewConnectionOnHold"), 64 | i18n("Received connection from %1, on hold (waiting for confirmation)", 65 | host)); 66 | 67 | auto dialog = new InvitationsConnectionDialog(nullptr); 68 | dialog->setRemoteHost(host); 69 | dialog->setAllowRemoteControl(KrfbConfig::allowDesktopControl()); 70 | 71 | connect(dialog, &InvitationsConnectionDialog::accepted, this, &PendingInvitationsRfbClient::dialogAccepted); 72 | connect(dialog, &InvitationsConnectionDialog::rejected, this, &PendingInvitationsRfbClient::reject); 73 | 74 | dialog->show(); 75 | } 76 | } 77 | 78 | bool PendingInvitationsRfbClient::checkPassword(const QByteArray & encryptedPassword) 79 | { 80 | qCDebug(KRFB) << "about to start authentication"; 81 | 82 | if(InvitationsRfbServer::instance->allowUnattendedAccess() && vncAuthCheckPassword( 83 | InvitationsRfbServer::instance->unattendedPassword().toLocal8Bit(), 84 | encryptedPassword) ) { 85 | d->askOnConnect = false; 86 | return true; 87 | } 88 | 89 | return vncAuthCheckPassword( 90 | InvitationsRfbServer::instance->desktopPassword().toLocal8Bit(), 91 | encryptedPassword); 92 | } 93 | 94 | void PendingInvitationsRfbClient::dialogAccepted() 95 | { 96 | auto dialog = qobject_cast(sender()); 97 | Q_ASSERT(dialog); 98 | 99 | auto client = new InvitationsRfbClient(m_rfbClient, parent()); 100 | client->setControlEnabled(dialog->allowRemoteControl()); 101 | accept(client); 102 | } 103 | -------------------------------------------------------------------------------- /events/xdp/xdpevents.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | 4 | SPDX-FileCopyrightText: 2018-2019 Jan Grulich 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #include "xdpevents.h" 10 | 11 | #include "rfbservermanager.h" 12 | #include "xdp_dbus_remotedesktop_interface.h" 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | class EventData 20 | { 21 | public: 22 | EventData(); 23 | 24 | //mouse 25 | int buttonMask = 0; 26 | int x = 0; 27 | int y = 0; 28 | 29 | QScopedPointer dbusXdpRemoteDesktopService; 30 | 31 | private: 32 | void init(); 33 | }; 34 | 35 | Q_GLOBAL_STATIC(EventData, data) 36 | 37 | EventData::EventData() 38 | { 39 | init(); 40 | } 41 | 42 | void EventData::init() 43 | { 44 | dbusXdpRemoteDesktopService.reset(new OrgFreedesktopPortalRemoteDesktopInterface(QStringLiteral("org.freedesktop.portal.Desktop"), 45 | QStringLiteral("/org/freedesktop/portal/desktop"), QDBusConnection::sessionBus())); 46 | } 47 | 48 | void XdpEventHandler::handleKeyboard(bool down, rfbKeySym keySym) 49 | { 50 | const QDBusObjectPath sessionHandle = frameBuffer()->customProperty(QStringLiteral("session_handle")).value(); 51 | data->dbusXdpRemoteDesktopService->NotifyKeyboardKeysym(sessionHandle, {}, keySym, down); 52 | } 53 | 54 | void XdpEventHandler::handlePointer(int buttonMask, int x, int y) 55 | { 56 | const uint streamNodeId = frameBuffer()->customProperty(QStringLiteral("stream_node_id")).toUInt(); 57 | const QDBusObjectPath sessionHandle = frameBuffer()->customProperty(QStringLiteral("session_handle")).value(); 58 | 59 | if (streamNodeId == 0 || sessionHandle.path().isEmpty()) { 60 | return; 61 | } 62 | 63 | if (x != data->x || y != data->y) { 64 | data->dbusXdpRemoteDesktopService->NotifyPointerMotionAbsolute(sessionHandle, QVariantMap(), streamNodeId, x, y); 65 | data->x = x; 66 | data->y = y; 67 | } 68 | 69 | if (buttonMask != data->buttonMask) { 70 | int i = 0; 71 | QList buttons = { BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, 0, 0, 0, 0, BTN_SIDE, BTN_EXTRA }; 72 | for (auto it = buttons.constBegin(); it != buttons.constEnd(); ++it) { 73 | int prevButtonState = (data->buttonMask >> i) & 0x01; 74 | int currentButtonState = (buttonMask >> i) & 0x01; 75 | 76 | if (prevButtonState != currentButtonState) { 77 | if (*it) { 78 | data->dbusXdpRemoteDesktopService->NotifyPointerButton(sessionHandle, QVariantMap(), *it, buttonMask); 79 | } else { 80 | int axis = 0; 81 | int steps = 0; 82 | switch (i) { 83 | case 3: 84 | axis = 0; // Vertical 85 | steps = -1; 86 | break; 87 | case 4: 88 | axis = 0; // Vertical 89 | steps = 1; 90 | break; 91 | case 5: 92 | axis = 1; // Horizontal 93 | steps = -1; 94 | break; 95 | case 6: 96 | axis = 1; // Horizontal 97 | steps = 1; 98 | break; 99 | } 100 | 101 | data->dbusXdpRemoteDesktopService->NotifyPointerAxisDiscrete(sessionHandle, QVariantMap(), axis, steps); 102 | } 103 | } 104 | ++i; 105 | } 106 | data->buttonMask = buttonMask; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "configurePresets": [ 4 | { 5 | "name": "dev", 6 | "displayName": "Build as debug", 7 | "generator": "Ninja", 8 | "binaryDir": "${sourceDir}/build", 9 | "cacheVariables": { 10 | "CMAKE_BUILD_TYPE": "Debug", 11 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" 12 | } 13 | }, 14 | { 15 | "name": "asan", 16 | "displayName": "Build with Asan support.", 17 | "generator": "Ninja", 18 | "binaryDir": "${sourceDir}/build-asan", 19 | "cacheVariables": { 20 | "CMAKE_BUILD_TYPE": "Debug", 21 | "ECM_ENABLE_SANITIZERS" : "'address;undefined'", 22 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" 23 | } 24 | }, 25 | { 26 | "name": "dev-clang", 27 | "displayName": "dev-clang", 28 | "generator": "Ninja", 29 | "binaryDir": "${sourceDir}/build-clang", 30 | "cacheVariables": { 31 | "CMAKE_BUILD_TYPE": "Debug", 32 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" 33 | }, 34 | "environment": { 35 | "CXX": "clang++", 36 | "CCACHE_DISABLE": "ON" 37 | } 38 | }, 39 | { 40 | "name": "unity", 41 | "displayName": "Build with CMake unity support.", 42 | "generator": "Ninja", 43 | "binaryDir": "${sourceDir}/build-unity", 44 | "cacheVariables": { 45 | "CMAKE_BUILD_TYPE": "Debug", 46 | "CMAKE_UNITY_BUILD": "ON", 47 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" 48 | } 49 | }, 50 | { 51 | "name": "release", 52 | "displayName": "Build as release mode.", 53 | "generator": "Ninja", 54 | "binaryDir": "${sourceDir}/build-release", 55 | "cacheVariables": { 56 | "CMAKE_BUILD_TYPE": "Release" 57 | } 58 | }, 59 | { 60 | "name": "profile", 61 | "displayName": "profile", 62 | "generator": "Ninja", 63 | "binaryDir": "${sourceDir}/build-profile", 64 | "cacheVariables": { 65 | "CMAKE_BUILD_TYPE": "RelWithDebInfo", 66 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" 67 | } 68 | }, 69 | { 70 | "name": "clazy", 71 | "displayName": "clazy", 72 | "generator": "Ninja", 73 | "binaryDir": "${sourceDir}/build-clazy", 74 | "cacheVariables": { 75 | "CMAKE_BUILD_TYPE": "Debug" 76 | }, 77 | "environment": { 78 | "CXX": "clazy", 79 | "CCACHE_DISABLE": "ON" 80 | } 81 | } 82 | 83 | ], 84 | "buildPresets": [ 85 | { 86 | "name": "dev", 87 | "configurePreset": "dev" 88 | }, 89 | { 90 | "name": "release", 91 | "configurePreset": "release" 92 | }, 93 | { 94 | "name": "dev-clang", 95 | "configurePreset": "dev-clang" 96 | }, 97 | { 98 | "name": "asan", 99 | "configurePreset": "asan" 100 | }, 101 | { 102 | "name": "unity", 103 | "configurePreset": "unity" 104 | }, 105 | { 106 | "name": "clazy", 107 | "configurePreset": "clazy", 108 | "environment": { 109 | "CLAZY_CHECKS" : "level0,level1,detaching-member,ifndef-define-typo,isempty-vs-count,qrequiredresult-candidates,reserve-candidates,signal-with-return-value,unneeded-cast,function-args-by-ref,function-args-by-value,returning-void-expression,no-ctor-missing-parent-argument,isempty-vs-count,qhash-with-char-pointer-key,raw-environment-function,qproperty-type-mismatch,old-style-connect,qstring-allocations,container-inside-loop,heap-allocated-small-trivial-type,inefficient-qlist,qstring-varargs,level2,detaching-member,heap-allocated-small-trivial-type,isempty-vs-count,qstring-varargs,qvariant-template-instantiation,raw-environment-function,reserve-candidates,signal-with-return-value,thread-with-slots,no-ctor-missing-parent-argument,no-missing-typeinfo", 110 | "CCACHE_DISABLE" : "ON" 111 | } 112 | } 113 | ], 114 | "testPresets": [ 115 | { 116 | "name": "dev", 117 | "configurePreset": "dev", 118 | "output": {"outputOnFailure": true}, 119 | "execution": {"noTestsAction": "error", "stopOnFailure": false} 120 | }, 121 | { 122 | "name": "asan", 123 | "configurePreset": "asan", 124 | "output": {"outputOnFailure": true}, 125 | "execution": {"noTestsAction": "error", "stopOnFailure": true} 126 | } 127 | ] 128 | } 129 | -------------------------------------------------------------------------------- /krfb/trayicon.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2010 Collabora Ltd 3 | SPDX-FileContributor: George Kiagiadakis 4 | SPDX-FileCopyrightText: 2001-2002 Tim Jansen 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | #include "trayicon.h" 9 | 10 | #include "mainwindow.h" 11 | #include "rfbservermanager.h" 12 | #include "rfbclient.h" 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | class ClientActions 27 | { 28 | public: 29 | ClientActions(RfbClient *client, QMenu *menu, QAction *before); 30 | virtual ~ClientActions(); 31 | 32 | private: 33 | QMenu *m_menu = nullptr; 34 | QAction *m_title = nullptr; 35 | QAction *m_disconnectAction = nullptr; 36 | QAction *m_enableControlAction = nullptr; 37 | QAction *m_separator = nullptr; 38 | }; 39 | 40 | ClientActions::ClientActions(RfbClient* client, QMenu* menu, QAction* before) 41 | : m_menu(menu) 42 | { 43 | m_title = m_menu->insertSection(before, client->name()); 44 | 45 | m_disconnectAction = new QAction(i18n("Disconnect"), m_menu); 46 | m_menu->insertAction(before, m_disconnectAction); 47 | 48 | QObject::connect(m_disconnectAction, &QAction::triggered, client, &RfbClient::closeConnection); 49 | 50 | if (client->controlCanBeEnabled()) { 51 | m_enableControlAction = new KToggleAction(i18n("Enable Remote Control"), m_menu); 52 | m_enableControlAction->setChecked(client->controlEnabled()); 53 | m_menu->insertAction(before, m_enableControlAction); 54 | 55 | QObject::connect(m_enableControlAction, &KToggleAction::triggered, 56 | client, &RfbClient::setControlEnabled); 57 | QObject::connect(client, &RfbClient::controlEnabledChanged, 58 | m_enableControlAction, &KToggleAction::setChecked); 59 | } else { 60 | m_enableControlAction = nullptr; 61 | } 62 | 63 | m_separator = m_menu->insertSeparator(before); 64 | } 65 | 66 | ClientActions::~ClientActions() 67 | { 68 | m_menu->removeAction(m_title); 69 | delete m_title; 70 | 71 | m_menu->removeAction(m_disconnectAction); 72 | delete m_disconnectAction; 73 | 74 | if (m_enableControlAction) { 75 | m_menu->removeAction(m_enableControlAction); 76 | delete m_enableControlAction; 77 | } 78 | 79 | m_menu->removeAction(m_separator); 80 | delete m_separator; 81 | } 82 | 83 | //********** 84 | 85 | TrayIcon::TrayIcon(QWidget *mainWindow) 86 | : KStatusNotifierItem(mainWindow) 87 | { 88 | setIconByPixmap(QIcon::fromTheme(QStringLiteral("krfb")).pixmap(22, 22, QIcon::Disabled)); 89 | 90 | setToolTipTitle(i18n("Desktop Sharing - disconnected")); 91 | setCategory(KStatusNotifierItem::ApplicationStatus); 92 | 93 | connect(RfbServerManager::instance(), &RfbServerManager::clientConnected, 94 | this, &TrayIcon::onClientConnected); 95 | connect(RfbServerManager::instance(), &RfbServerManager::clientDisconnected, 96 | this, &TrayIcon::onClientDisconnected); 97 | 98 | m_aboutAction = KStandardAction::aboutApp(this, &TrayIcon::showAbout, this); 99 | contextMenu()->addAction(m_aboutAction); 100 | } 101 | 102 | void TrayIcon::onClientConnected(RfbClient* client) 103 | { 104 | if (m_clientActions.isEmpty()) { //first client connected 105 | setIconByName(QStringLiteral("krfb")); 106 | setToolTipTitle(i18n("Desktop Sharing - connected with %1", client->name())); 107 | setStatus(KStatusNotifierItem::Active); 108 | } else { //Nth client connected, N != 1 109 | setToolTipTitle(i18n("Desktop Sharing - connected")); 110 | } 111 | 112 | m_clientActions[client] = new ClientActions(client, contextMenu(), m_aboutAction); 113 | } 114 | 115 | void TrayIcon::onClientDisconnected(RfbClient* client) 116 | { 117 | ClientActions *actions = m_clientActions.take(client); 118 | delete actions; 119 | 120 | if (m_clientActions.isEmpty()) { 121 | setIconByPixmap(QIcon::fromTheme(QStringLiteral("krfb")).pixmap(22, 22, QIcon::Disabled)); 122 | setToolTipTitle(i18n("Desktop Sharing - disconnected")); 123 | setStatus(KStatusNotifierItem::Passive); 124 | } else if (m_clientActions.size() == 1) { //clients number dropped back to 1 125 | RfbClient *client = m_clientActions.constBegin().key(); 126 | setToolTipTitle(i18n("Desktop Sharing - connected with %1", client->name())); 127 | } 128 | } 129 | 130 | void TrayIcon::showAbout() 131 | { 132 | auto *dialog = new KAboutApplicationDialog(KAboutData::applicationData()); 133 | dialog->setAttribute(Qt::WA_DeleteOnClose); 134 | dialog->show(); 135 | } 136 | -------------------------------------------------------------------------------- /snapcraft.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Scarlett Moore 2 | # 3 | # SPDX-License-Identifier: CC0-1.0 4 | --- 5 | name: krfb 6 | confinement: strict 7 | grade: stable 8 | base: core22 9 | adopt-info: krfb 10 | apps: 11 | krfb: 12 | extensions: 13 | - kde-neon-6 14 | common-id: org.kde.krfb.desktop 15 | desktop: usr/share/applications/org.kde.krfb.desktop 16 | command: usr/bin/krfb 17 | plugs: 18 | - audio-record 19 | environment: 20 | LD_LIBRARY_PATH: $SNAP/ffmpeg-platform/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:${LD_LIBRARY_PATH} 21 | PATH: $SNAP/ffmpeg-platform/usr/bin:${PATH} 22 | ALSA_CONFIG_PATH: "$SNAP/kf6/etc/asound.conf" 23 | plugs: 24 | ffmpeg-2204: 25 | interface: content 26 | target: ffmpeg-platform # the folder where this content snap will be mounted 27 | default-provider: ffmpeg-2204 28 | slots: 29 | session-dbus-interface: 30 | interface: dbus 31 | name: org.kde.krfb 32 | bus: session 33 | package-repositories: 34 | - type: apt 35 | components: 36 | - main 37 | suites: 38 | - jammy 39 | key-id: 444DABCF3667D0283F894EDDE6D4736255751E5D 40 | url: http://origin.archive.neon.kde.org/user 41 | key-server: keyserver.ubuntu.com 42 | parts: 43 | kpipewire: 44 | plugin: cmake 45 | source: https://invent.kde.org/plasma/kpipewire.git 46 | source-branch: master 47 | cmake-parameters: 48 | - -DCMAKE_INSTALL_PREFIX=/usr 49 | - -DCMAKE_BUILD_TYPE=Release 50 | - -DQT_MAJOR_VERSION=6 51 | - -DBUILD_WITH_QT6=ON 52 | - -DBUILD_TESTING=OFF 53 | - -DCMAKE_INSTALL_SYSCONFDIR=/etc 54 | - -DCMAKE_INSTALL_LOCALSTATEDIR=/var 55 | - -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY=ON 56 | - -DCMAKE_FIND_USE_PACKAGE_REGISTRY=OFF 57 | - -DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON 58 | - -DCMAKE_INSTALL_RUNSTATEDIR=/run 59 | - -DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=ON 60 | - -DCMAKE_VERBOSE_MAKEFILE=ON 61 | - -DCMAKE_INSTALL_LIBDIR=lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR 62 | - --log-level=STATUS 63 | - -DCMAKE_LIBRARY_PATH=lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR 64 | krfb: 65 | after: 66 | - kpipewire 67 | parse-info: 68 | - usr/share/metainfo/org.kde.krfb.appdata.xml 69 | plugin: cmake 70 | source: . 71 | source-type: local 72 | build-packages: 73 | - libxcb-render0-dev 74 | - libxcb-shape0-dev 75 | - libxcb-xfixes0-dev 76 | - libxcb-shm0-dev 77 | - libxcb-damage0-dev 78 | - libxcb-image0-dev 79 | - libvncserver-dev 80 | - libpipewire-0.3-dev 81 | - libepoxy-dev 82 | - libgbm-dev 83 | - libwayland-dev 84 | - libxdamage-dev 85 | - libxtst-dev 86 | build-snaps: 87 | - ffmpeg-2204-sdk 88 | stage-packages: 89 | - libxcb-render0 90 | - libxcb-shape0 91 | - libxcb-xfixes0 92 | - libxcb-shm0-dev 93 | - libxcb-damage0-dev 94 | - libxcb-image0-dev 95 | - libvncserver1 96 | - pipewire-bin 97 | - pipewire-audio-client-libraries 98 | - libepoxy0 99 | - libgbm1 100 | - libwayland-client0 101 | - libxdamage1 102 | - libxtst6 103 | cmake-parameters: 104 | - -DCMAKE_INSTALL_PREFIX=/usr 105 | - -DCMAKE_BUILD_TYPE=Release 106 | - -DQT_MAJOR_VERSION=6 107 | - -DBUILD_WITH_QT6=ON 108 | - -DBUILD_TESTING=OFF 109 | - -DCMAKE_INSTALL_SYSCONFDIR=/etc 110 | - -DCMAKE_INSTALL_LOCALSTATEDIR=/var 111 | - -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY=ON 112 | - -DCMAKE_FIND_USE_PACKAGE_REGISTRY=OFF 113 | - -DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON 114 | - -DCMAKE_INSTALL_RUNSTATEDIR=/run 115 | - -DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=ON 116 | - -DCMAKE_VERBOSE_MAKEFILE=ON 117 | - -DCMAKE_INSTALL_LIBDIR=lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR 118 | - --log-level=STATUS 119 | - -DCMAKE_LIBRARY_PATH=lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR 120 | build-environment: 121 | - CMAKE_FIND_ROOT_PATH: "${CMAKE_FIND_ROOT_PATH}:/snap/ffmpeg-2204-sdk/current" 122 | - PKG_CONFIG_PATH: "/snap/ffmpeg-2204-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pkgconfig" 123 | - LD_LIBRARY_PATH: "${LD_LIBRARY_PATH}:/snap/ffmpeg-2204-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR" 124 | prime: 125 | - -usr/lib/*/cmake/* 126 | - -usr/include/* 127 | - -usr/share/ECM/* 128 | - -usr/share/man/* 129 | - -usr/bin/X11 130 | - -usr/lib/gcc/$CRAFT_ARCH_TRIPLET_BUILD_FOR/6.0.0 131 | - -usr/lib/aspell/* 132 | - -usr/share/lintian 133 | cleanup: 134 | after: 135 | - krfb 136 | plugin: nil 137 | build-snaps: 138 | - core22 139 | - kf6-core22 140 | override-prime: | 141 | set -eux 142 | for snap in "core22" "kf6-core22"; do 143 | cd "/snap/$snap/current" && find . -type f,l -exec rm -rf "${CRAFT_PRIME}/{}" \; 144 | done 145 | -------------------------------------------------------------------------------- /krfb/ui/connectionwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | ConnectionWidget 3 | 4 | 5 | 6 | 0 7 | 0 8 | 500 9 | 212 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 0 18 | 0 19 | 20 | 21 | 22 | 23 | 128 24 | 128 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 0 36 | 0 37 | 38 | 39 | 40 | 41 | 13 42 | 75 43 | true 44 | 45 | 46 | 47 | Attention 48 | 49 | 50 | false 51 | 52 | 53 | 0 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 0 62 | 0 63 | 64 | 65 | 66 | -1 67 | 68 | 69 | 5 70 | 71 | 72 | Somebody is requesting a connection to your computer. Granting this will allow the remote user to watch your desktop. 73 | 74 | 75 | Qt::AutoText 76 | 77 | 78 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 79 | 80 | 81 | true 82 | 83 | 84 | 0 85 | 86 | 87 | 0 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 75 98 | true 99 | 100 | 101 | 102 | Remote system: 103 | 104 | 105 | false 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 75 114 | true 115 | 116 | 117 | 118 | 123.234.123.234 119 | 120 | 121 | false 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 0 132 | 0 133 | 134 | 135 | 136 | If you turn this option on, the remote user can enter keystrokes and use your mouse pointer. This gives them full control over your computer, so be careful. When the option is disabled the remote user can only watch your screen. 137 | 138 | 139 | Allow remote user to &control keyboard and mouse 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /krfb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config-krfb.h.cmake 2 | ${CMAKE_CURRENT_BINARY_DIR}/config-krfb.h 3 | ) 4 | 5 | include(GenerateExportHeader) 6 | 7 | ##################################### 8 | # First target: libkrfbprivate - a library 9 | # for linking plugins against. 10 | 11 | set (krfbprivate_SRCS 12 | framebuffer.cpp 13 | framebufferplugin.cpp 14 | events.cpp 15 | eventsplugin.cpp 16 | ) 17 | 18 | add_library (krfbprivate 19 | SHARED 20 | ${krfbprivate_SRCS} 21 | ) 22 | generate_export_header(krfbprivate BASE_NAME krfbprivate) 23 | 24 | 25 | target_link_libraries (krfbprivate 26 | Qt::Core 27 | Qt::Widgets 28 | Qt::GuiPrivate 29 | ${X11_X11_LIB} 30 | LibVNCServer::vncserver 31 | ) 32 | 33 | set_target_properties (krfbprivate PROPERTIES 34 | VERSION 5 35 | SOVERSION 5.0 36 | ) 37 | 38 | install (TARGETS krfbprivate 39 | ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} 40 | LIBRARY NAMELINK_SKIP 41 | ) 42 | 43 | ##################################### 44 | # Second target: krfb - the app 45 | # itself. 46 | 47 | set (krfb_SRCS 48 | connectiondialog.cpp 49 | framebuffermanager.cpp 50 | events.cpp 51 | eventsmanager.cpp 52 | main.cpp 53 | mainwindow.cpp 54 | sockethelpers.cpp 55 | trayicon.cpp 56 | rfbservermanager.cpp 57 | rfbserver.cpp 58 | rfbclient.cpp 59 | invitationsrfbserver.cpp 60 | invitationsrfbclient.cpp 61 | ) 62 | 63 | ecm_qt_declare_logging_category(krfb_SRCS 64 | HEADER krfbdebug.h 65 | IDENTIFIER KRFB 66 | CATEGORY_NAME krfb.krfb 67 | DESCRIPTION "KRFB Application" 68 | EXPORT KRFB 69 | ) 70 | 71 | kconfig_add_kcfg_files (krfb_SRCS 72 | krfbconfig.kcfgc 73 | ) 74 | 75 | ki18n_wrap_ui (krfb_UI_SRCS 76 | ui/configtcp.ui 77 | ui/configsecurity.ui 78 | ui/configframebuffer.ui 79 | ui/connectionwidget.ui 80 | ui/mainwidget.ui 81 | ) 82 | 83 | qt_add_resources(krfb_SRCS 84 | krfb.qrc 85 | ) 86 | 87 | add_executable (krfb 88 | ${krfb_SRCS} 89 | ${krfb_UI_SRCS} 90 | ) 91 | 92 | target_link_libraries (krfb 93 | krfbprivate 94 | ${JPEG_LIBRARIES} 95 | ${X11_Xext_LIB} 96 | ${X11_X11_LIB} 97 | ${X11_Xdamage_LIB} 98 | Qt::Network 99 | KF6::CoreAddons 100 | KF6::DBusAddons 101 | KF6::DNSSD 102 | KF6::I18n 103 | KF6::Notifications 104 | KF6::Wallet 105 | KF6::WidgetsAddons 106 | KF6::WindowSystem 107 | KF6::XmlGui 108 | KF6::StatusNotifierItem 109 | KF6::Crash 110 | LibVNCServer::vncserver 111 | ) 112 | 113 | if (X11_XTest_FOUND) 114 | target_link_libraries (krfb 115 | ${X11_XTest_LIB} 116 | ) 117 | endif (X11_XTest_FOUND) 118 | 119 | install (TARGETS krfb 120 | ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} 121 | ) 122 | 123 | ################################# 124 | kconfig_add_kcfg_files (krfbvm_SRCS 125 | krfbconfig.kcfgc 126 | ) 127 | 128 | ecm_qt_declare_logging_category(krfbvm_SRCS 129 | HEADER krfbdebug.h 130 | IDENTIFIER KRFB 131 | CATEGORY_NAME krfb.krfb 132 | DESCRIPTION "KRFB Application" 133 | EXPORT KRFB 134 | ) 135 | 136 | add_executable(krfb-virtualmonitor main-virtualmonitor.cpp ${krfbvm_SRCS} ${krfb_UI_SRCS} 137 | rfbserver.cpp rfbclient.cpp rfbservermanager.cpp eventsmanager.cpp framebuffermanager.cpp sockethelpers.cpp) 138 | target_link_libraries(krfb-virtualmonitor 139 | krfbprivate 140 | Qt::Gui 141 | Qt::Network 142 | KF6::ConfigGui 143 | KF6::CoreAddons 144 | KF6::I18n 145 | KF6::Notifications 146 | KF6::WindowSystem 147 | KF6::Crash 148 | ) 149 | 150 | install (TARGETS krfb-virtualmonitor 151 | ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} 152 | ) 153 | 154 | configure_file(org.kde.krfb.virtualmonitor.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/org.kde.krfb.virtualmonitor.desktop @ONLY) 155 | install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.krfb.virtualmonitor.desktop 156 | DESTINATION ${KDE_INSTALL_APPDIR} 157 | ) 158 | 159 | ########### install files ############### 160 | 161 | install (PROGRAMS org.kde.krfb.desktop 162 | DESTINATION ${KDE_INSTALL_APPDIR} 163 | ) 164 | 165 | install(FILES org.kde.krfb.appdata.xml 166 | DESTINATION ${KDE_INSTALL_METAINFODIR} 167 | ) 168 | 169 | install (FILES krfb.notifyrc 170 | DESTINATION ${KDE_INSTALL_DATADIR}/krfb 171 | ) 172 | -------------------------------------------------------------------------------- /events/x11/x11events.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the KDE project 3 | 4 | SPDX-FileCopyrightText: 2016 Oleg Chernovskiy 5 | 6 | SPDX-License-Identifier: GPL-2.0-or-later 7 | */ 8 | 9 | #include "x11events.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | enum { 20 | LEFTSHIFT = 1, 21 | RIGHTSHIFT = 2, 22 | ALTGR = 4 23 | }; 24 | 25 | class EventData 26 | { 27 | public: 28 | EventData(); 29 | 30 | //keyboard 31 | Display *dpy = nullptr; 32 | signed char modifiers[0x100] = {}; 33 | KeyCode keycodes[0x100] = {}; 34 | KeyCode leftShiftCode = 0; 35 | KeyCode rightShiftCode = 0; 36 | KeyCode altGrCode = 0; 37 | char modifierState = 0; 38 | 39 | //mouse 40 | int buttonMask = 0; 41 | int x = 0; 42 | int y = 0; 43 | 44 | private: 45 | void init(); 46 | }; 47 | 48 | Q_GLOBAL_STATIC(EventData, data) 49 | 50 | EventData::EventData() 51 | { 52 | init(); 53 | } 54 | 55 | void EventData::init() 56 | { 57 | buttonMask = 0; 58 | 59 | dpy = QX11Info::display(); 60 | //initialize keycodes 61 | KeySym key, *keymap; 62 | int i, j, minkey, maxkey, syms_per_keycode; 63 | 64 | memset(modifiers, -1, sizeof(modifiers)); 65 | 66 | XDisplayKeycodes(dpy, &minkey, &maxkey); 67 | Q_ASSERT(minkey >= 8); 68 | Q_ASSERT(maxkey < 256); 69 | keymap = (KeySym *) XGetKeyboardMapping(dpy, minkey, 70 | (maxkey - minkey + 1), 71 | &syms_per_keycode); 72 | Q_ASSERT(keymap); 73 | 74 | for (i = minkey; i <= maxkey; i++) { 75 | for (j = 0; j < syms_per_keycode; j++) { 76 | key = keymap[(i-minkey)*syms_per_keycode+j]; 77 | 78 | if (key >= ' ' && key < 0x100 && i == XKeysymToKeycode(dpy, key)) { 79 | keycodes[key] = i; 80 | modifiers[key] = j; 81 | } 82 | } 83 | } 84 | 85 | leftShiftCode = XKeysymToKeycode(dpy, XK_Shift_L); 86 | rightShiftCode = XKeysymToKeycode(dpy, XK_Shift_R); 87 | altGrCode = XKeysymToKeycode(dpy, XK_Mode_switch); 88 | 89 | XFree((char *)keymap); 90 | } 91 | 92 | /* this function adjusts the modifiers according to mod (as from modifiers) and data->modifierState */ 93 | static void tweakModifiers(signed char mod, bool down) 94 | { 95 | bool isShift = data->modifierState & (LEFTSHIFT | RIGHTSHIFT); 96 | 97 | if (mod < 0) { 98 | return; 99 | } 100 | 101 | if (isShift && mod != 1) { 102 | if (data->modifierState & LEFTSHIFT) { 103 | XTestFakeKeyEvent(data->dpy, data->leftShiftCode, 104 | down, CurrentTime); 105 | } 106 | 107 | if (data->modifierState & RIGHTSHIFT) { 108 | XTestFakeKeyEvent(data->dpy, data->rightShiftCode, 109 | down, CurrentTime); 110 | } 111 | } 112 | 113 | if (!isShift && mod == 1) { 114 | XTestFakeKeyEvent(data->dpy, data->leftShiftCode, 115 | down, CurrentTime); 116 | } 117 | 118 | if ((data->modifierState & ALTGR) && mod != 2) { 119 | XTestFakeKeyEvent(data->dpy, data->altGrCode, 120 | !down, CurrentTime); 121 | } 122 | 123 | if (!(data->modifierState & ALTGR) && mod == 2) { 124 | XTestFakeKeyEvent(data->dpy, data->altGrCode, 125 | down, CurrentTime); 126 | } 127 | } 128 | 129 | void X11EventHandler::handleKeyboard(bool down, rfbKeySym keySym) 130 | { 131 | #define ADJUSTMOD(sym,state) \ 132 | if(keySym==sym) { if(down) data->modifierState|=state; else data->modifierState&=~state; } 133 | 134 | if (QX11Info::isPlatformX11()) { 135 | ADJUSTMOD(XK_Shift_L, LEFTSHIFT); 136 | ADJUSTMOD(XK_Shift_R, RIGHTSHIFT); 137 | ADJUSTMOD(XK_Mode_switch, ALTGR); 138 | 139 | if (keySym >= ' ' && keySym < 0x100) { 140 | KeyCode k; 141 | 142 | if (down) { 143 | tweakModifiers(data->modifiers[keySym], True); 144 | } 145 | 146 | k = data->keycodes[keySym]; 147 | 148 | if (k != NoSymbol) { 149 | XTestFakeKeyEvent(data->dpy, k, down, CurrentTime); 150 | } 151 | 152 | if (down) { 153 | tweakModifiers(data->modifiers[keySym], False); 154 | } 155 | } else { 156 | KeyCode k = XKeysymToKeycode(data->dpy, keySym); 157 | 158 | if (k != NoSymbol) { 159 | XTestFakeKeyEvent(data->dpy, k, down, CurrentTime); 160 | } 161 | } 162 | } 163 | /* 164 | // Wayland platform and pipweire plugin in use 165 | if (KrfbConfig::preferredFrameBufferPlugin() == QStringLiteral("pw")) { 166 | 167 | }*/ 168 | } 169 | 170 | void X11EventHandler::handlePointer(int buttonMask, int x, int y) 171 | { 172 | if (QX11Info::isPlatformX11()) { 173 | XTestFakeMotionEvent(data->dpy, 0, x, y, CurrentTime); 174 | 175 | for (int i = 0; i < 5; i++) { 176 | if ((data->buttonMask&(1 << i)) != (buttonMask&(1 << i))) { 177 | XTestFakeButtonEvent(data->dpy, 178 | i + 1, 179 | (buttonMask&(1 << i)) ? True : False, 180 | CurrentTime); 181 | } 182 | } 183 | 184 | data->buttonMask = buttonMask; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /krfb/org.kde.krfb.desktop: -------------------------------------------------------------------------------- 1 | # KDE Config File 2 | [Desktop Entry] 3 | Type=Application 4 | Exec=krfb -qwindowtitle %c 5 | Icon=krfb 6 | X-DBUS-StartupType=Unique 7 | X-DocPath=krfb/index.html 8 | Terminal=false 9 | Name=Krfb 10 | Name[ar]=كرفب 11 | Name[ast]=Krfb 12 | Name[bg]=Krfb 13 | Name[bn]=কে-আর-এফ-বি 14 | Name[br]=Krfb 15 | Name[bs]=Krfb 16 | Name[ca]=Krfb 17 | Name[ca@valencia]=Krfb 18 | Name[cs]=Krfb 19 | Name[da]=Krfb 20 | Name[de]=Krfb 21 | Name[el]=Krfb 22 | Name[en_GB]=Krfb 23 | Name[eo]=Krfb 24 | Name[es]=Krfb 25 | Name[et]=Krfb 26 | Name[eu]=Krfb 27 | Name[fi]=Krfb 28 | Name[fr]=Krfb 29 | Name[ga]=Krfb 30 | Name[gl]=Krfb 31 | Name[he]=Krfb 32 | Name[hi]=केआरएफबी 33 | Name[hne]=केआरएफबी 34 | Name[hr]=Krfb 35 | Name[hu]=Krfb 36 | Name[ia]=Krfb 37 | Name[id]=Krfb 38 | Name[is]=Krfb 39 | Name[it]=Krfb 40 | Name[ja]=Krfb 41 | Name[ka]=Krfb 42 | Name[kk]=Krfb 43 | Name[km]=Krfb 44 | Name[ko]=Krfb 45 | Name[lt]=Krfb 46 | Name[lv]=Krfb 47 | Name[ml]=കെആര്‍എഫ്ബി 48 | Name[mr]=के-आर-एफ-बी 49 | Name[nb]=Krfb 50 | Name[nds]=KRfb 51 | Name[ne]=Krfb 52 | Name[nl]=Krfb 53 | Name[nn]=Krfb 54 | Name[pa]=Krfb 55 | Name[pl]=Krfb 56 | Name[pt]=Krfb 57 | Name[pt_BR]=Krfb 58 | Name[ro]=Krfb 59 | Name[ru]=Krfb 60 | Name[sa]=Krfb 61 | Name[si]=Krfb 62 | Name[sk]=Krfb 63 | Name[sl]=Krfb 64 | Name[sq]=Krfb 65 | Name[sr]=КРФБ 66 | Name[sr@ijekavian]=КРФБ 67 | Name[sr@ijekavianlatin]=KRFB 68 | Name[sr@latin]=KRFB 69 | Name[sv]=Krfb 70 | Name[tr]=Krfb 71 | Name[ug]=Krfb 72 | Name[uk]=Krfb 73 | Name[uz]=Krfb 74 | Name[uz@cyrillic]=Krfb 75 | Name[vi]=Krfb 76 | Name[zh_CN]=Krfb 77 | Name[zh_HK]=Krfb 78 | Name[zh_TW]=桌面分享_Krfb 79 | GenericName=Desktop Sharing (VNC) 80 | GenericName[ar]=مشاركة سطح المكتب (VNC) 81 | GenericName[bg]=Споделяне на работния плот (VNC) 82 | GenericName[ca]=Compartició de l'escriptori (VNC) 83 | GenericName[ca@valencia]=Compartiu l'escriptori (VNC) 84 | GenericName[cs]=Sdílení pracovní plochy (VNC) 85 | GenericName[da]=Skrivebordsdeling (VNC) 86 | GenericName[de]=Arbeitsflächen-Freigabe (VNC) 87 | GenericName[el]=Κοινή χρήση επιφάνειας εργασίας (VNC) 88 | GenericName[en_GB]=Desktop Sharing (VNC) 89 | GenericName[eo]=Kunhavigo de Labortablo (VNC) 90 | GenericName[es]=Escritorio compartido (VNC) 91 | GenericName[et]=Töölaua jagamine (VNC) 92 | GenericName[eu]=Mahaigaina partekatzea (VNC) 93 | GenericName[fi]=Työpöydän jakaminen (VNC) 94 | GenericName[fr]=Partage de bureaux (VNC) 95 | GenericName[gl]=Compartir o escritorio (VNC) 96 | GenericName[he]=שיתוף שולחנות עבודה (VNC) 97 | GenericName[hu]=Munkaasztal-megosztás (VNC) 98 | GenericName[ia]=Compartir de scriptorio (VNC) 99 | GenericName[it]=Condivisione del desktop (VNC) 100 | GenericName[ka]=სამუშაო მაგიდის გაზიარება(VNC). 101 | GenericName[ko]=데스크톱 공유(VNC) 102 | GenericName[lt]=Darbalaukio bendrinimas (VNC) 103 | GenericName[lv]=Darbvirsmas koplietošana (VNC) 104 | GenericName[nl]=Bureaublad delen (VNC) 105 | GenericName[nn]=Skrivebordsdeling (VNC) 106 | GenericName[pl]=Współdzielenie pulpitu (VNC) 107 | GenericName[pt]=Partilha do Ecrã (VNC) 108 | GenericName[pt_BR]=Compartilhamento de ambiente de trabalho (VNC) 109 | GenericName[ro]=Partajare birou (VNC) 110 | GenericName[ru]=Совместный доступ к рабочему столу (VNC) 111 | GenericName[sa]=डेस्कटॉप् साझेदारी (VNC) . 112 | GenericName[sk]=Zdieľanie pracovnej plochy (VNC) 113 | GenericName[sl]=Souporaba namizja (VNC) 114 | GenericName[sv]=Skrivbordsdelning (VNC) 115 | GenericName[tr]=Masaüstü Paylaşımı (VNC) 116 | GenericName[uk]=Спільні стільниці (VNC) 117 | GenericName[zh_CN]=桌面共享 (VNC) 118 | GenericName[zh_TW]=桌面分享 (VNC) 119 | Comment=Desktop Sharing 120 | Comment[af]=Werkskerm Deeling 121 | Comment[ar]=مشاركة سطح المكتب 122 | Comment[bg]=Споделяне на работния плот 123 | Comment[bn]=ডেস্কটপ ভাগাভাগি 124 | Comment[br]=Rannañ ar vurev 125 | Comment[bs]=Dijeljenje radne površine 126 | Comment[ca]=Compartir l'escriptori 127 | Comment[ca@valencia]=Compartir l'escriptori 128 | Comment[cs]=Sdílení pracovní plochy 129 | Comment[cy]=Rhannu Penbwrdd 130 | Comment[da]=Skrivebordsdeling 131 | Comment[de]=Arbeitsflächen-Freigabe 132 | Comment[el]=Κοινή χρήση επιφάνειας εργασίας 133 | Comment[en_GB]=Desktop Sharing 134 | Comment[eo]=Tabula komunigado 135 | Comment[es]=Escritorio compartido 136 | Comment[et]=Töölaua jagamine 137 | Comment[eu]=Mahaigaina partekatzea 138 | Comment[fi]=Työpöydän jakaminen 139 | Comment[fr]=Partage de bureaux 140 | Comment[ga]=Roinnt Deisce 141 | Comment[gl]=Compartición do escritorio 142 | Comment[he]=שיתוף שולחנות עבודה 143 | Comment[hi]=डेस्कटॉप साझेदारी 144 | Comment[hne]=डेस्कटाप साझेदारी 145 | Comment[hr]=Dijeljenje radne površine 146 | Comment[hu]=Munkaasztal-megosztás 147 | Comment[ia]=Compartir de scriptorio 148 | Comment[id]=Desktop Sharing 149 | Comment[is]=Skjáborðamiðlun 150 | Comment[it]=Condivisione del desktop 151 | Comment[ja]=デスクトップ共有 152 | Comment[ka]=სამუშაო მაგიდის გაზიარება 153 | Comment[kk]=Үстелді ортақтастыру 154 | Comment[km]=ការ​ចែក​រំលែក​ផ្ទែ​តុ 155 | Comment[ko]=데스크톱 공유 156 | Comment[lt]=Darbalaukio bendrinimas 157 | Comment[lv]=Darbvirsmas koplietošana 158 | Comment[mk]=Делење на работната површина 159 | Comment[ml]=പണിയിടം പങ്കുവെക്കല്‍ 160 | Comment[mr]=डेस्कटॉप शेअरींग 161 | Comment[ms]=Perkongsian Ruang Kerja 162 | Comment[nb]=Delte skrivebord 163 | Comment[nds]=Schriefdisch-Freegaav 164 | Comment[nl]=Bureaublad delen 165 | Comment[nn]=Skrivebordsdeling 166 | Comment[pa]=ਡੈਸਕਟਾਪ ਸ਼ੇਅਰਿੰਗ 167 | Comment[pl]=Współdzielenie pulpitu 168 | Comment[pt]=Partilha do Ecrã 169 | Comment[pt_BR]=Compartilhamento do ambiente de trabalho 170 | Comment[ro]=Partajare birou 171 | Comment[ru]=Параметры общего рабочего стола 172 | Comment[sa]=डेस्कटॉप् साझेदारी 173 | Comment[si]=වැඩතල හවුල් 174 | Comment[sk]=Zdieľanie pracovnej plochy 175 | Comment[sl]=Souporaba namizja 176 | Comment[sr]=Дељење површи 177 | Comment[sr@ijekavian]=Дијељење површи 178 | Comment[sr@ijekavianlatin]=Dijeljenje površi 179 | Comment[sr@latin]=Deljenje površi 180 | Comment[sv]=Dela ut skrivbordet 181 | Comment[ta]=பணிமேடை பகிர்வு 182 | Comment[tg]=Истифодаи Муштараки Мизи Корӣ 183 | Comment[th]=ใช้งานพื้นที่ทำงานร่วมกัน 184 | Comment[tr]=Masaüstü Paylaşımı 185 | Comment[ug]=ئۈستەلئۈستىنى ھەمبەھىرلەش 186 | Comment[uk]=Спільні стільниці 187 | Comment[xh]=Ulwahlulelano lwe Desktop 188 | Comment[zh_CN]=桌面共享 189 | Comment[zh_HK]=桌面分享 190 | Comment[zh_TW]=桌面分享 191 | Categories=Qt;KDE;Network;RemoteAccess; 192 | X-DBUS-ServiceName=org.kde.krfb 193 | X-KDE-Wayland-Interfaces=org_kde_kwin_fake_input,org_kde_kwin_remote_access_manager 194 | -------------------------------------------------------------------------------- /krfb/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2001-2003 Tim Jansen 3 | SPDX-License-Identifier: GPL-2.0-or-later 4 | */ 5 | 6 | #include "mainwindow.h" 7 | #include "trayicon.h" 8 | #include "invitationsrfbserver.h" 9 | #include "krfbconfig.h" 10 | #include "krfb_version.h" 11 | #include "krfbdebug.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | static bool checkX11Capabilities() 31 | { 32 | int bp1, bp2, majorv, minorv; 33 | Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2, 34 | &majorv, &minorv); 35 | 36 | if ((!r) || (((majorv * 1000) + minorv) < 2002)) { 37 | KMessageBox::error(nullptr, 38 | i18n("Your X11 Server does not support the required XTest extension " 39 | "version 2.2. Sharing your desktop is not possible."), 40 | i18n("Desktop Sharing Error")); 41 | return false; 42 | } 43 | 44 | return true; 45 | } 46 | 47 | static void checkOldX11PluginConfig() { 48 | if (KrfbConfig::preferredFrameBufferPlugin() == QStringLiteral("x11")) { 49 | qCDebug(KRFB) << "Detected deprecated configuration: preferredFrameBufferPlugin = x11"; 50 | KConfigSkeletonItem *config_item = KrfbConfig::self()->findItem( 51 | QStringLiteral("preferredFrameBufferPlugin")); 52 | if (config_item) { 53 | config_item->setProperty(QStringLiteral("xcb")); 54 | KrfbConfig::self()->save(); 55 | qCDebug(KRFB) << " Fixed preferredFrameBufferPlugin from x11 to xcb."; 56 | } 57 | } 58 | } 59 | 60 | static void checkWaylandPluginConfig() 61 | { 62 | if (KrfbConfig::preferredFrameBufferPlugin() != QStringLiteral("pw")) { 63 | qWarning() << "Wayland: Detected invalid configuration: " 64 | "preferredFrameBufferPlugin is not pipewire: " 65 | << KrfbConfig::preferredFrameBufferPlugin(); 66 | KConfigSkeletonItem *config_item = KrfbConfig::self()->findItem( 67 | QStringLiteral("preferredFrameBufferPlugin")); 68 | if (config_item) { 69 | config_item->setProperty(QStringLiteral("pw")); 70 | KrfbConfig::self()->save(); 71 | qCDebug(KRFB) << "Wayland: Fixed preferredFrameBufferPlugin to \"pw\"."; 72 | } 73 | } 74 | } 75 | 76 | int main(int argc, char *argv[]) 77 | { 78 | QApplication app(argc, argv); 79 | 80 | KLocalizedString::setApplicationDomain("krfb"); 81 | 82 | KAboutData aboutData(QStringLiteral("krfb"), 83 | i18n("Desktop Sharing"), 84 | QStringLiteral(KRFB_VERSION_STRING), 85 | i18n("VNC-compatible server to share desktops"), 86 | KAboutLicense::GPL, 87 | i18n("(c) 2009-2010, Collabora Ltd.\n" 88 | "(c) 2007, Alessandro Praduroux\n" 89 | "(c) 2001-2003, Tim Jansen\n" 90 | "(c) 2001, Johannes E. Schindelin\n" 91 | "(c) 2000-2001, Const Kaplinsky\n" 92 | "(c) 2000, Tridia Corporation\n" 93 | "(c) 1999, AT&T Laboratories Boston\n")); 94 | aboutData.addAuthor(i18n("George Goldberg"), 95 | i18n("Telepathy tubes support"), 96 | QStringLiteral("george.goldberg@collabora.co.uk")); 97 | aboutData.addAuthor(i18n("George Kiagiadakis"), 98 | QString(), 99 | QStringLiteral("george.kiagiadakis@collabora.co.uk")); 100 | aboutData.addAuthor(i18n("Alessandro Praduroux"), i18n("KDE4 porting"), QStringLiteral("pradu@pradu.it")); 101 | aboutData.addAuthor(i18n("Tim Jansen"), i18n("Original author"), QStringLiteral("tim@tjansen.de")); 102 | aboutData.addCredit(i18n("Johannes E. Schindelin"), 103 | i18n("libvncserver")); 104 | aboutData.addCredit(i18n("Const Kaplinsky"), 105 | i18n("TightVNC encoder")); 106 | aboutData.addCredit(i18n("Tridia Corporation"), 107 | i18n("ZLib encoder")); 108 | aboutData.addCredit(i18n("AT&T Laboratories Boston"), 109 | i18n("original VNC encoders and " 110 | "protocol design")); 111 | KAboutData::setApplicationData(aboutData); 112 | 113 | QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("krfb"))); 114 | 115 | KCrash::initialize(); 116 | 117 | QCommandLineParser parser; 118 | aboutData.setupCommandLine(&parser); 119 | const QCommandLineOption nodialogOption(QStringList{ QStringLiteral("nodialog") }, i18n("Do not show the invitations management dialog at startup")); 120 | parser.addOption(nodialogOption); 121 | 122 | parser.process(app); 123 | aboutData.processCommandLine(&parser); 124 | 125 | KDBusService service(KDBusService::Unique, &app); 126 | 127 | app.setQuitOnLastWindowClosed(false); 128 | 129 | if (KWindowSystem::isPlatformX11()) { 130 | if (!checkX11Capabilities()) { 131 | return 1; 132 | } 133 | 134 | // upgrade the configuration 135 | checkOldX11PluginConfig(); 136 | } else if (KWindowSystem::isPlatformWayland()) { 137 | // check that default plugin in Wayland is PipeWire 138 | checkWaylandPluginConfig(); 139 | } else { 140 | KMessageBox::error(nullptr, 141 | i18n("Desktop Sharing is not running under an X11 Server or Wayland.\n" 142 | "Other display servers are currently not supported."), 143 | i18n("Desktop Sharing Error")); 144 | return 1; 145 | } 146 | 147 | //init the core 148 | InvitationsRfbServer::init(); 149 | 150 | //init the GUI 151 | MainWindow mainWindow; 152 | TrayIcon trayicon(&mainWindow); 153 | 154 | QObject::connect(&service, &KDBusService::activateRequested, &mainWindow, [&mainWindow](const QStringList & /*arguments*/, const QString & /*workdir*/) { 155 | if (!mainWindow.isVisible()) { 156 | mainWindow.setVisible(true); 157 | } else { 158 | KWindowSystem::updateStartupId(mainWindow.windowHandle()); 159 | KWindowSystem::activateWindow(mainWindow.windowHandle()); 160 | } 161 | }); 162 | 163 | if (KrfbConfig::startMinimized()) { 164 | mainWindow.hide(); 165 | } else if (app.isSessionRestored() && KMainWindow::canBeRestored(1)) { 166 | mainWindow.restore(1, false); 167 | } else if (!parser.isSet(nodialogOption)) { 168 | mainWindow.show(); 169 | } 170 | 171 | sigset_t sigs; 172 | sigemptyset(&sigs); 173 | sigaddset(&sigs, SIGPIPE); 174 | sigprocmask(SIG_BLOCK, &sigs, nullptr); 175 | 176 | return app.exec(); 177 | } 178 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /krfb/main-virtualmonitor.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of the KDE project 2 | SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez 3 | 4 | SPDX-License-Identifier: GPL-3.0-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "sockethelpers.h" 18 | #include "krfb_version.h" 19 | #include "rfbserver.h" 20 | #include 21 | #include "rfbservermanager.h" 22 | 23 | class VirtualMonitorRfbClient : public RfbClient 24 | { 25 | public: 26 | explicit VirtualMonitorRfbClient(rfbClientPtr client, QObject *parent = nullptr) 27 | : RfbClient(client, parent) 28 | {} 29 | }; 30 | 31 | class PendingVirtualMonitorRfbClient : public PendingRfbClient 32 | { 33 | public: 34 | explicit PendingVirtualMonitorRfbClient(rfbClientPtr client, QObject *parent = nullptr) 35 | : PendingRfbClient(client, parent) 36 | {} 37 | ~PendingVirtualMonitorRfbClient() override {} 38 | 39 | static QByteArray password; 40 | 41 | protected: 42 | void processNewClient() override { 43 | qDebug() << "new client!"; 44 | const QString host = peerAddress(m_rfbClient->sock) + QLatin1Char(':') + QString::number(peerPort(m_rfbClient->sock)); 45 | 46 | KNotification::event(QStringLiteral("NewConnectionAutoAccepted"), 47 | i18n("Creating a Virtual Monitor from %1", host)); 48 | } 49 | bool checkPassword(const QByteArray & encryptedPassword) override { 50 | bool b = vncAuthCheckPassword(password, encryptedPassword); 51 | if (b) { 52 | QTimer::singleShot(0, this, [this] { 53 | accept(new VirtualMonitorRfbClient(m_rfbClient, parent())); 54 | }); 55 | } 56 | return b; 57 | } 58 | }; 59 | 60 | QByteArray PendingVirtualMonitorRfbClient::password; 61 | 62 | class VirtualMonitorRfbServer : public RfbServer 63 | { 64 | public: 65 | PendingRfbClient *newClient(rfbClientPtr client) override { 66 | qDebug() << "new client request"; 67 | return new PendingVirtualMonitorRfbClient(client, this); 68 | } 69 | }; 70 | 71 | int main(int argc, char *argv[]) 72 | { 73 | QApplication app(argc, argv); 74 | 75 | KLocalizedString::setApplicationDomain("krfb"); 76 | 77 | KAboutData aboutData(QStringLiteral("krfb-virtualmonitor"), 78 | i18n("Remote Virtual Monitor"), 79 | QStringLiteral(KRFB_VERSION_STRING), 80 | i18n("Offer a Virtual Monitor that can be accessed remotely"), 81 | KAboutLicense::GPL, 82 | i18n("(c) 2009-2010, Collabora Ltd.\n" 83 | "(c) 2007, Alessandro Praduroux\n" 84 | "(c) 2001-2003, Tim Jansen\n" 85 | "(c) 2001, Johannes E. Schindelin\n" 86 | "(c) 2000-2001, Const Kaplinsky\n" 87 | "(c) 2000, Tridia Corporation\n" 88 | "(c) 1999, AT&T Laboratories Boston\n")); 89 | aboutData.addAuthor(QStringLiteral("Aleix Pol i Gonzalez"), i18n("Virtual Monitor implementation"), QStringLiteral("aleixpol@kde.org")); 90 | aboutData.addAuthor(i18n("George Kiagiadakis"), QString(), QStringLiteral("george.kiagiadakis@collabora.co.uk")); 91 | aboutData.addAuthor(i18n("Alessandro Praduroux"), i18n("KDE4 porting"), QStringLiteral("pradu@pradu.it")); 92 | aboutData.addAuthor(i18n("Tim Jansen"), i18n("Original author"), QStringLiteral("tim@tjansen.de")); 93 | aboutData.addCredit(i18n("Johannes E. Schindelin"), 94 | i18n("libvncserver")); 95 | aboutData.addCredit(i18n("Const Kaplinsky"), 96 | i18n("TightVNC encoder")); 97 | aboutData.addCredit(i18n("Tridia Corporation"), 98 | i18n("ZLib encoder")); 99 | aboutData.addCredit(i18n("AT&T Laboratories Boston"), 100 | i18n("original VNC encoders and " 101 | "protocol design")); 102 | KAboutData::setApplicationData(aboutData); 103 | 104 | KCrash::initialize(); 105 | 106 | QCommandLineParser parser; 107 | aboutData.setupCommandLine(&parser); 108 | const QCommandLineOption resolutionOption({ QStringLiteral("resolution") }, i18n("Logical resolution of the new monitor"), i18n("resolution")); 109 | parser.addOption(resolutionOption); 110 | const QCommandLineOption nameOption({ QStringLiteral("name") }, i18n("Name of the monitor"), i18n("name")); 111 | parser.addOption(nameOption); 112 | const QCommandLineOption passwordOption({ QStringLiteral("password") }, i18n("Password for the client to connect to it"), i18n("password")); 113 | parser.addOption(passwordOption); 114 | const QCommandLineOption scaleOption({ QStringLiteral("scale") }, i18n("The device-pixel-ratio of the device, the scaling factor"), i18n("dpr"), QStringLiteral("1")); 115 | parser.addOption(scaleOption); 116 | const QCommandLineOption portOption({ QStringLiteral("port") }, i18n("The port we will be listening to"), i18n("number"), QStringLiteral("9999")); 117 | parser.addOption(portOption); 118 | 119 | parser.process(app); 120 | aboutData.processCommandLine(&parser); 121 | 122 | app.setQuitOnLastWindowClosed(false); 123 | 124 | if (!KWindowSystem::isPlatformWayland()) { 125 | qCritical() << "Virtual Monitors are only supported on Wayland"; 126 | return 1; 127 | } 128 | if (!parser.isSet(nameOption)) { 129 | qCritical() << "error: please define --name"; 130 | return 2; 131 | } else { 132 | if (!parser.isSet(passwordOption)) { 133 | qCritical() << "error: please define --password"; 134 | return 3; 135 | } 136 | if (!parser.isSet(resolutionOption)) { 137 | qCritical() << "error: please define --resolution"; 138 | return 4; 139 | } 140 | } 141 | if (!parser.isSet(portOption)) { 142 | qCritical() << "error: please define --port"; 143 | return 5; 144 | } 145 | const QString res = parser.value(resolutionOption); 146 | const auto resSplit = res.split(QLatin1Char('x')); 147 | if (resSplit.size() != 2) { 148 | qCritical() << "error: the resolution should be formatted as WIDTHxHEIGHT (e.g. --resolution 1920x1080)"; 149 | return 6; 150 | } 151 | 152 | 153 | if (parser.isSet(nameOption)) { 154 | RfbServerManager::s_pluginArgs = { 155 | { QStringLiteral("name"), parser.value(nameOption) }, 156 | { QStringLiteral("resolution"), QSize(resSplit[0].toInt(), resSplit[1].toInt()) }, 157 | { QStringLiteral("scale"), parser.value(scaleOption).toDouble() }, 158 | }; 159 | } 160 | 161 | VirtualMonitorRfbServer server; 162 | server.setPasswordRequired(true); 163 | server.setListeningPort(parser.value(portOption).toInt()); 164 | PendingVirtualMonitorRfbClient::password = parser.value(passwordOption).toUtf8(); 165 | 166 | sigset_t sigs; 167 | sigemptyset(&sigs); 168 | sigaddset(&sigs, SIGPIPE); 169 | sigprocmask(SIG_BLOCK, &sigs, nullptr); 170 | if (!server.start()) { 171 | return 1; 172 | } 173 | 174 | return app.exec(); 175 | } 176 | -------------------------------------------------------------------------------- /krfb/rfbservermanager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | SPDX-FileCopyrightText: 2001-2003 Tim Jansen 7 | 8 | SPDX-License-Identifier: GPL-2.0-or-later 9 | */ 10 | #include "rfbservermanager.h" 11 | #include "rfbserver.h" 12 | #include "framebuffermanager.h" 13 | #include "sockethelpers.h" 14 | #include "krfbconfig.h" 15 | #include "krfbdebug.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | using namespace std::chrono_literals; 29 | 30 | static const char *cur = 31 | " " 32 | " x " 33 | " xx " 34 | " xxx " 35 | " xxxx " 36 | " xxxxx " 37 | " xxxxxx " 38 | " xxxxxxx " 39 | " xxxxxxxx " 40 | " xxxxxxxxx " 41 | " xxxxxxxxxx " 42 | " xxxxx " 43 | " xx xxx " 44 | " x xxx " 45 | " xxx " 46 | " xxx " 47 | " xxx " 48 | " xxx " 49 | " "; 50 | 51 | static const char *mask = 52 | "xx " 53 | "xxx " 54 | "xxxx " 55 | "xxxxx " 56 | "xxxxxx " 57 | "xxxxxxx " 58 | "xxxxxxxx " 59 | "xxxxxxxxx " 60 | "xxxxxxxxxx " 61 | "xxxxxxxxxxx " 62 | "xxxxxxxxxxxx " 63 | "xxxxxxxxxx " 64 | "xxxxxxxx " 65 | "xxxxxxxx " 66 | "xx xxxxx " 67 | " xxxxx " 68 | " xxxxx " 69 | " xxxxx " 70 | " xxx "; 71 | 72 | 73 | struct RfbServerManagerStatic 74 | { 75 | RfbServerManager server; 76 | }; 77 | 78 | Q_GLOBAL_STATIC(RfbServerManagerStatic, s_instance) 79 | 80 | RfbServerManager* RfbServerManager::instance() 81 | { 82 | return &s_instance->server; 83 | } 84 | 85 | struct RfbServerManager::Private 86 | { 87 | QSharedPointer fb; 88 | rfbCursorPtr myCursor; 89 | QByteArray desktopName; 90 | QTimer rfbUpdateTimer; 91 | QSet servers; 92 | QSet clients; 93 | }; 94 | 95 | 96 | RfbServerManager::RfbServerManager() 97 | : QObject(), d(new Private) 98 | { 99 | init(); 100 | } 101 | 102 | RfbServerManager::~RfbServerManager() 103 | { 104 | delete d; 105 | } 106 | 107 | QSharedPointer RfbServerManager::framebuffer() const 108 | { 109 | return d->fb; 110 | } 111 | 112 | QVariantMap RfbServerManager::s_pluginArgs; 113 | 114 | void RfbServerManager::init() 115 | { 116 | //qDebug(); 117 | WId rootWindow = 0; 118 | 119 | if (KWindowSystem::isPlatformX11()) { 120 | QPlatformNativeInterface* native = qApp->platformNativeInterface(); 121 | rootWindow = reinterpret_cast(native->nativeResourceForScreen(QByteArrayLiteral("rootwindow"), QGuiApplication::primaryScreen())); 122 | } 123 | 124 | d->fb = FrameBufferManager::instance()->frameBuffer(rootWindow, s_pluginArgs); 125 | d->myCursor = rfbMakeXCursor(19, 19, (char *) cur, (char *) mask); 126 | d->myCursor->cleanup = false; 127 | d->desktopName = QStringLiteral("%1@%2 (shared desktop)") //FIXME check if we can use utf8 128 | .arg(KUser().loginName(),QHostInfo::localHostName()).toLatin1(); 129 | 130 | connect(d->fb.data(), &FrameBuffer::frameBufferChanged, this, &RfbServerManager::updateFrameBuffer); 131 | connect(&d->rfbUpdateTimer, &QTimer::timeout, this, &RfbServerManager::updateScreens); 132 | connect(qApp, &QApplication::aboutToQuit, this, &RfbServerManager::cleanup); 133 | } 134 | 135 | void RfbServerManager::updateFrameBuffer() 136 | { 137 | for (RfbServer *server : std::as_const(d->servers)) { 138 | server->updateFrameBuffer(d->fb->data(), d->fb->width(), d->fb->height(), d->fb->depth()); 139 | } 140 | } 141 | 142 | void RfbServerManager::updateScreens() 143 | { 144 | QList rects = d->fb->modifiedTiles(); 145 | const QPoint currentCursorPos = d->fb->cursorPosition(); 146 | 147 | for (RfbServer* server : std::as_const(d->servers)) { 148 | server->updateScreen(rects); 149 | server->updateCursorPosition(currentCursorPos); 150 | } 151 | 152 | //update() might disconnect some of the clients, which will synchronously 153 | //call the removeClient() method and will change d->clients, so we need 154 | //to copy the set here to avoid problems. 155 | const QSet clients = d->clients; 156 | for (RfbClient* client : clients) { 157 | client->update(); 158 | } 159 | } 160 | 161 | void RfbServerManager::cleanup() 162 | { 163 | //qDebug(); 164 | 165 | //copy because d->servers is going to be modified while we delete the servers 166 | const QSet servers = d->servers; 167 | qDeleteAll(servers); 168 | 169 | Q_ASSERT(d->servers.isEmpty()); 170 | Q_ASSERT(d->clients.isEmpty()); 171 | 172 | d->myCursor->cleanup = true; 173 | rfbFreeCursor(d->myCursor); 174 | d->fb.clear(); 175 | } 176 | 177 | void RfbServerManager::registerServer(RfbServer* server) 178 | { 179 | d->servers.insert(server); 180 | } 181 | 182 | void RfbServerManager::unregisterServer(RfbServer* server) 183 | { 184 | d->servers.remove(server); 185 | } 186 | 187 | rfbScreenInfoPtr RfbServerManager::newScreen() 188 | { 189 | rfbScreenInfoPtr screen = nullptr; 190 | 191 | if (!d->fb.isNull()) { 192 | int w = d->fb->width(); 193 | int h = d->fb->height(); 194 | int depth = d->fb->depth(); 195 | int bpp = depth >> 3; 196 | 197 | if (bpp != 1 && bpp != 2 && bpp != 4) { 198 | bpp = 4; 199 | } 200 | 201 | //qDebug() << "bpp: " << bpp; 202 | 203 | rfbLogEnable(KRFB().isDebugEnabled()); 204 | 205 | screen = rfbGetScreen(nullptr, nullptr, w, h, 8, 3, bpp); 206 | screen->paddedWidthInBytes = d->fb->paddedWidth(); 207 | d->fb->getServerFormat(screen->serverFormat); 208 | screen->frameBuffer = d->fb->data(); 209 | screen->desktopName = d->desktopName.constData(); 210 | screen->cursor = d->myCursor; 211 | } 212 | 213 | return screen; 214 | } 215 | 216 | void RfbServerManager::addClient(RfbClient* cc) 217 | { 218 | if (d->clients.size() == 0) { 219 | //qDebug() << "Starting framebuffer monitor"; 220 | d->fb->startMonitor(); 221 | d->rfbUpdateTimer.start(50ms); 222 | } 223 | d->clients.insert(cc); 224 | 225 | KNotification::event(QStringLiteral("UserAcceptsConnection"), 226 | i18n("The remote user %1 is now connected.", cc->name())); 227 | 228 | Q_EMIT clientConnected(cc); 229 | } 230 | 231 | void RfbServerManager::removeClient(RfbClient* cc) 232 | { 233 | d->clients.remove(cc); 234 | if (d->clients.size() == 0) { 235 | //qDebug() << "Stopping framebuffer monitor"; 236 | d->fb->stopMonitor(); 237 | d->rfbUpdateTimer.stop(); 238 | } 239 | 240 | KNotification::event(QStringLiteral("ConnectionClosed"), i18n("The remote user %1 disconnected.", cc->name())); 241 | 242 | Q_EMIT clientDisconnected(cc); 243 | } 244 | -------------------------------------------------------------------------------- /LICENSES/LGPL-3.0-only.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | 6 | Everyone is permitted to copy and distribute verbatim copies of this license 7 | document, but changing it is not allowed. 8 | 9 | This version of the GNU Lesser General Public License incorporates the terms 10 | and conditions of version 3 of the GNU General Public License, supplemented 11 | by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser General 16 | Public License, and the "GNU GPL" refers to version 3 of the GNU General Public 17 | License. 18 | 19 | "The Library" refers to a covered work governed by this License, other than 20 | an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided by the 23 | Library, but which is not otherwise based on the Library. Defining a subclass 24 | of a class defined by the Library is deemed a mode of using an interface provided 25 | by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an Application 28 | with the Library. The particular version of the Library with which the Combined 29 | Work was made is also called the "Linked Version". 30 | 31 | The "Minimal Corresponding Source" for a Combined Work means the Corresponding 32 | Source for the Combined Work, excluding any source code for portions of the 33 | Combined Work that, considered in isolation, are based on the Application, 34 | and not on the Linked Version. 35 | 36 | The "Corresponding Application Code" for a Combined Work means the object 37 | code and/or source code for the Application, including any data and utility 38 | programs needed for reproducing the Combined Work from the Application, but 39 | excluding the System Libraries of the Combined Work. 40 | 41 | 1. Exception to Section 3 of the GNU GPL. 42 | You may convey a covered work under sections 3 and 4 of this License without 43 | being bound by section 3 of the GNU GPL. 44 | 45 | 2. Conveying Modified Versions. 46 | If you modify a copy of the Library, and, in your modifications, a facility 47 | refers to a function or data to be supplied by an Application that uses the 48 | facility (other than as an argument passed when the facility is invoked), 49 | then you may convey a copy of the modified version: 50 | 51 | a) under this License, provided that you make a good faith effort to ensure 52 | that, in the event an Application does not supply the function or data, the 53 | facility still operates, and performs whatever part of its purpose remains 54 | meaningful, or 55 | 56 | b) under the GNU GPL, with none of the additional permissions of this License 57 | applicable to that copy. 58 | 59 | 3. Object Code Incorporating Material from Library Header Files. 60 | The object code form of an Application may incorporate material from a header 61 | file that is part of the Library. You may convey such object code under terms 62 | of your choice, provided that, if the incorporated material is not limited 63 | to numerical parameters, data structure layouts and accessors, or small macros, 64 | inline functions and templates (ten or fewer lines in length), you do both 65 | of the following: 66 | 67 | a) Give prominent notice with each copy of the object code that the Library 68 | is used in it and that the Library and its use are covered by this License. 69 | 70 | b) Accompany the object code with a copy of the GNU GPL and this license document. 71 | 72 | 4. Combined Works. 73 | You may convey a Combined Work under terms of your choice that, taken together, 74 | effectively do not restrict modification of the portions of the Library contained 75 | in the Combined Work and reverse engineering for debugging such modifications, 76 | if you also do each of the following: 77 | 78 | a) Give prominent notice with each copy of the Combined Work that the Library 79 | is used in it and that the Library and its use are covered by this License. 80 | 81 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 82 | document. 83 | 84 | c) For a Combined Work that displays copyright notices during execution, include 85 | the copyright notice for the Library among these notices, as well as a reference 86 | directing the user to the copies of the GNU GPL and this license document. 87 | 88 | d) Do one of the following: 89 | 90 | 0) Convey the Minimal Corresponding Source under the terms of this License, 91 | and the Corresponding Application Code in a form suitable for, and under terms 92 | that permit, the user to recombine or relink the Application with a modified 93 | version of the Linked Version to produce a modified Combined Work, in the 94 | manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 95 | 96 | 1) Use a suitable shared library mechanism for linking with the Library. 97 | A suitable mechanism is one that (a) uses at run time a copy of the Library 98 | already present on the user's computer system, and (b) will operate properly 99 | with a modified version of the Library that is interface-compatible with the 100 | Linked Version. 101 | 102 | e) Provide Installation Information, but only if you would otherwise be required 103 | to provide such information under section 6 of the GNU GPL, and only to the 104 | extent that such information is necessary to install and execute a modified 105 | version of the Combined Work produced by recombining or relinking the Application 106 | with a modified version of the Linked Version. (If you use option 4d0, the 107 | Installation Information must accompany the Minimal Corresponding Source and 108 | Corresponding Application Code. If you use option 4d1, you must provide the 109 | Installation Information in the manner specified by section 6 of the GNU GPL 110 | for conveying Corresponding Source.) 111 | 112 | 5. Combined Libraries. 113 | You may place library facilities that are a work based on the Library side 114 | by side in a single library together with other library facilities that are 115 | not Applications and are not covered by this License, and convey such a combined 116 | library under terms of your choice, if you do both of the following: 117 | 118 | a) Accompany the combined library with a copy of the same work based on the 119 | Library, uncombined with any other library facilities, conveyed under the 120 | terms of this License. 121 | 122 | b) Give prominent notice with the combined library that part of it is a work 123 | based on the Library, and explaining where to find the accompanying uncombined 124 | form of the same work. 125 | 126 | 6. Revised Versions of the GNU Lesser General Public License. 127 | The Free Software Foundation may publish revised and/or new versions of the 128 | GNU Lesser General Public License from time to time. Such new versions will 129 | be similar in spirit to the present version, but may differ in detail to address 130 | new problems or concerns. 131 | 132 | Each version is given a distinguishing version number. If the Library as you 133 | received it specifies that a certain numbered version of the GNU Lesser General 134 | Public License "or any later version" applies to it, you have the option of 135 | following the terms and conditions either of that published version or of 136 | any later version published by the Free Software Foundation. If the Library 137 | as you received it does not specify a version number of the GNU Lesser General 138 | Public License, you may choose any version of the GNU Lesser General Public 139 | License ever published by the Free Software Foundation. 140 | 141 | If the Library as you received it specifies that a proxy can decide whether 142 | future versions of the GNU Lesser General Public License shall 143 | apply, that proxy's public statement of acceptance of any version is permanent 144 | authorization for you to choose that version for the Library. 145 | -------------------------------------------------------------------------------- /dbus/xdp_dbus_screencast_interface.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 24 | 25 | 47 | 48 | 49 | 50 | 51 | 52 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /krfb/rfbclient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | #include "rfbclient.h" 10 | #include "connectiondialog.h" 11 | #include "krfbconfig.h" 12 | #include "sockethelpers.h" 13 | #include "eventsmanager.h" 14 | #include 15 | #include 16 | #include //for bzero() 17 | #include "krfbdebug.h" 18 | 19 | struct RfbClient::Private 20 | { 21 | Private(rfbClientPtr client) : 22 | controlEnabled(KrfbConfig::allowDesktopControl()), 23 | client(client) 24 | {} 25 | 26 | bool controlEnabled; 27 | rfbClientPtr client; 28 | QSocketNotifier *notifier; 29 | QSharedPointer eventHandler; 30 | QString remoteAddressString; 31 | }; 32 | 33 | RfbClient::RfbClient(rfbClientPtr client, QObject* parent) 34 | : QObject(parent), d(new Private(client)) 35 | { 36 | d->remoteAddressString = peerAddress(d->client->sock) + QLatin1Char(':') + 37 | QString::number(peerPort(d->client->sock)); 38 | 39 | d->notifier = new QSocketNotifier(client->sock, QSocketNotifier::Read, this); 40 | d->notifier->setEnabled(false); 41 | connect(d->notifier, &QSocketNotifier::activated, this, &RfbClient::onSocketActivated); 42 | 43 | d->eventHandler = EventsManager::instance()->eventHandler(); 44 | } 45 | 46 | RfbClient::~RfbClient() 47 | { 48 | //qDebug(); 49 | delete d; 50 | } 51 | 52 | QString RfbClient::name() const 53 | { 54 | return d->remoteAddressString; 55 | } 56 | 57 | //static 58 | bool RfbClient::controlCanBeEnabled() 59 | { 60 | return KrfbConfig::allowDesktopControl(); 61 | } 62 | 63 | bool RfbClient::controlEnabled() const 64 | { 65 | return d->controlEnabled; 66 | } 67 | 68 | void RfbClient::setControlEnabled(bool enabled) 69 | { 70 | if (controlCanBeEnabled() && d->controlEnabled != enabled) { 71 | d->controlEnabled = enabled; 72 | Q_EMIT controlEnabledChanged(enabled); 73 | } 74 | } 75 | 76 | bool RfbClient::isOnHold() const 77 | { 78 | return d->client->onHold ? true : false; 79 | } 80 | 81 | void RfbClient::setOnHold(bool onHold) 82 | { 83 | if (isOnHold() != onHold) { 84 | d->client->onHold = onHold; 85 | d->notifier->setEnabled(!onHold); 86 | Q_EMIT holdStatusChanged(onHold); 87 | } 88 | } 89 | 90 | void RfbClient::closeConnection() 91 | { 92 | d->notifier->setEnabled(false); 93 | rfbCloseClient(d->client); 94 | rfbClientConnectionGone(d->client); 95 | } 96 | 97 | rfbClientPtr RfbClient::getRfbClientPtr() 98 | { 99 | return d->client; 100 | } 101 | 102 | void RfbClient::handleKeyboardEvent(bool down, rfbKeySym keySym) 103 | { 104 | if (d->controlEnabled) { 105 | d->eventHandler->handleKeyboard(down, keySym); 106 | } 107 | } 108 | 109 | void RfbClient::handleMouseEvent(int buttonMask, int x, int y) 110 | { 111 | if (d->controlEnabled) { 112 | d->eventHandler->handlePointer(buttonMask, x, y); 113 | } 114 | } 115 | 116 | void RfbClient::onSocketActivated() 117 | { 118 | //Process not only one, but all pending messages. 119 | //poll() idea/code copied from vino: 120 | // Copyright (C) 2003 Sun Microsystems, Inc. 121 | // License: GPL v2 or later 122 | struct pollfd pollfd = { d->client->sock, POLLIN|POLLPRI, 0 }; 123 | 124 | while(poll(&pollfd, 1, 0) == 1) { 125 | rfbProcessClientMessage(d->client); 126 | 127 | //This is how we handle disconnection. 128 | //if rfbProcessClientMessage() finds out that it can't read the socket, 129 | //it closes it and sets it to -1. So, we just have to check this here 130 | //and call rfbClientConnectionGone() if necessary. This will call 131 | //the clientGoneHook which in turn will remove this RfbClient instance 132 | //from the server manager and will call deleteLater() to delete it 133 | if (d->client->sock == -1) { 134 | //qDebug() << "disconnected from socket signal"; 135 | d->notifier->setEnabled(false); 136 | rfbClientConnectionGone(d->client); 137 | break; 138 | } 139 | } 140 | } 141 | 142 | void RfbClient::update() 143 | { 144 | rfbUpdateClient(d->client); 145 | 146 | //This is how we handle disconnection. 147 | //if rfbUpdateClient() finds out that it can't write to the socket, 148 | //it closes it and sets it to -1. So, we just have to check this here 149 | //and call rfbClientConnectionGone() if necessary. This will call 150 | //the clientGoneHook which in turn will remove this RfbClient instance 151 | //from the server manager and will call deleteLater() to delete it 152 | if (d->client->sock == -1) { 153 | //qDebug() << "disconnected during update"; 154 | d->notifier->setEnabled(false); 155 | rfbClientConnectionGone(d->client); 156 | } 157 | } 158 | 159 | //************* 160 | 161 | PendingRfbClient::PendingRfbClient(rfbClientPtr client, QObject *parent) 162 | : QObject(parent), m_rfbClient(client) 163 | , m_notifier(new QSocketNotifier(client->sock, QSocketNotifier::Read, this)) 164 | { 165 | m_rfbClient->clientData = this; 166 | 167 | m_notifier->setEnabled(true); 168 | connect(m_notifier, &QSocketNotifier::activated, 169 | this, &PendingRfbClient::onSocketActivated); 170 | } 171 | 172 | PendingRfbClient::~PendingRfbClient() 173 | {} 174 | 175 | void PendingRfbClient::accept(RfbClient *newClient) 176 | { 177 | //qDebug() << "accepted connection"; 178 | 179 | m_rfbClient->clientData = newClient; 180 | newClient->setOnHold(false); 181 | 182 | Q_EMIT finished(newClient); 183 | deleteLater(); 184 | } 185 | 186 | static void clientGoneHookNoop(rfbClientPtr cl) { Q_UNUSED(cl); } 187 | 188 | void PendingRfbClient::reject() 189 | { 190 | //qDebug() << "refused connection"; 191 | 192 | //override the clientGoneHook that was previously set by RfbServer 193 | m_rfbClient->clientGoneHook = clientGoneHookNoop; 194 | rfbCloseClient(m_rfbClient); 195 | rfbClientConnectionGone(m_rfbClient); 196 | 197 | Q_EMIT finished(nullptr); 198 | deleteLater(); 199 | } 200 | 201 | bool PendingRfbClient::checkPassword(const QByteArray & encryptedPassword) 202 | { 203 | Q_UNUSED(encryptedPassword); 204 | 205 | return m_rfbClient->screen->authPasswdData == (void*)nullptr; 206 | } 207 | 208 | bool PendingRfbClient::vncAuthCheckPassword(const QByteArray& password, const QByteArray& encryptedPassword) const 209 | { 210 | if (password.isEmpty() && encryptedPassword.isEmpty()) { 211 | return true; 212 | } 213 | 214 | char passwd[MAXPWLEN+1]; // +1 to make sure there's a nullptr at the end 215 | unsigned char challenge[CHALLENGESIZE]; 216 | 217 | memcpy(challenge, m_rfbClient->authChallenge, CHALLENGESIZE); 218 | memset(passwd, 0, sizeof(passwd)); 219 | 220 | if (!password.isEmpty()) { 221 | strncpy(passwd, password.constData(), 222 | (MAXPWLEN <= password.size()) ? MAXPWLEN : password.size()); 223 | } 224 | 225 | rfbEncryptBytes(challenge, passwd); 226 | return memcmp(challenge, encryptedPassword.constData(), encryptedPassword.size()) == 0; 227 | } 228 | 229 | void PendingRfbClient::onSocketActivated() 230 | { 231 | //Process not only one, but all pending messages. 232 | //poll() idea/code copied from vino: 233 | // Copyright (C) 2003 Sun Microsystems, Inc. 234 | // License: GPL v2 or later 235 | struct pollfd pollfd = { m_rfbClient->sock, POLLIN|POLLPRI, 0 }; 236 | 237 | while(poll(&pollfd, 1, 0) == 1) { 238 | if(m_rfbClient->state == rfbClientRec::RFB_INITIALISATION) { 239 | m_notifier->setEnabled(false); 240 | //Client is Authenticated 241 | processNewClient(); 242 | break; 243 | } 244 | rfbProcessClientMessage(m_rfbClient); 245 | 246 | //This is how we handle disconnection. 247 | //if rfbProcessClientMessage() finds out that it can't read the socket, 248 | //it closes it and sets it to -1. So, we just have to check this here 249 | //and call rfbClientConnectionGone() if necessary. This will call 250 | //the clientGoneHook which in turn will remove this RfbClient instance 251 | //from the server manager and will call deleteLater() to delete it 252 | if (m_rfbClient->sock == -1) { 253 | qCDebug(KRFB) << "disconnected from socket signal"; 254 | m_notifier->setEnabled(false); 255 | rfbClientConnectionGone(m_rfbClient); 256 | break; 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /krfb/invitationsrfbserver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | SPDX-FileCopyrightText: 2001-2003 Tim Jansen 7 | 8 | SPDX-License-Identifier: GPL-2.0-or-later 9 | */ 10 | #include "invitationsrfbserver.h" 11 | #include "invitationsrfbclient.h" 12 | #include "krfbconfig.h" 13 | #include "krfbdebug.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | using KWallet::Wallet; 27 | 28 | // used for KWallet folder name 29 | static const QString s_krfbFolderName(QStringLiteral("krfb")); 30 | 31 | //static 32 | InvitationsRfbServer *InvitationsRfbServer::instance; 33 | 34 | //static 35 | void InvitationsRfbServer::init() 36 | { 37 | instance = new InvitationsRfbServer; 38 | instance->m_publicService = new KDNSSD::PublicService( 39 | i18n("%1@%2 (shared desktop)", 40 | KUser().loginName(), 41 | QHostInfo::localHostName()), 42 | QStringLiteral("_rfb._tcp"), 43 | KrfbConfig::port()); 44 | instance->setListeningAddress("0.0.0.0"); 45 | instance->setListeningPort(KrfbConfig::port()); 46 | instance->setPasswordRequired(true); 47 | 48 | instance->m_wallet = nullptr; 49 | if (KrfbConfig::noWallet()) { 50 | instance->readPasswordFromConfig(); 51 | } else { 52 | instance->openKWallet(); 53 | } 54 | } 55 | 56 | const QString& InvitationsRfbServer::desktopPassword() const 57 | { 58 | return m_desktopPassword; 59 | } 60 | 61 | void InvitationsRfbServer::setDesktopPassword(const QString& password) 62 | { 63 | m_desktopPassword = password; 64 | // this is called from GUI every time desktop password is edited. 65 | // make sure we save settings immediately each time 66 | saveSecuritySettings(); 67 | } 68 | 69 | const QString& InvitationsRfbServer::unattendedPassword() const 70 | { 71 | return m_unattendedPassword; 72 | } 73 | 74 | void InvitationsRfbServer::setUnattendedPassword(const QString& password) 75 | { 76 | m_unattendedPassword = password; 77 | // this is called from GUI every time unattended password is edited. 78 | // make sure we save settings immediately each time 79 | saveSecuritySettings(); 80 | } 81 | 82 | bool InvitationsRfbServer::allowUnattendedAccess() const 83 | { 84 | return m_allowUnattendedAccess; 85 | } 86 | 87 | bool InvitationsRfbServer::start() 88 | { 89 | if(RfbServer::start()) { 90 | if(KrfbConfig::publishService()) 91 | m_publicService->publishAsync(); 92 | return true; 93 | } 94 | return false; 95 | } 96 | 97 | void InvitationsRfbServer::stop() 98 | { 99 | if(m_publicService->isPublished()) 100 | m_publicService->stop(); 101 | RfbServer::stop(); 102 | } 103 | 104 | void InvitationsRfbServer::toggleUnattendedAccess(bool allow) 105 | { 106 | m_allowUnattendedAccess = allow; 107 | // this is called from GUI every time unattended access is toggled. 108 | // make sure we save settings immediately each time 109 | saveSecuritySettings(); 110 | } 111 | 112 | InvitationsRfbServer::InvitationsRfbServer() 113 | { 114 | m_desktopPassword = readableRandomString(4) + QLatin1Char('-') + readableRandomString(3); 115 | m_unattendedPassword = readableRandomString(4) + QLatin1Char('-') + readableRandomString(3); 116 | KConfigGroup krfbConfig(KSharedConfig::openConfig(),QStringLiteral("Security")); 117 | m_allowUnattendedAccess = krfbConfig.readEntry( 118 | "allowUnattendedAccess", QVariant(false)).toBool(); 119 | } 120 | 121 | InvitationsRfbServer::~InvitationsRfbServer() 122 | { 123 | InvitationsRfbServer::stop(); // calling virtual funcs in destructor is bad 124 | saveSecuritySettings(); 125 | // ^^ also saves passwords in kwallet, 126 | // do it before closing kwallet 127 | if (!KrfbConfig::noWallet() && m_wallet) { 128 | closeKWallet(); 129 | } 130 | } 131 | 132 | PendingRfbClient* InvitationsRfbServer::newClient(rfbClientPtr client) 133 | { 134 | return new PendingInvitationsRfbClient(client, this); 135 | } 136 | 137 | void InvitationsRfbServer::openKWallet() 138 | { 139 | m_wallet = Wallet::openWallet(Wallet::NetworkWallet(), 0, Wallet::Asynchronous); 140 | if (m_wallet) { 141 | connect(instance->m_wallet, &KWallet::Wallet::walletOpened, 142 | this, &InvitationsRfbServer::walletOpened); 143 | } 144 | } 145 | 146 | void InvitationsRfbServer::closeKWallet() 147 | { 148 | if (m_wallet && m_wallet->isOpen()) { 149 | delete m_wallet; // closes the wallet 150 | m_wallet = nullptr; 151 | } 152 | } 153 | 154 | void InvitationsRfbServer::walletOpened(bool opened) 155 | { 156 | QString desktopPassword; 157 | QString unattendedPassword; 158 | Q_ASSERT(m_wallet); 159 | 160 | if (opened && m_wallet->hasFolder(s_krfbFolderName) && m_wallet->setFolder(s_krfbFolderName) ) { 161 | if (m_wallet->readPassword(QStringLiteral("desktopSharingPassword"), desktopPassword) == 0 && 162 | !desktopPassword.isEmpty()) { 163 | m_desktopPassword = desktopPassword; 164 | Q_EMIT passwordChanged(m_desktopPassword); 165 | } 166 | 167 | if(m_wallet->readPassword(QStringLiteral("unattendedAccessPassword"), unattendedPassword) == 0 && 168 | !unattendedPassword.isEmpty()) { 169 | m_unattendedPassword = unattendedPassword; 170 | } 171 | 172 | } else { 173 | qCDebug(KRFB) << "Could not open KWallet, Falling back to config file"; 174 | readPasswordFromConfig(); 175 | } 176 | } 177 | 178 | // a random string that doesn't contain i, I, o, O, 1, l, 0 179 | // based on KRandom::randomString() 180 | QString InvitationsRfbServer::readableRandomString(int length) 181 | { 182 | QString str; 183 | while (length) { 184 | int r = QRandomGenerator::global()->bounded(62); 185 | r += 48; 186 | if (r > 57) { 187 | r += 7; 188 | } 189 | if (r > 90) { 190 | r += 6; 191 | } 192 | char c = char(r); 193 | if ((c == 'i') || 194 | (c == 'I') || 195 | (c == '1') || 196 | (c == 'l') || 197 | (c == 'o') || 198 | (c == 'O') || 199 | (c == '0')) { 200 | continue; 201 | } 202 | str += QLatin1Char(c); 203 | length--; 204 | } 205 | return str; 206 | } 207 | 208 | // one place to deal with all security configuration 209 | void InvitationsRfbServer::saveSecuritySettings() 210 | { 211 | KConfigGroup secConfigGroup(KSharedConfig::openConfig(), QStringLiteral("Security")); 212 | secConfigGroup.writeEntry("allowUnattendedAccess", m_allowUnattendedAccess); 213 | if (KrfbConfig::noWallet()) { 214 | // save passwords in config file only if not using kwallet integration 215 | secConfigGroup.writeEntry("desktopPassword", KStringHandler::obscure(m_desktopPassword)); 216 | secConfigGroup.writeEntry("unattendedPassword", KStringHandler::obscure(m_unattendedPassword)); 217 | } else { 218 | // using KWallet, erase possibly stored passwords from krfbrc file 219 | secConfigGroup.deleteEntry("desktopPassword"); 220 | secConfigGroup.deleteEntry("unattendedPassword"); 221 | // update passwords in kwallet 222 | if (m_wallet && m_wallet->isOpen()) { 223 | if (!m_wallet->hasFolder(s_krfbFolderName)) { 224 | m_wallet->createFolder(s_krfbFolderName); 225 | } 226 | if (m_wallet->currentFolder() != s_krfbFolderName) { 227 | m_wallet->setFolder(s_krfbFolderName); 228 | } 229 | m_wallet->writePassword(QStringLiteral("desktopSharingPassword"), m_desktopPassword); 230 | m_wallet->writePassword(QStringLiteral("unattendedAccessPassword"), m_unattendedPassword); 231 | } 232 | } 233 | KrfbConfig::self()->save(); 234 | } 235 | 236 | void InvitationsRfbServer::readPasswordFromConfig() 237 | { 238 | QString desktopPassword; 239 | QString unattendedPassword; 240 | KConfigGroup krfbConfig(KSharedConfig::openConfig(),QStringLiteral("Security")); 241 | 242 | desktopPassword = KStringHandler::obscure(krfbConfig.readEntry( 243 | "desktopPassword", QString())); 244 | if(!desktopPassword.isEmpty()) { 245 | m_desktopPassword = desktopPassword; 246 | Q_EMIT passwordChanged(m_desktopPassword); 247 | } 248 | 249 | unattendedPassword = KStringHandler::obscure(krfbConfig.readEntry( 250 | "unattendedPassword", QString())); 251 | if(!unattendedPassword.isEmpty()) { 252 | m_unattendedPassword = unattendedPassword; 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /krfb/rfbserver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-FileCopyrightText: 2009-2010 Collabora Ltd 3 | SPDX-FileContributor: George Goldberg 4 | SPDX-FileContributor: George Kiagiadakis 5 | SPDX-FileCopyrightText: 2007 Alessandro Praduroux 6 | 7 | SPDX-License-Identifier: GPL-2.0-or-later 8 | */ 9 | #include "rfbserver.h" 10 | #include "rfbservermanager.h" 11 | #include "krfbdebug.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | struct RfbServer::Private 19 | { 20 | QByteArray listeningAddress; 21 | int listeningPort; 22 | bool passwordRequired; 23 | rfbScreenInfoPtr screen; 24 | QPointer ipv4notifier; 25 | QPointer ipv6notifier; 26 | }; 27 | 28 | RfbServer::RfbServer(QObject *parent) 29 | : QObject(parent), d(new Private) 30 | { 31 | d->listeningAddress = "0.0.0.0"; 32 | d->listeningPort = 0; 33 | d->passwordRequired = true; 34 | d->screen = nullptr; 35 | 36 | RfbServerManager::instance()->registerServer(this); 37 | } 38 | 39 | RfbServer::~RfbServer() 40 | { 41 | if (d->screen) { 42 | rfbScreenCleanup(d->screen); 43 | } 44 | delete d; 45 | 46 | RfbServerManager::instance()->unregisterServer(this); 47 | } 48 | 49 | QByteArray RfbServer::listeningAddress() const 50 | { 51 | return d->listeningAddress; 52 | } 53 | 54 | int RfbServer::listeningPort() const 55 | { 56 | return d->listeningPort; 57 | } 58 | 59 | bool RfbServer::passwordRequired() const 60 | { 61 | return d->passwordRequired; 62 | } 63 | 64 | void RfbServer::setListeningAddress(const QByteArray& address) 65 | { 66 | d->listeningAddress = address; 67 | } 68 | 69 | void RfbServer::setListeningPort(int port) 70 | { 71 | d->listeningPort = port; 72 | } 73 | 74 | void RfbServer::setPasswordRequired(bool passwordRequired) 75 | { 76 | d->passwordRequired = passwordRequired; 77 | } 78 | 79 | bool RfbServer::start() 80 | { 81 | if (!d->screen) { 82 | d->screen = RfbServerManager::instance()->newScreen(); 83 | if (!d->screen) { 84 | qCDebug(KRFB) << "Unable to get rbfserver screen"; 85 | return false; 86 | } 87 | 88 | // server hooks 89 | d->screen->screenData = this; 90 | d->screen->newClientHook = newClientHook; 91 | d->screen->kbdAddEvent = keyboardHook; 92 | d->screen->ptrAddEvent = pointerHook; 93 | d->screen->passwordCheck = passwordCheck; 94 | d->screen->setXCutText = clipboardHook; 95 | d->screen->setXCutTextUTF8 = clipboardHookUtf8; 96 | } else { 97 | //if we already have a screen, stop listening first 98 | rfbShutdownServer(d->screen, false); 99 | } 100 | 101 | if (listeningAddress() != "0.0.0.0") { 102 | strncpy(d->screen->thisHost, listeningAddress().constData(), 254); 103 | } 104 | 105 | if (listeningPort() == 0) { 106 | d->screen->autoPort = 1; 107 | } 108 | 109 | d->screen->port = listeningPort(); 110 | d->screen->ipv6port = listeningPort(); 111 | 112 | // Disable/Enable password checking 113 | if (passwordRequired()) { 114 | d->screen->authPasswdData = (void *)1; 115 | } else { 116 | d->screen->authPasswdData = (void *)nullptr; 117 | } 118 | 119 | qCDebug(KRFB) << "Starting server. Listen port:" << listeningPort() 120 | << "Listen Address:" << listeningAddress() 121 | << "Password enabled:" << passwordRequired(); 122 | 123 | rfbInitServer(d->screen); 124 | 125 | if (!rfbIsActive(d->screen)) { 126 | qCDebug(KRFB) << "Failed to start server"; 127 | rfbShutdownServer(d->screen, false); 128 | return false; 129 | }; 130 | 131 | d->ipv4notifier = new QSocketNotifier(d->screen->listenSock, QSocketNotifier::Read, this); 132 | connect(d->ipv4notifier, &QSocketNotifier::activated, this, &RfbServer::onListenSocketActivated); 133 | if (d->screen->listen6Sock > 0) { 134 | // we're also listening on additional IPv6 socket, get events from there 135 | d->ipv6notifier = new QSocketNotifier(d->screen->listen6Sock, QSocketNotifier::Read, this); 136 | connect(d->ipv6notifier, &QSocketNotifier::activated, this, &RfbServer::onListenSocketActivated); 137 | } 138 | 139 | if (QX11Info::isPlatformX11()) { 140 | connect(QApplication::clipboard(), &QClipboard::dataChanged, 141 | this, &RfbServer::krfbSendServerCutText); 142 | } 143 | 144 | return true; 145 | } 146 | 147 | void RfbServer::stop() 148 | { 149 | if (d->screen) { 150 | rfbShutdownServer(d->screen, true); 151 | for (auto notifier : {d->ipv4notifier, d->ipv6notifier}) { 152 | if (notifier) { 153 | notifier->setEnabled(false); 154 | notifier->deleteLater(); 155 | } 156 | } 157 | } 158 | } 159 | 160 | void RfbServer::updateFrameBuffer(char *fb, int width, int height, int depth) 161 | { 162 | int bpp = depth >> 3; 163 | 164 | if (bpp != 1 && bpp != 2 && bpp != 4) { 165 | bpp = 4; 166 | } 167 | 168 | rfbNewFramebuffer(d->screen, fb, width, height, 8, 3, bpp); 169 | } 170 | 171 | void RfbServer::updateScreen(const QList & modifiedTiles) 172 | { 173 | if (d->screen) { 174 | QList::const_iterator it = modifiedTiles.constBegin(); 175 | for(; it != modifiedTiles.constEnd(); ++it) { 176 | rfbMarkRectAsModified(d->screen, it->x(), it->y(), it->right(), it->bottom()); 177 | } 178 | } 179 | } 180 | 181 | /* 182 | * Code copied from vino's bundled libvncserver: 183 | * SPDX-FileCopyrightText: 2000, 2001 Const Kaplinsky. All Rights Reserved. 184 | * SPDX-FileCopyrightText: 1999 AT &T Laboratories Cambridge. All Rights Reserved. 185 | * License: GPL v2 or later 186 | */ 187 | void krfb_rfbSetCursorPosition(rfbScreenInfoPtr screen, rfbClientPtr client, int x, int y) 188 | { 189 | rfbClientIteratorPtr iterator; 190 | rfbClientPtr cl; 191 | 192 | if (x == screen->cursorX || y == screen->cursorY) 193 | return; 194 | 195 | LOCK(screen->cursorMutex); 196 | screen->cursorX = x; 197 | screen->cursorY = y; 198 | UNLOCK(screen->cursorMutex); 199 | 200 | /* Inform all clients about this cursor movement. */ 201 | iterator = rfbGetClientIterator(screen); 202 | while ((cl = rfbClientIteratorNext(iterator)) != nullptr) { 203 | cl->cursorWasMoved = true; 204 | } 205 | rfbReleaseClientIterator(iterator); 206 | 207 | /* The cursor was moved by this client, so don't send CursorPos. */ 208 | if (client) { 209 | client->cursorWasMoved = false; 210 | } 211 | } 212 | 213 | void RfbServer::updateCursorPosition(const QPoint & position) 214 | { 215 | if (d->screen) { 216 | krfb_rfbSetCursorPosition(d->screen, nullptr, position.x(), position.y()); 217 | } 218 | } 219 | 220 | void RfbServer::krfbSendServerCutText() 221 | { 222 | if (d->screen) { 223 | QString text = QApplication::clipboard()->text(); 224 | QByteArray utf8Bytes = text.toUtf8(); 225 | QByteArray latin1Bytes = text.toLatin1(); 226 | // Try to send the clipboard text to the client in UTF-8. Use Latin1 if UTF-8 is not supported. 227 | rfbSendServerCutTextUTF8(d->screen, utf8Bytes.data(), utf8Bytes.length(), latin1Bytes.data(), latin1Bytes.length()); 228 | } 229 | } 230 | 231 | void RfbServer::onListenSocketActivated() 232 | { 233 | rfbProcessNewConnection(d->screen); 234 | } 235 | 236 | void RfbServer::pendingClientFinished(RfbClient *client) 237 | { 238 | //qDebug(); 239 | if (client) { 240 | RfbServerManager::instance()->addClient(client); 241 | client->getRfbClientPtr()->clientGoneHook = clientGoneHook; 242 | } 243 | } 244 | 245 | //static 246 | rfbNewClientAction RfbServer::newClientHook(rfbClientPtr cl) 247 | { 248 | //qDebug() << "New client"; 249 | auto server = static_cast(cl->screen->screenData); 250 | 251 | PendingRfbClient *pendingClient = server->newClient(cl); 252 | connect(pendingClient, &PendingRfbClient::finished, 253 | server, &RfbServer::pendingClientFinished); 254 | 255 | return RFB_CLIENT_ON_HOLD; 256 | } 257 | 258 | //static 259 | void RfbServer::clientGoneHook(rfbClientPtr cl) 260 | { 261 | //qDebug() << "client gone"; 262 | auto client = static_cast(cl->clientData); 263 | 264 | RfbServerManager::instance()->removeClient(client); 265 | client->deleteLater(); 266 | } 267 | 268 | //static 269 | rfbBool RfbServer::passwordCheck(rfbClientPtr cl, const char *encryptedPassword, int len) 270 | { 271 | auto client = static_cast(cl->clientData); 272 | Q_ASSERT(client); 273 | return client->checkPassword(QByteArray::fromRawData(encryptedPassword, len)); 274 | } 275 | 276 | //static 277 | void RfbServer::keyboardHook(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) 278 | { 279 | auto client = static_cast(cl->clientData); 280 | client->handleKeyboardEvent(down ? true : false, keySym); 281 | } 282 | 283 | //static 284 | void RfbServer::pointerHook(int bm, int x, int y, rfbClientPtr cl) 285 | { 286 | auto client = static_cast(cl->clientData); 287 | client->handleMouseEvent(bm, x, y); 288 | } 289 | 290 | //static 291 | void RfbServer::clipboardHook(char *str, int len, rfbClientPtr /*cl*/) 292 | { 293 | QString text = QString::fromLatin1(str, len); 294 | QApplication::clipboard()->setText(text); 295 | } 296 | 297 | void RfbServer::clipboardHookUtf8(char *str, int len, rfbClientPtr /*cl*/) 298 | { 299 | // The last byte is a null terminator 300 | QString text = QString::fromUtf8(str, len - 1); 301 | QApplication::clipboard()->setText(text); 302 | } 303 | --------------------------------------------------------------------------------