Skip to content

Commit

Permalink
Device integration for Wayland
Browse files Browse the repository at this point in the history
Closes: #42
  • Loading branch information
plfiorini committed Sep 2, 2023
1 parent 92779ed commit 19fed28
Show file tree
Hide file tree
Showing 28 changed files with 1,677 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ if(FEATURE_aurora_qpa)
add_subdirectory(src/plugins/platforms/eglfs/deviceintegration/eglfs_x11)
endif()
endif()
if(FEATURE_aurora_deviceintegration_wayland)
add_subdirectory(src/plugins/deviceintegration/wayland)
endif()
if(BUILD_TESTING)
if(TARGET AuroraCompositor)
add_subdirectory(tests/auto/compositor/compositor)
Expand Down
23 changes: 23 additions & 0 deletions features.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,29 @@ if(FEATURE_aurora_vulkan_server_buffer)
endif()
set(LIRI_FEATURE_aurora_vulkan_server_buffer "$<IF:${FEATURE_aurora_vulkan_server_buffer},1,0>")

# Device Integration: wayland
option(FEATURE_aurora_deviceintegration_wayland "Device Integration: wayland" ON)
if(FEATURE_aurora_deviceintegration_wayland)
find_package(EGL QUIET)
find_package(Wayland "${WAYLAND_MIN_VERSION}" COMPONENTS Egl QUIET)
find_package(KF5Wayland QUIET)

if(NOT TARGET EGL::EGL)
message(WARNING "You need EGL for Aurora::DeviceIntegration::Wayland")
set(FEATURE_aurora_deviceintegration_wayland OFF)
endif()
if(NOT TARGET Wayland::Egl)
message(WARNING "You need Wayland::Egl for Aurora::DeviceIntegration::Wayland")
set(FEATURE_aurora_deviceintegration_wayland OFF)
endif()
if(NOT KF5Wayland_FOUND)
message(WARNING "You need KWayland::Client for Aurora::DeviceIntegration::Wayland")
set(FEATURE_aurora_deviceintegration_wayland OFF)
endif()
endif()
add_feature_info("Aurora::DeviceIntegration::Wayland" FEATURE_aurora_deviceintegration_wayland "Build Wayland device integration")
set(LIRI_FEATURE_aurora_deviceintegration_wayland "$<IF:${FEATURE_aurora_deviceintegration_wayland},1,0>")

# xwayland
option(FEATURE_aurora_xwayland "XWayland support" ON)
if(FEATURE_aurora_xwayland)
Expand Down
42 changes: 42 additions & 0 deletions src/plugins/deviceintegration/wayland/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
include(ECMQtDeclareLoggingCategory)
ecm_qt_declare_logging_category(
AuroraDeviceIntegrationWayland_SOURCES
HEADER "waylandloggingcategories.h"
IDENTIFIER "Aurora::Platform::gLcWayland"
CATEGORY_NAME "aurora.platform.wayland"
DEFAULT_SEVERITY "Info"
DESCRIPTION "Aurora device integration for Wayland"
)

liri_add_plugin(AuroraDeviceIntegrationWayland
TYPE
"aurora/deviceintegration"
OUTPUT_NAME
wayland
SOURCES
eglintegration.cpp eglintegration.h
mousebuttons.cpp mousebuttons.h
waylandcursor.cpp waylandcursor.h
waylandinputmanager.cpp waylandinputmanager.h
waylandintegrationplugin.cpp waylandintegrationplugin.h
waylandkeyboard.cpp waylandkeyboard.h
waylandintegration.cpp waylandintegration.h
waylandoutput.cpp waylandoutput.h
waylandpointer.cpp waylandpointer.h
waylandscreenwindow.cpp waylandscreenwindow.h
waylandtouch.cpp waylandtouch.h
waylandwindow.cpp waylandwindow.h
wayland.json
${AuroraDeviceIntegrationWayland_SOURCES}
PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
Liri::AuroraPlatform
Liri::AuroraPlatformPrivate
EGL::EGL
Wayland::Egl
LIBRARIES
KF5::WaylandClient
)

liri_finalize_plugin(AuroraDeviceIntegrationWayland)
89 changes: 89 additions & 0 deletions src/plugins/deviceintegration/wayland/eglintegration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

#include <QByteArray>
#include <QList>

#include "eglintegration.h"
#include "waylandloggingcategories.h"
#include "waylandintegration.h"

namespace Aurora {

namespace Platform {

EglIntegration::EglIntegration(WaylandIntegration *integration)
: m_integration(integration)
{
}

EglIntegration::~EglIntegration()
{
destroy();
}

bool EglIntegration::isInitialized() const
{
return m_initialized;
}

EGLDisplay EglIntegration::display() const
{
return m_eglDisplay;
}

typedef const char *(*EGLGETERRORSTRINGPROC)(EGLint error);

bool EglIntegration::initialize()
{
if (m_initialized)
return true;

m_initialized = true;

if (hasEglExtension("EGL_EXT_platform_base")) {
if (hasEglExtension("EGL_KHR_platform_wayland")
|| hasEglExtension("EGL_EXT_platform_wayland")
|| hasEglExtension("EGL_MESA_platform_wayland")) {
static PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplay = nullptr;
if (!eglGetPlatformDisplay)
eglGetPlatformDisplay = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
eglGetProcAddress("eglGetPlatformDisplayEXT"));

m_eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, m_integration->display(),
nullptr);
} else {
qCWarning(gLcWayland) << "The EGL implementation does not support the Wayland platform";
return false;
}
} else {
QByteArray eglPlatform = qgetenv("EGL_PLATFORM");
if (eglPlatform.isEmpty())
setenv("EGL_PLATFORM", "wayland", true);

m_eglDisplay =
eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(m_integration->display()));
}

return true;
}

void EglIntegration::destroy()
{
if (m_eglDisplay != EGL_NO_DISPLAY) {
eglTerminate(m_eglDisplay);
m_eglDisplay = EGL_NO_DISPLAY;
}
}

bool EglIntegration::hasEglExtension(const char *name, EGLDisplay display)
{
QList<QByteArray> extensions =
QByteArray(reinterpret_cast<const char *>(eglQueryString(display, EGL_EXTENSIONS)))
.split(' ');
return extensions.contains(name);
}

} // namespace Platform

} // namespace Aurora
47 changes: 47 additions & 0 deletions src/plugins/deviceintegration/wayland/eglintegration.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <QPointer>

#ifndef EGL_NO_X11
# define EGL_NO_X11
#endif
#ifndef MESA_EGL_NO_X11_HEADERS
# define MESA_EGL_NO_X11_HEADERS
#endif

#include <EGL/egl.h>
#include <EGL/eglext.h>

namespace Aurora {

namespace Platform {

class WaylandIntegration;

class EglIntegration
{
public:
EglIntegration(WaylandIntegration *integration);
~EglIntegration();

bool isInitialized() const;

EGLDisplay display() const;

bool initialize();
void destroy();

static bool hasEglExtension(const char *name, EGLDisplay display = EGL_NO_DISPLAY);

private:
bool m_initialized = false;
QPointer<WaylandIntegration> m_integration;
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
};

} // namespace Platform

} // namespace Aurora
54 changes: 54 additions & 0 deletions src/plugins/deviceintegration/wayland/mousebuttons.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: 2022 David Redondo <[email protected]>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL

#include <QHash>

#include "mousebuttons.h"

#include <linux/input-event-codes.h>

namespace Aurora {

namespace Platform {

static const QHash<quint32, Qt::MouseButton> s_buttonToQtMouseButton = {
{ BTN_LEFT, Qt::LeftButton },
{ BTN_MIDDLE, Qt::MiddleButton },
{ BTN_RIGHT, Qt::RightButton },
// in QtWayland mapped like that
{ BTN_SIDE, Qt::ExtraButton1 },
// in QtWayland mapped like that
{ BTN_EXTRA, Qt::ExtraButton2 },
{ BTN_BACK, Qt::BackButton },
{ BTN_FORWARD, Qt::ForwardButton },
{ BTN_TASK, Qt::TaskButton },
// mapped like that in QtWayland
{ 0x118, Qt::ExtraButton6 },
{ 0x119, Qt::ExtraButton7 },
{ 0x11a, Qt::ExtraButton8 },
{ 0x11b, Qt::ExtraButton9 },
{ 0x11c, Qt::ExtraButton10 },
{ 0x11d, Qt::ExtraButton11 },
{ 0x11e, Qt::ExtraButton12 },
{ 0x11f, Qt::ExtraButton13 },
};

quint32 qtMouseButtonToButton(Qt::MouseButton button)
{
return s_buttonToQtMouseButton.key(button);
}

Qt::MouseButton buttonToQtMouseButton(quint32 button)
{
// All other values get mapped to ExtraButton24
// this is actually incorrect but doesn't matter in our usage
// we internally doesn't use these high extra buttons anyway
// it's only needed for recognizing whether buttons are pressed
// if multiple buttons are mapped to the value the evaluation whether
// buttons are pressed is correct and that's all we care about.
return s_buttonToQtMouseButton.value(button, Qt::ExtraButton24);
}

} // namespace Platform

} // namespace Aurora
15 changes: 15 additions & 0 deletions src/plugins/deviceintegration/wayland/mousebuttons.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2022 David Redondo <[email protected]>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL

#include <qnamespace.h>

namespace Aurora {

namespace Platform {

quint32 qtMouseButtonToButton(Qt::MouseButton button);
Qt::MouseButton buttonToQtMouseButton(quint32 button);

} // namespace Platform

} // namespace Aurora
3 changes: 3 additions & 0 deletions src/plugins/deviceintegration/wayland/wayland.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"Keys": [ "wayland" ]
}
26 changes: 26 additions & 0 deletions src/plugins/deviceintegration/wayland/waylandcursor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

#include <KWayland/Client/compositor.h>

#include "waylandcursor.h"
#include "waylandintegration.h"

namespace Aurora {

namespace Platform {

WaylandCursor::WaylandCursor(WaylandIntegration *integration, QObject *parent)
: QObject(parent)
, m_integration(integration)
, m_surface(integration->compositor()->createSurface(this))
{
}

WaylandCursor::~WaylandCursor()
{
}

} // namespace Platform

} // namespace Aurora
28 changes: 28 additions & 0 deletions src/plugins/deviceintegration/wayland/waylandcursor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <[email protected]>
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <KWayland/Client/surface.h>

namespace Aurora {

namespace Platform {

class WaylandIntegration;

class WaylandCursor : public QObject
{
Q_OBJECT
public:
explicit WaylandCursor(WaylandIntegration *integration, QObject *parent = nullptr);
~WaylandCursor();

private:
WaylandIntegration *const m_integration;
KWayland::Client::Surface *m_surface = nullptr;
};

} // namespace Platform

} // namespace Aurora
Loading

0 comments on commit 19fed28

Please sign in to comment.