Compare commits

..

6 Commits

Author SHA1 Message Date
795ca140e3 Update version number for 5.23.4
GIT_SILENT
2021-11-30 12:29:48 +00:00
07c1a4b7e8 Update version number for 5.23.3
GIT_SILENT
2021-11-09 12:12:47 +00:00
35a3b39608 Update version number for 5.23.2
GIT_SILENT
2021-10-26 12:26:47 +01:00
134594b8f2 Update version number for 5.23.1
GIT_SILENT
2021-10-19 13:08:42 +01:00
4d2459af03 Update kf5 version requirement to 5.86
GIT_SILENT
2021-10-11 20:59:10 +01:00
83192c0c63 Update version number for 5.23.0
GIT_SILENT
2021-10-07 12:17:51 +01:00
21 changed files with 180 additions and 700 deletions

View File

@ -1,9 +0,0 @@
# SPDX-FileCopyrightText: None
# SPDX-License-Identifier: CC0-1.0
include:
- project: sysadmin/ci-utilities
file:
- /gitlab-templates/reuse-lint.yml
- /gitlab-templates/linux-qt6.yml
- /gitlab-templates/freebsd-qt6.yml

View File

@ -1,9 +0,0 @@
# SPDX-FileCopyrightText: None
# SPDX-License-Identifier: CC0-1.0
Dependencies:
- 'on': ['@all']
'require':
'frameworks/extra-cmake-modules': '@latest-kf6'
'third-party/wayland': '@latest'
'third-party/wayland-protocols': '@latest'

View File

@ -4,39 +4,38 @@
cmake_minimum_required(VERSION 3.16)
project(layershellqt)
set(PROJECT_VERSION "6.0.0")
set(PROJECT_VERSION_MAJOR 6)
set(PROJECT_VERSION "5.23.4")
set(PROJECT_VERSION_MAJOR 5)
set(CMAKE_C_STANDARD 99)
set(QT_MIN_VERSION "6.6.0")
set(KF6_MIN_VERSION "6.0.0")
set(QT_MIN_VERSION "5.15.0")
set(KF5_MIN_VERSION "5.86")
set(KDE_COMPILERSETTINGS_LEVEL "5.82")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE)
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml)
find_package(Qt5XkbCommonSupport REQUIRED PRIVATE)
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMSetupVersion)
include(ECMDeprecationSettings)
include(ECMGenerateHeaders)
include(CMakePackageConfigHelpers)
include(FeatureSummary)
include(GenerateExportHeader)
include(KDEClangFormat)
include(ECMQtDeclareLoggingCategory)
include(ECMQmlModule)
find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml)
find_package(WaylandScanner REQUIRED)
find_package(WaylandScanner)
find_package(QtWaylandScanner)
find_package(Wayland 1.3 COMPONENTS Client Server)
find_package(WaylandProtocols REQUIRED)
find_package(WaylandProtocols)
find_package(PkgConfig REQUIRED)
pkg_check_modules(XKBCOMMON xkbcommon REQUIRED IMPORTED_TARGET)
@ -48,19 +47,14 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90")
ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX LAYERSHELLQT
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/layershellqt_version.h"
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)
kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
ecm_set_disabled_deprecation_versions(QT 6.5
KF 5.240
)
add_subdirectory(src)
add_subdirectory(tests)
set(CMAKECONFIG_INSTALL_DIR ${KDE_INSTALL_CMAKEPACKAGEDIR}/LayerShellQt)
set(CMAKECONFIG_INSTALL_DIR ${KDE_INSTALL_LIBDIR}/cmake/LayerShellQt)
install(EXPORT LayerShellQtTargets
NAMESPACE LayerShellQt::
DESTINATION ${CMAKECONFIG_INSTALL_DIR}

View File

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

View File

@ -1,17 +0,0 @@
# SPDX-FileCopyrightText: None
# SPDX-License-Identifier: CC0-1.0
maintainer:
- vladz
description: Layer Shell Qt
platforms:
- name: Linux
- name: FreeBSD
portingAid: false
deprecated: false
release: true
group: Plasma
public_lib: true
public_source_dirs:
- src/interfaces

View File

@ -3,14 +3,10 @@
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_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)
ecm_qt_declare_logging_category(LayerShellQtInterface
ecm_qt_declare_logging_category(LAYER_SHELL_SOURCES
HEADER
layershellqt_logging.h
IDENTIFIER
@ -19,19 +15,8 @@ ecm_qt_declare_logging_category(LayerShellQtInterface
layershellqt
)
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)
target_link_libraries(LayerShellQtInterface PRIVATE Qt::XkbCommonSupportPrivate)
endif()
add_library(LayerShellQtInterface SHARED qwaylandlayersurface.cpp interfaces/window.cpp interfaces/shell.cpp qwaylandlayershellintegration.cpp qwaylandlayershell.cpp ${LAYER_SHELL_SOURCES})
target_link_libraries(LayerShellQtInterface PRIVATE Qt::Gui Qt::WaylandClientPrivate Qt::XkbCommonSupportPrivate Wayland::Client PkgConfig::XKBCOMMON)
target_include_directories(LayerShellQtInterface PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/LayerShellQt>"
INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR}/>"
)
@ -42,10 +27,7 @@ set_target_properties(LayerShellQtInterface PROPERTIES VERSION ${LAYERSHELLQT_
)
add_library(layer-shell SHARED qwaylandlayershellintegrationplugin.cpp)
target_link_libraries(layer-shell LayerShellQtInterface Qt::WaylandClient Qt::WaylandClientPrivate Wayland::Client PkgConfig::XKBCOMMON)
if (TARGET Qt::XkbCommonSupportPrivate)
target_link_libraries(layer-shell Qt::XkbCommonSupportPrivate)
endif()
target_link_libraries(layer-shell LayerShellQtInterface Qt::WaylandClient Qt::WaylandClientPrivate Qt::XkbCommonSupportPrivate Wayland::Client PkgConfig::XKBCOMMON)
ecm_generate_headers(LayerShellQt_HEADERS
HEADER_NAMES
@ -63,7 +45,7 @@ generate_export_header(LayerShellQtInterface
)
install(TARGETS layer-shell
LIBRARY DESTINATION ${KDE_INSTALL_QTPLUGINDIR}/wayland-shell-integration)
LIBRARY DESTINATION ${QT_PLUGIN_INSTALL_DIR}/wayland-shell-integration)
install(TARGETS LayerShellQtInterface EXPORT LayerShellQtTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
@ -72,5 +54,3 @@ install(FILES
${CMAKE_CURRENT_BINARY_DIR}/LayerShellQt/layershellqt_export.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/LayerShellQt COMPONENT Devel
)
add_subdirectory(declarative)

View File

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

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

@ -5,14 +5,10 @@
*/
#include "window.h"
#include "../qwaylandlayershellintegration_p.h"
#include "../qwaylandlayersurface_p.h"
#include <layershellqt_logging.h>
#include <QPointer>
#include <optional>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <private/qwaylandshellsurface_p.h>
#include <private/qwaylandwindow_p.h>
using namespace LayerShellQt;
@ -28,12 +24,10 @@ public:
QString scope = QStringLiteral("window");
Window::Anchors anchors = {Window::AnchorTop | Window::AnchorBottom | Window::AnchorLeft | Window::AnchorRight};
int32_t exclusionZone = 0;
Window::Anchor exclusiveEdge = Window::AnchorNone;
Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityOnDemand;
Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityExclusive;
Window::Layer layer = Window::LayerTop;
QMargins margins;
Window::ScreenConfiguration screenConfiguration = Window::ScreenFromQWindow;
bool closeOnDismissed = true;
QWaylandLayerSurface *getSurface() const;
};
static QMap<QWindow *, Window *> s_map;
@ -45,9 +39,9 @@ Window::~Window()
void Window::setAnchors(Anchors anchors)
{
if (d->anchors != anchors) {
d->anchors = anchors;
Q_EMIT anchorsChanged();
if (auto surface = d->getSurface()) {
surface->setAnchor(anchors);
}
}
@ -58,9 +52,9 @@ Window::Anchors Window::anchors() const
void Window::setExclusiveZone(int32_t zone)
{
if (d->exclusionZone != zone) {
d->exclusionZone = zone;
Q_EMIT exclusionZoneChanged();
if (auto surface = d->getSurface()) {
surface->setExclusiveZone(zone);
}
}
@ -69,26 +63,11 @@ int32_t Window::exclusionZone() const
return d->exclusionZone;
}
void Window::setExclusiveEdge(Window::Anchor edge)
{
if (d->exclusiveEdge == edge) {
return;
}
d->exclusiveEdge = edge;
Q_EMIT exclusiveEdgeChanged();
}
Window::Anchor Window::exclusiveEdge() const
{
return d->exclusiveEdge;
}
void Window::setMargins(const QMargins &margins)
{
if (d->margins != margins) {
d->margins = margins;
Q_EMIT marginsChanged();
if (auto surface = d->getSurface()) {
surface->setMargins(margins);
}
}
@ -99,9 +78,9 @@ QMargins Window::margins() const
void Window::setKeyboardInteractivity(KeyboardInteractivity interactivity)
{
if (d->keyboardInteractivity != interactivity) {
d->keyboardInteractivity = interactivity;
Q_EMIT keyboardInteractivityChanged();
if (auto surface = d->getSurface()) {
surface->setKeyboardInteractivity(interactivity);
}
}
@ -112,9 +91,9 @@ Window::KeyboardInteractivity Window::keyboardInteractivity() const
void Window::setLayer(Layer layer)
{
if (d->layer != layer) {
d->layer = layer;
Q_EMIT layerChanged();
if (auto surface = d->getSurface()) {
surface->setLayer(layer);
}
}
@ -134,60 +113,15 @@ Window::Layer Window::layer() const
return d->layer;
}
Window::ScreenConfiguration Window::screenConfiguration() const
{
return d->screenConfiguration;
}
void Window::setScreenConfiguration(Window::ScreenConfiguration screenConfiguration)
{
d->screenConfiguration = screenConfiguration;
}
bool Window::closeOnDismissed() const
{
return d->closeOnDismissed;
}
void Window::setCloseOnDismissed(bool close)
{
d->closeOnDismissed = close;
}
Window::Window(QWindow *window)
: QObject(window)
, d(new WindowPrivate(window))
{
s_map.insert(d->parentWindow, this);
window->create();
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow *>(window->handle());
if (!waylandWindow) {
qCWarning(LAYERSHELLQT) << window << "is not a wayland window. Not creating zwlr_layer_surface";
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)
{
if (!window) {
return nullptr;
}
auto layerShellWindow = s_map.value(window);
if (layerShellWindow) {
return layerShellWindow;
@ -195,7 +129,20 @@ Window *Window::get(QWindow *window)
return new Window(window);
}
Window *Window::qmlAttachedProperties(QObject *object)
QWaylandLayerSurface *WindowPrivate::getSurface() const
{
return get(qobject_cast<QWindow *>(object));
if (!parentWindow) {
return nullptr;
}
auto ww = dynamic_cast<QtWaylandClient::QWaylandWindow *>(parentWindow->handle());
if (!ww) {
qCDebug(LAYERSHELLQT) << "window not a wayland window" << parentWindow;
return nullptr;
}
QWaylandLayerSurface *s = qobject_cast<QWaylandLayerSurface *>(ww->shellSurface());
if (!s) {
qCDebug(LAYERSHELLQT) << "window not using wlr-layer-shell" << parentWindow << ww->shellSurface();
return nullptr;
}
return s;
}

View File

@ -9,7 +9,6 @@
#define LAYERSHELLQTWINDOW_H
#include <QObject>
#include <QScreen>
#include <QWindow>
#include "layershellqt_export.h"
@ -21,23 +20,14 @@ class WindowPrivate;
class LAYERSHELLQT_EXPORT Window : public QObject
{
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:
~Window() override;
enum Anchor {
AnchorNone = 0,
AnchorTop = 1, ///< The top edge of the anchor rectangle
AnchorBottom = 2, ///< The bottom edge of the anchor rectangle
AnchorLeft = 4, ///< The left edge of the anchor rectangle
AnchorRight = 8, ///< The right edge of the anchor rectangle
AnchorTop = 1, // the top edge of the anchor rectangle
AnchorBottom = 2, // the bottom edge of the anchor rectangle
AnchorLeft = 4, // the left edge of the anchor rectangle
AnchorRight = 8, // the right edge of the anchor rectangle
};
Q_ENUM(Anchor);
Q_DECLARE_FLAGS(Anchors, Anchor)
@ -63,26 +53,12 @@ public:
};
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);
Anchors anchors() const;
void setExclusiveZone(int32_t zone);
int32_t exclusionZone() const;
void setExclusiveEdge(Window::Anchor edge);
Window::Anchor exclusiveEdge() const;
void setMargins(const QMargins &margins);
QMargins margins() const;
@ -92,9 +68,6 @@ public:
void setLayer(Layer layer);
Layer layer() const;
void setScreenConfiguration(ScreenConfiguration screenConfiguration);
ScreenConfiguration screenConfiguration() const;
/**
* Sets a string based identifier for this window.
* This may be used by a compositor to determine stacking
@ -105,31 +78,12 @@ public:
void setScope(const QString &scope);
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
* Ownership is not transferred
*/
static Window *get(QWindow *window);
static Window *qmlAttachedProperties(QObject *object);
Q_SIGNALS:
void anchorsChanged();
void exclusionZoneChanged();
void exclusiveEdgeChanged();
void marginsChanged();
void keyboardInteractivityChanged();
void layerChanged();
private:
Window(QWindow *window);
QScopedPointer<WindowPrivate> d;

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
*/
#include "qwaylandlayershell_p.h"
#include "qwaylandlayersurface_p.h"
namespace LayerShellQt
{
QWaylandLayerShell::QWaylandLayerShell(::wl_registry *registry, uint32_t id, uint32_t version)
: QtWayland::zwlr_layer_shell_v1(registry, id, version)
{
}
QWaylandLayerShell::~QWaylandLayerShell()
{
if (zwlr_layer_shell_v1_get_version(object()) >= ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION)
zwlr_layer_shell_v1_destroy(object());
}
QWaylandLayerSurface *QWaylandLayerShell::createLayerSurface(QtWaylandClient::QWaylandWindow *window)
{
return new QWaylandLayerSurface(this, window);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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 <wayland-client.h>
#include <QtWaylandClient/private/qwaylandshellintegration_p.h>
#include <qwayland-wlr-layer-shell-unstable-v1.h>
#include "qwaylandlayersurface_p.h"
namespace LayerShellQt
{
class LAYERSHELLQT_EXPORT QWaylandLayerShell : public QtWayland::zwlr_layer_shell_v1
{
public:
QWaylandLayerShell(::wl_registry *registry, uint32_t id, uint32_t version);
virtual ~QWaylandLayerShell();
QWaylandLayerSurface *createLayerSurface(QtWaylandClient::QWaylandWindow *window);
// TODO: Popups
};
}
#endif

View File

@ -5,32 +5,43 @@
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "qwaylandlayershell_p.h"
#include "qwaylandlayershellintegration_p.h"
#include "qwaylandlayersurface_p.h"
#include "qwaylandxdgactivationv1_p.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <qwayland-wlr-layer-shell-unstable-v1.h>
namespace LayerShellQt
{
QWaylandLayerShellIntegration::QWaylandLayerShellIntegration()
: QWaylandShellIntegrationTemplate<QWaylandLayerShellIntegration>(5)
, m_xdgActivation(new QWaylandXdgActivationV1)
{
}
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)
{
QWaylandShellIntegration::initialize(display);
display->addRegistryListener(registryLayer, this);
return m_layerShell != nullptr;
}
QtWaylandClient::QWaylandShellSurface *QWaylandLayerShellIntegration::createShellSurface(QtWaylandClient::QWaylandWindow *window)
{
return new QWaylandLayerSurface(this, window);
return m_layerShell->createLayerSurface(window);
}
void QWaylandLayerShellIntegration::registryLayer(void *data, struct wl_registry *registry, uint32_t id, const QString &interface, uint32_t version)
{
QWaylandLayerShellIntegration *shell = static_cast<QWaylandLayerShellIntegration *>(data);
if (interface == zwlr_layer_shell_v1_interface.name)
shell->m_layerShell.reset(new QWaylandLayerShell(registry, id, std::min(version, 4u)));
}
}
//#include "qwaylandlayershellintegration.moc"

View File

@ -8,26 +8,28 @@
#ifndef _LAYERSHELLINTEGRATION_P_H
#define _LAYERSHELLINTEGRATION_P_H
#include <wayland-client.h>
#include "layershellqt_export.h"
#include <QtWaylandClient/private/qwaylandshellintegration_p.h>
#include <qwayland-wlr-layer-shell-unstable-v1.h>
class QWaylandXdgActivationV1;
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:
QWaylandLayerShellIntegration();
~QWaylandLayerShellIntegration() override;
QWaylandXdgActivationV1 *activation() const { return m_xdgActivation.data(); }
bool initialize(QtWaylandClient::QWaylandDisplay *display) override;
QtWaylandClient::QWaylandShellSurface *createShellSurface(QtWaylandClient::QWaylandWindow *window) override;
private:
QScopedPointer<QWaylandXdgActivationV1> m_xdgActivation;
static void registryLayer(void *data, struct wl_registry *registry, uint32_t id, const QString &interface, uint32_t version);
QScopedPointer<QWaylandLayerShell> m_layerShell;
};
}

View File

@ -5,67 +5,41 @@
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "interfaces/window.h"
#include "layershellqt_logging.h"
#include "interfaces/shell.h"
#include "qwaylandlayershell_p.h"
#include "qwaylandlayersurface_p.h"
#include "qwaylandxdgactivationv1_p.h"
#include "layershellqt_logging.h"
#include <QtWaylandClient/private/qwaylandscreen_p.h>
#include <QtWaylandClient/private/qwaylandsurface_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
#include <QGuiApplication>
namespace LayerShellQt
{
QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell, QtWaylandClient::QWaylandWindow *window)
QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShell *shell, QtWaylandClient::QWaylandWindow *window)
: QtWaylandClient::QWaylandShellSurface(window)
, QtWayland::zwlr_layer_surface_v1()
, m_shell(shell)
, m_interface(Window::get(window->window()))
, m_window(window)
{
wl_output *output = nullptr;
if (m_interface->screenConfiguration() == Window::ScreenFromQWindow) {
auto waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen *>(window->window()->screen()->handle());
LayerShellQt::Window *interface = Window::get(window->window());
Q_ASSERT(interface);
// 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
if (!waylandScreen) {
QtWaylandClient::QWaylandScreen *screen = window->waylandScreen();
if (screen->isPlaceholder()) {
qCWarning(LAYERSHELLQT) << "Creating a layer shell for placeholder screen. This will be positioned incorrectly";
} else {
output = waylandScreen->output();
}
}
init(shell->get_layer_surface(window->waylandSurface()->object(), output, m_interface->layer(), m_interface->scope()));
connect(m_interface, &Window::layerChanged, this, [this]() {
setLayer(m_interface->layer());
});
set_anchor(m_interface->anchors());
connect(m_interface, &Window::anchorsChanged, this, [this]() {
set_anchor(m_interface->anchors());
});
setExclusiveZone(m_interface->exclusionZone());
connect(m_interface, &Window::exclusionZoneChanged, this, [this]() {
setExclusiveZone(m_interface->exclusionZone());
});
setExclusiveEdge(m_interface->exclusiveEdge());
connect(m_interface, &Window::exclusiveEdgeChanged, this, [this]() {
setExclusiveEdge(m_interface->exclusiveEdge());
});
init(shell->get_layer_surface(window->waylandSurface()->object(), screen->isPlaceholder() ? nullptr : screen->output(), interface->layer(), interface->scope()));
setMargins(m_interface->margins());
connect(m_interface, &Window::marginsChanged, this, [this]() {
setMargins(m_interface->margins());
});
Window::Anchors anchors = interface->anchors();
setKeyboardInteractivity(m_interface->keyboardInteractivity());
connect(m_interface, &Window::keyboardInteractivityChanged, this, [this]() {
setKeyboardInteractivity(m_interface->keyboardInteractivity());
});
set_anchor(interface->anchors());
setMargins(interface->margins());
setKeyboardInteractivity(interface->keyboardInteractivity());
setExclusiveZone(interface->exclusionZone());
QSize size = window->surfaceSize();
const Window::Anchors anchors = m_interface->anchors();
if ((anchors & Window::AnchorLeft) && (anchors & Window::AnchorRight)) {
size.setWidth(0);
}
@ -79,18 +53,13 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
QWaylandLayerSurface::~QWaylandLayerSurface()
{
if (m_waitForSyncCallback) {
wl_callback_destroy(m_waitForSyncCallback);
}
destroy();
}
void QWaylandLayerSurface::zwlr_layer_surface_v1_closed()
{
if (m_interface->closeOnDismissed()) {
window()->window()->close();
}
}
void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height)
{
@ -100,7 +69,7 @@ void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint
if (!m_configured) {
m_configured = true;
window()->resizeFromApplyConfigure(m_pendingSize);
sendExpose();
window()->handleExpose(QRect(QPoint(), m_pendingSize));
} else {
// Later configures are resizes, so we have to queue them up for a time when we
// are not painting to the window.
@ -108,17 +77,6 @@ void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint
}
}
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";
}
}
void QWaylandLayerSurface::applyConfigure()
{
window()->resizeFromApplyConfigure(m_pendingSize);
@ -127,7 +85,6 @@ void QWaylandLayerSurface::applyConfigure()
void QWaylandLayerSurface::setAnchor(uint anchor)
{
set_anchor(anchor);
setWindowGeometry(window()->windowContentGeometry());
}
void QWaylandLayerSurface::setExclusiveZone(int32_t zone)
@ -135,13 +92,6 @@ void QWaylandLayerSurface::setExclusiveZone(int32_t zone)
set_exclusive_zone(zone);
}
void QWaylandLayerSurface::setExclusiveEdge(uint32_t edge)
{
if (zwlr_layer_surface_v1_get_version(object()) >= ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_EDGE_SINCE_VERSION) {
set_exclusive_edge(edge);
}
}
void QWaylandLayerSurface::setMargins(const QMargins &margins)
{
set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
@ -158,111 +108,4 @@ void QWaylandLayerSurface::setLayer(uint32_t layer)
set_layer(layer);
}
void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry)
{
// if we are setting it to the last size we were configured at, we don't need to do anything
if (geometry.size() == m_pendingSize && !m_waitForSyncCallback) {
return;
}
const bool horizontallyConstrained = m_interface->anchors().testFlags({Window::AnchorLeft, Window::AnchorRight});
const bool verticallyConstrained = m_interface->anchors().testFlags({Window::AnchorTop, Window::AnchorBottom});
QSize size = geometry.size();
if (horizontallyConstrained) {
size.setWidth(0);
}
if (verticallyConstrained) {
size.setHeight(0);
}
set_size(size.width(), size.height());
requestWaylandSync();
}
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);
}
const wl_callback_listener QWaylandLayerSurface::syncCallbackListener = {
.done = [](void *data, struct wl_callback *callback, uint32_t time){
Q_UNUSED(time);
wl_callback_destroy(callback);
QWaylandLayerSurface *layerSurface = static_cast<QWaylandLayerSurface *>(data);
layerSurface->m_waitForSyncCallback = nullptr;
layerSurface->sendExpose();
}
};
void QWaylandLayerSurface::requestWaylandSync()
{
if (m_waitForSyncCallback) {
return;
}
m_waitForSyncCallback = wl_display_sync(m_window->display()->wl_display());
wl_callback_add_listener(m_waitForSyncCallback, &syncCallbackListener, this);
}
void QWaylandLayerSurface::handleWaylandSyncDone()
{
if (!window()->isExposed()) {
return;
}
sendExpose();
}
void QWaylandLayerSurface::sendExpose()
{
#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
window()->handleExpose(QRect(QPoint(), m_pendingSize));
#else
window()->sendRecursiveExposeEvent();
#endif
}
}

View File

@ -10,61 +10,40 @@
#include <wayland-client.h>
#include "qwaylandlayershellintegration_p.h"
#include "layershellqt_export.h"
#include <QtWaylandClient/private/qwaylandshellsurface_p.h>
#include <qwayland-wlr-layer-shell-unstable-v1.h>
namespace LayerShellQt
{
class Window;
class QWaylandLayerShell;
class LAYERSHELLQT_EXPORT QWaylandLayerSurface : public QtWaylandClient::QWaylandShellSurface, public QtWayland::zwlr_layer_surface_v1
{
Q_OBJECT
public:
QWaylandLayerSurface(QWaylandLayerShellIntegration *shell, QtWaylandClient::QWaylandWindow *window);
~QWaylandLayerSurface() override;
QWaylandLayerSurface(QWaylandLayerShell *shell, QtWaylandClient::QWaylandWindow *window);
virtual ~QWaylandLayerSurface();
bool isExposed() const override
{
return m_configured && !m_waitForSyncCallback;
return m_configured;
}
void attachPopup(QtWaylandClient::QWaylandShellSurface *popup) override;
void setAnchor(uint32_t anchor);
void setExclusiveZone(int32_t zone);
void setExclusiveEdge(uint32_t edge);
void setMargins(const QMargins &margins);
void setKeyboardInteractivity(uint32_t interactivity);
void setLayer(uint32_t layer);
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 requestWaylandSync();
void handleWaylandSyncDone();
void sendExpose();
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;
QtWaylandClient::QWaylandWindow *m_window;
QSize m_pendingSize;
QString m_activationToken;
bool m_configured = false;
static const wl_callback_listener syncCallbackListener;
struct wl_callback *m_waitForSyncCallback = nullptr;
};
}

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

@ -25,7 +25,7 @@
THIS SOFTWARE.
</copyright>
<interface name="zwlr_layer_shell_v1" version="5">
<interface name="zwlr_layer_shell_v1" version="4">
<description summary="create surfaces that are layers of the desktop">
Clients can use this interface to assign the surface_layer role to
wl_surfaces. Such surfaces are assigned to a "layer" of the output and
@ -100,7 +100,7 @@
</request>
</interface>
<interface name="zwlr_layer_surface_v1" version="5">
<interface name="zwlr_layer_surface_v1" version="4">
<description summary="layer metadata interface">
An interface that may be implemented by a wl_surface, for surfaces that
are designed to be rendered as a layer of a stacked desktop-like
@ -367,7 +367,6 @@
<entry name="invalid_size" value="1" summary="size is invalid"/>
<entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
<entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/>
<entry name="invalid_exclusive_edge" value="4" summary="exclusive edge is invalid given the surface anchors"/>
</enum>
<enum name="anchor" bitfield="true">
@ -387,21 +386,5 @@
</description>
<arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
</request>
<!-- Version 5 additions -->
<request name="set_exclusive_edge" since="5">
<description summary="set the edge the exclusive zone will be applied to">
Requests an edge for the exclusive zone to apply. The exclusive
edge will be automatically deduced from anchor points when possible,
but when the surface is anchored to a corner, it will be necessary
to set it explicitly to disambiguate, as it is not possible to deduce
which one of the two corner edges should be used.
The edge must be one the surface is anchored to, otherwise the
invalid_exclusive_edge protocol error will be raised.
</description>
<arg name="edge" type="uint"/>
</request>
</interface>
</protocol>

View File

@ -14,6 +14,7 @@
#include <QMetaEnum>
#include <interfaces/shell.h>
#include <interfaces/window.h>
using namespace LayerShellQt;
@ -32,7 +33,7 @@ template<typename T>
T stringToEnum(QMetaEnum metaEnum, const QString &str)
{
T ret = {};
const auto splitted = str.split(QLatin1Char('|'), Qt::SkipEmptyParts);
const auto splitted = str.split(QLatin1Char('|'));
for (const auto &value : splitted) {
ret |= T(metaEnum.keyToValue(qPrintable(value)));
}
@ -41,7 +42,7 @@ T stringToEnum(QMetaEnum metaEnum, const QString &str)
class BasicWindow : public QRasterWindow
{
void paintEvent(QPaintEvent *) override
void paintEvent(QPaintEvent *)
{
QPainter p(this);
p.fillRect(QRect(0, 0, width(), height()), Qt::red);
@ -50,6 +51,8 @@ class BasicWindow : public QRasterWindow
int main(int argc, char **argv)
{
Shell::useLayerShell();
QGuiApplication app(argc, argv);
const auto layerMetaEnum = QMetaEnum::fromType<Window::Layer>();
@ -76,8 +79,6 @@ int main(int argc, char **argv)
BasicWindow window;
LayerShellQt::Window *layerShell = LayerShellQt::Window::get(&window);
layerShell->setLayer(Window::LayerBottom);
if (parser.isSet(marginsOption)) {
int margins = parser.value(marginsOption).toInt();
layerShell->setMargins({margins, margins, margins, margins});
@ -101,10 +102,6 @@ int main(int argc, char **argv)
window.show();
BasicWindow window2;
window2.resize(400, 400);
window2.show();
// just so you don't block yourself out whilst testing
QTimer::singleShot(5000, &app, &QGuiApplication::quit);
return app.exec();

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
}
}