Compare commits

...

5 Commits

Author SHA1 Message Date
Oleg Chernovskiy
73107409ee Implemented VNC input for mouse pointer
This implementation has several serious restrictions
What works:
- single clicks
- mouse move

What doesn't, due to FakeInput protocol:
- absolute mouse move
- keyboard

What is not implemented yet but possibly can be:
- drag'n'drop
2017-06-05 01:09:19 +03:00
Oleg Chernovskiy
09f360ded6 Remade Krfb event handler as a plugin 2017-06-05 01:09:19 +03:00
Oleg Chernovskiy
d517bf8573 Implement GBM framebuffer for KWin wayland server
This commit creates a new plugin for KWin-on-Wayland integration. It is
independent from X11 and uses GBM and custom Wayland protocol to pass buffers
from KWin side to KRfb.

It also introduces mentioned components as an optional dependencies to
KRfb and is build only if all of them are present (which is highly
likely on a modern system)

- No support for input yet
- No support for multi-screen yet
- No support for resizing yet
2017-06-05 01:09:19 +03:00
Oleg Chernovskiy
469782625a Fix KRfb crash on Wayland platform
This allows KRfb to be normally started
on Wayland platform, i.e. show main
window and attempt to load plugins
2017-06-05 01:09:19 +03:00
Oleg Chernovskiy
056b9a1ab6 Fix indentation and typo 2017-06-05 01:09:19 +03:00
42 changed files with 2048 additions and 203 deletions

View File

@@ -6,7 +6,7 @@ include(FeatureSummary)
find_package(Qt5 REQUIRED COMPONENTS Core DBus Widgets X11Extras)
find_package(ECM 1.7.0 NO_MODULE REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
include(KDEInstallDirs)
include(KDECMakeSettings)
@@ -29,6 +29,39 @@ find_package(KF5 REQUIRED COMPONENTS
XmlGui
)
find_package(KF5Wayland CONFIG)
set_package_properties(KF5Wayland PROPERTIES DESCRIPTION "KDE Frameworks Wayland integration package"
URL "https://github.com/KDE/kwayland"
TYPE OPTIONAL
PURPOSE "Required for wayland integration with KWin server"
)
find_package(epoxy)
set_package_properties(epoxy PROPERTIES DESCRIPTION "libepoxy"
URL "http://github.com/anholt/libepoxy"
TYPE OPTIONAL
PURPOSE "OpenGL dispatch library for GBM backend"
)
find_package(Libdrm)
set_package_properties(Libdrm PROPERTIES DESCRIPTION "Libdrm"
TYPE OPTIONAL
PURPOSE "Required for GBM access to compositor buffers on Wayland"
)
set(HAVE_DRM FALSE)
if(KF5Wayland_FOUND AND Libdrm_FOUND AND epoxy_FOUND)
set(HAVE_DRM TRUE)
endif()
find_package(gbm)
set_package_properties(gbm PROPERTIES TYPE OPTIONAL PURPOSE "Required for egl ouput of drm backend.")
set(HAVE_GBM FALSE)
if(HAVE_DRM AND gbm_FOUND)
set(HAVE_GBM TRUE)
endif()
find_package(X11 REQUIRED)
if(WIN32)
@@ -70,6 +103,7 @@ endif(Q_WS_X11)
add_subdirectory(krfb)
add_subdirectory(framebuffers)
add_subdirectory(events)
add_subdirectory(doc)
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

View File

@@ -0,0 +1,126 @@
#.rst:
# FindLibdrm
# -------
#
# Try to find libdrm on a Unix system.
#
# This will define the following variables:
#
# ``Libdrm_FOUND``
# True if (the requested version of) libdrm is available
# ``Libdrm_VERSION``
# The version of libdrm
# ``Libdrm_LIBRARIES``
# This can be passed to target_link_libraries() instead of the ``Libdrm::Libdrm``
# target
# ``Libdrm_INCLUDE_DIRS``
# This should be passed to target_include_directories() if the target is not
# used for linking
# ``Libdrm_DEFINITIONS``
# This should be passed to target_compile_options() if the target is not
# used for linking
#
# If ``Libdrm_FOUND`` is TRUE, it will also define the following imported target:
#
# ``Libdrm::Libdrm``
# The libdrm library
#
# In general we recommend using the imported target, as it is easier to use.
# Bear in mind, however, that if the target is in the link interface of an
# exported library, it must be made available by the package config file.
#=============================================================================
# Copyright 2014 Alex Merry <alex.merry@kde.org>
# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "CMake 2.8.12 is required by FindLibdrm.cmake")
endif()
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use FindLibdrm.cmake")
endif()
if(NOT WIN32)
# Use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
pkg_check_modules(PKG_Libdrm QUIET libdrm)
set(Libdrm_DEFINITIONS ${PKG_Libdrm_CFLAGS_OTHER})
set(Libdrm_VERSION ${PKG_Libdrm_VERSION})
find_path(Libdrm_INCLUDE_DIR
NAMES
xf86drm.h
HINTS
${PKG_Libdrm_INCLUDE_DIRS}
)
find_library(Libdrm_LIBRARY
NAMES
drm
HINTS
${PKG_Libdrm_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libdrm
FOUND_VAR
Libdrm_FOUND
REQUIRED_VARS
Libdrm_LIBRARY
Libdrm_INCLUDE_DIR
VERSION_VAR
Libdrm_VERSION
)
if(Libdrm_FOUND AND NOT TARGET Libdrm::Libdrm)
add_library(Libdrm::Libdrm UNKNOWN IMPORTED)
set_target_properties(Libdrm::Libdrm PROPERTIES
IMPORTED_LOCATION "${Libdrm_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${Libdrm_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}"
INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}/libdrm"
)
endif()
mark_as_advanced(Libdrm_LIBRARY Libdrm_INCLUDE_DIR)
# compatibility variables
set(Libdrm_LIBRARIES ${Libdrm_LIBRARY})
set(Libdrm_INCLUDE_DIRS ${Libdrm_INCLUDE_DIR})
set(Libdrm_VERSION_STRING ${Libdrm_VERSION})
else()
message(STATUS "FindLibdrm.cmake cannot find libdrm on Windows systems.")
set(Libdrm_FOUND FALSE)
endif()
include(FeatureSummary)
set_package_properties(Libdrm PROPERTIES
URL "https://wiki.freedesktop.org/dri/"
DESCRIPTION "Userspace interface to kernel DRM services."
)

View File

@@ -0,0 +1,56 @@
# - Try to find libepoxy
# Once done this will define
#
# epoxy_FOUND - System has libepoxy
# epoxy_LIBRARY - The libepoxy library
# epoxy_INCLUDE_DIR - The libepoxy include dir
# epoxy_DEFINITIONS - Compiler switches required for using libepoxy
# epoxy_HAS_GLX - Whether GLX support is available
# Copyright (c) 2014 Fredrik Höglund <fredrik@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
if (NOT WIN32)
find_package(PkgConfig)
pkg_check_modules(PKG_epoxy QUIET epoxy)
set(epoxy_DEFINITIONS ${PKG_epoxy_CFLAGS})
find_path(epoxy_INCLUDE_DIR NAMES epoxy/gl.h HINTS ${PKG_epoxy_INCLUDEDIR} ${PKG_epoxy_INCLUDE_DIRS})
find_library(epoxy_LIBRARY NAMES epoxy HINTS ${PKG_epoxy_LIBDIR} ${PKG_epoxy_LIBRARY_DIRS})
find_file(epoxy_GLX_HEADER NAMES epoxy/glx.h HINTS ${epoxy_INCLUDE_DIR})
if (epoxy_GLX_HEADER STREQUAL "epoxy_GLX_HEADER-NOTFOUND")
set(epoxy_HAS_GLX FALSE CACHE BOOL "whether glx is available")
else ()
set(epoxy_HAS_GLX TRUE CACHE BOOL "whether glx is available")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(epoxy DEFAULT_MSG epoxy_LIBRARY epoxy_INCLUDE_DIR)
mark_as_advanced(epoxy_INCLUDE_DIR epoxy_LIBRARY epoxy_HAS_GLX)
endif()

125
cmake/modules/Findgbm.cmake Normal file
View File

@@ -0,0 +1,125 @@
#.rst:
# Findgbm
# -------
#
# Try to find gbm on a Unix system.
#
# This will define the following variables:
#
# ``gbm_FOUND``
# True if (the requested version of) gbm is available
# ``gbm_VERSION``
# The version of gbm
# ``gbm_LIBRARIES``
# This can be passed to target_link_libraries() instead of the ``gbm::gbm``
# target
# ``gbm_INCLUDE_DIRS``
# This should be passed to target_include_directories() if the target is not
# used for linking
# ``gbm_DEFINITIONS``
# This should be passed to target_compile_options() if the target is not
# used for linking
#
# If ``gbm_FOUND`` is TRUE, it will also define the following imported target:
#
# ``gbm::gbm``
# The gbm library
#
# In general we recommend using the imported target, as it is easier to use.
# Bear in mind, however, that if the target is in the link interface of an
# exported library, it must be made available by the package config file.
#=============================================================================
# Copyright 2014 Alex Merry <alex.merry@kde.org>
# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "CMake 2.8.12 is required by Findgbm.cmake")
endif()
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Findgbm.cmake")
endif()
if(NOT WIN32)
# Use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
pkg_check_modules(PKG_gbm QUIET gbm)
set(gbm_DEFINITIONS ${PKG_gbm_CFLAGS_OTHER})
set(gbm_VERSION ${PKG_gbm_VERSION})
find_path(gbm_INCLUDE_DIR
NAMES
gbm.h
HINTS
${PKG_gbm_INCLUDE_DIRS}
)
find_library(gbm_LIBRARY
NAMES
gbm
HINTS
${PKG_gbm_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gbm
FOUND_VAR
gbm_FOUND
REQUIRED_VARS
gbm_LIBRARY
gbm_INCLUDE_DIR
VERSION_VAR
gbm_VERSION
)
if(gbm_FOUND AND NOT TARGET gbm::gbm)
add_library(gbm::gbm UNKNOWN IMPORTED)
set_target_properties(gbm::gbm PROPERTIES
IMPORTED_LOCATION "${gbm_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${gbm_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${gbm_INCLUDE_DIR}"
)
endif()
mark_as_advanced(gbm_LIBRARY gbm_INCLUDE_DIR)
# compatibility variables
set(gbm_LIBRARIES ${gbm_LIBRARY})
set(gbm_INCLUDE_DIRS ${gbm_INCLUDE_DIR})
set(gbm_VERSION_STRING ${gbm_VERSION})
else()
message(STATUS "Findgbm.cmake cannot find gbm on Windows systems.")
set(gbm_FOUND FALSE)
endif()
include(FeatureSummary)
set_package_properties(gbm PROPERTIES
URL "http://www.mesa3d.org"
DESCRIPTION "Mesa gbm library."
)

4
events/CMakeLists.txt Normal file
View File

@@ -0,0 +1,4 @@
add_subdirectory (x11)
if(HAVE_GBM)
add_subdirectory (fakeinput)
endif()

View File

@@ -0,0 +1,25 @@
include_directories (${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
set (krfb_events_gbm_SRCS
fakeinputevents.cpp
fakeinputeventsplugin.cpp
)
add_library(krfb_events_fakeinput
MODULE
${krfb_events_gbm_SRCS}
)
target_link_libraries (krfb_events_fakeinput
${GBM_XTest_LIB}
KF5::CoreAddons
KF5::WaylandClient
KF5::I18n
krfbprivate
)
install (TARGETS krfb_events_fakeinput
DESTINATION ${PLUGIN_INSTALL_DIR}/krfb
)

View File

@@ -0,0 +1,118 @@
/*
This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "fakeinputevents.h"
// Qt
#include <QApplication>
#include <QDesktopWidget>
#include <QGlobalStatic>
// KDE
#include <KLocalizedString>
// KWayland
#include <KWayland/Client/registry.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/fakeinput.h>
class EventData
{
public:
EventData() = default;
//mouse
int buttonMask = 0;
int oldX = 0;
int oldY = 0;
};
FakeInputEventHandler::FakeInputEventHandler()
: EventHandler(), m_eventData(new EventData())
{
initWaylandConnection();
}
void FakeInputEventHandler::initWaylandConnection()
{
using namespace KWayland::Client;
ConnectionThread *conn = ConnectionThread::fromApplication(this);
Registry *registry = new Registry(this);
registry->create(conn);
connect(registry, &Registry::fakeInputAnnounced, this,
[this, registry] (qint32 name, qint32 version) {
m_interface = registry->createFakeInput(name, version, this);
}
);
registry->setup();
}
void FakeInputEventHandler::authIfNeeded()
{
if (!m_authRequested) {
m_interface->authenticate(i18n("Krfb"), i18n("Remote VNC input"));
m_authRequested = true;
}
}
void FakeInputEventHandler::handleKeyboard(bool down, rfbKeySym keySym)
{
if (!m_interface)
return;
authIfNeeded();
// TODO: implement button handling
// both in FakeInput interface and here
Q_UNUSED(down)
Q_UNUSED(keySym)
}
void FakeInputEventHandler::handlePointer(int buttonMask, int x, int y)
{
if (!m_interface)
return;
authIfNeeded();
int oldMask = m_eventData->buttonMask;
int oldX = m_eventData->oldX;
int oldY = m_eventData->oldY;
if (!(oldMask & 1) && buttonMask & 1) { // single left click
m_interface->requestPointerButtonClick(Qt::LeftButton);
}
if (!(oldMask & 2) && buttonMask & 2) { // single right click
m_interface->requestPointerButtonClick(Qt::RightButton);
}
if (!(oldMask & 4) && buttonMask & 4) { // single middle click
m_interface->requestPointerButtonClick(Qt::MiddleButton);
}
if (!(oldMask & 8) && buttonMask & 8) { // wheel up
m_interface->requestPointerAxis(Qt::Vertical, +10);
}
if (!(oldMask & 16) && buttonMask & 16) { // wheel down
m_interface->requestPointerAxis(Qt::Vertical, -10);
}
if (oldX != x || oldY != y) {
m_interface->requestPointerMove(QSizeF(x - oldX, y - oldY));
}
m_eventData->buttonMask = buttonMask;
}

View File

@@ -0,0 +1,54 @@
/*
This file is part of the KDE project
Copyright (C) 2016 by Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef EVENTS_GBMEVENTS_H
#define EVENTS_GBMEVENTS_H
#include "../../krfb/events.h"
#include <QScopedPointer>
namespace KWayland
{
namespace Client
{
class FakeInput;
}
}
class EventData;
class FakeInputEventHandler : public EventHandler
{
public:
FakeInputEventHandler();
virtual void handleKeyboard(bool down, rfbKeySym key);
virtual void handlePointer(int buttonMask, int x, int y);
private:
void initWaylandConnection();
void authIfNeeded();
QScopedPointer<EventData> m_eventData;
KWayland::Client::FakeInput *m_interface = nullptr;
bool m_authRequested = false;
};
#endif

View File

@@ -0,0 +1,41 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "fakeinputeventsplugin.h"
#include "fakeinputevents.h"
#include <KPluginFactory>
K_PLUGIN_FACTORY_WITH_JSON(FakeInputEventsPluginFactory, "krfb_events_fakeinput.json",
registerPlugin<FakeInputEventsPlugin>();)
FakeInputEventsPlugin::FakeInputEventsPlugin(QObject *parent, const QVariantList &args)
: EventsPlugin(parent, args)
{
}
EventHandler *FakeInputEventsPlugin::eventHandler()
{
// works only under Wayland
return new FakeInputEventHandler();
}
#include "fakeinputeventsplugin.moc"

View File

@@ -0,0 +1,45 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_EVENTS_GBM_GBMEVENTSPLUGIN_H
#define KRFB_EVENTS_GBM_GBMEVENTSPLUGIN_H
#include "eventsplugin.h"
#include <QWidget>
class EventHandler;
class FakeInputEventsPlugin : public EventsPlugin
{
Q_OBJECT
public:
FakeInputEventsPlugin(QObject *parent, const QVariantList &args);
virtual ~FakeInputEventsPlugin() = default;
EventHandler *eventHandler() override;
private:
Q_DISABLE_COPY(FakeInputEventsPlugin)
};
#endif // Header guard

View File

@@ -0,0 +1,17 @@
[Desktop Entry]
Encoding=UTF-8
Comment=KWin FakeInput based event handler for KRfb
Comment[ru]=Обработчик событий для KRfb на базе интерфейса FakeInput KWin
Comment[x-test]=KWin FakeInput based event handler for KRfbxx
Name=KWin FakeInput based event handler for KRfb
Name[ru]=Обработчик событий для KRfb на базе интерфейса FakeInput KWin
Name[x-test]=xxKWin FakeInput based event handler for KRfbxx
Type=Service
ServiceTypes=krfb/events
X-KDE-Library=krfb_events_fakeinput
X-KDE-PluginInfo-Name=fakeinput
X-KDE-PluginInfo-Version=0.1
X-KDE-PluginInfo-Website=http://www.kde.org
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true

View File

@@ -0,0 +1,17 @@
{
"Encoding": "UTF-8",
"KPlugin": {
"Description": "KWin FakeInput based event handler for KRfb",
"Description[x-test]": "xxKWin FakeInput based event handler for KRfbxx",
"EnabledByDefault": true,
"Id": "fakeinput",
"License": "GPL",
"Name": "KWin FakeInput Event handler for KRfb",
"Name[x-test]": "xxKWin FakeInput Event handler for KRfbxx",
"ServiceTypes": [
"krfb/events"
],
"Version": "0.1",
"Website": "http://www.kde.org"
}
}

23
events/x11/CMakeLists.txt Normal file
View File

@@ -0,0 +1,23 @@
include_directories (${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
set (krfb_events_x11_SRCS
x11events.cpp
x11eventsplugin.cpp
)
add_library(krfb_events_x11
MODULE
${krfb_events_x11_SRCS}
)
target_link_libraries (krfb_events_x11
${X11_XTest_LIB}
KF5::CoreAddons
krfbprivate
)
install (TARGETS krfb_events_x11
DESTINATION ${PLUGIN_INSTALL_DIR}/krfb
)

View File

@@ -0,0 +1,17 @@
[Desktop Entry]
Encoding=UTF-8
Comment=X11 XFakeInput based event handler for KRfb
Comment[ru]=Обработчик событий для KRfb на базе XFakeInput
Comment[x-test]=xxX11 XFakeInput based event handler for KRfbxx
Name=X11 XFakeInput based event handler for KRfb
Name[ru]=Обработчик событий для KRfb на базе XFakeInput
Name[x-test]=xxX11 XFakeInput based event handler for KRfbxx
Type=Service
ServiceTypes=krfb/events
X-KDE-Library=krfb_events_x11
X-KDE-PluginInfo-Name=x11
X-KDE-PluginInfo-Version=0.1
X-KDE-PluginInfo-Website=http://www.kde.org
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true

View File

@@ -0,0 +1,17 @@
{
"Encoding": "UTF-8",
"KPlugin": {
"Description": "X11 XFakeInput based event handler for KRfb",
"Description[x-test]": "xxX11 XFakeInput based event handler for KRfbxx",
"EnabledByDefault": true,
"Id": "x11",
"License": "GPL",
"Name": "X11 Event handler for KRfb",
"Name[x-test]": "xxX11 Event handler for KRfbxx",
"ServiceTypes": [
"krfb/events"
],
"Version": "0.1",
"Website": "http://www.kde.org"
}
}

200
events/x11/x11events.cpp Normal file
View File

@@ -0,0 +1,200 @@
/*
This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "x11events.h"
#include <QApplication>
#include <QX11Info>
#include <QDesktopWidget>
#include <QGlobalStatic>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
enum {
LEFTSHIFT = 1,
RIGHTSHIFT = 2,
ALTGR = 4
};
class EventData
{
public:
EventData();
//keyboard
Display *dpy;
signed char modifiers[0x100];
KeyCode keycodes[0x100];
KeyCode leftShiftCode;
KeyCode rightShiftCode;
KeyCode altGrCode;
char modifierState;
//mouse
int buttonMask;
private:
void init();
};
Q_GLOBAL_STATIC(EventData, data)
EventData::EventData()
{
init();
}
void EventData::init()
{
dpy = QX11Info::display();
buttonMask = 0;
//initialize keycodes
KeySym key, *keymap;
int i, j, minkey, maxkey, syms_per_keycode;
memset(modifiers, -1, sizeof(modifiers));
XDisplayKeycodes(dpy, &minkey, &maxkey);
Q_ASSERT(minkey >= 8);
Q_ASSERT(maxkey < 256);
keymap = (KeySym *) XGetKeyboardMapping(dpy, minkey,
(maxkey - minkey + 1),
&syms_per_keycode);
Q_ASSERT(keymap);
for (i = minkey; i <= maxkey; i++) {
for (j = 0; j < syms_per_keycode; j++) {
key = keymap[(i-minkey)*syms_per_keycode+j];
if (key >= ' ' && key < 0x100 && i == XKeysymToKeycode(dpy, key)) {
keycodes[key] = i;
modifiers[key] = j;
}
}
}
leftShiftCode = XKeysymToKeycode(dpy, XK_Shift_L);
rightShiftCode = XKeysymToKeycode(dpy, XK_Shift_R);
altGrCode = XKeysymToKeycode(dpy, XK_Mode_switch);
XFree((char *)keymap);
}
/* this function adjusts the modifiers according to mod (as from modifiers) and data->modifierState */
static void tweakModifiers(signed char mod, bool down)
{
bool isShift = data->modifierState & (LEFTSHIFT | RIGHTSHIFT);
if (mod < 0) {
return;
}
if (isShift && mod != 1) {
if (data->modifierState & LEFTSHIFT) {
XTestFakeKeyEvent(data->dpy, data->leftShiftCode,
down, CurrentTime);
}
if (data->modifierState & RIGHTSHIFT) {
XTestFakeKeyEvent(data->dpy, data->rightShiftCode,
down, CurrentTime);
}
}
if (!isShift && mod == 1) {
XTestFakeKeyEvent(data->dpy, data->leftShiftCode,
down, CurrentTime);
}
if ((data->modifierState & ALTGR) && mod != 2) {
XTestFakeKeyEvent(data->dpy, data->altGrCode,
!down, CurrentTime);
}
if (!(data->modifierState & ALTGR) && mod == 2) {
XTestFakeKeyEvent(data->dpy, data->altGrCode,
down, CurrentTime);
}
}
void X11EventHandler::handleKeyboard(bool down, rfbKeySym keySym)
{
#define ADJUSTMOD(sym,state) \
if(keySym==sym) { if(down) data->modifierState|=state; else data->modifierState&=~state; }
ADJUSTMOD(XK_Shift_L, LEFTSHIFT);
ADJUSTMOD(XK_Shift_R, RIGHTSHIFT);
ADJUSTMOD(XK_Mode_switch, ALTGR);
if (keySym >= ' ' && keySym < 0x100) {
KeyCode k;
if (down) {
tweakModifiers(data->modifiers[keySym], True);
}
k = data->keycodes[keySym];
if (k != NoSymbol) {
XTestFakeKeyEvent(data->dpy, k, down, CurrentTime);
}
if (down) {
tweakModifiers(data->modifiers[keySym], False);
}
} else {
KeyCode k = XKeysymToKeycode(data->dpy, keySym);
if (k != NoSymbol) {
XTestFakeKeyEvent(data->dpy, k, down, CurrentTime);
}
}
}
void X11EventHandler::handlePointer(int buttonMask, int x, int y)
{
QDesktopWidget *desktopWidget = QApplication::desktop();
int screen = desktopWidget->screenNumber();
if (screen < 0) {
screen = 0;
}
XTestFakeMotionEvent(data->dpy, screen, x, y, CurrentTime);
for (int i = 0; i < 5; i++) {
if ((data->buttonMask&(1 << i)) != (buttonMask&(1 << i))) {
XTestFakeButtonEvent(data->dpy,
i + 1,
(buttonMask&(1 << i)) ? True : False,
CurrentTime);
}
}
data->buttonMask = buttonMask;
}
#include "x11events.moc"

40
events/x11/x11events.h Normal file
View File

@@ -0,0 +1,40 @@
/*
This file is part of the KDE project
Copyright (C) 2016 by Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef EVENTS_X11EVENTS_H
#define EVENTS_X11EVENTS_H
#include "../../krfb/events.h"
class X11EventHandler : public EventHandler
{
Q_OBJECT
public:
explicit X11EventHandler(QObject *parent = nullptr)
: EventHandler(parent)
{
};
virtual void handleKeyboard(bool down, rfbKeySym key);
virtual void handlePointer(int buttonMask, int x, int y);
};
#endif

View File

@@ -0,0 +1,45 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "x11eventsplugin.h"
#include "x11events.h"
#include <KPluginFactory>
#include <QX11Info>
K_PLUGIN_FACTORY_WITH_JSON(X11EventsPluginFactory, "krfb_events_x11.json",
registerPlugin<X11EventsPlugin>();)
X11EventsPlugin::X11EventsPlugin(QObject *parent, const QVariantList &args)
: EventsPlugin(parent, args)
{
}
EventHandler *X11EventsPlugin::eventHandler()
{
// works only under X11
if(!QX11Info::isPlatformX11())
return nullptr;
return new X11EventHandler();
}
#include "x11eventsplugin.moc"

View File

@@ -0,0 +1,45 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_EVENTS_X11_X11EVENTSPLUGIN_H
#define KRFB_EVENTS_X11_X11EVENTSPLUGIN_H
#include "eventsplugin.h"
#include <QWidget>
class EventHandler;
class X11EventsPlugin : public EventsPlugin
{
Q_OBJECT
public:
X11EventsPlugin(QObject *parent, const QVariantList &args);
virtual ~X11EventsPlugin() = default;
EventHandler *eventHandler() override;
private:
Q_DISABLE_COPY(X11EventsPlugin)
};
#endif // Header guard

View File

@@ -1,3 +1,5 @@
add_subdirectory (qt)
add_subdirectory (x11)
if(HAVE_GBM)
add_subdirectory (gbm)
endif()

View File

@@ -0,0 +1,29 @@
include_directories (${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
set (krfb_framebuffer_gbm_SRCS
logging.cpp
gbmframebuffer.cpp
gbmframebufferplugin.cpp
)
add_library(krfb_framebuffer_gbm
MODULE
${krfb_framebuffer_gbm_SRCS}
)
target_link_libraries (krfb_framebuffer_gbm
Qt5::Core
Qt5::Gui
KF5::CoreAddons
KF5::WaylandClient
${epoxy_LIBRARY}
Libdrm::Libdrm
gbm::gbm
krfbprivate
)
install (TARGETS krfb_framebuffer_gbm
DESTINATION ${PLUGIN_INSTALL_DIR}/krfb
)

View File

@@ -0,0 +1,330 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "gbmframebuffer.h"
#include "logging.h"
#include "gbmframebuffer.moc"
// KWayland
#include <KWayland/Client/registry.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/remote_access.h>
// Qt
#include <QApplication>
#include <QScreen>
#include <QtCore/QThread>
// system
#include <fcntl.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <libdrm/drm_mode.h>
static QString formatGLError(GLenum err)
{
switch(err) {
case GL_NO_ERROR: return QStringLiteral("GL_NO_ERROR");
case GL_INVALID_ENUM: return QStringLiteral("GL_INVALID_ENUM");
case GL_INVALID_VALUE: return QStringLiteral("GL_INVALID_VALUE");
case GL_INVALID_OPERATION: return QStringLiteral("GL_INVALID_OPERATION");
case GL_STACK_OVERFLOW: return QStringLiteral("GL_STACK_OVERFLOW");
case GL_STACK_UNDERFLOW: return QStringLiteral("GL_STACK_UNDERFLOW");
case GL_OUT_OF_MEMORY: return QStringLiteral("GL_OUT_OF_MEMORY");
default: return QLatin1String("0x") + QString::number(err, 16);
}
}
GbmFrameBuffer::GbmFrameBuffer(WId id, QObject *parent)
: FrameBuffer(id, parent)
{
// TODO: check out the case when new resolution was applied on KWin side
// TODO: check possibility of multi-screen configuration
QSize size = QApplication::screens().first()->size();
m_img = new QImage(size, QImage::Format_ARGB32);
fb = reinterpret_cast<char*>(m_img->bits());
// open DRM device
setupDrm();
// get EGL client extensions
initClientEglExtensions();
// initialize EGL context and display
initEgl();
// get KWin connection
initWaylandConnection();
}
void GbmFrameBuffer::setupDrm()
{
m_drmFd = open("/dev/dri/card0", O_RDWR);
m_gbmDevice = gbm_create_device(m_drmFd);
if(!m_gbmDevice) {
qCCritical(KRFB_GBM) << "Cannot create GBM device:" << strerror(errno);
m_valid = false;
return;
}
}
// cloned from KWin AbstractEglBackend
void GbmFrameBuffer::initClientEglExtensions()
{
if(!m_valid)
return;
// Get the list of client extensions
const char* clientExtensionsCString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
const QByteArray clientExtensionsString = QByteArray::fromRawData(clientExtensionsCString, qstrlen(clientExtensionsCString));
if (clientExtensionsString.isEmpty()) {
// If eglQueryString() returned NULL, the implementation doesn't support
// EGL_EXT_client_extensions. Expect an EGL_BAD_DISPLAY error.
qCCritical(KRFB_GBM) << "No client extensions defined!" << formatGLError(eglGetError());
m_valid = false;
}
m_egl.extensions = clientExtensionsString.split(' ');
}
void GbmFrameBuffer::initEgl()
{
if(!m_valid)
return;
// Use eglGetPlatformDisplayEXT() to get the display pointer
// if the implementation supports it.
if (!m_egl.extensions.contains(QByteArrayLiteral("EGL_EXT_platform_base")) ||
!m_egl.extensions.contains(QByteArrayLiteral("EGL_MESA_platform_gbm"))) {
qCCritical(KRFB_GBM) << "One of required EGL extensions is missing";
m_valid = false;
return;
}
m_egl.display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, m_gbmDevice, nullptr);
if (m_egl.display == EGL_NO_DISPLAY) {
qCCritical(KRFB_GBM) << "Error during obtaining EGL display:" << formatGLError(eglGetError());
m_valid = false;
return;
}
EGLint major, minor;
if (eglInitialize(m_egl.display, &major, &minor) == EGL_FALSE) {
qCCritical(KRFB_GBM) << "Error during eglInitialize:" << formatGLError(eglGetError());
m_valid = false;
return;
}
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
qCCritical(KRFB_GBM) << "bind OpenGL API failed";
m_valid = false;
return;
}
qCDebug(KRFB_GBM) << "Egl Initialize succeeded";
qCDebug(KRFB_GBM) << QString("EGL version: %1.%2").arg(major).arg(minor);
m_egl.context = eglCreateContext(m_egl.display, nullptr, EGL_NO_CONTEXT, nullptr);
if(m_egl.context == EGL_NO_CONTEXT) {
qCCritical(KRFB_GBM) << "Couldn't create EGL context:" << formatGLError(eglGetError());
m_valid = false;
}
}
void GbmFrameBuffer::initWaylandConnection()
{
if(!m_valid)
return;
using namespace KWayland::Client;
ConnectionThread *conn = ConnectionThread::fromApplication(this);
if(!conn) { // trying to instantiate wayland not having a wayland platform?
m_valid = false;
return;
}
// what do we do if server dies?
// since we use foreign connection, the whole application will be disconnected,
// not only plugin, let's assume application will die anyway
Registry *registry = new Registry(this);
registry->create(conn);
connect(registry, &Registry::remoteAccessManagerAnnounced, this,
[this, registry] (qint32 name, qint32 version) {
m_interface = registry->createRemoteAccessManager(name, version, this);
connect(m_interface, &RemoteAccessManager::bufferReady, this, &GbmFrameBuffer::obtainBuffer);
}
);
registry->setup();
}
void GbmFrameBuffer::obtainBuffer(KWayland::Client::RemoteBuffer *rbuf)
{
using namespace KWayland::Client;
connect(rbuf, &RemoteBuffer::paramsObtained, this,
[this, rbuf] (qint32 fd, quint32 width, quint32 height, quint32 stride, quint32 format) {
updateHandle(fd, width, height, stride, format);
// deleteLater() is not working due to QTBUG-18434 (or similar)
// TODO: try with Qt 5.8.0
delete rbuf;
}
);
}
void GbmFrameBuffer::updateHandle(qint32 gbmHandle, quint32 width, quint32 height, quint32 stride, quint32 format)
{
qCDebug(KRFB_GBM) << QString("Incoming GBM fd %1, %2x%3, stride %4, fourcc 0x%5")
.arg(gbmHandle).arg(width).arg(height).arg(stride).arg(QString::number(format, 16));
if(!gbm_device_is_format_supported(m_gbmDevice, format, GBM_BO_USE_SCANOUT)) {
qCCritical(KRFB_GBM) << "GBM format is not supported by device!";
return;
}
if(this->width() != (int) width || this->height() != (int) height) {
qCCritical(KRFB_GBM) << QString("Size of GBM buffer (%3x%4) is not equal to expected (%1x%2)!")
.arg(this->width()).arg(this->height()).arg(width).arg(height);
return;
}
// import GBM buffer that was passed from KWin
gbm_import_fd_data importInfo = {gbmHandle, width, height, stride, format};
gbm_bo *imported = gbm_bo_import(m_gbmDevice, GBM_BO_IMPORT_FD, &importInfo, GBM_BO_USE_SCANOUT);
if(!imported) {
qCCritical(KRFB_GBM) << "Cannot import passed GBM fd:" << strerror(errno);
return;
}
// bind context to render thread
eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context);
// create EGL image from imported BO
EGLImageKHR image = eglCreateImageKHR(m_egl.display, NULL, EGL_NATIVE_PIXMAP_KHR, imported, NULL);
if (image == EGL_NO_IMAGE_KHR) {
qCCritical(KRFB_GBM) << "Error creating EGLImageKHR" << formatGLError(glGetError());
return;
}
// create GL 2D texture for framebuffer
GLuint texture;
glGenTextures(1, &texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, texture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
// bind framebuffer to copy pixels from
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
qCCritical(KRFB_GBM) << "glCheckFramebufferStatus failed:" << formatGLError(glGetError());
glDeleteTextures(1, &texture);
glDeleteFramebuffers(1, &framebuffer);
eglDestroyImageKHR(m_egl.display, image);
return;
}
glViewport(0, 0, width, height);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_img->bits());
tiles.append(m_img->rect());
// unbind all
glDeleteTextures(1, &texture);
glDeleteFramebuffers(1, &framebuffer);
eglDestroyImageKHR(m_egl.display, image);
// from this point buffer object can be safely freed
close(gbmHandle);
}
GbmFrameBuffer::~GbmFrameBuffer()
{
fb = nullptr;
delete m_img;
m_img = nullptr;
if(m_egl.context != EGL_NO_CONTEXT) {
eglDestroyContext(m_egl.display, m_egl.context);
}
if(m_gbmDevice) {
gbm_device_destroy(m_gbmDevice);
}
if(m_drmFd) {
close(m_drmFd);
}
}
int GbmFrameBuffer::depth()
{
return m_img->depth();
}
int GbmFrameBuffer::height()
{
return m_img->height();
}
int GbmFrameBuffer::width()
{
return m_img->width();
}
void GbmFrameBuffer::getServerFormat(rfbPixelFormat &format)
{
format.bitsPerPixel = 32;
format.depth = 32;
format.trueColour = true;
format.bigEndian = false;
// GL images have different shift
format.redShift = 0;
format.greenShift = 8;
format.blueShift = 16;
format.redMax = 0xff;
format.greenMax = 0xff;
format.blueMax = 0xff;
}
void GbmFrameBuffer::updateFrameBuffer()
{
// do nothing
}
int GbmFrameBuffer::paddedWidth()
{
return m_img->bytesPerLine();
}
void GbmFrameBuffer::startMonitor()
{
// not needed - we get events as a signals from Wayland interface
// no other updates are possible
}
void GbmFrameBuffer::stopMonitor()
{
}

View File

@@ -0,0 +1,85 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_FRAMEBUFFER_GBM_GBMFRAMEBUFFER_H
#define KRFB_FRAMEBUFFER_GBM_GBMFRAMEBUFFER_H
#include "framebuffer.h"
// Qt
#include <QImage>
// system
#include <gbm.h>
#include <epoxy/egl.h>
#include <epoxy/gl.h>
namespace KWayland
{
namespace Client
{
class RemoteAccessManager;
class RemoteBuffer;
}
}
/**
@author Oleg Chernovskiy <adonai@xaker.ru>
*/
class GbmFrameBuffer : public FrameBuffer
{
Q_OBJECT
public:
explicit GbmFrameBuffer(WId id, QObject *parent = 0);
~GbmFrameBuffer();
int depth() override;
int height() override;
int width() override;
int paddedWidth() override;
void getServerFormat(rfbPixelFormat &format) override;
void startMonitor() override;
void stopMonitor() override;
inline bool isValid() { return m_valid; };
public Q_SLOTS:
void updateFrameBuffer();
private:
void initWaylandConnection();
void setupDrm();
void initClientEglExtensions();
void initEgl();
void obtainBuffer(KWayland::Client::RemoteBuffer *rbuf);
void updateHandle(qint32 gbmHandle, quint32 width, quint32 height, quint32 stride, quint32 format);
qint32 m_drmFd = 0; // for GBM buffer mmap
gbm_device *m_gbmDevice = nullptr; // for passed GBM buffer retrieval
struct {
QList<QByteArray> extensions;
EGLDisplay display = EGL_NO_DISPLAY;
EGLContext context = EGL_NO_CONTEXT;
} m_egl;
KWayland::Client::RemoteAccessManager *m_interface = nullptr;
QImage *m_img;
bool m_valid = true;
};
#endif

View File

@@ -0,0 +1,50 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "gbmframebufferplugin.h"
#include "gbmframebuffer.h"
#include <KPluginFactory>
K_PLUGIN_FACTORY_WITH_JSON(GbmFrameBufferPluginFactory, "krfb_framebuffer_gbm.json",
registerPlugin<GbmFrameBufferPlugin>();)
GbmFrameBufferPlugin::GbmFrameBufferPlugin(QObject *parent, const QVariantList &args)
: FrameBufferPlugin(parent, args)
{
}
GbmFrameBufferPlugin::~GbmFrameBufferPlugin()
{
}
FrameBuffer *GbmFrameBufferPlugin::frameBuffer(WId id)
{
auto p = new GbmFrameBuffer(id);
if (!p->isValid()) {
delete p;
return nullptr;
}
return p;
}
#include "gbmframebufferplugin.moc"

View File

@@ -0,0 +1,45 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_FRAMEBUFFER_GBM_GBMFRAMEBUFFERPLUGIN_H
#define KRFB_FRAMEBUFFER_GBM_GBMFRAMEBUFFERPLUGIN_H
#include "framebufferplugin.h"
#include <QWidget>
class FrameBuffer;
class GbmFrameBufferPlugin : public FrameBufferPlugin
{
Q_OBJECT
public:
GbmFrameBufferPlugin(QObject *parent, const QVariantList &args);
virtual ~GbmFrameBufferPlugin();
FrameBuffer *frameBuffer(WId id) override;
private:
Q_DISABLE_COPY(GbmFrameBufferPlugin)
};
#endif // Header guard

View File

@@ -0,0 +1,62 @@
{
"Encoding": "UTF-8",
"KPlugin": {
"Description": "GBM based Framebuffer for KRfb.",
"Description[ca@valencia]": "«Framebuffer» basat en GBM per al KRfb.",
"Description[ca]": "«Framebuffer» basat en GBM per al KRfb.",
"Description[cs]": "Framebuffer založený na GBM pro KRfb.",
"Description[de]": "GBM-basierter Framebuffer für KRfb",
"Description[es]": "Framebuffer basado en GBM para KRfb.",
"Description[fi]": "QT-perustainen Kehyspuskuri KRfb:lle",
"Description[gl]": "Framebuffer baseado en GBM para KRfb.",
"Description[it]": "Framebuffer basato su GBM per KRfb.",
"Description[ko]": "KRfb용 GBM 기반 프레임버퍼입니다.",
"Description[nl]": "Op GBM gebaseerd framebuffer voor KRfb.",
"Description[pl]": "Bufor ramki na podstawie GBM dla KRfb.",
"Description[pt]": "'Framebuffer' baseado no GBM para o KRfb.",
"Description[pt_BR]": "Framebuffer baseado no GBM para o KRfb.",
"Description[sk]": "Framebuffer založený na GBM pre KRfb.",
"Description[sl]": "Slikovni medpomnilnik za KRfb, ki temelji na GBM",
"Description[sr@ijekavian]": "Кадробафер за КРФБ на основу КуТу",
"Description[sr@ijekavianlatin]": "Kadrobafer za KRFB na osnovu GBMu",
"Description[sr@latin]": "Kadrobafer za KRFB na osnovu GBMu",
"Description[sr]": "Кадробафер за КРФБ на основу КуТу",
"Description[sv]": "X11-rambuffert för Krfb.",
"Description[uk]": "Заснований на GBM буфер кадрів для KRfb.",
"Description[x-test]": "xxGBM based Framebuffer for KRfb.xx",
"Description[zh_CN]": "KRfb 的基于 GBM 的帧缓冲。",
"EnabledByDefault": true,
"Id": "gbm",
"License": "GPL",
"Name": "GBM Framebuffer for KRfb",
"Name[ast]": "Framebuffer GBM pa KRfb",
"Name[ca@valencia]": "«Framebuffer» GBM per al KRfb.",
"Name[ca]": "«Framebuffer» GBM per al KRfb.",
"Name[cs]": "GBM Framebuffer pro KRfb",
"Name[de]": "GBM-Framebuffer für KRfb",
"Name[es]": "Framebuffer de GBM para KRfb",
"Name[fi]": "QT-kehyspuskuri KRfb:lle",
"Name[gl]": "Framebuffer de GBM para KRfb",
"Name[it]": "Framebuffer GBM per KRfb",
"Name[ko]": "KRfb용 GBM 프레임버퍼",
"Name[nl]": "GBM-framebuffer voor KRfb",
"Name[pl]": "Bufor ramki GBM dla KRfb",
"Name[pt]": "'Framebuffer' do GBM para o KRfb",
"Name[pt_BR]": "Framebuffer do GBM para o KRfb",
"Name[sk]": "GBM Framebuffer pre KRfb",
"Name[sl]": "Slikovni medpomnilnik GBM za KRfb",
"Name[sr@ijekavian]": "КуТ‑ов кадробафер за КРФБ",
"Name[sr@ijekavianlatin]": "GBMov kadrobafer za KRFB",
"Name[sr@latin]": "GBMov kadrobafer za KRFB",
"Name[sr]": "КуТ‑ов кадробафер за КРФБ",
"Name[sv]": "X11-rambuffert för Krfb",
"Name[uk]": "Буфер кадрів на GBM для KRfb",
"Name[x-test]": "xxGBM Framebuffer for KRfbxx",
"Name[zh_CN]": "KRfb 的 GBM 帧缓冲",
"ServiceTypes": [
"krfb/framebuffer"
],
"Version": "0.1",
"Website": "http://www.kde.org"
}
}

View File

@@ -0,0 +1,21 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "logging.h"
Q_LOGGING_CATEGORY(KRFB_GBM, "krfb-gbm", QtCriticalMsg)

View File

@@ -0,0 +1,26 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_FRAMEBUFFER_GBM_LOGGING
#define KRFB_FRAMEBUFFER_GBM_LOGGING
#include <QDebug>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(KRFB_GBM)
#endif

View File

@@ -23,9 +23,10 @@
#include "qtframebuffer.h"
#include <KPluginFactory>
#include <QX11Info>
K_PLUGIN_FACTORY_WITH_JSON(QtFrameBufferPluginFactory, "krfb_framebuffer_qt.json",
registerPlugin<QtFrameBufferPlugin>();)
registerPlugin<QtFrameBufferPlugin>();)
QtFrameBufferPlugin::QtFrameBufferPlugin(QObject *parent, const QVariantList &args)
: FrameBufferPlugin(parent, args)
@@ -38,6 +39,10 @@ QtFrameBufferPlugin::~QtFrameBufferPlugin()
FrameBuffer *QtFrameBufferPlugin::frameBuffer(WId id)
{
// works only under X11
if(!QX11Info::isPlatformX11())
return nullptr;
return new QtFrameBuffer(id);
}

View File

@@ -23,9 +23,10 @@
#include "x11framebuffer.h"
#include <KPluginFactory>
#include <QX11Info>
K_PLUGIN_FACTORY_WITH_JSON(X11FrameBufferPluginFactory, "krfb_framebuffer_x11.json",
registerPlugin<X11FrameBufferPlugin>();)
registerPlugin<X11FrameBufferPlugin>();)
X11FrameBufferPlugin::X11FrameBufferPlugin(QObject *parent, const QVariantList &args)
: FrameBufferPlugin(parent, args)
@@ -38,6 +39,10 @@ X11FrameBufferPlugin::~X11FrameBufferPlugin()
FrameBuffer *X11FrameBufferPlugin::frameBuffer(WId id)
{
// works only under X11
if(!QX11Info::isPlatformX11())
return nullptr;
return new X11FrameBuffer(id);
}

View File

@@ -11,6 +11,8 @@ include(GenerateExportHeader)
set (krfbprivate_SRCS
framebuffer.cpp
framebufferplugin.cpp
events.cpp
eventsplugin.cpp
)
add_library (krfbprivate
@@ -39,6 +41,7 @@ install (TARGETS krfbprivate
install (FILES
krfb-framebuffer.desktop
krfb-events.desktop
DESTINATION ${SERVICETYPES_INSTALL_DIR}
)
@@ -48,8 +51,8 @@ install (FILES
set (krfb_SRCS
connectiondialog.cpp
events.cpp
framebuffermanager.cpp
eventsmanager.cpp
main.cpp
mainwindow.cpp
sockethelpers.cpp
@@ -118,4 +121,4 @@ install(FILES org.kde.krfb.appdata.xml
install (FILES krfb.notifyrc
DESTINATION ${DATA_INSTALL_DIR}/krfb
)

View File

@@ -24,177 +24,9 @@
#include "events.h"
#include <QApplication>
#include <QX11Info>
#include <QDesktopWidget>
#include <QGlobalStatic>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
enum {
LEFTSHIFT = 1,
RIGHTSHIFT = 2,
ALTGR = 4
};
class EventData
EventHandler::EventHandler(QObject *parent)
: QObject(parent)
{
public:
EventData();
//keyboard
Display *dpy;
signed char modifiers[0x100];
KeyCode keycodes[0x100];
KeyCode leftShiftCode;
KeyCode rightShiftCode;
KeyCode altGrCode;
char modifierState;
//mouse
int buttonMask;
private:
void init();
};
Q_GLOBAL_STATIC(EventData, data)
EventData::EventData()
{
init();
}
void EventData::init()
{
dpy = QX11Info::display();
buttonMask = 0;
//initialize keycodes
KeySym key, *keymap;
int i, j, minkey, maxkey, syms_per_keycode;
memset(modifiers, -1, sizeof(modifiers));
XDisplayKeycodes(dpy, &minkey, &maxkey);
Q_ASSERT(minkey >= 8);
Q_ASSERT(maxkey < 256);
keymap = (KeySym *) XGetKeyboardMapping(dpy, minkey,
(maxkey - minkey + 1),
&syms_per_keycode);
Q_ASSERT(keymap);
for (i = minkey; i <= maxkey; i++) {
for (j = 0; j < syms_per_keycode; j++) {
key = keymap[(i-minkey)*syms_per_keycode+j];
if (key >= ' ' && key < 0x100 && i == XKeysymToKeycode(dpy, key)) {
keycodes[key] = i;
modifiers[key] = j;
}
}
}
leftShiftCode = XKeysymToKeycode(dpy, XK_Shift_L);
rightShiftCode = XKeysymToKeycode(dpy, XK_Shift_R);
altGrCode = XKeysymToKeycode(dpy, XK_Mode_switch);
XFree((char *)keymap);
}
/* this function adjusts the modifiers according to mod (as from modifiers) and data->modifierState */
static void tweakModifiers(signed char mod, bool down)
{
bool isShift = data->modifierState & (LEFTSHIFT | RIGHTSHIFT);
if (mod < 0) {
return;
}
if (isShift && mod != 1) {
if (data->modifierState & LEFTSHIFT) {
XTestFakeKeyEvent(data->dpy, data->leftShiftCode,
down, CurrentTime);
}
if (data->modifierState & RIGHTSHIFT) {
XTestFakeKeyEvent(data->dpy, data->rightShiftCode,
down, CurrentTime);
}
}
if (!isShift && mod == 1) {
XTestFakeKeyEvent(data->dpy, data->leftShiftCode,
down, CurrentTime);
}
if ((data->modifierState & ALTGR) && mod != 2) {
XTestFakeKeyEvent(data->dpy, data->altGrCode,
!down, CurrentTime);
}
if (!(data->modifierState & ALTGR) && mod == 2) {
XTestFakeKeyEvent(data->dpy, data->altGrCode,
down, CurrentTime);
}
}
void EventHandler::handleKeyboard(bool down, rfbKeySym keySym)
{
#define ADJUSTMOD(sym,state) \
if(keySym==sym) { if(down) data->modifierState|=state; else data->modifierState&=~state; }
ADJUSTMOD(XK_Shift_L, LEFTSHIFT);
ADJUSTMOD(XK_Shift_R, RIGHTSHIFT);
ADJUSTMOD(XK_Mode_switch, ALTGR);
if (keySym >= ' ' && keySym < 0x100) {
KeyCode k;
if (down) {
tweakModifiers(data->modifiers[keySym], True);
}
k = data->keycodes[keySym];
if (k != NoSymbol) {
XTestFakeKeyEvent(data->dpy, k, down, CurrentTime);
}
if (down) {
tweakModifiers(data->modifiers[keySym], False);
}
} else {
KeyCode k = XKeysymToKeycode(data->dpy, keySym);
if (k != NoSymbol) {
XTestFakeKeyEvent(data->dpy, k, down, CurrentTime);
}
}
}
void EventHandler::handlePointer(int buttonMask, int x, int y)
{
QDesktopWidget *desktopWidget = QApplication::desktop();
int screen = desktopWidget->screenNumber();
if (screen < 0) {
screen = 0;
}
XTestFakeMotionEvent(data->dpy, screen, x, y, CurrentTime);
for (int i = 0; i < 5; i++) {
if ((data->buttonMask&(1 << i)) != (buttonMask&(1 << i))) {
XTestFakeButtonEvent(data->dpy,
i + 1,
(buttonMask&(1 << i)) ? True : False,
CurrentTime);
}
}
data->buttonMask = buttonMask;
}
#include "events.moc"

View File

@@ -26,12 +26,18 @@
#define EVENTS_H
#include "rfb.h"
#include "krfbprivate_export.h"
class EventHandler
#include <QObject>
class KRFBPRIVATE_EXPORT EventHandler : public QObject
{
Q_OBJECT
public:
static void handleKeyboard(bool down, rfbKeySym key);
static void handlePointer(int buttonMask, int x, int y);
explicit EventHandler(QObject *parent = nullptr);
virtual ~EventHandler() = default;
virtual void handleKeyboard(bool down, rfbKeySym key) = 0;
virtual void handlePointer(int buttonMask, int x, int y) = 0;
};
#endif

118
krfb/eventsmanager.cpp Normal file
View File

@@ -0,0 +1,118 @@
/* This file is part of the KDE project
Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
@author George Goldberg <george.goldberg@collabora.co.uk>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "eventsmanager.h"
#include "eventsplugin.h"
#include "krfbconfig.h"
#include <QDebug>
#include <QGlobalStatic>
#include <KPluginFactory>
#include <KPluginLoader>
#include <KPluginMetaData>
#include <QtCore/QSharedPointer>
class EventsManagerStatic
{
public:
EventsManager instance;
};
Q_GLOBAL_STATIC(EventsManagerStatic, eventsManagerStatic)
EventsManager::EventsManager()
{
//qDebug();
loadPlugins();
}
EventsManager::~EventsManager()
{
//qDebug();
}
EventsManager *EventsManager::instance()
{
//qDebug();
return &eventsManagerStatic->instance;
}
void EventsManager::loadPlugins()
{
//qDebug();
const QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("krfb"), [](const KPluginMetaData & md) {
return md.serviceTypes().contains(QStringLiteral("krfb/events"));
});
QVectorIterator<KPluginMetaData> i(plugins);
i.toBack();
QSet<QString> unique;
while (i.hasPrevious()) {
KPluginMetaData data = i.previous();
// only load plugins once, even if found multiple times!
if (unique.contains(data.name()))
continue;
KPluginFactory *factory = KPluginLoader(data.fileName()).factory();
if (!factory) {
qDebug() << "KPluginFactory could not load the plugin:" << data.fileName();
} else {
qDebug() << "found plugin at " << data.fileName();
}
EventsPlugin *plugin = factory->create<EventsPlugin>(this);
if (plugin) {
m_plugins.insert(data.pluginId(), plugin);
qDebug() << "Loaded plugin with name " << data.pluginId();
} else {
qDebug() << "unable to load plugin for " << data.fileName();
}
unique.insert (data.name());
}
}
QSharedPointer<EventHandler> EventsManager::eventHandler()
{
QMap<QString, EventsPlugin *>::const_iterator iter = m_plugins.constBegin();
while (iter != m_plugins.constEnd()) {
QSharedPointer<EventHandler> eventHandler(iter.value()->eventHandler());
if (eventHandler)
return eventHandler;
++iter;
}
// No valid events plugin found.
qDebug() << "No valid event handlers found. returning null.";
return QSharedPointer<EventHandler>();
}
#include "eventsmanager.moc"

63
krfb/eventsmanager.h Normal file
View File

@@ -0,0 +1,63 @@
/* This file is part of the KDE project
Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
@author George Goldberg <george.goldberg@collabora.co.uk>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_EVENTSMANAGER_H
#define KRFB_EVENTSMANAGER_H
#include "events.h"
#include "krfbprivate_export.h"
#include <QtCore/QMap>
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
#include <QtCore/QWeakPointer>
#include <QWidget>
class EventsPlugin;
class KPluginFactory;
class KRFBPRIVATE_EXPORT EventsManager : public QObject
{
Q_OBJECT
friend class EventsManagerStatic;
public:
static EventsManager *instance();
virtual ~EventsManager();
QSharedPointer<EventHandler> eventHandler();
private:
Q_DISABLE_COPY(EventsManager)
EventsManager();
void loadPlugins();
QMap<QString, EventsPlugin *> m_plugins;
QList<QWeakPointer<EventHandler> > m_eventHandlers;
};
#endif // Header guard

35
krfb/eventsplugin.cpp Normal file
View File

@@ -0,0 +1,35 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <kanedias@xaker.ru>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "eventsplugin.h"
#include "events.h"
EventsPlugin::EventsPlugin(QObject *parent, const QVariantList &)
: QObject(parent)
{
}
EventsPlugin::~EventsPlugin()
{
}
#include "eventsplugin.moc"

44
krfb/eventsplugin.h Normal file
View File

@@ -0,0 +1,44 @@
/* This file is part of the KDE project
Copyright (C) 2009 Collabora Ltd <info@collabora.co.uk>
@author George Goldberg <george.goldberg@collabora.co.uk>
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 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef LIB_KRFB_EVENTSPLUGIN_H
#define LIB_KRFB_EVENTSPLUGIN_H
#include "krfbprivate_export.h"
#include <QtCore/QVariantList>
#include <QWidget>
class EventHandler;
class KRFBPRIVATE_EXPORT EventsPlugin : public QObject
{
Q_OBJECT
public:
EventsPlugin(QObject *parent, const QVariantList &args);
virtual ~EventsPlugin();
virtual EventHandler *eventHandler() = 0;
};
#endif // Header guard

View File

@@ -71,25 +71,25 @@ void FrameBufferManager::loadPlugins()
i.toBack();
QSet<QString> unique;
while (i.hasPrevious()) {
KPluginMetaData data = i.previous();
KPluginMetaData data = i.previous();
// only load plugins once, even if found multiple times!
if (unique.contains(data.name()))
continue;
KPluginFactory *factory = KPluginLoader(data.fileName()).factory();
if (!factory) {
qDebug() << "KPluginFactory could not load the plugin:" << data.fileName();
} else {
qDebug() << "found plugin at " << data.fileName();
}
FrameBufferPlugin *plugin = factory->create<FrameBufferPlugin>(this);
if (plugin) {
m_plugins.insert(data.pluginId(), plugin);
qDebug() << "Loaded plugin with name " << data.pluginId();
} else {
qDebug() << "unable to load pluign for " << data.fileName();
}
KPluginFactory *factory = KPluginLoader(data.fileName()).factory();
if (!factory) {
qDebug() << "KPluginFactory could not load the plugin:" << data.fileName();
} else {
qDebug() << "found plugin at " << data.fileName();
}
FrameBufferPlugin *plugin = factory->create<FrameBufferPlugin>(this);
if (plugin) {
m_plugins.insert(data.pluginId(), plugin);
qDebug() << "Loaded plugin with name " << data.pluginId();
} else {
qDebug() << "unable to load plugin for " << data.fileName();
}
unique.insert (data.name());
}
}

7
krfb/krfb-events.desktop Normal file
View File

@@ -0,0 +1,7 @@
[Desktop Entry]
Type=ServiceType
X-KDE-ServiceType=krfb/events
Comment=Event plugins for KRfb
Comment[ru]=Модули обработки событий для Krfb
Comment[x-test]=xxEvent plugins for KRfbxx

7
krfb/krfb-events.json Normal file
View File

@@ -0,0 +1,7 @@
{
"KPlugin": {
"Description": "Events plugins for KRfb",
"Description[x-test]": "xxFrame Buffer plugins for KRfbxx"
},
"X-KDE-ServiceType": "krfb/events"
}

View File

@@ -41,6 +41,9 @@ static const char description[] = I18N_NOOP("VNC-compatible server to share "
static bool checkX11Capabilities()
{
if(!QX11Info::isPlatformX11())
return false;
int bp1, bp2, majorv, minorv;
Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2,
&majorv, &minorv);
@@ -56,6 +59,15 @@ static bool checkX11Capabilities()
return true;
}
static bool checkWaylandCapabilities()
{
if (!QGuiApplication::platformName().contains(QStringLiteral("wayland"), Qt::CaseInsensitive)) {
return false;
}
return true;
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
@@ -63,10 +75,10 @@ int main(int argc, char *argv[])
KLocalizedString::setApplicationDomain("krfb");
KAboutData aboutData("krfb",
i18n("Desktop Sharing"),
KRFB_VERSION,
i18n("Desktop Sharing"),
KRFB_VERSION,
i18n(description),
KAboutLicense::GPL,
KAboutLicense::GPL,
i18n("(c) 2009-2010, Collabora Ltd.\n"
"(c) 2007, Alessandro Praduroux\n"
"(c) 2001-2003, Tim Jansen\n"
@@ -105,7 +117,10 @@ int main(int argc, char *argv[])
app.setQuitOnLastWindowClosed(false);
if (!checkX11Capabilities()) {
bool supportsX11 = checkX11Capabilities();
bool supportsWayland = checkWaylandCapabilities();
if (!supportsWayland && !supportsX11) {
return 1;
}

View File

@@ -21,9 +21,12 @@
#include "connectiondialog.h"
#include "krfbconfig.h"
#include "sockethelpers.h"
#include "events.h"
#include "eventsmanager.h"
// Qt
#include <QtCore/QSocketNotifier>
#include <QSharedPointer>
#include <QDebug>
// system
#include <poll.h>
#include <strings.h> //for bzero()
@@ -37,6 +40,7 @@ struct RfbClient::Private
bool controlEnabled;
rfbClientPtr client;
QSocketNotifier *notifier;
QSharedPointer<EventHandler> eventHandler;
QString remoteAddressString;
};
@@ -49,6 +53,8 @@ RfbClient::RfbClient(rfbClientPtr client, QObject* parent)
d->notifier = new QSocketNotifier(client->sock, QSocketNotifier::Read, this);
d->notifier->setEnabled(false);
connect(d->notifier, &QSocketNotifier::activated, this, &RfbClient::onSocketActivated);
d->eventHandler = EventsManager::instance()->eventHandler();
}
RfbClient::~RfbClient()
@@ -110,14 +116,14 @@ rfbClientPtr RfbClient::getRfbClientPtr()
void RfbClient::handleKeyboardEvent(bool down, rfbKeySym keySym)
{
if (d->controlEnabled) {
EventHandler::handleKeyboard(down, keySym);
d->eventHandler->handleKeyboard(down, keySym);
}
}
void RfbClient::handleMouseEvent(int buttonMask, int x, int y)
{
if (d->controlEnabled) {
EventHandler::handlePointer(buttonMask, x, y);
d->eventHandler->handlePointer(buttonMask, x, y);
}
}