diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1605134..3cbbe39 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,10 +6,11 @@ remove_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS) add_library(LayerShellQtInterface) qt6_generate_wayland_protocol_client_sources(LayerShellQtInterface FILES ${WaylandProtocols_DATADIR}/stable/xdg-shell/xdg-shell.xml + ${WaylandProtocols_DATADIR}/staging/xdg-activation/xdg-activation-v1.xml ${CMAKE_CURRENT_SOURCE_DIR}/wlr-layer-shell-unstable-v1.xml ) -ecm_qt_declare_logging_category(LAYER_SHELL_SOURCES +ecm_qt_declare_logging_category(LayerShellQtInterface HEADER layershellqt_logging.h IDENTIFIER @@ -18,7 +19,14 @@ ecm_qt_declare_logging_category(LAYER_SHELL_SOURCES layershellqt ) -target_sources(LayerShellQtInterface PRIVATE qwaylandlayersurface.cpp interfaces/window.cpp interfaces/shell.cpp qwaylandlayershellintegration.cpp ${LAYER_SHELL_SOURCES}) +target_sources(LayerShellQtInterface PRIVATE + qwaylandxdgactivationv1.cpp + qwaylandlayersurface.cpp + qwaylandlayershellintegration.cpp + interfaces/window.cpp + interfaces/shell.cpp +) + target_link_libraries(LayerShellQtInterface PUBLIC Qt::Gui) target_link_libraries(LayerShellQtInterface PRIVATE Qt::WaylandClientPrivate Wayland::Client PkgConfig::XKBCOMMON) if (TARGET Qt::XkbCommonSupportPrivate) diff --git a/src/qwaylandlayershellintegration.cpp b/src/qwaylandlayershellintegration.cpp index 5d92a23..8d90d26 100644 --- a/src/qwaylandlayershellintegration.cpp +++ b/src/qwaylandlayershellintegration.cpp @@ -7,6 +7,7 @@ #include "qwaylandlayershellintegration_p.h" #include "qwaylandlayersurface_p.h" +#include "qwaylandxdgactivationv1_p.h" #include #include @@ -15,6 +16,7 @@ namespace LayerShellQt { QWaylandLayerShellIntegration::QWaylandLayerShellIntegration() : QWaylandShellIntegrationTemplate(4) + , m_xdgActivation(new QWaylandXdgActivationV1) { } diff --git a/src/qwaylandlayershellintegration_p.h b/src/qwaylandlayershellintegration_p.h index 08c5699..43e8c8c 100644 --- a/src/qwaylandlayershellintegration_p.h +++ b/src/qwaylandlayershellintegration_p.h @@ -13,6 +13,8 @@ #include #include +class QWaylandXdgActivationV1; + namespace LayerShellQt { @@ -22,7 +24,10 @@ public: QWaylandLayerShellIntegration(); ~QWaylandLayerShellIntegration() override; + QWaylandXdgActivationV1 *activation() const { return m_xdgActivation.data(); } QtWaylandClient::QWaylandShellSurface *createShellSurface(QtWaylandClient::QWaylandWindow *window) override; +private: + QScopedPointer m_xdgActivation; }; } diff --git a/src/qwaylandlayersurface.cpp b/src/qwaylandlayersurface.cpp index 29fb7ba..ed57f4a 100644 --- a/src/qwaylandlayersurface.cpp +++ b/src/qwaylandlayersurface.cpp @@ -8,16 +8,20 @@ #include "interfaces/window.h" #include "layershellqt_logging.h" #include "qwaylandlayersurface_p.h" +#include "qwaylandxdgactivationv1_p.h" #include #include #include +#include + namespace LayerShellQt { -QWaylandLayerSurface::QWaylandLayerSurface(QtWayland::zwlr_layer_shell_v1 *shell, QtWaylandClient::QWaylandWindow *window) +QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell, QtWaylandClient::QWaylandWindow *window) : QtWaylandClient::QWaylandShellSurface(window) , QtWayland::zwlr_layer_surface_v1() + , m_shell(shell) , m_interface(Window::get(window->window())) { wl_output *output = nullptr; @@ -155,4 +159,54 @@ void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry) set_size(size.width(), size.height()); } +bool QWaylandLayerSurface::requestActivate() +{ + QWaylandXdgActivationV1 *activation = m_shell->activation(); + if (!activation->isActive()) { + return false; + } + if (!m_activationToken.isEmpty()) { + activation->activate(m_activationToken, window()->wlSurface()); + m_activationToken = {}; + return true; + } else { + const auto focusWindow = QGuiApplication::focusWindow(); + const auto wlWindow = focusWindow ? static_cast(focusWindow->handle()) : window(); + if (const auto seat = wlWindow->display()->lastInputDevice()) { + const auto tokenProvider = activation->requestXdgActivationToken( + wlWindow->display(), wlWindow->wlSurface(), 0, QString()); + connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, this, + [this](const QString &token) { + m_shell->activation()->activate(token, window()->wlSurface()); + }); + connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, tokenProvider, &QObject::deleteLater); + return true; + } + } + return false; } + +void QWaylandLayerSurface::setXdgActivationToken(const QString &token) +{ + m_activationToken = token; +} + +void QWaylandLayerSurface::requestXdgActivationToken(quint32 serial) +{ + QWaylandXdgActivationV1 *activation = m_shell->activation(); + if (!activation->isActive()) { + return; + } + auto tokenProvider = activation->requestXdgActivationToken( + window()->display(), window()->wlSurface(), serial, QString()); + + connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, this, + [this](const QString &token) { + Q_EMIT window()->xdgActivationTokenCreated(token); + }); + connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, tokenProvider, &QObject::deleteLater); + +} + +} + diff --git a/src/qwaylandlayersurface_p.h b/src/qwaylandlayersurface_p.h index dec2da0..4b5940c 100644 --- a/src/qwaylandlayersurface_p.h +++ b/src/qwaylandlayersurface_p.h @@ -10,6 +10,8 @@ #include +#include "qwaylandlayershellintegration_p.h" + #include "layershellqt_export.h" #include #include @@ -23,7 +25,7 @@ class LAYERSHELLQT_EXPORT QWaylandLayerSurface : public QtWaylandClient::QWaylan { Q_OBJECT public: - QWaylandLayerSurface(QtWayland::zwlr_layer_shell_v1 *shell, QtWaylandClient::QWaylandWindow *window); + QWaylandLayerSurface(QWaylandLayerShellIntegration *shell, QtWaylandClient::QWaylandWindow *window); ~QWaylandLayerSurface() override; bool isExposed() const override @@ -43,12 +45,18 @@ public: void applyConfigure() override; void setWindowGeometry(const QRect &geometry) override; + bool requestActivate() override; + void setXdgActivationToken(const QString &token) override; + void requestXdgActivationToken(quint32 serial) override; + private: void zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height) override; void zwlr_layer_surface_v1_closed() override; + QWaylandLayerShellIntegration *m_shell; LayerShellQt::Window *m_interface; QSize m_pendingSize; + QString m_activationToken; bool m_configured = false; }; diff --git a/src/qwaylandxdgactivationv1.cpp b/src/qwaylandxdgactivationv1.cpp new file mode 100644 index 0000000..d89ffcb --- /dev/null +++ b/src/qwaylandxdgactivationv1.cpp @@ -0,0 +1,44 @@ +/** Copyright (C) 2020 Aleix Pol Gonzalez + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +#include "qwaylandxdgactivationv1_p.h" +#include +#include + +QWaylandXdgActivationV1::QWaylandXdgActivationV1() + : QWaylandClientExtensionTemplate(1) +{ + initialize(); +} + +QWaylandXdgActivationV1::~QWaylandXdgActivationV1() +{ + if (isActive()) { + destroy(); + } +} + +QWaylandXdgActivationTokenV1 *QWaylandXdgActivationV1::requestXdgActivationToken(QtWaylandClient::QWaylandDisplay *display, + struct ::wl_surface *surface, + std::optional serial, + const QString &app_id) +{ + auto wl = get_activation_token(); + auto provider = new QWaylandXdgActivationTokenV1; + provider->init(wl); + + if (surface) { + provider->set_surface(surface); + } + if (!app_id.isEmpty()) { + provider->set_app_id(app_id); + } + if (serial && display->lastInputDevice()) { + provider->set_serial(*serial, display->lastInputDevice()->wl_seat()); + } + provider->commit(); + return provider; +} + +#include "moc_qwaylandxdgactivationv1_p.cpp" diff --git a/src/qwaylandxdgactivationv1_p.h b/src/qwaylandxdgactivationv1_p.h new file mode 100644 index 0000000..5012fb1 --- /dev/null +++ b/src/qwaylandxdgactivationv1_p.h @@ -0,0 +1,48 @@ +/** Copyright (C) 2020 Aleix Pol Gonzalez + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + +#ifndef QWAYLANDXDGACTIVATIONV1_P_H +#define QWAYLANDXDGACTIVATIONV1_P_H + +#include "qwayland-xdg-activation-v1.h" +#include + +#include + +namespace QtWaylandClient +{ +class QWaylandDisplay; +class QWaylandSurface; +} + +class QWaylandXdgActivationTokenV1 : public QObject, public QtWayland::xdg_activation_token_v1 +{ + Q_OBJECT +public: + ~QWaylandXdgActivationTokenV1() override + { + destroy(); + } + +protected: + void xdg_activation_token_v1_done(const QString &token) override + { + Q_EMIT done(token); + } + +Q_SIGNALS: + void done(const QString &token); +}; + +class QWaylandXdgActivationV1 : public QWaylandClientExtensionTemplate, public QtWayland::xdg_activation_v1 +{ +public: + QWaylandXdgActivationV1(); + ~QWaylandXdgActivationV1() override; + + QWaylandXdgActivationTokenV1 * + requestXdgActivationToken(QtWaylandClient::QWaylandDisplay *display, struct ::wl_surface *surface, std::optional serial, const QString &app_id); +}; + +#endif // QWAYLANDXDGACTIVATIONV1_P_H