Compare commits

...

44 Commits

Author SHA1 Message Date
Albert Astals Cid
941ade4b4e GIT_SILENT Upgrade release service version to 21.12.0. 2021-12-02 22:38:16 +01:00
l10n daemon script
af461a8bad SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-26 02:26:30 +00:00
l10n daemon script
08e2d13758 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-25 02:31:15 +00:00
Heiko Becker
4b7734a726 GIT_SILENT Upgrade release service version to 21.11.90. 2021-11-22 23:39:55 +01:00
Heiko Becker
6794b9d9fb Fix clean parallel build
The newly introduced krfb-virtualmonitor also needs
ui_connectionwidget.h (via rfbclient -> connectiondialog) and fails
with "krfb/connectiondialog.h:25:10: fatal error: ui_connectionwidget.h:
No such file or directory #include "ui_connectionwidget.h" when doing
a clean build with a high enough number of jobs.
Fix it by introducing a krfb_UI_SRCS variable, which is used by both
executable targets.
2021-11-16 22:25:56 +01:00
l10n daemon script
cf2d198c1f SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-14 02:27:52 +00:00
l10n daemon script
7285574c74 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-12 02:30:26 +00:00
l10n daemon script
899bc892c3 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-10 02:23:29 +00:00
Heiko Becker
4815017e04 GIT_SILENT Upgrade release service version to 21.11.80. 2021-11-08 20:22:43 +01:00
l10n daemon script
ba8a97b7c8 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-07 01:13:33 +00:00
l10n daemon script
f7b690ea7d SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-04 01:17:08 +00:00
Aleix Pol
1d23966d79 pipewire: Support SPA_META_VideoDamage
Inform about the regions that changed so everything doesn't need to be
sent on every frame.
2021-11-03 14:28:54 +00:00
Aleix Pol
61d464676c pipewire: Support cursors 2021-11-03 14:28:54 +00:00
Aleix Pol
775d3c7a97 Let the framebuffer provide the cursor position
In the piperwire case, we get it through pipewire, not QCursor. Still
default to QCursor for xcb and qt backends.
2021-11-03 14:28:54 +00:00
l10n daemon script
18f98326d4 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-02 01:13:56 +00:00
l10n daemon script
0b65306f15 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-11-01 01:17:59 +00:00
Heiko Becker
4a2c13135d GIT_SILENT Update Appstream for new release
(cherry picked from commit 874c804ab8)
2021-10-31 11:32:38 +01:00
l10n daemon script
5860226875 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-10-31 01:13:15 +00:00
Yuri Chornoivan
f30d0b65e3 Fix minor typo 2021-10-30 19:16:40 +03:00
Aleix Pol
4707bde236 Introduce krfb-virtualmonitor
It implements a KWin protocol that is oriented towards serving a virtual
display specifically.
It requests KWin a stream that will act as a monitor that we can feed
into remote clients.
2021-10-29 14:05:34 +00:00
Aleix Pol
608762c7ac Allow passing plugin backends some arguments
WId is irrelevant on Wayland and it doesn't fully describe everything we
might be doing, we can pass a variant map to make sure all necessary
information is provided.
2021-10-29 14:05:34 +00:00
Laurent Montel
be01a1e42b GIT_SILENT: add missing override 2021-10-27 06:46:58 +02:00
Aleix Pol
00c3d1c2ed Add missing includes 2021-10-14 15:46:24 +02:00
Aleix Pol
a90970900a Fix API deprecation warning 2021-10-14 13:41:16 +00:00
Aleix Pol
d1e7614716 Also set the IPv6 port when setting the port
Otherwise we only use the requested port for IPv4 and IPv6 remains the
default.
2021-10-14 13:41:16 +00:00
Aleix Pol
2127fc927d Enable rfb logging together with the debug category of the app
So that if a user enables debug (it needs to be done explicitly as we
default to Info), they also get the underlying logs.
2021-10-14 13:41:16 +00:00
Aleix Pol
9d5d45c7af PendingRfbClient: Include its own QSocketNotifier
Instead of keeping it in its only subclass PendingInvitationsRfbClient.
The notifier is necessary for pending clients overall and entirely
unrelated to the task of PendingInvitationsRfbClient.
2021-10-14 13:41:16 +00:00
Aleix Pol
b4eccc2134 pipewire: Use C99
Reduces the amount of warnings we get
2021-10-14 13:41:16 +00:00
l10n daemon script
97cbf48059 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-10-12 01:17:15 +00:00
l10n daemon script
c8207581f4 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-10-11 01:18:41 +00:00
Nicolas Fella
4727061d74 Add Linux and FreeBSD CI 2021-10-07 13:22:55 +02:00
Heiko Becker
3bf587a097 GIT_SILENT Update Appstream for new release
(cherry picked from commit 13316b761d)
2021-10-05 00:29:55 +02:00
Laurent Montel
26c468009f GIT_SILENT: remove .arcconfig 2021-10-02 09:51:38 +02:00
Laurent Montel
fb909eadf4 Add .kde-ci.yml 2021-09-30 13:31:20 +02:00
l10n daemon script
f72674db18 GIT_SILENT made messages (after extraction) 2021-09-10 00:17:48 +00:00
Laurent Montel
df9e6d62d2 use nullptr 2021-08-31 08:46:39 +02:00
Laurent Montel
b55de9645e Use std::chrono_literals 2021-08-31 08:46:39 +02:00
Laurent Montel
a9241dfe88 We can use std::as_const 2021-08-31 08:46:39 +02:00
Laurent Montel
23c0218f3d GIT_SILENT: time to increase version 2021-08-31 08:46:39 +02:00
Heiko Becker
4a524c6f0a GIT_SILENT Update Appstream for new release
(cherry picked from commit 99ef2060a8)
2021-08-27 23:13:18 +02:00
Heiko Becker
cb86f9c018 GIT_SILENT Update Appstream for new release
(cherry picked from commit 08bac276d3)
2021-08-05 00:06:47 +02:00
l10n daemon script
0eaf1bc550 SVN_SILENT made messages (.desktop file) - always resolve ours
In case of conflict in i18n, keep the version of the branch "ours"
To resolve a particular conflict, "git checkout --ours path/to/file.desktop"
2021-07-19 01:15:25 +00:00
l10n daemon script
cb7164d755 GIT_SILENT made messages (after extraction) 2021-07-19 00:17:20 +00:00
Albert Astals Cid
75bff9d5f9 GIT_SILENT Upgrade release service version to 21.11.70. 2021-07-10 20:21:28 +02:00
48 changed files with 755 additions and 115 deletions

View File

@@ -1,3 +0,0 @@
{
"phabricator.uri" : "https://phabricator.kde.org/"
}

6
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,6 @@
# SPDX-FileCopyrightText: None
# SPDX-License-Identifier: CC0-1.0
include:
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml

21
.kde-ci.yml Normal file
View File

@@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: None
# SPDX-License-Identifier: CC0-1.0
Dependencies:
- 'on': ['@all']
'require':
'frameworks/extra-cmake-modules': '@stable'
'frameworks/ki18n': '@stable'
'frameworks/kconfig': '@stable'
'frameworks/kcoreaddons': '@stable'
'frameworks/kcrash': '@stable'
'frameworks/kdbusaddons': '@stable'
'frameworks/kdnssd': '@stable'
'frameworks/kdoctools': '@stable'
'frameworks/knotifications': '@stable'
'frameworks/kwallet': '@stable'
'frameworks/kwidgetsaddons': '@stable'
'frameworks/kwindowsystem': '@stable'
'frameworks/kxmlgui': '@stable'
'frameworks/kwayland': '@stable'
'libraries/plasma-wayland-protocols': '@latest' # can be switched to @stable when 1.5.0 is released

View File

@@ -2,14 +2,14 @@ cmake_minimum_required(VERSION 3.16)
# KDE Application Version, managed by release script
set (RELEASE_SERVICE_VERSION_MAJOR "21")
set (RELEASE_SERVICE_VERSION_MINOR "07")
set (RELEASE_SERVICE_VERSION_MICRO "70")
set (RELEASE_SERVICE_VERSION_MINOR "12")
set (RELEASE_SERVICE_VERSION_MICRO "0")
set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(krfb VERSION ${RELEASE_SERVICE_VERSION})
set(QT_MIN_VERSION 5.15.0)
set(KF5_MIN_VERSION 5.83.0)
set(KF5_MIN_VERSION 5.85.0)
find_package(ECM ${KF5_MIN_VERSION} NO_MODULE REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ${ECM_MODULE_PATH})
@@ -38,6 +38,7 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
DocTools
Notifications
Wallet
Wayland
WidgetsAddons
WindowSystem
XmlGui
@@ -80,6 +81,14 @@ find_package(LibVNCServer REQUIRED)
pkg_check_modules(PipeWire IMPORTED_TARGET libpipewire-0.3)
add_feature_info(PipeWire PipeWire_FOUND "Required for pipewire screencast plugin")
find_package(PlasmaWaylandProtocols 1.5.0)
if(PipeWire_FOUND AND PlasmaWaylandProtocols_FOUND)
find_package(QtWaylandScanner REQUIRED)
find_package(Qt5WaylandClient)
find_package(Qt5XkbCommonSupport)
find_package(Wayland REQUIRED COMPONENTS Client)
endif()
find_package(gbm)
set_package_properties(gbm PROPERTIES

View File

@@ -31,7 +31,7 @@ class X11EventsPlugin : public EventsPlugin
Q_OBJECT
public:
X11EventsPlugin(QObject *parent, const QVariantList &args);
virtual ~X11EventsPlugin() = default;
~X11EventsPlugin() override = default;
EventHandler *eventHandler() override;

View File

@@ -33,7 +33,7 @@ class XdpEventsPlugin : public EventsPlugin
Q_OBJECT
public:
XdpEventsPlugin(QObject *parent, const QVariantList &args);
virtual ~XdpEventsPlugin() = default;
~XdpEventsPlugin() override = default;
EventHandler *eventHandler() override;

View File

@@ -5,8 +5,14 @@ include_directories (${CMAKE_CURRENT_SOURCE_DIR}
set (krfb_framebuffer_pw_SRCS
pw_framebuffer.cpp
pw_framebufferplugin.cpp
screencasting.cpp
)
ecm_add_qtwayland_client_protocol(krfb_framebuffer_pw_SRCS
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/screencast.xml
BASENAME zkde-screencast-unstable-v1
)
ecm_qt_declare_logging_category(krfb_framebuffer_pw_SRCS
HEADER krfb_fb_pipewire_debug.h
@@ -32,12 +38,15 @@ add_library(krfb_framebuffer_pw
MODULE
${krfb_framebuffer_pw_SRCS}
)
set_property(TARGET krfb_framebuffer_pw PROPERTY C_STANDARD 99)
target_link_libraries(krfb_framebuffer_pw
Qt5::Core
Qt5::Gui
Qt5::DBus
KF5::CoreAddons
KF5::WaylandClient
Wayland::Client
krfbprivate
PkgConfig::PipeWire
)

View File

@@ -22,6 +22,9 @@
#include <QDebug>
#include <QRandomGenerator>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/registry.h>
// pipewire
#include <sys/ioctl.h>
@@ -38,6 +41,7 @@
#include "xdp_dbus_screencast_interface.h"
#include "xdp_dbus_remotedesktop_interface.h"
#include "krfb_fb_pipewire_debug.h"
#include "screencasting.h"
#if HAVE_DMA_BUF
#include <fcntl.h>
@@ -171,6 +175,10 @@ private:
// sanity indicator
bool isValid = true;
QImage cursorTexture;
QPoint cursorPosition;
QPoint cursorHotspot;
#if HAVE_DMA_BUF
struct EGLStruct {
QList<QByteArray> extensions;
@@ -552,6 +560,10 @@ void PWFrameBuffer::Private::onStreamStateChanged(void *data, pw_stream_state /*
}
}
#define CURSOR_BPP 4
#define CURSOR_META_SIZE(w,h) (sizeof(struct spa_meta_cursor) + \
sizeof(struct spa_meta_bitmap) + w * h * CURSOR_BPP)
/**
* @brief PWFrameBuffer::Private::onStreamFormatChanged - being executed after stream is set to active
* and after setup has been requested to connect to it. The actual video format is being negotiated here.
@@ -579,7 +591,6 @@ void PWFrameBuffer::Private::onStreamParamChanged(void *data, uint32_t id, const
auto builder = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
// setup buffers and meta header for new format
const struct spa_pod *params[3];
#if HAVE_DMA_BUF
const auto bufferTypes = d->m_eglInitialized ? (1 << SPA_DATA_DmaBuf) | (1 << SPA_DATA_MemFd) | (1 << SPA_DATA_MemPtr) :
@@ -588,23 +599,38 @@ void PWFrameBuffer::Private::onStreamParamChanged(void *data, uint32_t id, const
const auto bufferTypes = (1 << SPA_DATA_MemFd) | (1 << SPA_DATA_MemPtr);
#endif /* HAVE_DMA_BUF */
params[0] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
QVector<const struct spa_pod *> params = {
reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
SPA_PARAM_BUFFERS_size, SPA_POD_Int(size),
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(stride),
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(8, 1, 32),
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
SPA_PARAM_BUFFERS_align, SPA_POD_Int(16),
SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(bufferTypes)));
params[1] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(bufferTypes))),
reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))));
params[2] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(&builder,
SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)))),
reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type,
SPA_POD_Id(SPA_META_VideoCrop), SPA_PARAM_META_size,
SPA_POD_Int(sizeof(struct spa_meta_region))));
pw_stream_update_params(d->pwStream, params, 3);
SPA_POD_Int(sizeof(struct spa_meta_region)))),
reinterpret_cast<spa_pod*>(spa_pod_builder_add_object ( &builder,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id (SPA_META_Cursor),
SPA_PARAM_META_size, SPA_POD_CHOICE_RANGE_Int (CURSOR_META_SIZE (64, 64),
CURSOR_META_SIZE (1, 1),
CURSOR_META_SIZE (1024, 1024)))),
reinterpret_cast<spa_pod*>(spa_pod_builder_add_object ( &builder,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoDamage),
SPA_PARAM_META_size, SPA_POD_CHOICE_RANGE_Int(
sizeof(struct spa_meta_region) * 16,
sizeof(struct spa_meta_region) * 1,
sizeof(struct spa_meta_region) * 16))),
};
pw_stream_update_params(d->pwStream, params.data(), params.size());
}
/**
@@ -638,6 +664,13 @@ void PWFrameBuffer::Private::onStreamProcess(void *data)
pw_stream_queue_buffer(d->pwStream, buffer);
}
static QImage::Format spaToQImageFormat(quint32 format)
{
return format == SPA_VIDEO_FORMAT_BGR ? QImage::Format_BGR888
: format == SPA_VIDEO_FORMAT_RGBx ? QImage::Format_RGBX8888
: QImage::Format_RGB32;
}
void PWFrameBuffer::Private::handleFrame(pw_buffer *pwBuffer)
{
auto spaBuffer = pwBuffer->buffer;
@@ -747,6 +780,28 @@ void PWFrameBuffer::Private::handleFrame(pw_buffer *pwBuffer)
}
#endif /* HAVE_DMA_BUF */
// process cursor
{
struct spa_meta_cursor *cursor = static_cast<struct spa_meta_cursor*>(spa_buffer_find_meta_data (spaBuffer, SPA_META_Cursor, sizeof (*cursor)));
if (spa_meta_cursor_is_valid (cursor)) {
struct spa_meta_bitmap *bitmap = nullptr;
if (cursor->bitmap_offset)
bitmap = SPA_MEMBER (cursor, cursor->bitmap_offset, struct spa_meta_bitmap);
if (bitmap && bitmap->size.width > 0 && bitmap->size.height > 0) {
const uint8_t *bitmap_data;
bitmap_data = SPA_MEMBER (bitmap, bitmap->offset, uint8_t);
cursorHotspot = { cursor->hotspot.x, cursor->hotspot.y };
cursorTexture = QImage(bitmap_data, bitmap->size.width, bitmap->size.height, bitmap->stride, spaToQImageFormat(bitmap->format));
}
cursorPosition = QPoint{ cursor->position.x, cursor->position.y };
}
}
struct spa_meta_region* videoMetadata =
static_cast<struct spa_meta_region*>(spa_buffer_find_meta_data(
spaBuffer, SPA_META_VideoCrop, sizeof(*videoMetadata)));
@@ -824,15 +879,21 @@ void PWFrameBuffer::Private::handleFrame(pw_buffer *pwBuffer)
}
if (videoFormat->format != SPA_VIDEO_FORMAT_RGB) {
const QImage::Format format = videoFormat->format == SPA_VIDEO_FORMAT_BGR ? QImage::Format_BGR888
: videoFormat->format == SPA_VIDEO_FORMAT_RGBx ? QImage::Format_RGBX8888
: QImage::Format_RGB32;
QImage img((uchar*) q->fb, videoSize.width(), videoSize.height(), dstStride, format);
QImage img((uchar*) q->fb, videoSize.width(), videoSize.height(), dstStride, spaToQImageFormat(videoFormat->format));
img.convertTo(QImage::Format_RGB888);
}
q->tiles.append(QRect(0, 0, videoSize.width(), videoSize.height()));
if (spa_meta* vdMeta = spa_buffer_find_meta(spaBuffer, SPA_META_VideoDamage)) {
struct spa_meta_region *r;
spa_meta_for_each(r, vdMeta) {
if (!spa_meta_region_is_valid(r))
break;
q->tiles.append(QRect(r->region.position.x, r->region.position.y, r->region.size.width, r->region.size.height));
}
} else {
q->tiles.append(QRect(0, 0, videoSize.width(), videoSize.height()));
}
}
/**
@@ -904,10 +965,6 @@ PWFrameBuffer::PWFrameBuffer(WId winid, QObject *parent)
: FrameBuffer (winid, parent),
d(new Private(this))
{
// D-Bus is most important in init chain, no toys for us if something is wrong with XDP
// PipeWire connectivity is initialized after D-Bus session is started
d->initDbus();
fb = nullptr;
}
@@ -917,6 +974,38 @@ PWFrameBuffer::~PWFrameBuffer()
fb = nullptr;
}
void PWFrameBuffer::initDBus()
{
d->initDbus();
}
void PWFrameBuffer::startVirtualMonitor(const QString& name, const QSize& resolution, qreal dpr)
{
d->videoSize = resolution * dpr;
using namespace KWayland::Client;
auto connection = ConnectionThread::fromApplication(this);
if (!connection) {
qWarning() << "Failed getting Wayland connection from QPA";
QCoreApplication::exit(1);
return;
}
auto registry = new Registry(this);
connect(registry, &KWayland::Client::Registry::interfaceAnnounced, this, [this, registry, name, dpr, resolution] (const QByteArray &interfaceName, quint32 wlname, quint32 version) {
if (interfaceName != "zkde_screencast_unstable_v1")
return;
auto screencasting = new Screencasting(registry, wlname, version, this);
auto r = screencasting->createVirtualMonitorStream(name, resolution, dpr, Screencasting::Metadata);
connect(r, &ScreencastingStream::created, this, [this] (quint32 nodeId) {
d->pwStreamNodeId = nodeId;
d->initPw();
});
});
registry->create(connection);
registry->setup();
}
int PWFrameBuffer::depth()
{
return 32;
@@ -970,3 +1059,8 @@ bool PWFrameBuffer::isValid() const
{
return d->isValid;
}
QPoint PWFrameBuffer::cursorPosition()
{
return d->cursorPosition;
}

View File

@@ -33,6 +33,9 @@ public:
PWFrameBuffer(WId winid, QObject *parent = nullptr);
virtual ~PWFrameBuffer() override;
void initDBus();
void startVirtualMonitor(const QString &name, const QSize &resolution, qreal dpr);
int depth() override;
int height() override;
int width() override;
@@ -40,6 +43,7 @@ public:
void getServerFormat(rfbPixelFormat &format) override;
void startMonitor() override;
void stopMonitor() override;
QPoint cursorPosition() override;
QVariant customProperty(const QString &property) const override;

View File

@@ -36,10 +36,18 @@ PWFrameBufferPlugin::~PWFrameBufferPlugin()
{
}
FrameBuffer *PWFrameBufferPlugin::frameBuffer(WId id)
FrameBuffer *PWFrameBufferPlugin::frameBuffer(WId id, const QVariantMap &args)
{
//NOTE WId is irrelevant in Wayland
auto pwfb = new PWFrameBuffer(id);
if (args.contains(QLatin1String("name"))) {
pwfb->startVirtualMonitor(args[QStringLiteral("name")].toString(), args[QStringLiteral("resolution")].toSize(), args[QStringLiteral("scale")].toDouble());
} else {
// D-Bus is most important in XDG-Desktop-Portals init chain, no toys for us if something is wrong with XDP
// PipeWire connectivity is initialized after D-Bus session is started
pwfb->initDBus();
}
// sanity check for dbus/wayland/pipewire errors
if (!pwfb->isValid()) {

View File

@@ -35,7 +35,7 @@ public:
PWFrameBufferPlugin(QObject *parent, const QVariantList &args);
virtual ~PWFrameBufferPlugin() override;
FrameBuffer *frameBuffer(WId id) override;
FrameBuffer *frameBuffer(WId id, const QVariantMap &args) override;
private:
Q_DISABLE_COPY(PWFrameBufferPlugin)

View File

@@ -0,0 +1,136 @@
/*
SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "screencasting.h"
#include "qwayland-zkde-screencast-unstable-v1.h"
#include <KWayland/Client/output.h>
#include <KWayland/Client/plasmawindowmanagement.h>
#include <KWayland/Client/registry.h>
#include <QDebug>
#include <QRect>
using namespace KWayland::Client;
class ScreencastingStreamPrivate : public QtWayland::zkde_screencast_stream_unstable_v1
{
public:
ScreencastingStreamPrivate(ScreencastingStream *q)
: q(q)
{
}
~ScreencastingStreamPrivate()
{
close();
q->deleteLater();
}
void zkde_screencast_stream_unstable_v1_created(uint32_t node) override
{
m_nodeId = node;
Q_EMIT q->created(node);
}
void zkde_screencast_stream_unstable_v1_closed() override
{
Q_EMIT q->closed();
}
void zkde_screencast_stream_unstable_v1_failed(const QString &error) override
{
Q_EMIT q->failed(error);
}
uint m_nodeId = 0;
QPointer<ScreencastingStream> q;
};
ScreencastingStream::ScreencastingStream(QObject *parent)
: QObject(parent)
, d(new ScreencastingStreamPrivate(this))
{
}
ScreencastingStream::~ScreencastingStream() = default;
quint32 ScreencastingStream::nodeId() const
{
return d->m_nodeId;
}
class ScreencastingPrivate : public QtWayland::zkde_screencast_unstable_v1
{
public:
ScreencastingPrivate(Registry *registry, int id, int version, Screencasting *q)
: QtWayland::zkde_screencast_unstable_v1(*registry, id, version)
, q(q)
{
}
ScreencastingPrivate(::zkde_screencast_unstable_v1 *screencasting, Screencasting *q)
: QtWayland::zkde_screencast_unstable_v1(screencasting)
, q(q)
{
}
~ScreencastingPrivate()
{
destroy();
}
Screencasting *const q;
};
Screencasting::Screencasting(QObject *parent)
: QObject(parent)
{
}
Screencasting::Screencasting(Registry *registry, int id, int version, QObject *parent)
: QObject(parent)
, d(new ScreencastingPrivate(registry, id, version, this))
{
}
Screencasting::~Screencasting() = default;
ScreencastingStream *Screencasting::createOutputStream(Output *output, CursorMode mode)
{
auto stream = new ScreencastingStream(this);
stream->setObjectName(output->model());
stream->d->init(d->stream_output(*output, mode));
return stream;
}
ScreencastingStream *Screencasting::createWindowStream(PlasmaWindow *window, CursorMode mode)
{
auto stream = createWindowStream(QString::fromUtf8(window->uuid()), mode);
stream->setObjectName(window->appId());
return stream;
}
ScreencastingStream *Screencasting::createWindowStream(const QString &uuid, CursorMode mode)
{
auto stream = new ScreencastingStream(this);
stream->d->init(d->stream_window(uuid, mode));
return stream;
}
ScreencastingStream * Screencasting::createVirtualMonitorStream(const QString& name, const QSize& resolution, qreal dpr, Screencasting::CursorMode mode)
{
auto stream = new ScreencastingStream(this);
stream->d->init(d->stream_virtual_output(name, resolution.width(), resolution.height(), wl_fixed_from_double(dpr), mode));
return stream;
}
void Screencasting::setup(::zkde_screencast_unstable_v1 *screencasting)
{
d.reset(new ScreencastingPrivate(screencasting, this));
}
void Screencasting::destroy()
{
d.reset(nullptr);
}

View File

@@ -0,0 +1,78 @@
/*
SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include <QObject>
#include <QSharedPointer>
#include <QVector>
#include <optional>
struct zkde_screencast_unstable_v1;
namespace KWayland
{
namespace Client
{
class PlasmaWindow;
class Registry;
class Output;
}
}
class ScreencastingPrivate;
class ScreencastingSourcePrivate;
class ScreencastingStreamPrivate;
class ScreencastingStream : public QObject
{
Q_OBJECT
public:
ScreencastingStream(QObject *parent);
~ScreencastingStream() override;
quint32 nodeId() const;
Q_SIGNALS:
void created(quint32 nodeid);
void failed(const QString &error);
void closed();
private:
friend class Screencasting;
QScopedPointer<ScreencastingStreamPrivate> d;
};
class Screencasting : public QObject
{
Q_OBJECT
public:
explicit Screencasting(QObject *parent = nullptr);
explicit Screencasting(KWayland::Client::Registry *registry, int id, int version, QObject *parent = nullptr);
~Screencasting() override;
enum CursorMode {
Hidden = 1,
Embedded = 2,
Metadata = 4,
};
Q_ENUM(CursorMode);
ScreencastingStream *createOutputStream(KWayland::Client::Output *output, CursorMode mode);
ScreencastingStream *createWindowStream(KWayland::Client::PlasmaWindow *window, CursorMode mode);
ScreencastingStream *createWindowStream(const QString &uuid, CursorMode mode);
ScreencastingStream *createVirtualMonitorStream(const QString &name, const QSize &resolution, qreal dpr, CursorMode mode);
void setup(zkde_screencast_unstable_v1 *screencasting);
void destroy();
Q_SIGNALS:
void initialized();
void removed();
void sourcesChanged();
private:
QScopedPointer<ScreencastingPrivate> d;
};

View File

@@ -40,8 +40,8 @@
"Id": "qt",
"License": "GPL",
"Name": "Qt Framebuffer for KRfb",
"Name[ca@valencia]": "«Framebuffer» de les Qt per al KRfb.",
"Name[ca]": "«Framebuffer» de les Qt per al KRfb.",
"Name[ca@valencia]": "«Framebuffer» de les Qt per al KRfb",
"Name[ca]": "«Framebuffer» de les Qt per al KRfb",
"Name[cs]": "Qt Framebuffer pro KRfb",
"Name[da]": "Qt-framebuffer til KRfb",
"Name[de]": "Qt-Framebuffer für KRfb",

View File

@@ -36,8 +36,9 @@ QtFrameBufferPlugin::~QtFrameBufferPlugin()
{
}
FrameBuffer *QtFrameBufferPlugin::frameBuffer(WId id)
FrameBuffer *QtFrameBufferPlugin::frameBuffer(WId id, const QVariantMap &args)
{
Q_UNUSED(args);
return new QtFrameBuffer(id);
}

View File

@@ -35,7 +35,7 @@ public:
QtFrameBufferPlugin(QObject *parent, const QVariantList &args);
~QtFrameBufferPlugin() override;
FrameBuffer *frameBuffer(WId id) override;
FrameBuffer *frameBuffer(WId id, const QVariantMap &args) override;
private:
Q_DISABLE_COPY(QtFrameBufferPlugin)

View File

@@ -40,8 +40,8 @@
"Id": "xcb",
"License": "GPL",
"Name": "X11 Framebuffer for KRfb",
"Name[ca@valencia]": "«Framebuffer» de l'X11 per al KRfb.",
"Name[ca]": "«Framebuffer» de l'X11 per al KRfb.",
"Name[ca@valencia]": "«Framebuffer» de l'X11 per al KRfb",
"Name[ca]": "«Framebuffer» de l'X11 per al KRfb",
"Name[cs]": "X11 Framebuffer pro KRfb",
"Name[da]": "X11-framebuffer til KRfb",
"Name[de]": "X11-Framebuffer für KRfb",

View File

@@ -605,7 +605,7 @@ QList<QRect> XCBFrameBuffer::modifiedTiles() {
} else {
// not using shared memory
// will use just xcb_image_get() and copy pixels
for (const QRect& r : qAsConst(tiles)) {
for (const QRect& r : std::as_const(tiles)) {
// I did not find XGetSubImage() analog in XCB!!
// need function that copies pixels from one image to another
xcb_image_t *damagedImage = xcb_image_get(

View File

@@ -37,8 +37,9 @@ XCBFrameBufferPlugin::~XCBFrameBufferPlugin()
}
FrameBuffer *XCBFrameBufferPlugin::frameBuffer(WId id)
FrameBuffer *XCBFrameBufferPlugin::frameBuffer(WId id, const QVariantMap &args)
{
Q_UNUSED(args);
return new XCBFrameBuffer(id);
}

View File

@@ -35,7 +35,7 @@ public:
XCBFrameBufferPlugin(QObject *parent, const QVariantList &args);
~XCBFrameBufferPlugin() override;
FrameBuffer *frameBuffer(WId id) override;
FrameBuffer *frameBuffer(WId id, const QVariantMap &args) override;
private:
Q_DISABLE_COPY(XCBFrameBufferPlugin)

View File

@@ -78,7 +78,7 @@ kconfig_add_kcfg_files (krfb_SRCS
krfbconfig.kcfgc
)
ki18n_wrap_ui (krfb_SRCS
ki18n_wrap_ui (krfb_UI_SRCS
ui/configtcp.ui
ui/configsecurity.ui
ui/configframebuffer.ui
@@ -92,6 +92,7 @@ qt5_add_resources(krfb_SRCS
add_executable (krfb
${krfb_SRCS}
${krfb_UI_SRCS}
)
target_link_libraries (krfb
@@ -123,6 +124,41 @@ install (TARGETS krfb
${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
)
#################################
kconfig_add_kcfg_files (krfbvm_SRCS
krfbconfig.kcfgc
)
ecm_qt_declare_logging_category(krfbvm_SRCS
HEADER krfbdebug.h
IDENTIFIER KRFB
CATEGORY_NAME krfb.krfb
DESCRIPTION "KRFB Application"
EXPORT KRFB
)
add_executable(krfb-virtualmonitor main-virtualmonitor.cpp ${krfbvm_SRCS} ${krfb_UI_SRCS}
rfbserver.cpp rfbclient.cpp rfbservermanager.cpp eventsmanager.cpp framebuffermanager.cpp sockethelpers.cpp)
target_link_libraries(krfb-virtualmonitor
krfbprivate
Qt5::Gui
Qt5::Network
KF5::ConfigGui
KF5::CoreAddons
KF5::I18n
KF5::Notifications
KF5::WindowSystem
)
install (TARGETS krfb-virtualmonitor
${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
)
configure_file(org.kde.krfb.virtualmonitor.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/org.kde.krfb.virtualmonitor.desktop @ONLY)
install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.krfb.virtualmonitor.desktop
DESTINATION ${KDE_INSTALL_APPDIR}
)
########### install files ###############
install (PROGRAMS org.kde.krfb.desktop

View File

@@ -36,7 +36,7 @@ class KRFBPRIVATE_EXPORT EventHandler : public QObject
Q_OBJECT
public:
explicit EventHandler(QObject *parent = nullptr);
virtual ~EventHandler() = default;
~EventHandler() override = default;
virtual void handleKeyboard(bool down, rfbKeySym key) = 0;
virtual void handlePointer(int buttonMask, int x, int y) = 0;

View File

@@ -64,7 +64,7 @@ void EventsManager::loadPlugins()
{
//qDebug();
const QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("krfb/events"));
const QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("krfb/events"));
QVectorIterator<KPluginMetaData> i(plugins);
i.toBack();

View File

@@ -43,7 +43,7 @@ class KRFBPRIVATE_EXPORT EventsManager : public QObject
public:
static EventsManager *instance();
virtual ~EventsManager();
~EventsManager() override;
QSharedPointer<EventHandler> eventHandler();

View File

@@ -33,7 +33,7 @@ class KRFBPRIVATE_EXPORT EventsPlugin : public QObject
Q_OBJECT
public:
EventsPlugin(QObject *parent, const QVariantList &args);
virtual ~EventsPlugin();
~EventsPlugin() override;
virtual EventHandler *eventHandler() = 0;
};

View File

@@ -10,8 +10,7 @@
#include "framebuffer.h"
#include <config-krfb.h>
#include <X11/Xutil.h>
#include <QCursor>
FrameBuffer::FrameBuffer(WId id, QObject *parent)
@@ -73,3 +72,8 @@ void FrameBuffer::startMonitor()
void FrameBuffer::stopMonitor()
{
}
QPoint FrameBuffer::cursorPosition()
{
return QCursor::pos();
}

View File

@@ -42,10 +42,12 @@ public:
virtual int depth();
virtual void startMonitor();
virtual void stopMonitor();
virtual QPoint cursorPosition();
virtual void getServerFormat(rfbPixelFormat &format);
virtual QVariant customProperty(const QString &property) const;
Q_SIGNALS:
void frameBufferChanged();

View File

@@ -93,7 +93,7 @@ void FrameBufferManager::loadPlugins()
}
}
QSharedPointer<FrameBuffer> FrameBufferManager::frameBuffer(WId id)
QSharedPointer<FrameBuffer> FrameBufferManager::frameBuffer(WId id, const QVariantMap &args)
{
//qDebug();
@@ -118,7 +118,7 @@ QSharedPointer<FrameBuffer> FrameBufferManager::frameBuffer(WId id)
if (iter.key() == KrfbConfig::preferredFrameBufferPlugin()) {
qCDebug(KRFB) << "Using FrameBuffer:" << KrfbConfig::preferredFrameBufferPlugin();
QSharedPointer<FrameBuffer> frameBuffer(iter.value()->frameBuffer(id));
QSharedPointer<FrameBuffer> frameBuffer(iter.value()->frameBuffer(id, args));
if (frameBuffer) {
m_frameBuffers.insert(id, frameBuffer.toWeakRef());

View File

@@ -45,7 +45,7 @@ public:
~FrameBufferManager() override;
QSharedPointer<FrameBuffer> frameBuffer(WId id);
QSharedPointer<FrameBuffer> frameBuffer(WId id, const QVariantMap &args);
private:
Q_DISABLE_COPY(FrameBufferManager)

View File

@@ -37,7 +37,7 @@ public:
explicit FrameBufferPlugin(QObject *parent, const QVariantList &args);
~FrameBufferPlugin() override;
virtual FrameBuffer *frameBuffer(WId id) = 0;
virtual FrameBuffer *frameBuffer(WId id, const QVariantMap &args) = 0;
};
#endif // Header guard

View File

@@ -52,10 +52,6 @@ PendingInvitationsRfbClient::PendingInvitationsRfbClient(rfbClientPtr client, QO
d(new Private(client))
{
d->client->clientGoneHook = clientGoneHookNoop;
d->notifier = new QSocketNotifier(client->sock, QSocketNotifier::Read, this);
d->notifier->setEnabled(true);
connect(d->notifier, &QSocketNotifier::activated,
this, &PendingInvitationsRfbClient::onSocketActivated);
}
PendingInvitationsRfbClient::~PendingInvitationsRfbClient()
@@ -90,39 +86,6 @@ void PendingInvitationsRfbClient::processNewClient()
}
}
void PendingInvitationsRfbClient::onSocketActivated()
{
//Process not only one, but all pending messages.
//poll() idea/code copied from vino:
// Copyright (C) 2003 Sun Microsystems, Inc.
// License: GPL v2 or later
struct pollfd pollfd = { d->client->sock, POLLIN|POLLPRI, 0 };
while(poll(&pollfd, 1, 0) == 1) {
if(d->client->state == rfbClientRec::RFB_INITIALISATION) {
d->notifier->setEnabled(false);
//Client is Authenticated
processNewClient();
break;
}
rfbProcessClientMessage(d->client);
//This is how we handle disconnection.
//if rfbProcessClientMessage() finds out that it can't read the socket,
//it closes it and sets it to -1. So, we just have to check this here
//and call rfbClientConnectionGone() if necessary. This will call
//the clientGoneHook which in turn will remove this RfbClient instance
//from the server manager and will call deleteLater() to delete it
if (d->client->sock == -1) {
qCDebug(KRFB) << "disconnected from socket signal";
d->notifier->setEnabled(false);
rfbClientConnectionGone(d->client);
break;
}
}
}
bool PendingInvitationsRfbClient::checkPassword(const QByteArray & encryptedPassword)
{
qCDebug(KRFB) << "about to start authentication";

View File

@@ -37,7 +37,6 @@ public:
protected Q_SLOTS:
void processNewClient() override;
virtual void onSocketActivated();
bool checkPassword(const QByteArray & encryptedPassword) override;
private Q_SLOTS:

View File

@@ -21,7 +21,6 @@
#include "invitationsrfbserver.h"
#include "invitationsrfbclient.h"
#include "krfbconfig.h"
#include "rfbservermanager.h"
#include "krfbdebug.h"
#include <QTimer>
#include <QApplication>
@@ -178,7 +177,7 @@ void InvitationsRfbServer::walletOpened(bool opened)
if (m_wallet->readPassword(QStringLiteral("desktopSharingPassword"), desktopPassword) == 0 &&
!desktopPassword.isEmpty()) {
m_desktopPassword = desktopPassword;
emit passwordChanged(m_desktopPassword);
Q_EMIT passwordChanged(m_desktopPassword);
}
if(m_wallet->readPassword(QStringLiteral("unattendedAccessPassword"), unattendedPassword) == 0 &&
@@ -195,7 +194,7 @@ void InvitationsRfbServer::walletOpened(bool opened)
"desktopPassword", QString()));
if(!desktopPassword.isEmpty()) {
m_desktopPassword = desktopPassword;
emit passwordChanged(m_desktopPassword);
Q_EMIT passwordChanged(m_desktopPassword);
}
unattendedPassword = KStringHandler::obscure(krfbConfig.readEntry(

View File

@@ -3,8 +3,8 @@ Type=ServiceType
X-KDE-ServiceType=krfb/events
Comment=Event plugins for KRfb
Comment[ca]=Connectors d'esdeveniments per al KRfb.
Comment[ca@valencia]=Connectors d'esdeveniments per al KRfb.
Comment[ca]=Connectors d'esdeveniments per al KRfb
Comment[ca@valencia]=Connectors d'esdeveniments per al KRfb
Comment[cs]=Moduly událostí pro KRfb
Comment[da]=Hændelses-plugins til KRfb
Comment[de]=Ereignis-Module für KRfb

View File

@@ -1,8 +1,8 @@
{
"KPlugin": {
"Description": "Events plugins for KRfb",
"Description[ca@valencia]": "Connectors d'esdeveniments per al KRfb.",
"Description[ca]": "Connectors d'esdeveniments per al KRfb.",
"Description[ca@valencia]": "Connectors d'esdeveniments per al KRfb",
"Description[ca]": "Connectors d'esdeveniments per al KRfb",
"Description[cs]": "Moduly událostí pro KRfb",
"Description[da]": "Hændelses-plugins til KRfb",
"Description[de]": "Ereignis-Module für KRfb",

View File

@@ -5,8 +5,8 @@ X-KDE-ServiceType=krfb/framebuffer
Comment=Frame Buffer plugins for KRfb
Comment[bg]=Приставки за фреймбуфер за KRfb
Comment[bs]=Priključci framebafera za KRfb
Comment[ca]=Connectors de «framebuffer» per al KRfb.
Comment[ca@valencia]=Connectors de «framebuffer» per al KRfb.
Comment[ca]=Connectors de «framebuffer» per al KRfb
Comment[ca@valencia]=Connectors de «framebuffer» per al KRfb
Comment[cs]=Moduly Frame bufferu pro KRfb
Comment[da]=Framebuffer-plugins til KRfb
Comment[de]=Framebuffer-Module für KRfb

View File

@@ -1,8 +1,8 @@
{
"KPlugin": {
"Description": "Frame Buffer plugins for KRfb",
"Description[ca@valencia]": "Connectors de «Frame Buffer» per al KRfb.",
"Description[ca]": "Connectors de «Frame Buffer» per al KRfb.",
"Description[ca@valencia]": "Connectors de «Frame Buffer» per al KRfb",
"Description[ca]": "Connectors de «Frame Buffer» per al KRfb",
"Description[cs]": "Moduly Frame bufferu pro KRfb",
"Description[da]": "Framebuffer-plugins til KRfb",
"Description[de]": "Framebuffer-Module für KRfb",

View File

@@ -0,0 +1,173 @@
/* This file is part of the KDE project
Copyright (C) 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
*/
#include <QApplication>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QDebug>
#include <QTimer>
#include <KNotification>
#include <KLocalizedString>
#include <KWindowSystem>
#include <KAboutData>
#include "sockethelpers.h"
#include "krfb_version.h"
#include "rfbserver.h"
#include <signal.h>
#include "rfbservermanager.h"
class VirtualMonitorRfbClient : public RfbClient
{
public:
explicit VirtualMonitorRfbClient(rfbClientPtr client, QObject *parent = nullptr)
: RfbClient(client, parent)
{}
};
class PendingVirtualMonitorRfbClient : public PendingRfbClient
{
public:
explicit PendingVirtualMonitorRfbClient(rfbClientPtr client, QObject *parent = nullptr)
: PendingRfbClient(client, parent)
{}
~PendingVirtualMonitorRfbClient() override {}
static QByteArray password;
protected:
void processNewClient() override {
qDebug() << "new client!";
const QString host = peerAddress(m_rfbClient->sock) + QLatin1Char(':') + QString::number(peerPort(m_rfbClient->sock));
KNotification::event(QStringLiteral("NewConnectionAutoAccepted"),
i18n("Creating a Virtual Monitor from %1", host));
}
bool checkPassword(const QByteArray & encryptedPassword) override {
bool b = vncAuthCheckPassword(password, encryptedPassword);
if (b) {
QTimer::singleShot(0, this, [this] {
accept(new VirtualMonitorRfbClient(m_rfbClient, parent()));
});
}
return b;
}
};
QByteArray PendingVirtualMonitorRfbClient::password;
class VirtualMonitorRfbServer : public RfbServer
{
public:
PendingRfbClient *newClient(rfbClientPtr client) {
qDebug() << "new client request";
return new PendingVirtualMonitorRfbClient(client, this);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
KLocalizedString::setApplicationDomain("krfb");
KAboutData aboutData(QStringLiteral("krfb-virtualmonitor"),
i18n("Remote Virtual Monitor"),
QStringLiteral(KRFB_VERSION_STRING),
i18n("Offer a Virtual Monitor that can be accessed remotely"),
KAboutLicense::GPL,
i18n("(c) 2009-2010, Collabora Ltd.\n"
"(c) 2007, Alessandro Praduroux\n"
"(c) 2001-2003, Tim Jansen\n"
"(c) 2001, Johannes E. Schindelin\n"
"(c) 2000-2001, Const Kaplinsky\n"
"(c) 2000, Tridia Corporation\n"
"(c) 1999, AT&T Laboratories Boston\n"));
aboutData.addAuthor(QStringLiteral("Aleix Pol i Gonzalez"), i18n("Virtual Monitor implementation"), QStringLiteral("aleixpol@kde.org"));
aboutData.addAuthor(i18n("George Kiagiadakis"), QString(), QStringLiteral("george.kiagiadakis@collabora.co.uk"));
aboutData.addAuthor(i18n("Alessandro Praduroux"), i18n("KDE4 porting"), QStringLiteral("pradu@pradu.it"));
aboutData.addAuthor(i18n("Tim Jansen"), i18n("Original author"), QStringLiteral("tim@tjansen.de"));
aboutData.addCredit(i18n("Johannes E. Schindelin"),
i18n("libvncserver"));
aboutData.addCredit(i18n("Const Kaplinsky"),
i18n("TightVNC encoder"));
aboutData.addCredit(i18n("Tridia Corporation"),
i18n("ZLib encoder"));
aboutData.addCredit(i18n("AT&T Laboratories Boston"),
i18n("original VNC encoders and "
"protocol design"));
KAboutData::setApplicationData(aboutData);
QCommandLineParser parser;
aboutData.setupCommandLine(&parser);
const QCommandLineOption resolutionOption({ QStringLiteral("resolution") }, i18n("Logical resolution of the new monitor"), i18n("resolution"));
parser.addOption(resolutionOption);
const QCommandLineOption nameOption({ QStringLiteral("name") }, i18n("Name of the monitor"), i18n("name"));
parser.addOption(nameOption);
const QCommandLineOption passwordOption({ QStringLiteral("password") }, i18n("Password for the client to connect to it"), i18n("password"));
parser.addOption(passwordOption);
const QCommandLineOption scaleOption({ QStringLiteral("scale") }, i18n("The device-pixel-ratio of the device, the scaling factor"), i18n("dpr"), QStringLiteral("1"));
parser.addOption(scaleOption);
const QCommandLineOption portOption({ QStringLiteral("port") }, i18n("The port we will be listening to"), i18n("number"), QStringLiteral("9999"));
parser.addOption(portOption);
parser.process(app);
aboutData.processCommandLine(&parser);
app.setQuitOnLastWindowClosed(false);
if (!KWindowSystem::isPlatformWayland()) {
qCritical() << "Virtual Monitors are only supported on Wayland";
return 1;
}
if (!parser.isSet(nameOption)) {
qCritical() << "error: please define --name";
return 2;
} else {
if (!parser.isSet(passwordOption)) {
qCritical() << "error: please define --password";
return 3;
}
if (!parser.isSet(resolutionOption)) {
qCritical() << "error: please define --resolution";
return 4;
}
}
if (!parser.isSet(portOption)) {
qCritical() << "error: please define --port";
return 5;
}
const QString res = parser.value(resolutionOption);
const auto resSplit = res.split(QLatin1Char('x'));
if (resSplit.size() != 2) {
qCritical() << "error: the resolution should be formatted as WIDTHxHEIGHT (e.g. --resolution 1920x1080)";
return 6;
}
if (parser.isSet(nameOption)) {
RfbServerManager::s_pluginArgs = {
{ QStringLiteral("name"), parser.value(nameOption) },
{ QStringLiteral("resolution"), QSize(resSplit[0].toInt(), resSplit[1].toInt()) },
{ QStringLiteral("scale"), parser.value(scaleOption).toDouble() },
};
}
VirtualMonitorRfbServer server;
server.setPasswordRequired(true);
server.setListeningPort(parser.value(portOption).toInt());
PendingVirtualMonitorRfbClient::password = parser.value(passwordOption).toUtf8();
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGPIPE);
sigprocmask(SIG_BLOCK, &sigs, nullptr);
server.start();
return app.exec();
}

View File

@@ -39,7 +39,7 @@
class TCP: public QWidget, public Ui::TCP
{
public:
TCP(QWidget *parent = nullptr) : QWidget(parent) {
explicit TCP(QWidget *parent = nullptr) : QWidget(parent) {
setupUi(this);
}
};

View File

@@ -43,11 +43,13 @@
<summary xml:lang="ca">Comparteix l'escriptori amb un altre ordinador a través de VNC</summary>
<summary xml:lang="ca-valencia">Comparteix l'escriptori amb un altre ordinador a través de VNC</summary>
<summary xml:lang="cs">Sdílejte své pracovní prostředí na jiný počítač pomocí VNC</summary>
<summary xml:lang="da">Del dit skrivebord til en anden computer via VNC</summary>
<summary xml:lang="de">Verbindung Ihrer Arbeitsfläche zu anderen Rechnern über VNC</summary>
<summary xml:lang="el">Μοιραστείτε την επιφάνεια εργασίας σας με άλλον υπολογιστή μέσω VNC</summary>
<summary xml:lang="en-GB">Share your desktop to another computer via VNC</summary>
<summary xml:lang="es">Compartir su escritorio con otro equipo usando VNC</summary>
<summary xml:lang="et">Oma töölaua jagamine VNC kaudu teise arvutisse</summary>
<summary xml:lang="eu">Partekatu zure mahaigaina beste ordenagailu batekin VNC erabiliz</summary>
<summary xml:lang="fi">Jaa työpöytä toiselle koneelle VNC:n kautta</summary>
<summary xml:lang="fr">Partager votre bureau avec un autre ordinateur grâce à « VNC »</summary>
<summary xml:lang="ia">Compartir tu scriptorio a un altere computator via VNC</summary>
@@ -146,9 +148,9 @@
</provides>
<project_group>KDE</project_group>
<releases>
<release version="21.04.3" date="2021-07-08"/>
<release version="21.04.2" date="2021-06-10"/>
<release version="21.04.1" date="2021-05-13"/>
<release version="21.04.0" date="2021-04-22"/>
<release version="21.08.3" date="2021-11-04"/>
<release version="21.08.2" date="2021-10-07"/>
<release version="21.08.1" date="2021-09-02"/>
<release version="21.08.0" date="2021-08-12"/>
</releases>
</component>

View File

@@ -84,6 +84,7 @@ GenericName[el]=Κοινή χρήση επιφάνειας εργασίας (VNC
GenericName[en_GB]=Desktop Sharing (VNC)
GenericName[es]=Escritorio compartido (VNC)
GenericName[et]=Töölaua jagamine (VNC)
GenericName[eu]=Mahaigaina partekatzea (VNC)
GenericName[fi]=Työpöydän jakaminen (VNC)
GenericName[fr]=Partage de bureaux (VNC)
GenericName[ia]=Compartir de scriptorio (VNC)

View File

@@ -0,0 +1,44 @@
# KDE Config File
[Desktop Entry]
Type=Application
Exec=@CMAKE_INSTALL_PREFIX@/bin/krfb-virtualmonitor
Icon=krfb
Terminal=false
Name=KRFBs Virtual Monitor
Name[ca]=Monitor virtual del Krfb
Name[ca@valencia]=Monitor virtual del Krfb
Name[el]=Εικονική οθόνη του KRFB
Name[es]=Monitor virtual de KRFB
Name[fi]=KRFB:n virtuaalinäyttö
Name[fr]=Moniteur virtuel « Krfb »
Name[ia]=Virtual Monitor de KRFB
Name[it]=Monitor virtuale di KRFB
Name[ko]=KRFBs
Name[nl]=Virtuele monitor van KRFB
Name[pl]=Monitor wirtualny KRFB
Name[pt]=Monitor Virtual do KRFB
Name[pt_BR]=Monitor virtual do KRFB
Name[sl]=Navidezni monitor KRFB
Name[sv]=Krfb:s virtuella bildskärm
Name[uk]=Віртуальний монітор KRFB
Name[x-test]=xxKRFBs Virtual Monitorxx
Comment=Remote Virtual Monitor
Comment[ca]=Monitor virtual remot
Comment[ca@valencia]=Monitor virtual remot
Comment[el]=Απομακρυσμένη εικονική οθόνη
Comment[es]=Monitor virtual remoto
Comment[fi]=Virtuaalinen etänäyttö
Comment[fr]=Moniteur virtuel distant
Comment[ia]=Monitor Virtual Remote
Comment[it]=Monitor virtuale remoto
Comment[ko]=
Comment[nl]=Virtual Monitor op afstand
Comment[pl]=Zdalny monitor wirtualny
Comment[pt]=Monitor Virtual Remoto
Comment[pt_BR]=Monitor virtual remoto
Comment[sl]=Oddaljeni navidezni monitor
Comment[sv]=Virtuell fjärrbildskärm
Comment[uk]=Віддалений віртуальний монітор
Comment[x-test]=xxRemote Virtual Monitorxx
NoDisplay=true
X-KDE-Wayland-Interfaces=zkde_screencast_unstable_v1

View File

@@ -25,6 +25,7 @@
#include <QSocketNotifier>
#include <poll.h>
#include <strings.h> //for bzero()
#include "krfbdebug.h"
struct RfbClient::Private
{
@@ -170,8 +171,13 @@ void RfbClient::update()
PendingRfbClient::PendingRfbClient(rfbClientPtr client, QObject *parent)
: QObject(parent), m_rfbClient(client)
, m_notifier(new QSocketNotifier(client->sock, QSocketNotifier::Read, this))
{
m_rfbClient->clientData = this;
m_notifier->setEnabled(true);
connect(m_notifier, &QSocketNotifier::activated,
this, &PendingRfbClient::onSocketActivated);
}
PendingRfbClient::~PendingRfbClient()
@@ -230,3 +236,35 @@ bool PendingRfbClient::vncAuthCheckPassword(const QByteArray& password, const QB
rfbEncryptBytes(challenge, passwd);
return memcmp(challenge, encryptedPassword.constData(), encryptedPassword.size()) == 0;
}
void PendingRfbClient::onSocketActivated()
{
//Process not only one, but all pending messages.
//poll() idea/code copied from vino:
// Copyright (C) 2003 Sun Microsystems, Inc.
// License: GPL v2 or later
struct pollfd pollfd = { m_rfbClient->sock, POLLIN|POLLPRI, 0 };
while(poll(&pollfd, 1, 0) == 1) {
if(m_rfbClient->state == rfbClientRec::RFB_INITIALISATION) {
m_notifier->setEnabled(false);
//Client is Authenticated
processNewClient();
break;
}
rfbProcessClientMessage(m_rfbClient);
//This is how we handle disconnection.
//if rfbProcessClientMessage() finds out that it can't read the socket,
//it closes it and sets it to -1. So, we just have to check this here
//and call rfbClientConnectionGone() if necessary. This will call
//the clientGoneHook which in turn will remove this RfbClient instance
//from the server manager and will call deleteLater() to delete it
if (m_rfbClient->sock == -1) {
qCDebug(KRFB) << "disconnected from socket signal";
m_notifier->setEnabled(false);
rfbClientConnectionGone(m_rfbClient);
break;
}
}
}

View File

@@ -23,6 +23,8 @@
#include "rfb.h"
#include <QObject>
class QSocketNotifier;
class RfbClient : public QObject
{
Q_OBJECT
@@ -104,6 +106,11 @@ protected:
bool vncAuthCheckPassword(const QByteArray & password, const QByteArray & encryptedPassword) const;
rfbClientPtr m_rfbClient;
private:
void onSocketActivated();
QSocketNotifier *const m_notifier;
};
#endif // RFBCLIENT_H

View File

@@ -117,6 +117,7 @@ bool RfbServer::start()
}
d->screen->port = listeningPort();
d->screen->ipv6port = listeningPort();
// Disable/Enable password checking
if (passwordRequired()) {

View File

@@ -24,6 +24,7 @@
#include "framebuffermanager.h"
#include "sockethelpers.h"
#include "krfbconfig.h"
#include "krfbdebug.h"
#include <QTimer>
#include <QApplication>
#include <QDesktopWidget>
@@ -33,6 +34,9 @@
#include <KLocalizedString>
#include <KUser>
#include <KNotification>
#include <chrono>
using namespace std::chrono_literals;
static const char *cur =
" "
@@ -116,11 +120,12 @@ QSharedPointer<FrameBuffer> RfbServerManager::framebuffer() const
return d->fb;
}
QVariantMap RfbServerManager::s_pluginArgs;
void RfbServerManager::init()
{
//qDebug();
d->fb = FrameBufferManager::instance()->frameBuffer(QApplication::desktop()->winId());
d->fb = FrameBufferManager::instance()->frameBuffer(QApplication::desktop()->winId(), s_pluginArgs);
d->myCursor = rfbMakeXCursor(19, 19, (char *) cur, (char *) mask);
d->myCursor->cleanup = false;
d->desktopName = QStringLiteral("%1@%2 (shared desktop)") //FIXME check if we can use utf8
@@ -133,7 +138,7 @@ void RfbServerManager::init()
void RfbServerManager::updateFrameBuffer()
{
Q_FOREACH(RfbServer *server, d->servers) {
for (RfbServer *server : std::as_const(d->servers)) {
server->updateFrameBuffer(d->fb->data(), d->fb->width(), d->fb->height(), d->fb->depth());
}
}
@@ -141,9 +146,9 @@ void RfbServerManager::updateFrameBuffer()
void RfbServerManager::updateScreens()
{
QList<QRect> rects = d->fb->modifiedTiles();
QPoint currentCursorPos = QCursor::pos();
const QPoint currentCursorPos = d->fb->cursorPosition();
for (RfbServer* server : qAsConst(d->servers)) {
for (RfbServer* server : std::as_const(d->servers)) {
server->updateScreen(rects);
server->updateCursorPosition(currentCursorPos);
}
@@ -199,7 +204,7 @@ rfbScreenInfoPtr RfbServerManager::newScreen()
//qDebug() << "bpp: " << bpp;
rfbLogEnable(0);
rfbLogEnable(KRFB().isDebugEnabled());
screen = rfbGetScreen(nullptr, nullptr, w, h, 8, 3, bpp);
screen->paddedWidthInBytes = d->fb->paddedWidth();
@@ -217,7 +222,7 @@ void RfbServerManager::addClient(RfbClient* cc)
if (d->clients.size() == 0) {
//qDebug() << "Starting framebuffer monitor";
d->fb->startMonitor();
d->rfbUpdateTimer.start(50);
d->rfbUpdateTimer.start(50ms);
}
d->clients.insert(cc);

View File

@@ -23,6 +23,7 @@
#include "rfb.h"
#include "framebuffer.h"
#include <QObject>
#include <QVariantMap>
class RfbClient;
struct RfbServerManagerStatic;
@@ -35,6 +36,7 @@ public:
static RfbServerManager *instance();
QSharedPointer<FrameBuffer> framebuffer() const;
static QVariantMap s_pluginArgs;
Q_SIGNALS:
void clientConnected(RfbClient *cc);
void clientDisconnected(RfbClient *cc);

View File

@@ -41,11 +41,11 @@ public:
virtual ~ClientActions();
private:
QMenu *m_menu;
QAction *m_title;
QAction *m_disconnectAction;
QAction *m_enableControlAction;
QAction *m_separator;
QMenu *m_menu = nullptr;
QAction *m_title = nullptr;
QAction *m_disconnectAction = nullptr;
QAction *m_enableControlAction = nullptr;
QAction *m_separator = nullptr;
};
ClientActions::ClientActions(RfbClient* client, QMenu* menu, QAction* before)