Compare commits

..

2 Commits

Author SHA1 Message Date
1943de8501 Add a (temporary) way to attach popups to layer surfaces
The new API is temporary. It's needed to help us with porting plasma to
the layer shell protocol until Qt 6.6 is released, which includes
QWaylandShellSurface::attachPopup().
2023-04-03 16:47:55 +03:00
7d1fb40d07 Port to QWaylandWindow::setShellIntegration()
With QWaylandWindow::setShellIntegration(), it's possible to use
xdg-shell and layer-shell protocols in the same process. It's important
for plasmashell, where we want to use the layer shell protocol for
special surfaces such as the desktop background, and the xdg shell
protocol for dialogs.

In order to make a QWindow use the layer shell protocol, you need to
call LayerShellQt::Window::get() before the window is mapped.
2023-04-03 14:47:00 +03:00
18 changed files with 154 additions and 494 deletions

View File

@ -5,5 +5,3 @@ Dependencies:
- 'on': ['@all'] - 'on': ['@all']
'require': 'require':
'frameworks/extra-cmake-modules': '@latest-kf6' 'frameworks/extra-cmake-modules': '@latest-kf6'
'third-party/wayland': '@latest'
'third-party/wayland-protocols': '@latest'

View File

@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.16)
project(layershellqt) project(layershellqt)
set(PROJECT_VERSION "5.27.80") set(PROJECT_VERSION "5.27.80")
set(PROJECT_VERSION_MAJOR 6) set(PROJECT_VERSION_MAJOR 5)
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
@ -13,7 +13,7 @@ set(QT_MIN_VERSION "6.5.0")
set(KF6_MIN_VERSION "5.240.0") set(KF6_MIN_VERSION "5.240.0")
set(KDE_COMPILERSETTINGS_LEVEL "5.82") set(KDE_COMPILERSETTINGS_LEVEL "5.82")
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE) find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE)
@ -32,7 +32,11 @@ include(KDEClangFormat)
include(ECMQtDeclareLoggingCategory) include(ECMQtDeclareLoggingCategory)
find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml) find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml)
if (QT_MAJOR_VERSION EQUAL "5")
find_package(Qt5XkbCommonSupport REQUIRED PRIVATE)
find_package(QtWaylandScanner REQUIRED)
endif()
find_package(WaylandScanner REQUIRED) find_package(WaylandScanner REQUIRED)
find_package(Wayland 1.3 COMPONENTS Client Server) find_package(Wayland 1.3 COMPONENTS Client Server)
find_package(WaylandProtocols REQUIRED) find_package(WaylandProtocols REQUIRED)
@ -47,13 +51,13 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90")
ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX LAYERSHELLQT ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX LAYERSHELLQT
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/layershellqt_version.h" VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/layershellqt_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/LayerShellQtConfigVersion.cmake" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/LayerShellQtConfigVersion.cmake"
SOVERSION ${PROJECT_VERSION_MAJOR}) SOVERSION 5)
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h) file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h)
kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES}) kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
ecm_set_disabled_deprecation_versions(QT 6.5 ecm_set_disabled_deprecation_versions(QT 5.15.2
KF 5.240 KF 5.101
) )
add_subdirectory(src) add_subdirectory(src)

View File

@ -4,6 +4,6 @@
@PACKAGE_INIT@ @PACKAGE_INIT@
include(CMakeFindDependencyMacro) include(CMakeFindDependencyMacro)
find_dependency(Qt6Gui "@QT_MIN_VERSION@") find_dependency(Qt@QT_MAJOR_VERSION@Gui "@QT_MIN_VERSION@")
include("${CMAKE_CURRENT_LIST_DIR}/LayerShellQtTargets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/LayerShellQtTargets.cmake")

View File

@ -4,13 +4,17 @@
remove_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS) remove_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS)
add_library(LayerShellQtInterface) add_library(LayerShellQtInterface)
if (QT_MAJOR_VERSION EQUAL "5")
ecm_add_qtwayland_client_protocol(LAYER_SHELL_SOURCES PROTOCOL ${WaylandProtocols_DATADIR}/stable/xdg-shell/xdg-shell.xml BASENAME xdg-shell)
ecm_add_qtwayland_client_protocol(LAYER_SHELL_SOURCES PROTOCOL wlr-layer-shell-unstable-v1.xml BASENAME wlr-layer-shell-unstable-v1)
else()
qt6_generate_wayland_protocol_client_sources(LayerShellQtInterface FILES qt6_generate_wayland_protocol_client_sources(LayerShellQtInterface FILES
${WaylandProtocols_DATADIR}/stable/xdg-shell/xdg-shell.xml ${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 ${CMAKE_CURRENT_SOURCE_DIR}/wlr-layer-shell-unstable-v1.xml
) )
endif()
ecm_qt_declare_logging_category(LayerShellQtInterface ecm_qt_declare_logging_category(LAYER_SHELL_SOURCES
HEADER HEADER
layershellqt_logging.h layershellqt_logging.h
IDENTIFIER IDENTIFIER
@ -19,16 +23,8 @@ ecm_qt_declare_logging_category(LayerShellQtInterface
layershellqt layershellqt
) )
target_sources(LayerShellQtInterface PRIVATE target_sources(LayerShellQtInterface PRIVATE qwaylandlayersurface.cpp interfaces/window.cpp interfaces/shell.cpp qwaylandlayershellintegration.cpp qwaylandlayershell.cpp ${LAYER_SHELL_SOURCES})
qwaylandxdgactivationv1.cpp target_link_libraries(LayerShellQtInterface PRIVATE Qt::Gui Qt::WaylandClientPrivate Wayland::Client PkgConfig::XKBCOMMON)
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) if (TARGET Qt::XkbCommonSupportPrivate)
target_link_libraries(LayerShellQtInterface PRIVATE Qt::XkbCommonSupportPrivate) target_link_libraries(LayerShellQtInterface PRIVATE Qt::XkbCommonSupportPrivate)
endif() endif()
@ -72,5 +68,3 @@ install(FILES
${CMAKE_CURRENT_BINARY_DIR}/LayerShellQt/layershellqt_export.h ${CMAKE_CURRENT_BINARY_DIR}/LayerShellQt/layershellqt_export.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/LayerShellQt COMPONENT Devel DESTINATION ${KDE_INSTALL_INCLUDEDIR}/LayerShellQt COMPONENT Devel
) )
add_subdirectory(declarative)

View File

@ -1,9 +0,0 @@
# SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleix.pol_gonzalez@mercedes-benz.com>
# SPDX-License-Identifier: BSD-3-Clause
qt_add_qml_module(LayerShellQtQml
URI "org.kde.layershell"
VERSION 1.0
SOURCES layershellqtplugin.cpp)
target_link_libraries(LayerShellQtQml PRIVATE Qt::Qml LayerShellQtInterface)

View File

@ -1,24 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleix.pol_gonzalez@mercedes-benz.com>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <QQmlExtensionPlugin>
#include "../interfaces/window.h"
#include <qqml.h>
QML_DECLARE_TYPEINFO(LayerShellQt::Window, QML_HAS_ATTACHED_PROPERTIES)
class Plugin : public QQmlExtensionPlugin
{
Q_PLUGIN_METADATA(IID "org.kde.layershellqt")
Q_OBJECT
public:
void registerTypes(const char *uri) override {
Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.layershell"));
qmlRegisterType<LayerShellQt::Window>(uri, 1, 0, "Window");
}
};
#include "layershellqtplugin.moc"

View File

@ -31,11 +31,10 @@ public:
QString scope = QStringLiteral("window"); QString scope = QStringLiteral("window");
Window::Anchors anchors = {Window::AnchorTop | Window::AnchorBottom | Window::AnchorLeft | Window::AnchorRight}; Window::Anchors anchors = {Window::AnchorTop | Window::AnchorBottom | Window::AnchorLeft | Window::AnchorRight};
int32_t exclusionZone = 0; int32_t exclusionZone = 0;
Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityNone; Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityExclusive;
Window::Layer layer = Window::LayerTop; Window::Layer layer = Window::LayerTop;
QMargins margins; QMargins margins;
Window::ScreenConfiguration screenConfiguration = Window::ScreenFromQWindow; std::optional<QPointer<QScreen>> desiredOutput;
bool closeOnDismissed = true;
}; };
static QMap<QWindow *, Window *> s_map; static QMap<QWindow *, Window *> s_map;
@ -47,11 +46,9 @@ Window::~Window()
void Window::setAnchors(Anchors anchors) void Window::setAnchors(Anchors anchors)
{ {
if (d->anchors != anchors) {
d->anchors = anchors; d->anchors = anchors;
Q_EMIT anchorsChanged(); Q_EMIT anchorsChanged();
} }
}
Window::Anchors Window::anchors() const Window::Anchors Window::anchors() const
{ {
@ -60,11 +57,9 @@ Window::Anchors Window::anchors() const
void Window::setExclusiveZone(int32_t zone) void Window::setExclusiveZone(int32_t zone)
{ {
if (d->exclusionZone != zone) {
d->exclusionZone = zone; d->exclusionZone = zone;
Q_EMIT exclusionZoneChanged(); Q_EMIT exclusionZoneChanged();
} }
}
int32_t Window::exclusionZone() const int32_t Window::exclusionZone() const
{ {
@ -73,11 +68,9 @@ int32_t Window::exclusionZone() const
void Window::setMargins(const QMargins &margins) void Window::setMargins(const QMargins &margins)
{ {
if (d->margins != margins) {
d->margins = margins; d->margins = margins;
Q_EMIT marginsChanged(); Q_EMIT marginsChanged();
} }
}
QMargins Window::margins() const QMargins Window::margins() const
{ {
@ -86,11 +79,9 @@ QMargins Window::margins() const
void Window::setKeyboardInteractivity(KeyboardInteractivity interactivity) void Window::setKeyboardInteractivity(KeyboardInteractivity interactivity)
{ {
if (d->keyboardInteractivity != interactivity) {
d->keyboardInteractivity = interactivity; d->keyboardInteractivity = interactivity;
Q_EMIT keyboardInteractivityChanged(); Q_EMIT keyboardInteractivityChanged();
} }
}
Window::KeyboardInteractivity Window::keyboardInteractivity() const Window::KeyboardInteractivity Window::keyboardInteractivity() const
{ {
@ -99,10 +90,7 @@ Window::KeyboardInteractivity Window::keyboardInteractivity() const
void Window::setLayer(Layer layer) void Window::setLayer(Layer layer)
{ {
if (d->layer != layer) {
d->layer = layer; d->layer = layer;
Q_EMIT layerChanged();
}
} }
void Window::setScope(const QString &scope) void Window::setScope(const QString &scope)
@ -121,24 +109,19 @@ Window::Layer Window::layer() const
return d->layer; return d->layer;
} }
Window::ScreenConfiguration Window::screenConfiguration() const QScreen *Window::desiredOutput() const
{ {
return d->screenConfiguration; // Don't use .value_or here to avoid a temporary QPointer
if (d->desiredOutput.has_value()) {
return d->desiredOutput.value();
} }
void Window::setScreenConfiguration(Window::ScreenConfiguration screenConfiguration) return d->parentWindow->screen();
{
d->screenConfiguration = screenConfiguration;
} }
bool Window::closeOnDismissed() const void Window::setDesiredOutput(QScreen *output)
{ {
return d->closeOnDismissed; d->desiredOutput = output;
}
void Window::setCloseOnDismissed(bool close)
{
d->closeOnDismissed = close;
} }
#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
@ -164,40 +147,17 @@ Window::Window(QWindow *window)
window->create(); window->create();
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow *>(window->handle()); if (auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow *>(window->handle())) {
if (!waylandWindow) { static QWaylandLayerShellIntegration integration;
qCWarning(LAYERSHELLQT) << window << "is not a wayland window. Not creating zwlr_layer_surface"; waylandWindow->setShellIntegration(&integration);
return;
} }
static QWaylandLayerShellIntegration *shellIntegration = nullptr;
if (!shellIntegration) {
shellIntegration = new QWaylandLayerShellIntegration();
if (!shellIntegration->initialize(waylandWindow->display())) {
delete shellIntegration;
shellIntegration = nullptr;
qCWarning(LAYERSHELLQT) << "Failed to initialize layer-shell integration, possibly because compositor does not support the layer-shell protocol";
return;
}
}
waylandWindow->setShellIntegration(shellIntegration);
} }
Window *Window::get(QWindow *window) Window *Window::get(QWindow *window)
{ {
if (!window) {
return nullptr;
}
auto layerShellWindow = s_map.value(window); auto layerShellWindow = s_map.value(window);
if (layerShellWindow) { if (layerShellWindow) {
return layerShellWindow; return layerShellWindow;
} }
return new Window(window); return new Window(window);
} }
Window *Window::qmlAttachedProperties(QObject *object)
{
return get(qobject_cast<QWindow *>(object));
}

View File

@ -25,14 +25,6 @@ class WindowPrivate;
class LAYERSHELLQT_EXPORT Window : public QObject class LAYERSHELLQT_EXPORT Window : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(Anchors anchors READ anchors WRITE setAnchors NOTIFY anchorsChanged)
Q_PROPERTY(QString scope READ scope WRITE setScope)
Q_PROPERTY(QMargins margins READ margins WRITE setMargins NOTIFY marginsChanged)
Q_PROPERTY(qint32 exclusionZone READ exclusionZone WRITE setExclusiveZone NOTIFY exclusionZoneChanged)
Q_PROPERTY(Layer layer READ layer WRITE setLayer NOTIFY layerChanged)
Q_PROPERTY(KeyboardInteractivity keyboardInteractivity READ keyboardInteractivity WRITE setKeyboardInteractivity NOTIFY keyboardInteractivityChanged)
Q_PROPERTY(ScreenConfiguration screenConfiguration READ screenConfiguration WRITE setScreenConfiguration)
public: public:
~Window() override; ~Window() override;
@ -66,17 +58,6 @@ public:
}; };
Q_ENUM(KeyboardInteractivity) Q_ENUM(KeyboardInteractivity)
/**
* This enum type is used to specify which screen to place the surface on.
* ScreenFromQWindow (the default) reads QWindow::screen() while ScreenFromCompositor
* passes nil and lets the compositor decide.
*/
enum ScreenConfiguration {
ScreenFromQWindow = 0,
ScreenFromCompositor = 1,
};
Q_ENUM(ScreenConfiguration)
void setAnchors(Anchors anchor); void setAnchors(Anchors anchor);
Anchors anchors() const; Anchors anchors() const;
@ -92,8 +73,13 @@ public:
void setLayer(Layer layer); void setLayer(Layer layer);
Layer layer() const; Layer layer() const;
void setScreenConfiguration(ScreenConfiguration screenConfiguration); /**
ScreenConfiguration screenConfiguration() const; * If set, the compositor will try to put the window on the given screen.
* If its not set, then the compositor will decide where to put the window.
* Under normal circumstances, this should be the active output.
*/
void setDesiredOutput(QScreen *output);
QScreen *desiredOutput() const;
/** /**
* Sets a string based identifier for this window. * Sets a string based identifier for this window.
@ -105,15 +91,6 @@ public:
void setScope(const QString &scope); void setScope(const QString &scope);
QString scope() const; QString scope() const;
/**
* Whether the QWindow should be closed when the layer surface is dismissed by the compositor.
* For example, if the associated screen has been removed.
*
* This can be used to map the window on another screen.
*/
void setCloseOnDismissed(bool close);
bool closeOnDismissed() const;
/** /**
* Gets the LayerShell Window for a given Qt Window * Gets the LayerShell Window for a given Qt Window
* Ownership is not transferred * Ownership is not transferred
@ -124,8 +101,6 @@ public:
static void attachPopup(QWindow *window, xdg_popup *popup); static void attachPopup(QWindow *window, xdg_popup *popup);
#endif #endif
static Window *qmlAttachedProperties(QObject *object);
Q_SIGNALS: Q_SIGNALS:
void anchorsChanged(); void anchorsChanged();
void exclusionZoneChanged(); void exclusionZoneChanged();

View File

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
* SPDX-FileCopyrightText: 2018 Drew DeVault <sir@cmpwn.com>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "qwaylandlayershell_p.h"
#include "qwaylandlayersurface_p.h"
namespace LayerShellQt
{
QWaylandLayerShell::QWaylandLayerShell()
: QWaylandClientExtensionTemplate<QWaylandLayerShell>(4)
, QtWayland::zwlr_layer_shell_v1()
{
initialize();
}
QWaylandLayerShell::~QWaylandLayerShell()
{
if (zwlr_layer_shell_v1_get_version(object()) >= ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION)
zwlr_layer_shell_v1_destroy(object());
}
}

View File

@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
* SPDX-FileCopyrightText: 2018 Drew DeVault <sir@cmpwn.com>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef _LAYERSHELL_H
#define _LAYERSHELL_H
#include "layershellqt_export.h"
#include <wayland-client.h>
#include <QtWaylandClient/private/qwaylandshellintegration_p.h>
#include <qwayland-wlr-layer-shell-unstable-v1.h>
namespace LayerShellQt
{
class LAYERSHELLQT_EXPORT QWaylandLayerShell : public QWaylandClientExtensionTemplate<QWaylandLayerShell>, public QtWayland::zwlr_layer_shell_v1
{
public:
QWaylandLayerShell();
~QWaylandLayerShell() override;
};
}
#endif

View File

@ -5,31 +5,34 @@
* SPDX-License-Identifier: LGPL-3.0-or-later * SPDX-License-Identifier: LGPL-3.0-or-later
*/ */
#include "qwaylandlayershell_p.h"
#include "qwaylandlayershellintegration_p.h" #include "qwaylandlayershellintegration_p.h"
#include "qwaylandlayersurface_p.h" #include "qwaylandlayersurface_p.h"
#include "qwaylandxdgactivationv1_p.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h> #include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h> #include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <qwayland-wlr-layer-shell-unstable-v1.h>
namespace LayerShellQt namespace LayerShellQt
{ {
QWaylandLayerShellIntegration::QWaylandLayerShellIntegration() QWaylandLayerShellIntegration::QWaylandLayerShellIntegration()
: QWaylandShellIntegrationTemplate<QWaylandLayerShellIntegration>(4) : m_layerShell(new QWaylandLayerShell())
, m_xdgActivation(new QWaylandXdgActivationV1)
{ {
} }
QWaylandLayerShellIntegration::~QWaylandLayerShellIntegration() QWaylandLayerShellIntegration::~QWaylandLayerShellIntegration()
{ {
if (object() && zwlr_layer_shell_v1_get_version(object()) >= ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION) {
zwlr_layer_shell_v1_destroy(object());
} }
bool QWaylandLayerShellIntegration::initialize(QtWaylandClient::QWaylandDisplay *display)
{
Q_UNUSED(display)
return m_layerShell->isActive();
} }
QtWaylandClient::QWaylandShellSurface *QWaylandLayerShellIntegration::createShellSurface(QtWaylandClient::QWaylandWindow *window) QtWaylandClient::QWaylandShellSurface *QWaylandLayerShellIntegration::createShellSurface(QtWaylandClient::QWaylandWindow *window)
{ {
return new QWaylandLayerSurface(this, window); return new QWaylandLayerSurface(m_layerShell.get(), window);
} }

View File

@ -8,26 +8,26 @@
#ifndef _LAYERSHELLINTEGRATION_P_H #ifndef _LAYERSHELLINTEGRATION_P_H
#define _LAYERSHELLINTEGRATION_P_H #define _LAYERSHELLINTEGRATION_P_H
#include <wayland-client.h>
#include "layershellqt_export.h" #include "layershellqt_export.h"
#include <QtWaylandClient/private/qwaylandshellintegration_p.h> #include <QtWaylandClient/private/qwaylandshellintegration_p.h>
#include <qwayland-wlr-layer-shell-unstable-v1.h>
class QWaylandXdgActivationV1;
namespace LayerShellQt namespace LayerShellQt
{ {
class QWaylandLayerShell;
class LAYERSHELLQT_EXPORT QWaylandLayerShellIntegration : public QtWaylandClient::QWaylandShellIntegrationTemplate<QWaylandLayerShellIntegration>, public QtWayland::zwlr_layer_shell_v1 class LAYERSHELLQT_EXPORT QWaylandLayerShellIntegration : public QtWaylandClient::QWaylandShellIntegration
{ {
public: public:
QWaylandLayerShellIntegration(); QWaylandLayerShellIntegration();
~QWaylandLayerShellIntegration() override; ~QWaylandLayerShellIntegration() override;
QWaylandXdgActivationV1 *activation() const { return m_xdgActivation.data(); } bool initialize(QtWaylandClient::QWaylandDisplay *display) override;
QtWaylandClient::QWaylandShellSurface *createShellSurface(QtWaylandClient::QWaylandWindow *window) override; QtWaylandClient::QWaylandShellSurface *createShellSurface(QtWaylandClient::QWaylandWindow *window) override;
private: private:
QScopedPointer<QWaylandXdgActivationV1> m_xdgActivation; QScopedPointer<QWaylandLayerShell> m_layerShell;
}; };
} }

View File

@ -7,26 +7,26 @@
#include "interfaces/window.h" #include "interfaces/window.h"
#include "layershellqt_logging.h" #include "layershellqt_logging.h"
#include "qwaylandlayershell_p.h"
#include "qwaylandlayersurface_p.h" #include "qwaylandlayersurface_p.h"
#include "qwaylandxdgactivationv1_p.h"
#include <QtWaylandClient/private/qwaylandscreen_p.h> #include <QtWaylandClient/private/qwaylandscreen_p.h>
#include <QtWaylandClient/private/qwaylandsurface_p.h> #include <QtWaylandClient/private/qwaylandsurface_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h> #include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QGuiApplication>
namespace LayerShellQt namespace LayerShellQt
{ {
QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell, QtWaylandClient::QWaylandWindow *window) QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShell *shell, QtWaylandClient::QWaylandWindow *window)
: QtWaylandClient::QWaylandShellSurface(window) : QtWaylandClient::QWaylandShellSurface(window)
, QtWayland::zwlr_layer_surface_v1() , QtWayland::zwlr_layer_surface_v1()
, m_shell(shell)
, m_interface(Window::get(window->window()))
{ {
LayerShellQt::Window *interface = Window::get(window->window());
Q_ASSERT(interface);
wl_output *output = nullptr; wl_output *output = nullptr;
if (m_interface->screenConfiguration() == Window::ScreenFromQWindow) { QScreen *screen = interface->desiredOutput();
auto waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen *>(window->window()->screen()->handle()); if (screen) {
auto waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen *>(screen->handle());
// Qt will always assign a screen to a window, but if the compositor has no screens available a dummy QScreen object is created // Qt will always assign a screen to a window, but if the compositor has no screens available a dummy QScreen object is created
// this will not cast to a QWaylandScreen // this will not cast to a QWaylandScreen
if (!waylandScreen) { if (!waylandScreen) {
@ -35,32 +35,32 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
output = waylandScreen->output(); output = waylandScreen->output();
} }
} }
init(shell->get_layer_surface(window->waylandSurface()->object(), output, m_interface->layer(), m_interface->scope())); init(shell->get_layer_surface(window->waylandSurface()->object(), output, interface->layer(), interface->scope()));
connect(m_interface, &Window::layerChanged, this, [this]() { connect(interface, &Window::layerChanged, this, [this, interface]() {
setLayer(m_interface->layer()); setLayer(interface->layer());
}); });
set_anchor(m_interface->anchors()); set_anchor(interface->anchors());
connect(m_interface, &Window::anchorsChanged, this, [this]() { connect(interface, &Window::anchorsChanged, this, [this, interface]() {
set_anchor(m_interface->anchors()); set_anchor(interface->anchors());
}); });
setExclusiveZone(m_interface->exclusionZone()); setExclusiveZone(interface->exclusionZone());
connect(m_interface, &Window::exclusionZoneChanged, this, [this]() { connect(interface, &Window::exclusionZoneChanged, this, [this, interface]() {
setExclusiveZone(m_interface->exclusionZone()); setExclusiveZone(interface->exclusionZone());
}); });
setMargins(m_interface->margins()); setMargins(interface->margins());
connect(m_interface, &Window::marginsChanged, this, [this]() { connect(interface, &Window::marginsChanged, this, [this, interface]() {
setMargins(m_interface->margins()); setMargins(interface->margins());
}); });
setKeyboardInteractivity(m_interface->keyboardInteractivity()); setKeyboardInteractivity(interface->keyboardInteractivity());
connect(m_interface, &Window::keyboardInteractivityChanged, this, [this]() { connect(interface, &Window::keyboardInteractivityChanged, this, [this, interface]() {
setKeyboardInteractivity(m_interface->keyboardInteractivity()); setKeyboardInteractivity(interface->keyboardInteractivity());
}); });
QSize size = window->surfaceSize(); QSize size = window->surfaceSize();
const Window::Anchors anchors = m_interface->anchors(); const Window::Anchors anchors = interface->anchors();
if ((anchors & Window::AnchorLeft) && (anchors & Window::AnchorRight)) { if ((anchors & Window::AnchorLeft) && (anchors & Window::AnchorRight)) {
size.setWidth(0); size.setWidth(0);
} }
@ -79,10 +79,8 @@ QWaylandLayerSurface::~QWaylandLayerSurface()
void QWaylandLayerSurface::zwlr_layer_surface_v1_closed() void QWaylandLayerSurface::zwlr_layer_surface_v1_closed()
{ {
if (m_interface->closeOnDismissed()) {
window()->window()->close(); window()->window()->close();
} }
}
void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height) void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height)
{ {
@ -100,19 +98,6 @@ void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint
} }
} }
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
void QWaylandLayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface *popup)
{
std::any anyRole = popup->surfaceRole();
if (auto role = std::any_cast<::xdg_popup *>(&anyRole)) {
get_popup(*role);
} else {
qCWarning(LAYERSHELLQT) << "Cannot attach popup of unknown type";
}
}
#endif
void QWaylandLayerSurface::applyConfigure() void QWaylandLayerSurface::applyConfigure()
{ {
window()->resizeFromApplyConfigure(m_pendingSize); window()->resizeFromApplyConfigure(m_pendingSize);
@ -144,69 +129,4 @@ void QWaylandLayerSurface::setLayer(uint32_t layer)
set_layer(layer); set_layer(layer);
} }
void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry)
{
const bool horizontallyConstrained = m_interface->anchors() & (Window::AnchorLeft & Window::AnchorRight);
const bool verticallyConstrained = m_interface->anchors() & (Window::AnchorTop & Window::AnchorBottom);
QSize size = geometry.size();
if (horizontallyConstrained) {
size.setWidth(0);
} }
if (verticallyConstrained) {
size.setHeight(0);
}
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<QtWaylandClient::QWaylandWindow*>(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);
}
}

View File

@ -10,31 +10,25 @@
#include <wayland-client.h> #include <wayland-client.h>
#include "qwaylandlayershellintegration_p.h"
#include "layershellqt_export.h" #include "layershellqt_export.h"
#include <QtWaylandClient/private/qwaylandshellsurface_p.h> #include <QtWaylandClient/private/qwaylandshellsurface_p.h>
#include <qwayland-wlr-layer-shell-unstable-v1.h> #include <qwayland-wlr-layer-shell-unstable-v1.h>
namespace LayerShellQt namespace LayerShellQt
{ {
class QWaylandLayerShell;
class Window;
class LAYERSHELLQT_EXPORT QWaylandLayerSurface : public QtWaylandClient::QWaylandShellSurface, public QtWayland::zwlr_layer_surface_v1 class LAYERSHELLQT_EXPORT QWaylandLayerSurface : public QtWaylandClient::QWaylandShellSurface, public QtWayland::zwlr_layer_surface_v1
{ {
Q_OBJECT Q_OBJECT
public: public:
QWaylandLayerSurface(QWaylandLayerShellIntegration *shell, QtWaylandClient::QWaylandWindow *window); QWaylandLayerSurface(QWaylandLayerShell *shell, QtWaylandClient::QWaylandWindow *window);
~QWaylandLayerSurface() override; ~QWaylandLayerSurface() override;
bool isExposed() const override bool isExposed() const override
{ {
return m_configured; return m_configured;
} }
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
void attachPopup(QtWaylandClient::QWaylandShellSurface *popup) override;
#endif
void setAnchor(uint32_t anchor); void setAnchor(uint32_t anchor);
void setExclusiveZone(int32_t zone); void setExclusiveZone(int32_t zone);
@ -43,20 +37,12 @@ public:
void setLayer(uint32_t layer); void setLayer(uint32_t layer);
void applyConfigure() override; void applyConfigure() override;
void setWindowGeometry(const QRect &geometry) override;
bool requestActivate() override;
void setXdgActivationToken(const QString &token) override;
void requestXdgActivationToken(quint32 serial) override;
private: private:
void zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height) override; void zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height) override;
void zwlr_layer_surface_v1_closed() override; void zwlr_layer_surface_v1_closed() override;
QWaylandLayerShellIntegration *m_shell;
LayerShellQt::Window *m_interface;
QSize m_pendingSize; QSize m_pendingSize;
QString m_activationToken;
bool m_configured = false; bool m_configured = false;
}; };

View File

@ -1,44 +0,0 @@
/** Copyright (C) 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "qwaylandxdgactivationv1_p.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandinputdevice_p.h>
QWaylandXdgActivationV1::QWaylandXdgActivationV1()
: QWaylandClientExtensionTemplate<QWaylandXdgActivationV1>(1)
{
initialize();
}
QWaylandXdgActivationV1::~QWaylandXdgActivationV1()
{
if (isActive()) {
destroy();
}
}
QWaylandXdgActivationTokenV1 *QWaylandXdgActivationV1::requestXdgActivationToken(QtWaylandClient::QWaylandDisplay *display,
struct ::wl_surface *surface,
std::optional<uint32_t> 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"

View File

@ -1,48 +0,0 @@
/** Copyright (C) 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef QWAYLANDXDGACTIVATIONV1_P_H
#define QWAYLANDXDGACTIVATIONV1_P_H
#include "qwayland-xdg-activation-v1.h"
#include <QObject>
#include <QtWaylandClient/QWaylandClientExtension>
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<QWaylandXdgActivationV1>, public QtWayland::xdg_activation_v1
{
public:
QWaylandXdgActivationV1();
~QWaylandXdgActivationV1() override;
QWaylandXdgActivationTokenV1 *
requestXdgActivationToken(QtWaylandClient::QWaylandDisplay *display, struct ::wl_surface *surface, std::optional<uint32_t> serial, const QString &app_id);
};
#endif // QWAYLANDXDGACTIVATIONV1_P_H

View File

@ -32,7 +32,7 @@ template<typename T>
T stringToEnum(QMetaEnum metaEnum, const QString &str) T stringToEnum(QMetaEnum metaEnum, const QString &str)
{ {
T ret = {}; T ret = {};
const auto splitted = str.split(QLatin1Char('|'), Qt::SkipEmptyParts); const auto splitted = str.split(QLatin1Char('|'));
for (const auto &value : splitted) { for (const auto &value : splitted) {
ret |= T(metaEnum.keyToValue(qPrintable(value))); ret |= T(metaEnum.keyToValue(qPrintable(value)));
} }
@ -41,7 +41,7 @@ T stringToEnum(QMetaEnum metaEnum, const QString &str)
class BasicWindow : public QRasterWindow class BasicWindow : public QRasterWindow
{ {
void paintEvent(QPaintEvent *) override void paintEvent(QPaintEvent *)
{ {
QPainter p(this); QPainter p(this);
p.fillRect(QRect(0, 0, width(), height()), Qt::red); p.fillRect(QRect(0, 0, width(), height()), Qt::red);

View File

@ -1,110 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleix.pol_gonzalez@mercedes-benz.com>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
import QtQuick 2.15
import org.kde.layershell 1.0 as LayerShell
Item
{
Text {
text: "A normal Window"
anchors.centerIn: parent
}
Window {
LayerShell.Window.anchors: LayerShell.Window.AnchorLeft
LayerShell.Window.layer: LayerShell.Window.LayerBackground
LayerShell.Window.exclusionZone: -1
width: 200
height: 150
Rectangle {
anchors.fill: parent
color: "green"
Text {
anchors.centerIn: parent
text: "left bg"
}
}
visible: true
}
Window {
LayerShell.Window.scope: "dock"
LayerShell.Window.anchors: LayerShell.Window.AnchorLeft
LayerShell.Window.layer: LayerShell.Window.LayerTop
LayerShell.Window.exclusionZone: width
width: 100
height: 100
Rectangle {
anchors.fill: parent
color: "red"
Text {
anchors.centerIn: parent
text: "left"
}
}
visible: true
}
Window {
LayerShell.Window.scope: "normal"
LayerShell.Window.anchors: LayerShell.Window.AnchorRight
width: 100
height: 100
Rectangle {
anchors.fill: parent
color: "red"
Text {
anchors.centerIn: parent
text: "right"
}
}
visible: true
}
Window {
LayerShell.Window.scope: "normal"
LayerShell.Window.anchors: LayerShell.Window.AnchorTop
width: 100
height: 100
Rectangle {
anchors.fill: parent
color: "red"
Text {
anchors.centerIn: parent
text: "top"
}
}
visible: true
}
Window {
LayerShell.Window.scope: "normal"
LayerShell.Window.anchors: LayerShell.Window.AnchorBottom
width: 100
height: 100
Rectangle {
anchors.fill: parent
color: "red"
Text {
anchors.centerIn: parent
text: "bottom"
}
}
visible: true
}
}