Compare commits

..

47 Commits

Author SHA1 Message Date
078f36f8f3 Update version number for 5.92.0
GIT_SILENT
2024-01-10 12:29:03 +00:00
7d3194034c Use ECM QML module so the module can be used outside of repository 2024-01-04 14:42:17 -05:00
e3098a660a Fix constrained check
The value in parantheses was always zero.
2023-12-21 13:58:24 +00:00
d379bc8d8e Update version number for 5.91.90
GIT_SILENT
2023-12-20 18:54:50 +00:00
715e629dd8 Update version number for 5.91.0
GIT_SILENT
2023-12-20 12:02:54 +00:00
8ae3b0aef8 Qt6 check code as apps is qt6 only. 2023-12-15 21:44:24 +01:00
6f0bca5593 Revert "Add a (temporary) way to attach popups to layer surfaces"
This reverts commit fdab1544fb.

Qt 6.6 is out with all the necessary multi-shell apis.
2023-12-08 11:55:52 +00:00
d1ab27dd53 Update Qt version requirement to 6.6.0
GIT_SILENT
2023-12-08 12:10:27 +01:00
4569e78e25 Update version number for 5.90.90
GIT_SILENT
2023-12-07 16:41:03 +00:00
ddb0490592 Change default keyboard interactivity to OnDemand
OnDemand is a better default as it still ensures that the window will
receive keyboard input by default, but it's less aggressive.
2023-11-30 10:06:18 +00:00
3c116e7550 Revert "Change default keyboard interactivity from exclusive to none"
This reverts commit be63783888.

It broke keyboard input in sddm greeter. While defaulting to a non-spec
value is not great, it's also not that critical. It might be worth
considering synchronizing Qt::WindowDoesNotAcceptFocus with the keyboard
interactivity flag, but the tricky part is that the keyboard interactivty
is not just a boolean.

BUG: 477251
2023-11-30 10:06:18 +00:00
9e1c5357ac Update version number for 5.90.0
GIT_SILENT
2023-11-29 10:24:25 +00:00
76e8f33cbc GIT_SILENT: Port to new CI template 2023-11-19 16:20:06 +01:00
25bc38dac1 Update version number for 5.81.80
GIT_SILENT
2023-11-17 12:28:29 +00:00
aa167e8da5 Update version number for 5.81.0
GIT_SILENT
2023-11-09 12:31:25 +00:00
de9fdb3fb7 Support XDG activation
QWaylandLayerShellIntegration has virtual hooks for Xdg Activation.

This is important to hook up in layer shell because activation using
requestActivate in Qt will go through this path. It also means we have
support for us to drop the implementation in KWindowSystem in favour of
calling into Qt.
2023-11-06 12:41:20 +00:00
00b26a196d set ecm soversion to project major
again probably not used but feels best to make them match
2023-11-03 10:19:42 +00:00
fcaf8cf95d Update PROJECT_VERSION_MAJOR to 6, this is mostly used in some internal soversions 2023-11-01 19:22:21 +00:00
1573a89aac Skip empty parts for stringToEnum template
metaEnum.keyToValue("") will results all flags get set, thus creating a
enum with empty (0) flags become impossible. This patch fixes that.
2023-09-26 17:25:20 +08:00
721c0ae334 Remove an inappropriate log message 2023-09-06 14:52:55 +03:00
143fd1755a Expose the Window interface to QML
If we are designing our UI's windows from QML, it makes sense that we
might want to configure how they're placed from the same place.

Everything was already in place but for a few technical bits which this
change adds.

Signed-off-by: Victoria Fischer <victoria.fischer@mbition.io>
2023-07-13 11:23:01 +02:00
d6aeaef1dc We use Qt6/kf6 only 2023-06-26 20:42:27 +02:00
c97826ab18 It compiles fine without deprecated methods 2023-06-12 14:00:48 +02:00
3bfed84c45 Now we depend against qt6 2023-06-08 19:17:22 +02:00
4cb2a27a4c Use qt6 only 2023-06-04 09:17:37 +02:00
9750fd8be7 Avoid emitting excessive changed signals
If the layer shell surface properties don't change, don't emit the
changed signals and issue wayland requests.
2023-05-17 14:57:09 +03:00
5e88f449b0 Introduce Window::closeOnDismissed() flag
This can be used to control the sending of QEvent::Close event.
2023-05-16 17:58:48 +03:00
497d50c4df Emit Window::layerChanged signal
Otherwise it's not possible to change layers at runtime.
2023-05-13 12:18:12 +03:00
541497ff5f Add wayland to third-party deps 2023-05-05 10:22:39 +02:00
1358743441 Call LayerShell::set_size when the window geometry changes
Without this when krunner expands, the frame after kwin will resize it
back to the last size the layer shell requested to be resized to.

To detect when we should not send an explicit size on window resize
events we check the anchors; if we're constrained on opposing edges we
want the compositor alone to set the size.
2023-05-01 14:38:36 +00:00
be63783888 Change default keyboard interactivity from exclusive to none
To be in line with the default of the protocol
2023-04-27 12:28:02 +02:00
87753746b9 chore: add missing override in example 2023-04-24 23:23:09 +03:00
49f31bb22d Replace Window::desiredOutput with a Window::screenConfiguration enum
To not overlap with QWindow::screen too much, introduce an enum to make it
more clear what the options and the resulting behaviour are.
2023-04-24 20:11:13 +00:00
511b92f4ab Port to QWaylandShellSurface::attachPopup() 2023-04-22 12:11:04 +03:00
fdab1544fb 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-22 12:11:04 +03:00
2985398375 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-22 12:11:01 +03:00
07e63cab8c Require C++20 2023-04-20 08:45:39 +02:00
488c6d759c Replace KF5 with KF6 2023-02-28 15:05:58 +01:00
d69a528b6c Require Qt 6.4 2023-02-28 15:05:34 +01:00
cfbfe94e79 Use KF6 libs on CI 2023-02-28 15:05:15 +01:00
2b757f3d82 Remove Qt5 CI 2023-02-28 15:05:03 +01:00
3c85e2e889 Use the QScreen of the QWindow as default output
If the Window::setDesiredOutput API was not called for the QWindow, use
QWindow::screen(). This allows assigning QWindows to specific screens using
the plain Qt API.

Passing nullptr to Window::setDesiredOutput explicitly results in nil as
desired output for the layer, which lets the compositor select a screen.
2023-02-22 08:23:17 +01:00
b9f8f6447d Update version number for 5.27.80
GIT_SILENT
2023-01-27 14:56:01 +00:00
7de801802b Revert "Show all headers in qtc6"
There was no consensus for this in Plasma.
This reverts commit 22df3fe914.
2023-01-24 08:49:43 +01:00
22df3fe914 Show all headers in qtc6 2023-01-22 17:38:12 +00:00
8d14abc707 Update kf5 version requirement to 5.102.0
GIT_SILENT
2023-01-21 20:06:42 +00:00
d06bcbe25b Update version number for 5.28.80
GIT_SILENT
2023-01-19 12:28:59 +00:00
18 changed files with 359 additions and 196 deletions

View File

@ -2,8 +2,8 @@
# SPDX-License-Identifier: CC0-1.0
include:
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/reuse-lint.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux-qt6.yml
- https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd-qt6.yml
- project: sysadmin/ci-utilities
file:
- /gitlab-templates/reuse-lint.yml
- /gitlab-templates/linux-qt6.yml
- /gitlab-templates/freebsd-qt6.yml

View File

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

View File

@ -4,19 +4,19 @@
cmake_minimum_required(VERSION 3.16)
project(layershellqt)
set(PROJECT_VERSION "5.27.6")
set(PROJECT_VERSION_MAJOR 5)
set(PROJECT_VERSION "5.92.0")
set(PROJECT_VERSION_MAJOR 6)
set(CMAKE_C_STANDARD 99)
set(QT_MIN_VERSION "5.15.2")
set(KF5_MIN_VERSION "5.102.0")
set(QT_MIN_VERSION "6.6.0")
set(KF6_MIN_VERSION "5.240.0")
set(KDE_COMPILERSETTINGS_LEVEL "5.82")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${ECM_MODULE_PATH})
include(KDEInstallDirs)
@ -29,15 +29,11 @@ include(CMakePackageConfigHelpers)
include(FeatureSummary)
include(GenerateExportHeader)
include(KDEClangFormat)
include(ECMQmlModule)
include(ECMQtDeclareLoggingCategory)
include(ECMQmlModule)
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(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml)
find_package(WaylandScanner REQUIRED)
find_package(Wayland 1.3 COMPONENTS Client Server)
find_package(WaylandProtocols REQUIRED)
@ -52,13 +48,13 @@ 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 5)
SOVERSION ${PROJECT_VERSION_MAJOR})
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h)
kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
ecm_set_disabled_deprecation_versions(QT 5.15.2
KF 5.101
ecm_set_disabled_deprecation_versions(QT 6.5
KF 5.240
)
add_subdirectory(src)

View File

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

View File

@ -4,17 +4,13 @@
remove_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS)
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}/staging/xdg-activation/xdg-activation-v1.xml
${CMAKE_CURRENT_SOURCE_DIR}/wlr-layer-shell-unstable-v1.xml
)
endif()
)
ecm_qt_declare_logging_category(LAYER_SHELL_SOURCES
ecm_qt_declare_logging_category(LayerShellQtInterface
HEADER
layershellqt_logging.h
IDENTIFIER
@ -23,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 qwaylandlayershell.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)

View File

@ -1,8 +1,10 @@
# 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")
target_sources(LayerShellQtQml PRIVATE layershellqtplugin.cpp)
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

@ -5,11 +5,15 @@
*/
#include "window.h"
#include "../qwaylandlayershellintegration_p.h"
#include <layershellqt_logging.h>
#include <QPointer>
#include <optional>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
using namespace LayerShellQt;
class LayerShellQt::WindowPrivate
@ -24,10 +28,11 @@ public:
QString scope = QStringLiteral("window");
Window::Anchors anchors = {Window::AnchorTop | Window::AnchorBottom | Window::AnchorLeft | Window::AnchorRight};
int32_t exclusionZone = 0;
Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityExclusive;
Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityOnDemand;
Window::Layer layer = Window::LayerTop;
QMargins margins;
std::optional<QPointer<QScreen>> desiredOutput;
Window::ScreenConfiguration screenConfiguration = Window::ScreenFromQWindow;
bool closeOnDismissed = true;
};
static QMap<QWindow *, Window *> s_map;
@ -39,8 +44,10 @@ Window::~Window()
void Window::setAnchors(Anchors anchors)
{
if (d->anchors != anchors) {
d->anchors = anchors;
Q_EMIT anchorsChanged();
}
}
Window::Anchors Window::anchors() const
@ -50,8 +57,10 @@ Window::Anchors Window::anchors() const
void Window::setExclusiveZone(int32_t zone)
{
if (d->exclusionZone != zone) {
d->exclusionZone = zone;
Q_EMIT exclusionZoneChanged();
}
}
int32_t Window::exclusionZone() const
@ -61,8 +70,10 @@ int32_t Window::exclusionZone() const
void Window::setMargins(const QMargins &margins)
{
if (d->margins != margins) {
d->margins = margins;
Q_EMIT marginsChanged();
}
}
QMargins Window::margins() const
@ -72,8 +83,10 @@ QMargins Window::margins() const
void Window::setKeyboardInteractivity(KeyboardInteractivity interactivity)
{
if (d->keyboardInteractivity != interactivity) {
d->keyboardInteractivity = interactivity;
Q_EMIT keyboardInteractivityChanged();
}
}
Window::KeyboardInteractivity Window::keyboardInteractivity() const
@ -83,7 +96,10 @@ Window::KeyboardInteractivity Window::keyboardInteractivity() const
void Window::setLayer(Layer layer)
{
if (d->layer != layer) {
d->layer = layer;
Q_EMIT layerChanged();
}
}
void Window::setScope(const QString &scope)
@ -102,19 +118,24 @@ Window::Layer Window::layer() const
return d->layer;
}
QScreen *Window::desiredOutput() const
Window::ScreenConfiguration Window::screenConfiguration() const
{
// Don't use .value_or here to avoid a temporary QPointer
if (d->desiredOutput.has_value()) {
return d->desiredOutput.value();
}
return d->parentWindow->screen();
return d->screenConfiguration;
}
void Window::setDesiredOutput(QScreen *output)
void Window::setScreenConfiguration(Window::ScreenConfiguration screenConfiguration)
{
d->desiredOutput = output;
d->screenConfiguration = screenConfiguration;
}
bool Window::closeOnDismissed() const
{
return d->closeOnDismissed;
}
void Window::setCloseOnDismissed(bool close)
{
d->closeOnDismissed = close;
}
Window::Window(QWindow *window)
@ -122,6 +143,27 @@ Window::Window(QWindow *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)

View File

@ -21,15 +21,15 @@ class WindowPrivate;
class LAYERSHELLQT_EXPORT Window : public QObject
{
Q_OBJECT
Q_PROPERTY(int anchors READ anchors WRITE setAnchorsInt NOTIFY anchorsChanged)
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(QWindow *window = nullptr);
~Window() override;
enum Anchor {
@ -62,6 +62,17 @@ 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;
@ -77,13 +88,8 @@ public:
void setLayer(Layer layer);
Layer layer() 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;
void setScreenConfiguration(ScreenConfiguration screenConfiguration);
ScreenConfiguration screenConfiguration() const;
/**
* Sets a string based identifier for this window.
@ -95,8 +101,14 @@ public:
void setScope(const QString &scope);
QString scope() const;
/// Workaround needed for Qt 5 not to get confused with types, not necessary on Qt 6
void setAnchorsInt(int x) { setAnchors(Anchors(x)); }
/**
* 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
@ -114,6 +126,7 @@ Q_SIGNALS:
void layerChanged();
private:
Window(QWindow *window);
QScopedPointer<WindowPrivate> d;
};

View File

@ -1,29 +0,0 @@
/*
* 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

@ -1,32 +0,0 @@
/*
* 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);
~QWaylandLayerShell() override;
QWaylandLayerSurface *createLayerSurface(QtWaylandClient::QWaylandWindow *window);
// TODO: Popups
};
}
#endif

View File

@ -5,45 +5,32 @@
* 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>(4)
, m_xdgActivation(new QWaylandXdgActivationV1)
{
}
QWaylandLayerShellIntegration::~QWaylandLayerShellIntegration()
{
}
bool QWaylandLayerShellIntegration::initialize(QtWaylandClient::QWaylandDisplay *display)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QWaylandShellIntegration::initialize(display);
#endif
display->addRegistryListener(registryLayer, this);
return m_layerShell != nullptr;
if (object() && zwlr_layer_shell_v1_get_version(object()) >= ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION) {
zwlr_layer_shell_v1_destroy(object());
}
}
QtWaylandClient::QWaylandShellSurface *QWaylandLayerShellIntegration::createShellSurface(QtWaylandClient::QWaylandWindow *window)
{
return m_layerShell->createLayerSurface(window);
return new QWaylandLayerSurface(this, 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,28 +8,26 @@
#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::QWaylandShellIntegration
class LAYERSHELLQT_EXPORT QWaylandLayerShellIntegration : public QtWaylandClient::QWaylandShellIntegrationTemplate<QWaylandLayerShellIntegration>, public QtWayland::zwlr_layer_shell_v1
{
public:
QWaylandLayerShellIntegration();
~QWaylandLayerShellIntegration() override;
bool initialize(QtWaylandClient::QWaylandDisplay *display) override;
QWaylandXdgActivationV1 *activation() const { return m_xdgActivation.data(); }
QtWaylandClient::QWaylandShellSurface *createShellSurface(QtWaylandClient::QWaylandWindow *window) override;
private:
static void registryLayer(void *data, struct wl_registry *registry, uint32_t id, const QString &interface, uint32_t version);
QScopedPointer<QWaylandLayerShell> m_layerShell;
QScopedPointer<QWaylandXdgActivationV1> m_xdgActivation;
};
}

View File

@ -5,28 +5,28 @@
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "interfaces/shell.h"
#include "interfaces/window.h"
#include "layershellqt_logging.h"
#include "qwaylandlayershell_p.h"
#include "qwaylandlayersurface_p.h"
#include "qwaylandxdgactivationv1_p.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(QWaylandLayerShell *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()))
{
LayerShellQt::Window *interface = Window::get(window->window());
Q_ASSERT(interface);
wl_output *output = nullptr;
QScreen *screen = interface->desiredOutput();
if (screen) {
auto waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen *>(screen->handle());
if (m_interface->screenConfiguration() == Window::ScreenFromQWindow) {
auto waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen *>(window->window()->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
// this will not cast to a QWaylandScreen
if (!waylandScreen) {
@ -35,32 +35,32 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShell *shell, QtWaylandC
output = waylandScreen->output();
}
}
init(shell->get_layer_surface(window->waylandSurface()->object(), output, interface->layer(), interface->scope()));
connect(interface, &Window::layerChanged, this, [this, interface]() {
setLayer(interface->layer());
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(interface->anchors());
connect(interface, &Window::anchorsChanged, this, [this, interface]() {
set_anchor(interface->anchors());
set_anchor(m_interface->anchors());
connect(m_interface, &Window::anchorsChanged, this, [this]() {
set_anchor(m_interface->anchors());
});
setExclusiveZone(interface->exclusionZone());
connect(interface, &Window::exclusionZoneChanged, this, [this, interface]() {
setExclusiveZone(interface->exclusionZone());
setExclusiveZone(m_interface->exclusionZone());
connect(m_interface, &Window::exclusionZoneChanged, this, [this]() {
setExclusiveZone(m_interface->exclusionZone());
});
setMargins(interface->margins());
connect(interface, &Window::marginsChanged, this, [this, interface]() {
setMargins(interface->margins());
setMargins(m_interface->margins());
connect(m_interface, &Window::marginsChanged, this, [this]() {
setMargins(m_interface->margins());
});
setKeyboardInteractivity(interface->keyboardInteractivity());
connect(interface, &Window::keyboardInteractivityChanged, this, [this, interface]() {
setKeyboardInteractivity(interface->keyboardInteractivity());
setKeyboardInteractivity(m_interface->keyboardInteractivity());
connect(m_interface, &Window::keyboardInteractivityChanged, this, [this]() {
setKeyboardInteractivity(m_interface->keyboardInteractivity());
});
QSize size = window->surfaceSize();
const Window::Anchors anchors = interface->anchors();
const Window::Anchors anchors = m_interface->anchors();
if ((anchors & Window::AnchorLeft) && (anchors & Window::AnchorRight)) {
size.setWidth(0);
}
@ -79,7 +79,9 @@ QWaylandLayerSurface::~QWaylandLayerSurface()
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)
@ -98,6 +100,17 @@ 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);
@ -106,6 +119,7 @@ void QWaylandLayerSurface::applyConfigure()
void QWaylandLayerSurface::setAnchor(uint anchor)
{
set_anchor(anchor);
setWindowGeometry(window()->windowContentGeometry());
}
void QWaylandLayerSurface::setExclusiveZone(int32_t zone)
@ -129,4 +143,69 @@ void QWaylandLayerSurface::setLayer(uint32_t layer)
set_layer(layer);
}
void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry)
{
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());
}
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,25 +10,29 @@
#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 QWaylandLayerShell;
class Window;
class LAYERSHELLQT_EXPORT QWaylandLayerSurface : public QtWaylandClient::QWaylandShellSurface, public QtWayland::zwlr_layer_surface_v1
{
Q_OBJECT
public:
QWaylandLayerSurface(QWaylandLayerShell *shell, QtWaylandClient::QWaylandWindow *window);
QWaylandLayerSurface(QWaylandLayerShellIntegration *shell, QtWaylandClient::QWaylandWindow *window);
~QWaylandLayerSurface() override;
bool isExposed() const override
{
return m_configured;
}
void attachPopup(QtWaylandClient::QWaylandShellSurface *popup) override;
void setAnchor(uint32_t anchor);
void setExclusiveZone(int32_t zone);
@ -37,12 +41,20 @@ public:
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 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;
};

View File

@ -0,0 +1,44 @@
/** 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

@ -0,0 +1,48 @@
/** 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

@ -14,7 +14,6 @@
#include <QMetaEnum>
#include <interfaces/shell.h>
#include <interfaces/window.h>
using namespace LayerShellQt;
@ -33,7 +32,7 @@ template<typename T>
T stringToEnum(QMetaEnum metaEnum, const QString &str)
{
T ret = {};
const auto splitted = str.split(QLatin1Char('|'));
const auto splitted = str.split(QLatin1Char('|'), Qt::SkipEmptyParts);
for (const auto &value : splitted) {
ret |= T(metaEnum.keyToValue(qPrintable(value)));
}
@ -42,7 +41,7 @@ T stringToEnum(QMetaEnum metaEnum, const QString &str)
class BasicWindow : public QRasterWindow
{
void paintEvent(QPaintEvent *)
void paintEvent(QPaintEvent *) override
{
QPainter p(this);
p.fillRect(QRect(0, 0, width(), height()), Qt::red);
@ -51,8 +50,6 @@ class BasicWindow : public QRasterWindow
int main(int argc, char **argv)
{
Shell::useLayerShell();
QGuiApplication app(argc, argv);
const auto layerMetaEnum = QMetaEnum::fromType<Window::Layer>();
@ -79,6 +76,8 @@ 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});
@ -102,6 +101,10 @@ 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

@ -5,7 +5,6 @@
*/
import QtQuick 2.15
import QtQuick.Window 2.15
import org.kde.layershell 1.0 as LayerShell
Item
@ -20,10 +19,6 @@ Item
LayerShell.Window.layer: LayerShell.Window.LayerBackground
LayerShell.Window.exclusionZone: -1
Component.onCompleted: {
console.log("xxxx", LayerShell.Window.AnchorLeft, LayerShell.Window.anchors)
}
width: 200
height: 150
Rectangle {