-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes: #42
Showing
26 changed files
with
1,859 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
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 | ||
waylandbackend.cpp waylandbackend.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 | ||
waylandtouch.cpp waylandtouch.h | ||
waylandwindow.cpp waylandwindow.h | ||
wayland.json | ||
${AuroraDeviceIntegrationWayland_SOURCES} | ||
PUBLIC_LIBRARIES | ||
Qt::Core | ||
Qt::Gui | ||
Liri::AuroraCore | ||
Liri::AuroraPlatform | ||
Liri::AuroraPlatformPrivate | ||
Liri::AuroraXkbCommonSupport | ||
Liri::AuroraXkbCommonSupportPrivate | ||
EGL::EGL | ||
Wayland::Egl | ||
LIBRARIES | ||
Liri::AuroraGlobalPrivate | ||
KF5::WaylandClient | ||
) | ||
|
||
liri_finalize_plugin(AuroraDeviceIntegrationWayland) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <[email protected]> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <QByteArray> | ||
#include <QList> | ||
|
||
#include "eglintegration.h" | ||
#include "waylandbackend.h" | ||
#include "waylandloggingcategories.h" | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
EglIntegration::EglIntegration() | ||
{ | ||
} | ||
|
||
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, | ||
WaylandBackend::instance()->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>(WaylandBackend::instance()->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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// 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 EglIntegration | ||
{ | ||
public: | ||
EglIntegration(); | ||
~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; | ||
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY; | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"Keys": [ "wayland" ] | ||
} |
324 changes: 324 additions & 0 deletions
324
src/plugins/deviceintegration/wayland/waylandbackend.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,324 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <KWayland/Client/region.h> | ||
#include <KWayland/Client/surface.h> | ||
#include <KWayland/Client/xdgshell.h> | ||
|
||
#include "waylandbackend.h" | ||
#include "waylandloggingcategories.h" | ||
#include "waylandoutput.h" | ||
#include "waylandwindow.h" | ||
|
||
using namespace KWayland::Client; | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
Q_GLOBAL_STATIC(WaylandBackend, gWaylandBackend) | ||
|
||
WaylandBackend::WaylandBackend(QObject *parent) | ||
: QObject(parent) | ||
, m_connectionThread(new QThread()) | ||
, m_connectionThreadObject(new KWayland::Client::ConnectionThread()) | ||
, m_eventQueue(new EventQueue(this)) | ||
, m_registry(new Registry(this)) | ||
{ | ||
m_connectionThreadObject->moveToThread(m_connectionThread); | ||
} | ||
|
||
WaylandBackend::~WaylandBackend() | ||
{ | ||
if (m_connectionThreadObject) { | ||
m_connectionThreadObject->flush(); | ||
m_connectionThreadObject->deleteLater(); | ||
m_connectionThreadObject = nullptr; | ||
} | ||
|
||
if (m_connectionThread) { | ||
m_connectionThread->quit(); | ||
m_connectionThread->deleteLater(); | ||
m_connectionThread = nullptr; | ||
} | ||
} | ||
|
||
wl_display *WaylandBackend::display() const | ||
{ | ||
if (m_connectionThreadObject) | ||
return m_connectionThreadObject->display(); | ||
return nullptr; | ||
} | ||
|
||
#if LIRI_FEATURE_aurora_xkbcommon | ||
struct xkb_context *WaylandBackend::xkbContext() const | ||
{ | ||
return m_xkbContext.get(); | ||
} | ||
#endif | ||
|
||
void WaylandBackend::initialize() | ||
{ | ||
// Compositor | ||
connect(m_registry, &Registry::compositorAnnounced, this, | ||
[this](quint32 name, quint32 version) { | ||
if (version < 4) { | ||
qCCritical(gLcWayland, "wl_compositor version 4 or later is required"); | ||
qFatal("Aborting..."); | ||
} | ||
m_compositor = m_registry->createCompositor(name, version); | ||
}); | ||
|
||
// Compositor for sub-surfaces | ||
connect(m_registry, &Registry::subCompositorAnnounced, this, | ||
[this](quint32 name, quint32 version) { | ||
m_subCompositor = m_registry->createSubCompositor(name, version); | ||
}); | ||
|
||
// Shared memory pool | ||
connect(m_registry, &Registry::shmAnnounced, this, [this](quint32 name, quint32 version) { | ||
m_shmPool = m_registry->createShmPool(name, version); | ||
}); | ||
|
||
// Seat | ||
connect(m_registry, &Registry::seatAnnounced, this, [this](quint32 name, quint32 version) { | ||
m_seat = m_registry->createSeat(name, version); | ||
}); | ||
|
||
// Output | ||
connect(m_registry, &Registry::outputAnnounced, this, [this](quint32 name, quint32 version) { | ||
m_hostOutputsCount++; | ||
|
||
auto *hostOutput = m_registry->createOutput(name, version); | ||
|
||
connect(hostOutput, &KWayland::Client::Output::changed, this, | ||
&WaylandBackend::handleOutputChanged); | ||
}); | ||
|
||
// XDG shell | ||
connect(m_registry, &Registry::xdgShellStableAnnounced, this, | ||
[this](quint32 name, quint32 version) { | ||
m_xdgShell = m_registry->createXdgShell(name, version); | ||
}); | ||
|
||
// XDG decoration | ||
connect(m_registry, &Registry::xdgDecorationAnnounced, this, | ||
[this](quint32 name, quint32 version) { | ||
m_xdgDecorationManager = m_registry->createXdgDecorationManager(name, version); | ||
}); | ||
|
||
// Verify we have what we need | ||
connect(m_registry, &Registry::interfacesAnnounced, this, [this]() { | ||
if (!m_xdgShell || !m_xdgShell->isValid()) | ||
qCritical("The xdg_wm_base interface was not found, cannot continue!"); | ||
}); | ||
|
||
// Connection | ||
connect( | ||
m_connectionThreadObject, &ConnectionThread::connected, this, | ||
[this]() { | ||
qCDebug(gLcWayland) << "Connected to:" << m_connectionThreadObject->socketName(); | ||
|
||
// Create the event queue | ||
m_eventQueue->setup(m_connectionThreadObject); | ||
m_registry->setEventQueue(m_eventQueue); | ||
|
||
// Registry | ||
m_registry->create(m_connectionThreadObject); | ||
m_registry->setup(); | ||
m_connectionThreadObject->flush(); | ||
}, | ||
Qt::QueuedConnection); | ||
connect( | ||
m_connectionThreadObject, &ConnectionThread::connectionDied, this, | ||
[this]() { | ||
emit statusChanged(DeviceIntegration::Status::Failed); | ||
|
||
destroyOutputs(); | ||
|
||
if (m_seat) | ||
m_seat->destroy(); | ||
|
||
if (m_shmPool) | ||
m_shmPool->destroy(); | ||
|
||
if (m_xdgDecorationManager) | ||
m_xdgDecorationManager->destroy(); | ||
if (m_xdgShell) | ||
m_xdgShell->destroy(); | ||
|
||
if (m_subCompositor) | ||
m_subCompositor->destroy(); | ||
if (m_compositor) | ||
m_compositor->destroy(); | ||
if (m_registry) | ||
m_registry->destroy(); | ||
if (m_eventQueue) | ||
m_eventQueue->destroy(); | ||
}, | ||
Qt::QueuedConnection); | ||
connect(m_connectionThreadObject, &ConnectionThread::failed, this, [this]() { | ||
qCDebug(gLcWayland) << "Failed to connect to:" << m_connectionThreadObject->socketName(); | ||
|
||
emit statusChanged(DeviceIntegration::Status::Failed); | ||
|
||
destroyOutputs(); | ||
}); | ||
|
||
// Connect | ||
m_connectionThread->start(); | ||
m_connectionThreadObject->initConnection(); | ||
} | ||
|
||
void WaylandBackend::destroy() | ||
{ | ||
destroyOutputs(); | ||
|
||
if (m_xdgDecorationManager) { | ||
m_xdgDecorationManager->release(); | ||
m_xdgDecorationManager->destroy(); | ||
} | ||
if (m_xdgShell) { | ||
m_xdgShell->release(); | ||
m_xdgShell->destroy(); | ||
} | ||
|
||
if (m_subCompositor) { | ||
m_subCompositor->release(); | ||
m_subCompositor->destroy(); | ||
} | ||
if (m_seat) { | ||
m_seat->release(); | ||
m_seat->destroy(); | ||
} | ||
if (m_shmPool) { | ||
m_shmPool->release(); | ||
m_shmPool->destroy(); | ||
} | ||
if (m_compositor) { | ||
m_compositor->release(); | ||
m_compositor->destroy(); | ||
} | ||
if (m_registry) { | ||
m_registry->release(); | ||
m_registry->destroy(); | ||
} | ||
|
||
if (m_connectionThread) { | ||
m_connectionThread->quit(); | ||
m_connectionThread->wait(); | ||
} | ||
|
||
if (m_eventQueue) | ||
m_eventQueue->release(); | ||
} | ||
|
||
void WaylandBackend::flush() | ||
{ | ||
if (m_connectionThreadObject) | ||
m_connectionThreadObject->flush(); | ||
} | ||
|
||
WaylandBackend *WaylandBackend::instance() | ||
{ | ||
return gWaylandBackend(); | ||
} | ||
|
||
KWayland::Client::Compositor *WaylandBackend::compositor() const | ||
{ | ||
return m_compositor; | ||
} | ||
|
||
KWayland::Client::SubCompositor *WaylandBackend::subCompositor() const | ||
{ | ||
return m_subCompositor; | ||
} | ||
|
||
KWayland::Client::ShmPool *WaylandBackend::shmPool() const | ||
{ | ||
return m_shmPool; | ||
} | ||
|
||
KWayland::Client::Seat *WaylandBackend::seat() const | ||
{ | ||
return m_seat; | ||
} | ||
|
||
KWayland::Client::XdgShell *WaylandBackend::xdgShell() const | ||
{ | ||
return m_xdgShell; | ||
} | ||
|
||
KWayland::Client::XdgDecorationManager *WaylandBackend::xdgDecorationManager() const | ||
{ | ||
return m_xdgDecorationManager; | ||
} | ||
|
||
Outputs WaylandBackend::outputs() const | ||
{ | ||
return m_outputs; | ||
} | ||
|
||
WaylandWindow *WaylandBackend::findWindow(KWayland::Client::Surface *surface) const | ||
{ | ||
for (auto *wlWindow : qAsConst(m_windows)) { | ||
if (wlWindow->surface() == surface) | ||
return wlWindow; | ||
} | ||
|
||
return nullptr; | ||
} | ||
|
||
WaylandOutput *WaylandBackend::findOutput(KWayland::Client::Surface *surface) const | ||
{ | ||
if (auto *wlWindow = findWindow(surface)) | ||
return static_cast<WaylandOutput *>(wlWindow->output()); | ||
|
||
return nullptr; | ||
} | ||
|
||
QList<WaylandWindow *> WaylandBackend::windows() const | ||
{ | ||
return m_windows; | ||
} | ||
|
||
void WaylandBackend::registerWindow(WaylandWindow *window) | ||
{ | ||
m_windows.append(window); | ||
} | ||
|
||
void WaylandBackend::unregisterWindow(WaylandWindow *window) | ||
{ | ||
m_windows.removeOne(window); | ||
} | ||
|
||
void WaylandBackend::handleOutputChanged() | ||
{ | ||
auto *hostOutput = static_cast<KWayland::Client::Output *>(sender()); | ||
if (!hostOutput) | ||
return; | ||
|
||
const auto index = m_outputs.size() + 1; | ||
auto *output = new WaylandOutput(hostOutput, QStringLiteral("WL-%1").arg(index)); | ||
m_outputs.append(output); | ||
emit outputAdded(output); | ||
|
||
if (m_outputs.size() == m_hostOutputsCount) | ||
emit statusChanged(DeviceIntegration::Status::Ready); | ||
} | ||
|
||
void WaylandBackend::destroyOutputs() | ||
{ | ||
auto it = m_outputs.begin(); | ||
while (it != m_outputs.end()) { | ||
auto *output = static_cast<WaylandOutput *>(*it); | ||
emit outputRemoved(output); | ||
output->destroy(); | ||
output->deleteLater(); | ||
it = m_outputs.erase(it); | ||
} | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#pragma once | ||
|
||
#include <QThread> | ||
|
||
#include <LiriAuroraPlatform/DeviceIntegration> | ||
|
||
#include <KWayland/Client/connection_thread.h> | ||
#include <KWayland/Client/compositor.h> | ||
#include <KWayland/Client/event_queue.h> | ||
#include <KWayland/Client/registry.h> | ||
#include <KWayland/Client/seat.h> | ||
#include <KWayland/Client/subcompositor.h> | ||
#include <KWayland/Client/shm_pool.h> | ||
#include <KWayland/Client/xdgdecoration.h> | ||
#include <KWayland/Client/xdgshell.h> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandOutput; | ||
class WaylandWindow; | ||
|
||
class WaylandBackend : public QObject | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit WaylandBackend(QObject *parent = nullptr); | ||
~WaylandBackend(); | ||
|
||
wl_display *display() const; | ||
|
||
void initialize(); | ||
void destroy(); | ||
|
||
void flush(); | ||
|
||
KWayland::Client::Compositor *compositor() const; | ||
KWayland::Client::SubCompositor *subCompositor() const; | ||
KWayland::Client::ShmPool *shmPool() const; | ||
KWayland::Client::Seat *seat() const; | ||
KWayland::Client::XdgShell *xdgShell() const; | ||
KWayland::Client::XdgDecorationManager *xdgDecorationManager() const; | ||
|
||
Outputs outputs() const; | ||
|
||
WaylandWindow *findWindow(KWayland::Client::Surface *surface) const; | ||
WaylandOutput *findOutput(KWayland::Client::Surface *surface) const; | ||
|
||
QList<WaylandWindow *> windows() const; | ||
|
||
void registerWindow(WaylandWindow *window); | ||
void unregisterWindow(WaylandWindow *window); | ||
|
||
static WaylandBackend *instance(); | ||
|
||
signals: | ||
void statusChanged(DeviceIntegration::Status status); | ||
void outputAdded(WaylandOutput *output); | ||
void outputRemoved(WaylandOutput *output); | ||
|
||
private: | ||
QThread *m_connectionThread = nullptr; | ||
KWayland::Client::ConnectionThread *m_connectionThreadObject = nullptr; | ||
KWayland::Client::EventQueue *m_eventQueue = nullptr; | ||
KWayland::Client::Registry *m_registry = nullptr; | ||
KWayland::Client::Compositor *m_compositor = nullptr; | ||
KWayland::Client::SubCompositor *m_subCompositor = nullptr; | ||
KWayland::Client::ShmPool *m_shmPool = nullptr; | ||
KWayland::Client::Seat *m_seat = nullptr; | ||
KWayland::Client::XdgShell *m_xdgShell = nullptr; | ||
KWayland::Client::XdgDecorationManager *m_xdgDecorationManager = nullptr; | ||
|
||
int m_hostOutputsCount = 0; | ||
Outputs m_outputs; | ||
|
||
QList<WaylandWindow *> m_windows; | ||
|
||
private slots: | ||
void handleOutputChanged(); | ||
void destroyOutputs(); | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <QtMath> | ||
|
||
#include <KWayland/Client/compositor.h> | ||
|
||
#include "waylandbackend.h" | ||
#include "waylandcursor.h" | ||
#include "waylandwindow.h" | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
WaylandCursor::WaylandCursor(WaylandWindow *window, QObject *parent) | ||
: QObject(parent) | ||
, m_window(window) | ||
, m_surface(WaylandBackend::instance()->compositor()->createSurface(this)) | ||
{ | ||
} | ||
|
||
WaylandCursor::~WaylandCursor() | ||
{ | ||
if (m_surface) { | ||
m_surface->release(); | ||
m_surface->destroy(); | ||
m_surface = nullptr; | ||
} | ||
} | ||
|
||
bool WaylandCursor::isEnabled() const | ||
{ | ||
return m_enabled; | ||
} | ||
|
||
void WaylandCursor::setEnabled(bool enabled) | ||
{ | ||
if (m_enabled == enabled) | ||
return; | ||
|
||
m_enabled = enabled; | ||
render(); | ||
} | ||
|
||
KWayland::Client::Pointer *WaylandCursor::pointer() const | ||
{ | ||
return m_pointer; | ||
} | ||
|
||
void WaylandCursor::setPointer(KWayland::Client::Pointer *pointer) | ||
{ | ||
if (m_pointer == pointer) | ||
return; | ||
|
||
m_pointer = pointer; | ||
if (m_pointer) | ||
m_pointer->setCursor(m_surface, m_hotSpot); | ||
} | ||
|
||
void WaylandCursor::update(const QImage &image, const QPoint &hotSpot, qreal scale) | ||
{ | ||
if (m_image != image || m_scale != scale || m_hotSpot != hotSpot) { | ||
m_image = image; | ||
m_buffer = WaylandBackend::instance()->shmPool()->createBuffer(m_image); | ||
m_scale = scale; | ||
m_hotSpot = hotSpot; | ||
render(); | ||
} | ||
} | ||
|
||
void WaylandCursor::render() | ||
{ | ||
if (m_enabled) { | ||
m_surface->attachBuffer(m_buffer); | ||
m_surface->setScale(qCeil(m_scale)); | ||
m_surface->damageBuffer(QRect(0, 0, INT32_MAX, INT32_MAX)); | ||
} else { | ||
m_surface->attachBuffer(KWayland::Client::Buffer::Ptr()); | ||
} | ||
m_surface->commit(KWayland::Client::Surface::CommitFlag::None); | ||
|
||
m_window->present(); | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#pragma once | ||
|
||
#include <KWayland/Client/pointer.h> | ||
#include <KWayland/Client/surface.h> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandWindow; | ||
|
||
class WaylandCursor : public QObject | ||
{ | ||
Q_OBJECT | ||
Q_PROPERTY(bool enabled READ isEnabled NOTIFY enabledChanged) | ||
public: | ||
explicit WaylandCursor(WaylandWindow *window, QObject *parent = nullptr); | ||
~WaylandCursor(); | ||
|
||
bool isEnabled() const; | ||
void setEnabled(bool enabled); | ||
|
||
KWayland::Client::Pointer *pointer() const; | ||
void setPointer(KWayland::Client::Pointer *pointer); | ||
|
||
void update(const QImage &image, const QPoint &hotSpot, qreal scale); | ||
|
||
signals: | ||
void enabledChanged(bool enabled); | ||
|
||
private: | ||
bool m_enabled = false; | ||
QPointer<WaylandWindow> m_window; | ||
KWayland::Client::Surface *m_surface = nullptr; | ||
KWayland::Client::Pointer *m_pointer = nullptr; | ||
QImage m_image; | ||
KWayland::Client::Buffer::Ptr m_buffer; | ||
QPoint m_hotSpot; | ||
qreal m_scale = 1; | ||
|
||
void render(); | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
120 changes: 120 additions & 0 deletions
120
src/plugins/deviceintegration/wayland/waylandinputmanager.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include "waylandbackend.h" | ||
#include "waylandinputmanager.h" | ||
#include "waylandkeyboard.h" | ||
#include "waylandpointer.h" | ||
#include "waylandtouch.h" | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
WaylandInputManager::WaylandInputManager(QObject *parent) | ||
: InputManager(parent) | ||
{ | ||
auto *seat = WaylandBackend::instance()->seat(); | ||
|
||
handleHasKeyboardChanged(seat->hasKeyboard()); | ||
handleHasPointerChanged(seat->hasPointer()); | ||
handleHasTouchChanged(seat->hasTouch()); | ||
|
||
connect(seat, &KWayland::Client::Seat::hasKeyboardChanged, this, | ||
&WaylandInputManager::handleHasKeyboardChanged); | ||
connect(seat, &KWayland::Client::Seat::hasPointerChanged, this, | ||
&WaylandInputManager::handleHasPointerChanged); | ||
connect(seat, &KWayland::Client::Seat::hasTouchChanged, this, | ||
&WaylandInputManager::handleHasTouchChanged); | ||
} | ||
|
||
WaylandInputManager::~WaylandInputManager() | ||
{ | ||
} | ||
|
||
QList<KeyboardDevice *> WaylandInputManager::keyboardDevices() const | ||
{ | ||
return QList<KeyboardDevice *>() << m_keyboard; | ||
} | ||
|
||
QList<PointerDevice *> WaylandInputManager::pointerDevices() const | ||
{ | ||
return QList<PointerDevice *>() << m_pointer; | ||
} | ||
|
||
QList<TouchDevice *> WaylandInputManager::touchDevices() const | ||
{ | ||
return QList<TouchDevice *>() << m_touch; | ||
} | ||
|
||
int WaylandInputManager::deviceCount(InputDevice::DeviceType deviceType) const | ||
{ | ||
switch (deviceType) { | ||
case InputDevice::DeviceType::Keyboard: | ||
return m_keyboard ? 1 : 0; | ||
case InputDevice::DeviceType::Pointer: | ||
return m_pointer ? 1 : 0; | ||
case InputDevice::DeviceType::Touch: | ||
return m_touch ? 1 : 0; | ||
default: | ||
return 0; | ||
} | ||
} | ||
|
||
void WaylandInputManager::handleHasKeyboardChanged(bool hasKeyboard) | ||
{ | ||
auto *seat = WaylandBackend::instance()->seat(); | ||
|
||
if (hasKeyboard) { | ||
m_keyboard = new WaylandKeyboard(seat, this); | ||
emit deviceAdded(m_keyboard); | ||
emit keyboardAdded(m_keyboard); | ||
} else { | ||
if (m_keyboard) { | ||
emit deviceRemoved(m_keyboard); | ||
emit keyboardRemoved(m_keyboard); | ||
m_keyboard->deleteLater(); | ||
m_keyboard = nullptr; | ||
} | ||
} | ||
} | ||
|
||
void WaylandInputManager::handleHasPointerChanged(bool hasPointer) | ||
{ | ||
auto *seat = WaylandBackend::instance()->seat(); | ||
|
||
if (hasPointer) { | ||
m_pointer = new WaylandPointer(seat, this); | ||
emit deviceAdded(m_pointer); | ||
emit pointerAdded(m_pointer); | ||
} else { | ||
if (m_pointer) { | ||
emit deviceRemoved(m_pointer); | ||
emit pointerRemoved(m_pointer); | ||
m_pointer->deleteLater(); | ||
m_pointer = nullptr; | ||
} | ||
} | ||
} | ||
|
||
void WaylandInputManager::handleHasTouchChanged(bool hasTouch) | ||
{ | ||
auto *seat = WaylandBackend::instance()->seat(); | ||
|
||
if (hasTouch) { | ||
m_touch = new WaylandTouch(seat, this); | ||
emit deviceAdded(m_touch); | ||
emit touchAdded(m_touch); | ||
} else { | ||
if (m_pointer) { | ||
emit deviceRemoved(m_touch); | ||
emit touchRemoved(m_touch); | ||
m_touch->deleteLater(); | ||
m_touch = nullptr; | ||
} | ||
} | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
45 changes: 45 additions & 0 deletions
45
src/plugins/deviceintegration/wayland/waylandinputmanager.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <QMap> | ||
#include <QPointer> | ||
|
||
#include <LiriAuroraPlatform/InputManager> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandKeyboard; | ||
class WaylandPointer; | ||
class WaylandTouch; | ||
|
||
typedef QMap<InputDevice::DeviceType, InputDevice *> InputDevicesMap; | ||
|
||
class WaylandInputManager : public InputManager | ||
{ | ||
Q_OBJECT | ||
public: | ||
WaylandInputManager(QObject *parent = nullptr); | ||
~WaylandInputManager(); | ||
|
||
QList<KeyboardDevice *> keyboardDevices() const override; | ||
QList<PointerDevice *> pointerDevices() const override; | ||
QList<TouchDevice *> touchDevices() const override; | ||
|
||
int deviceCount(InputDevice::DeviceType deviceType) const override; | ||
|
||
private: | ||
WaylandKeyboard *m_keyboard = nullptr; | ||
WaylandPointer *m_pointer = nullptr; | ||
WaylandTouch *m_touch = nullptr; | ||
|
||
private slots: | ||
void handleHasKeyboardChanged(bool hasKeyboard); | ||
void handleHasPointerChanged(bool hasPointer); | ||
void handleHasTouchChanged(bool hasTouch); | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
146 changes: 146 additions & 0 deletions
146
src/plugins/deviceintegration/wayland/waylandintegration.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <QImage> | ||
|
||
#include "eglintegration.h" | ||
#include "waylandbackend.h" | ||
#include "waylandinputmanager.h" | ||
#include "waylandintegration.h" | ||
#include "waylandloggingcategories.h" | ||
#include "waylandoutput.h" | ||
#include "waylandwindow.h" | ||
|
||
#include <wayland-egl.h> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
WaylandIntegration::WaylandIntegration(QObject *parent) | ||
: DeviceIntegration(parent) | ||
, m_eglIntegration(new EglIntegration()) | ||
{ | ||
} | ||
|
||
WaylandIntegration::~WaylandIntegration() | ||
{ | ||
} | ||
|
||
void WaylandIntegration::initialize() | ||
{ | ||
connect(WaylandBackend::instance(), &WaylandBackend::statusChanged, this, | ||
[this](DeviceIntegration::Status status) { DeviceIntegration::setStatus(status); }); | ||
connect(WaylandBackend::instance(), &WaylandBackend::outputAdded, this, | ||
&WaylandIntegration::outputAdded); | ||
connect(WaylandBackend::instance(), &WaylandBackend::outputRemoved, this, | ||
&WaylandIntegration::outputRemoved); | ||
|
||
WaylandBackend::instance()->initialize(); | ||
|
||
if (m_eglIntegration) | ||
m_eglIntegration->initialize(); | ||
} | ||
|
||
void WaylandIntegration::destroy() | ||
{ | ||
qCDebug(gLcWayland, "Wayland device integration is about to be destroyed..."); | ||
|
||
WaylandBackend::instance()->destroy(); | ||
|
||
if (m_eglIntegration) | ||
m_eglIntegration->destroy(); | ||
|
||
qCInfo(gLcWayland, "Wayland device integration destroyed successfully"); | ||
} | ||
|
||
EGLNativeDisplayType WaylandIntegration::platformDisplay() const | ||
{ | ||
return reinterpret_cast<EGLNativeDisplayType>(display()); | ||
} | ||
|
||
EGLDisplay WaylandIntegration::eglDisplay() const | ||
{ | ||
if (m_eglIntegration && m_eglIntegration->isInitialized()) | ||
return m_eglIntegration->display(); | ||
return EGL_NO_DISPLAY; | ||
} | ||
|
||
wl_display *WaylandIntegration::display() const | ||
{ | ||
return WaylandBackend::instance()->display(); | ||
} | ||
|
||
EGLNativeWindowType WaylandIntegration::createNativeWindow(Window *window, const QSize &size, | ||
const QSurfaceFormat &format) | ||
{ | ||
Q_UNUSED(format) | ||
|
||
auto *wlWindow = static_cast<WaylandWindow *>(window); | ||
if (!wlWindow) { | ||
qCWarning(gLcWayland) << "Window" << window << "cannot be cast to WaylandWindow"; | ||
return 0; | ||
} | ||
|
||
auto *surface = wlWindow->surface()->operator wl_surface *(); | ||
if (surface) { | ||
qCDebug(gLcWayland, "Creating native window with size %dx%d...", size.width(), | ||
size.height()); | ||
return reinterpret_cast<EGLNativeWindowType>( | ||
wl_egl_window_create(surface, size.width(), size.height())); | ||
} else { | ||
qCWarning(gLcWayland) << "Unable to get Wayland surface from window" << window; | ||
return 0; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
void WaylandIntegration::destroyNativeWindow(EGLNativeWindowType nativeWindow) | ||
{ | ||
if (nativeWindow) { | ||
auto *eglWindow = reinterpret_cast<wl_egl_window *>(nativeWindow); | ||
wl_egl_window_destroy(eglWindow); | ||
} | ||
} | ||
|
||
void WaylandIntegration::waitForVSync(Window *window) const | ||
{ | ||
} | ||
|
||
void WaylandIntegration::presentBuffer(Window *window) | ||
{ | ||
auto *waylandWindow = static_cast<WaylandWindow *>(window); | ||
if (waylandWindow) | ||
waylandWindow->present(); | ||
} | ||
|
||
Window *WaylandIntegration::createWindow(Output *output, QWindow *qtWindow) | ||
{ | ||
return new WaylandWindow(output, qtWindow); | ||
} | ||
|
||
Window *WaylandIntegration::getWindow(QWindow *qtWindow) const | ||
{ | ||
const auto windows = WaylandBackend::instance()->windows(); | ||
for (auto *window : windows) { | ||
if (window->qtWindow() == qtWindow) | ||
return static_cast<Window *>(window); | ||
} | ||
|
||
return nullptr; | ||
} | ||
|
||
InputManager *WaylandIntegration::createInputManager(QObject *parent) | ||
{ | ||
return new WaylandInputManager(parent); | ||
} | ||
|
||
Outputs WaylandIntegration::outputs() const | ||
{ | ||
return WaylandBackend::instance()->outputs(); | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
52 changes: 52 additions & 0 deletions
52
src/plugins/deviceintegration/wayland/waylandintegration.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#pragma once | ||
|
||
#include <LiriAuroraPlatform/DeviceIntegration> | ||
|
||
struct wl_display; | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class EglIntegration; | ||
class WaylandWindow; | ||
|
||
class WaylandIntegration : public DeviceIntegration | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit WaylandIntegration(QObject *parent = nullptr); | ||
~WaylandIntegration(); | ||
|
||
void initialize() override; | ||
void destroy() override; | ||
|
||
EGLNativeDisplayType platformDisplay() const override; | ||
EGLDisplay eglDisplay() const override; | ||
|
||
wl_display *display() const; | ||
|
||
EGLNativeWindowType createNativeWindow(Window *window, const QSize &size, | ||
const QSurfaceFormat &format) override; | ||
void destroyNativeWindow(EGLNativeWindowType nativeWindow) override; | ||
|
||
void waitForVSync(Window *window) const override; | ||
void presentBuffer(Window *window) override; | ||
|
||
Window *createWindow(Output *output, QWindow *qtWindow) override; | ||
Window *getWindow(QWindow *qtWindow) const override; | ||
|
||
InputManager *createInputManager(QObject *parent = nullptr) override; | ||
|
||
Outputs outputs() const override; | ||
|
||
private: | ||
QScopedPointer<EglIntegration> m_eglIntegration; | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
23 changes: 23 additions & 0 deletions
23
src/plugins/deviceintegration/wayland/waylandintegrationplugin.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: LGPL-3.0-or-later | ||
|
||
#include "waylandintegration.h" | ||
#include "waylandintegrationplugin.h" | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
WaylandIntegrationPlugin::WaylandIntegrationPlugin(QObject *parent) | ||
: DeviceIntegrationPlugin(parent) | ||
{ | ||
} | ||
|
||
DeviceIntegration *WaylandIntegrationPlugin::create() | ||
{ | ||
return new WaylandIntegration(this); | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
24 changes: 24 additions & 0 deletions
24
src/plugins/deviceintegration/wayland/waylandintegrationplugin.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: LGPL-3.0-or-later | ||
|
||
#pragma once | ||
|
||
#include <LiriAuroraPlatform/DeviceIntegrationPlugin> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandIntegrationPlugin : public DeviceIntegrationPlugin | ||
{ | ||
Q_OBJECT | ||
Q_PLUGIN_METADATA(IID "io.liri.Aurora.DeviceIntegrationPlugin/1" FILE "wayland.json") | ||
public: | ||
explicit WaylandIntegrationPlugin(QObject *parent = nullptr); | ||
|
||
DeviceIntegration *create() override; | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include "waylandkeyboard.h" | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
WaylandKeyboard::WaylandKeyboard(KWayland::Client::Seat *hostSeat, QObject *parent) | ||
: KeyboardDevice(parent) | ||
, m_hostSeat(hostSeat) | ||
, m_hostKeyboard(hostSeat->createKeyboard(this)) | ||
{ | ||
connect(m_hostKeyboard, &KWayland::Client::Keyboard::keymapChanged, this, | ||
[this](int fd, quint32 size) { handleKeymapChanged(fd, size); }); | ||
connect(m_hostKeyboard, &KWayland::Client::Keyboard::keyChanged, this, | ||
[this](quint32 key, KWayland::Client::Keyboard::KeyState state, quint32 time) { | ||
handleKeyChanged(key, | ||
state == KWayland::Client::Keyboard::KeyState::Pressed | ||
? KeyState::Pressed | ||
: KeyState::Released, | ||
time); | ||
}); | ||
connect(m_hostKeyboard, &KWayland::Client::Keyboard::modifiersChanged, this, | ||
[this](quint32 depressed, quint32 latched, quint32 locked, quint32 group) { | ||
handleModifiers(depressed, latched, locked, group); | ||
}); | ||
connect(m_hostKeyboard, &KWayland::Client::Keyboard::keyRepeatChanged, this, | ||
[this]() { | ||
setKeyRepeatEnabled(true); | ||
setKeyRepeatRate(m_hostKeyboard->keyRepeatRate()); | ||
setKeyRepeatDelay(m_hostKeyboard->keyRepeatDelay()); | ||
}); | ||
} | ||
|
||
QString WaylandKeyboard::seatName() const | ||
{ | ||
return m_hostSeat->name(); | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <LiriAuroraPlatform/KeyboardDevice> | ||
|
||
#include <KWayland/Client/seat.h> | ||
#include <KWayland/Client/keyboard.h> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandKeyboard : public KeyboardDevice | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit WaylandKeyboard(KWayland::Client::Seat *hostSeat, QObject *parent = nullptr); | ||
|
||
QString seatName() const override; | ||
|
||
private: | ||
KWayland::Client::Seat *const m_hostSeat = nullptr; | ||
KWayland::Client::Keyboard *m_hostKeyboard = nullptr; | ||
|
||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
159 changes: 159 additions & 0 deletions
159
src/plugins/deviceintegration/wayland/waylandoutput.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <LiriAuroraPlatform/private/output_p.h> | ||
|
||
#include "waylandbackend.h" | ||
#include "waylandoutput.h" | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
static Output::Subpixel convertSubpixel(KWayland::Client::Output::SubPixel subpixel) | ||
{ | ||
switch (subpixel) { | ||
case KWayland::Client::Output::SubPixel::None: | ||
return Output::Subpixel::None; | ||
case KWayland::Client::Output::SubPixel::HorizontalRGB: | ||
return Output::Subpixel::HorizontalRGB; | ||
case KWayland::Client::Output::SubPixel::HorizontalBGR: | ||
return Output::Subpixel::HorizontalBGR; | ||
case KWayland::Client::Output::SubPixel::VerticalRGB: | ||
return Output::Subpixel::VerticalRGB; | ||
case KWayland::Client::Output::SubPixel::VerticalBGR: | ||
return Output::Subpixel::VerticalBGR; | ||
default: | ||
return Output::Subpixel::Unknown; | ||
} | ||
} | ||
|
||
static Output::Transform convertTransform(KWayland::Client::Output::Transform transform) | ||
{ | ||
switch (transform) { | ||
case KWayland::Client::Output::Transform::Rotated90: | ||
return Output::Transform::Rotated90; | ||
case KWayland::Client::Output::Transform::Rotated180: | ||
return Output::Transform::Rotated180; | ||
case KWayland::Client::Output::Transform::Rotated270: | ||
return Output::Transform::Rotated270; | ||
case KWayland::Client::Output::Transform::Flipped: | ||
return Output::Transform::Flipped; | ||
case KWayland::Client::Output::Transform::Flipped90: | ||
return Output::Transform::Flipped90; | ||
case KWayland::Client::Output::Transform::Flipped180: | ||
return Output::Transform::Flipped180; | ||
case KWayland::Client::Output::Transform::Flipped270: | ||
return Output::Transform::Flipped270; | ||
default: | ||
return Output::Transform::Normal; | ||
} | ||
} | ||
|
||
static Output::Mode convertMode(const KWayland::Client::Output::Mode &mode) | ||
{ | ||
Output::Mode m; | ||
|
||
if (mode.flags.testFlag(KWayland::Client::Output::Mode::Flag::Preferred)) | ||
m.flags.setFlag(Output::Mode::Flag::Preferred); | ||
if (mode.flags.testFlag(KWayland::Client::Output::Mode::Flag::Current)) | ||
m.flags.setFlag(Output::Mode::Flag::Current); | ||
|
||
m.size = mode.size; | ||
m.refreshRate = mode.refreshRate; | ||
|
||
return m; | ||
} | ||
|
||
WaylandOutput::WaylandOutput(KWayland::Client::Output *output, const QString &name, QObject *parent) | ||
: Output(parent) | ||
, m_name(name) | ||
, m_output(output) | ||
{ | ||
updateInfo(); | ||
|
||
connect(output, &KWayland::Client::Output::changed, this, &WaylandOutput::updateInfo); | ||
connect(output, &KWayland::Client::Output::modeChanged, this, | ||
&WaylandOutput::handleModeChanged); | ||
} | ||
|
||
WaylandOutput::~WaylandOutput() | ||
{ | ||
destroy(); | ||
} | ||
|
||
QString WaylandOutput::name() const | ||
{ | ||
return m_name; | ||
} | ||
|
||
QString WaylandOutput::description() const | ||
{ | ||
return m_output ? m_output->description() : QString(); | ||
} | ||
|
||
void WaylandOutput::destroy() | ||
{ | ||
if (m_output) { | ||
m_output->destroy(); | ||
m_output->deleteLater(); | ||
} | ||
} | ||
|
||
void WaylandOutput::updateInfo() | ||
{ | ||
auto *d = OutputPrivate::get(this); | ||
|
||
d->setManufacturer(m_output->manufacturer()); | ||
d->setModel(m_output->model()); | ||
d->setPhysicalSize(m_output->physicalSize()); | ||
d->setSubpixel(convertSubpixel(m_output->subPixel())); | ||
d->setTransform(convertTransform(m_output->transform())); | ||
d->setGlobalPosition(m_output->globalPosition()); | ||
d->setScale(m_output->scale()); | ||
|
||
if (d->modes.length() == 0) { | ||
const auto modes = m_output->modes(); | ||
for (const auto &mode : modes) { | ||
handleModeAdded(mode); | ||
if (mode.flags.testFlag(KWayland::Client::Output::Mode::Flag::Current)) | ||
handleModeChanged(mode); | ||
} | ||
} | ||
} | ||
|
||
void WaylandOutput::handleModeAdded(const KWayland::Client::Output::Mode &mode) | ||
{ | ||
auto m = convertMode(mode); | ||
|
||
auto *d = OutputPrivate::get(this); | ||
d->modes.append(m); | ||
|
||
emit modeAdded(m); | ||
} | ||
|
||
void WaylandOutput::handleModeChanged(const KWayland::Client::Output::Mode &newMode) | ||
{ | ||
auto *d = OutputPrivate::get(this); | ||
|
||
QList<Output::Mode>::iterator it; | ||
for (it = d->modes.begin(); it != d->modes.end(); ++it) { | ||
const auto mode = (*it); | ||
|
||
if (mode.refreshRate == newMode.refreshRate && mode.size == mode.size) { | ||
if (mode.flags.testFlag(Output::Mode::Flag::Preferred) | ||
== newMode.flags.testFlag(KWayland::Client::Output::Mode::Flag::Preferred)) { | ||
d->currentMode = it; | ||
emit modeChanged(mode); | ||
emit pixelSizeChanged(pixelSize()); | ||
emit modeSizeChanged(modeSize()); | ||
emit refreshRateChanged(refreshRate()); | ||
emit geometryChanged(geometry()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#pragma once | ||
|
||
#include <LiriAuroraPlatform/Output> | ||
|
||
#include <KWayland/Client/output.h> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandIntegration; | ||
|
||
class WaylandOutput : public Output | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit WaylandOutput(KWayland::Client::Output *output, const QString &name, | ||
QObject *parent = nullptr); | ||
~WaylandOutput(); | ||
|
||
QString name() const override; | ||
QString description() const override; | ||
|
||
void destroy(); | ||
|
||
protected: | ||
KWayland::Client::Output *m_output = nullptr; | ||
|
||
private: | ||
QString m_name; | ||
|
||
private slots: | ||
void updateInfo(); | ||
void handleModeAdded(const KWayland::Client::Output::Mode &mode); | ||
void handleModeChanged(const KWayland::Client::Output::Mode &mode); | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
102 changes: 102 additions & 0 deletions
102
src/plugins/deviceintegration/wayland/waylandpointer.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <LiriAuroraPlatform/Output> | ||
|
||
#include <KWayland/Client/surface.h> | ||
|
||
#include "waylandbackend.h" | ||
#include "waylandcursor.h" | ||
#include "waylandcursor.h" | ||
#include "waylandoutput.h" | ||
#include "waylandpointer.h" | ||
#include "waylandwindow.h" | ||
|
||
#include <linux/input-event-codes.h> | ||
|
||
static const QHash<quint32, Qt::MouseButton> s_buttonToQtMouseButton = { | ||
{ BTN_LEFT, Qt::LeftButton }, | ||
{ BTN_MIDDLE, Qt::MiddleButton }, | ||
{ BTN_RIGHT, Qt::RightButton }, | ||
{ BTN_SIDE, Qt::ExtraButton1 }, | ||
{ BTN_EXTRA, Qt::ExtraButton2 }, | ||
{ BTN_BACK, Qt::BackButton }, | ||
{ BTN_FORWARD, Qt::ForwardButton }, | ||
{ BTN_TASK, Qt::TaskButton }, | ||
{ 0x118, Qt::ExtraButton6 }, | ||
{ 0x119, Qt::ExtraButton7 }, | ||
{ 0x11a, Qt::ExtraButton8 }, | ||
{ 0x11b, Qt::ExtraButton9 }, | ||
{ 0x11c, Qt::ExtraButton10 }, | ||
{ 0x11d, Qt::ExtraButton11 }, | ||
{ 0x11e, Qt::ExtraButton12 }, | ||
{ 0x11f, Qt::ExtraButton13 }, | ||
}; | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
WaylandPointer::WaylandPointer(KWayland::Client::Seat *hostSeat, QObject *parent) | ||
: PointerDevice(parent) | ||
, m_hostSeat(hostSeat) | ||
, m_hostPointer(hostSeat->createPointer(this)) | ||
{ | ||
connect(m_hostPointer, &KWayland::Client::Pointer::entered, this, | ||
[this](quint32, const QPointF &relativeToSurface) { | ||
m_enteredSurface = m_hostPointer->enteredSurface(); | ||
|
||
auto *wlWindow = | ||
WaylandBackend::instance()->findWindow(m_hostPointer->enteredSurface()); | ||
if (wlWindow) { | ||
wlWindow->cursor()->setPointer(m_hostPointer); | ||
wlWindow->cursor()->setEnabled(true); | ||
} | ||
}); | ||
connect(m_hostPointer, &KWayland::Client::Pointer::left, this, [this](quint32) { | ||
if (!m_enteredSurface.isNull()) { | ||
auto *wlWindow = WaylandBackend::instance()->findWindow(m_enteredSurface.data()); | ||
if (wlWindow) { | ||
wlWindow->cursor()->setPointer(nullptr); | ||
wlWindow->cursor()->setEnabled(false); | ||
} | ||
|
||
m_enteredSurface.clear(); | ||
} | ||
}); | ||
connect(m_hostPointer, &KWayland::Client::Pointer::motion, this, | ||
[this](const QPointF &relativeToSurface, quint32) { | ||
if (!m_enteredSurface.isNull()) { | ||
auto *wlWindow = | ||
WaylandBackend::instance()->findWindow(m_enteredSurface.data()); | ||
if (wlWindow) { | ||
auto absPos = wlWindow->output()->globalPosition() + relativeToSurface; | ||
emit motion(absPos); | ||
} | ||
} | ||
}); | ||
connect(m_hostPointer, &KWayland::Client::Pointer::buttonStateChanged, this, | ||
[this](quint32 serial, quint32, quint32 button, | ||
KWayland::Client::Pointer::ButtonState state) { | ||
Qt::MouseButton mouseButton = buttonToQtMouseButton(button); | ||
|
||
if (state == KWayland::Client::Pointer::ButtonState::Pressed) | ||
emit buttonPressed(mouseButton); | ||
else if (state == KWayland::Client::Pointer::ButtonState::Released) | ||
emit buttonReleased(mouseButton); | ||
}); | ||
} | ||
|
||
QString WaylandPointer::seatName() const | ||
{ | ||
return m_hostSeat->name(); | ||
} | ||
|
||
Qt::MouseButton WaylandPointer::buttonToQtMouseButton(quint32 button) | ||
{ | ||
return s_buttonToQtMouseButton.value(button, Qt::MaxMouseButton); | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <LiriAuroraPlatform/PointerDevice> | ||
|
||
#include <KWayland/Client/seat.h> | ||
#include <KWayland/Client/pointer.h> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandPointer : public PointerDevice | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit WaylandPointer(KWayland::Client::Seat *hostSeat, QObject *parent = nullptr); | ||
|
||
QString seatName() const override; | ||
|
||
private: | ||
KWayland::Client::Seat *const m_hostSeat = nullptr; | ||
KWayland::Client::Pointer *m_hostPointer = nullptr; | ||
QPointer<KWayland::Client::Surface> m_enteredSurface; | ||
|
||
Qt::MouseButton buttonToQtMouseButton(quint32 button); | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include "waylandtouch.h" | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
WaylandTouch::WaylandTouch(KWayland::Client::Seat *hostSeat, QObject *parent) | ||
: TouchDevice(parent) | ||
, m_hostSeat(hostSeat) | ||
, m_hostTouch(hostSeat->createTouch(this)) | ||
{ | ||
} | ||
|
||
QString WaylandTouch::seatName() const | ||
{ | ||
return m_hostSeat->name(); | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <QPointer> | ||
|
||
#include <LiriAuroraPlatform/TouchDevice> | ||
|
||
#include <KWayland/Client/seat.h> | ||
#include <KWayland/Client/touch.h> | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandTouch : public TouchDevice | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit WaylandTouch(KWayland::Client::Seat *hostSeat, QObject *parent = nullptr); | ||
|
||
QString seatName() const override; | ||
|
||
private: | ||
KWayland::Client::Seat *const m_hostSeat = nullptr; | ||
KWayland::Client::Touch *m_hostTouch = nullptr; | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
174 changes: 174 additions & 0 deletions
174
src/plugins/deviceintegration/wayland/waylandwindow.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#include <QScreen> | ||
|
||
#include "waylandbackend.h" | ||
#include "waylandcursor.h" | ||
#include "waylandloggingcategories.h" | ||
#include "waylandoutput.h" | ||
#include "waylandwindow.h" | ||
|
||
enum ResourceType { | ||
WlSurfaceResourceType | ||
}; | ||
|
||
static int resourceType(const QByteArray &name) | ||
{ | ||
static const QByteArray names[] = { QByteArrayLiteral("wl_surface") }; | ||
const int numResourceTypes = sizeof(names) / sizeof(names[0]); | ||
|
||
for (int i = 0; i < numResourceTypes; ++i) { | ||
if (name.toLower() == names[i]) | ||
return i; | ||
} | ||
|
||
return -1; | ||
} | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
WaylandWindow::WaylandWindow(Output *output, QWindow *qtWindow, QObject *parent) | ||
: Window(output, qtWindow, parent) | ||
, m_output(static_cast<WaylandOutput *>(output)) | ||
, m_cursor(new WaylandCursor(this, this)) | ||
, m_shapeCursorSource(new Core::ShapeCursorSource(this)) | ||
{ | ||
WaylandBackend::instance()->registerWindow(this); | ||
} | ||
|
||
WaylandWindow::~WaylandWindow() | ||
{ | ||
WaylandBackend::instance()->unregisterWindow(this); | ||
destroy(); | ||
} | ||
|
||
WaylandCursor *WaylandWindow::cursor() const | ||
{ | ||
return m_cursor; | ||
} | ||
|
||
KWayland::Client::Surface *WaylandWindow::surface() const | ||
{ | ||
return m_surface; | ||
} | ||
|
||
void *WaylandWindow::resource(const QByteArray &name) | ||
{ | ||
void *result = nullptr; | ||
|
||
switch (resourceType(name)) { | ||
case WlSurfaceResourceType: | ||
if (m_surface) | ||
result = m_surface->operator wl_surface *(); | ||
break; | ||
default: | ||
break; | ||
} | ||
|
||
return result; | ||
} | ||
|
||
bool WaylandWindow::create() | ||
{ | ||
// Do not create twice | ||
if (m_surface || m_xdgToplevel) | ||
return true; | ||
|
||
const auto geometry = qtWindow()->screen()->geometry(); | ||
const auto size = geometry.size(); | ||
|
||
// Create a surface | ||
m_surface = WaylandBackend::instance()->compositor()->createSurface(this); | ||
m_surface->setSize(size); | ||
m_surface->setOpaqueRegion( | ||
WaylandBackend::instance()->compositor()->createRegion(QRegion(geometry)).get()); | ||
m_surface->commit(KWayland::Client::Surface::CommitFlag::None); | ||
|
||
// Create a toplevel window | ||
m_xdgToplevel = WaylandBackend::instance()->xdgShell()->createSurface(m_surface, this); | ||
connect(m_xdgToplevel, &KWayland::Client::XdgShellSurface::configureRequested, this, | ||
[this](const QSize &size, KWayland::Client::XdgShellSurface::States states, | ||
quint32 serial) { m_xdgToplevel->ackConfigure(serial); }); | ||
m_xdgToplevel->setTitle(QStringLiteral("Aurora Compositor")); | ||
m_xdgToplevel->setMinSize(size); | ||
m_xdgToplevel->setMaxSize(size); | ||
|
||
// We don't want the compositor to draw any decoration for us | ||
if (WaylandBackend::instance()->xdgDecorationManager()) { | ||
m_xdgDecoration = WaylandBackend::instance()->xdgDecorationManager()->getToplevelDecoration( | ||
m_xdgToplevel, this); | ||
m_xdgDecoration->setMode(KWayland::Client::XdgDecoration::Mode::ClientSide); | ||
} | ||
|
||
// Load X cursor theme | ||
connect(m_shapeCursorSource, &Core::CursorSource::changed, this, [this] { | ||
m_cursor->update(m_shapeCursorSource->image(), m_shapeCursorSource->hotSpot().toPoint(), | ||
m_output->scale()); | ||
}); | ||
m_shapeCursorSource->loadTheme(QStringLiteral("default"), 32, m_output->scale()); | ||
|
||
// Set default cursor | ||
QCursor cursor(Qt::ArrowCursor); | ||
changeCursor(&cursor); | ||
|
||
return true; | ||
} | ||
|
||
void WaylandWindow::destroy() | ||
{ | ||
if (m_destroyed) | ||
return; | ||
|
||
m_destroyed = true; | ||
|
||
qCDebug(gLcWayland) << "Window for" << qtWindow() << "is about to be destroyed..."; | ||
|
||
if (m_xdgDecoration) { | ||
m_xdgDecoration->release(); | ||
m_xdgDecoration->destroy(); | ||
m_xdgDecoration = nullptr; | ||
} | ||
|
||
if (m_xdgToplevel) { | ||
m_xdgToplevel->release(); | ||
m_xdgToplevel->destroy(); | ||
m_xdgToplevel = nullptr; | ||
} | ||
|
||
if (m_surface) { | ||
m_surface->release(); | ||
m_surface->destroy(); | ||
m_surface = nullptr; | ||
} | ||
} | ||
|
||
void WaylandWindow::changeCursor(QCursor *cursor) | ||
{ | ||
const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor; | ||
if (m_cursorShape == newShape && newShape != Qt::BitmapCursor) | ||
return; | ||
|
||
if (m_cursorShape == Qt::BitmapCursor) | ||
m_cursorImage = QImage(); | ||
|
||
m_cursorShape = newShape; | ||
if (newShape == Qt::BitmapCursor) { | ||
// Use the custom cursor image | ||
m_cursor->update(cursor->pixmap().toImage(), cursor->hotSpot(), m_output->scale()); | ||
} else { | ||
// Load the image from the cursor theme | ||
m_shapeCursorSource->setShape(newShape); | ||
} | ||
} | ||
|
||
void WaylandWindow::present() | ||
{ | ||
m_surface->commit(KWayland::Client::Surface::CommitFlag::None); | ||
} | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// SPDX-FileCopyrightText: 2023 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
#pragma once | ||
|
||
#include <LiriAuroraPlatform/Window> | ||
#include <LiriAuroraCore/ShapeCursorSource> | ||
|
||
#include <KWayland/Client/xdgdecoration.h> | ||
#include <KWayland/Client/xdgshell.h> | ||
#include <KWayland/Client/region.h> | ||
#include <KWayland/Client/surface.h> | ||
|
||
struct wl_egl_window; | ||
|
||
namespace Aurora { | ||
|
||
namespace Platform { | ||
|
||
class WaylandCursor; | ||
|
||
class WaylandWindow : public Window | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit WaylandWindow(Output *output, QWindow *window, QObject *parent = nullptr); | ||
~WaylandWindow(); | ||
|
||
WaylandCursor *cursor() const; | ||
|
||
KWayland::Client::Surface *surface() const; | ||
|
||
void *resource(const QByteArray &name) override; | ||
|
||
bool create() override; | ||
void destroy() override; | ||
|
||
void changeCursor(QCursor *cursor) override; | ||
|
||
void present(); | ||
|
||
private: | ||
bool m_destroyed = false; | ||
WaylandOutput *m_output = nullptr; | ||
WaylandCursor *m_cursor = nullptr; | ||
KWayland::Client::Surface *m_surface = nullptr; | ||
KWayland::Client::XdgShellSurface *m_xdgToplevel = nullptr; | ||
KWayland::Client::XdgDecoration *m_xdgDecoration = nullptr; | ||
|
||
Core::ShapeCursorSource *m_shapeCursorSource = nullptr; | ||
Qt::CursorShape m_cursorShape = Qt::BlankCursor; | ||
QImage m_cursorImage; | ||
}; | ||
|
||
} // namespace Platform | ||
|
||
} // namespace Aurora |