Compare commits

..

21 Commits

Author SHA1 Message Date
7a746346b0 Update version for new release 6.4.91 2025-10-02 15:55:45 +05:30
ebd64dd395 Update version for new release 6.4.90 2025-09-18 17:26:46 +05:30
ca0ac57fb4 Update Qt version requirement to 6.9.0
GIT_SILENT
2025-09-18 14:00:16 +05:30
d085a88c81 Update Frameworks version requirement to 6.18.0
GIT_SILENT
2025-09-18 14:00:16 +05:30
5e57a060c6 Register anchors flags to QML
CCBUG: 507602
2025-08-05 13:04:50 +02:00
d436a779d7 Request activate on show
Unless the window doesn't have keyboard interactivity or the caller
wants it not to.

To match XDG Shell behavior and general Qt window behavior.
2025-08-03 10:08:40 +00:00
f599e829ad When activating, also try token from XDG_ACTIVATION_TOKEN
This matches upstream QWaylandXdgSurface behavior.

It also makes various activation magic e.g. KDBusService work.
2025-07-30 23:29:13 +00:00
397398dfd8 Port to declarative type registration
BUG: 507602
2025-07-30 21:39:23 +02:00
7a074a3684 update version for new release 2025-05-19 18:33:35 +05:30
8b54edb695 update version for new release 2025-05-15 15:14:19 +05:30
ffa33fef9f Update Qt version requirement to 6.8.0
GIT_SILENT
2025-05-15 14:20:07 +05:30
3522070454 Update Frameworks version requirement to 6.14.0
GIT_SILENT
2025-05-15 14:20:07 +05:30
80d5e3c935 Expose setDesiredSize to the C++ API
Making it possible for clients to call setDesiredSize directly,

The idea is that under Wayland, the panel calls this intead of setGeometry,
not trying to set an abosulute geometry that might cause the panel sized wrongly,
but just sets an hint which will ensure the panel won't overlap another one

used by https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/5437

CCBUG:489703
2025-04-30 17:23:48 +02:00
b37ac92e9f CI: Add linux-qt6-next build 2025-02-12 07:28:37 +01:00
c8c8e3e983 Add xml/yaml linting 2025-02-01 09:52:29 +01:00
72d40f696e Fix build with Qt 6.10
The private parts have been extracted into a separate CMake config file, which we need to search for now

See https://bugreports.qt.io/browse/QTBUG-87776
2025-01-29 15:34:52 +01:00
ac333b19c7 update version for new release 2025-01-09 12:46:54 +00:00
c85d6e7baa update version for new release 2025-01-09 11:01:05 +00:00
e534206172 Update Frameworks version requirement to 6.10.0
GIT_SILENT
2025-01-09 10:29:52 +00:00
edb8f67b1b It compiles without deprecated methods 2024-12-18 13:24:21 +01:00
1796255496 update version for new release 2024-10-03 13:11:32 +01:00
14 changed files with 216 additions and 68 deletions

View File

@ -7,3 +7,6 @@ include:
- /gitlab-templates/reuse-lint.yml
- /gitlab-templates/linux-qt6.yml
- /gitlab-templates/freebsd-qt6.yml
- /gitlab-templates/xml-lint.yml
- /gitlab-templates/yaml-lint.yml
- /gitlab-templates/linux-qt6-next.yml

View File

@ -2,11 +2,11 @@
# SPDX-License-Identifier: CC0-1.0
Dependencies:
- 'on': ['@all']
'require':
- 'on': ['@all']
'require':
'frameworks/extra-cmake-modules': '@latest-kf6'
'third-party/wayland': '@latest'
'third-party/wayland-protocols': '@latest'
Options:
require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows']
require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows']

View File

@ -4,13 +4,13 @@
cmake_minimum_required(VERSION 3.16)
project(layershellqt)
set(PROJECT_VERSION "6.1.90")
set(PROJECT_VERSION "6.4.91")
set(PROJECT_VERSION_MAJOR 6)
set(CMAKE_C_STANDARD 99)
set(QT_MIN_VERSION "6.7.0")
set(KF6_MIN_VERSION "6.5.0")
set(QT_MIN_VERSION "6.9.0")
set(KF6_MIN_VERSION "6.18.0")
set(KDE_COMPILERSETTINGS_LEVEL "5.82")
set(CMAKE_CXX_STANDARD 20)
@ -34,6 +34,11 @@ include(ECMQmlModule)
include(KDEGitCommitHooks)
find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml)
if (Qt6WaylandClient_VERSION VERSION_GREATER_EQUAL "6.10.0")
find_package(Qt6WaylandClientPrivate ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE)
endif()
find_package(WaylandScanner REQUIRED)
find_package(Wayland 1.3 COMPONENTS Client Server)
find_package(WaylandProtocols REQUIRED)
@ -55,8 +60,8 @@ kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT)
ecm_set_disabled_deprecation_versions(QT 6.5
KF 5.240
ecm_set_disabled_deprecation_versions(QT 6.8.1
KF 6.9.0
)
add_subdirectory(src)

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: CC0-1.0
maintainer:
- vladz
- vladz
description: Layer Shell Qt
platforms:
- name: Linux

View File

@ -5,6 +5,8 @@ remove_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS)
add_library(LayerShellQtInterface)
qt6_extract_metatypes(LayerShellQtInterface)
if (Qt6_VERSION VERSION_GREATER_EQUAL "6.8.0")
set(private_code_option "PRIVATE_CODE")
endif()

View File

@ -4,7 +4,8 @@
ecm_add_qml_module(LayerShellQtQml
URI "org.kde.layershell"
VERSION 1.0
SOURCES layershellqtplugin.cpp)
SOURCES types.h types.cpp
GENERATE_PLUGIN_SOURCE)
target_link_libraries(LayerShellQtQml PRIVATE Qt::Qml LayerShellQtInterface)
ecm_finalize_qml_module(LayerShellQtQml DESTINATION ${KDE_INSTALL_QMLDIR})
ecm_finalize_qml_module(LayerShellQtQml DESTINATION ${KDE_INSTALL_QMLDIR})

View File

@ -1,51 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleix.pol_gonzalez@mercedes-benz.com>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "../interfaces/window.h"
#include <QQmlExtensionPlugin>
#include <qqml.h>
QML_DECLARE_TYPEINFO(LayerShellQt::Window, QML_HAS_ATTACHED_PROPERTIES)
class ExtQMargins
{
QMargins m_margins;
Q_GADGET
Q_PROPERTY(int left READ left WRITE setLeft FINAL)
Q_PROPERTY(int right READ right WRITE setRight FINAL)
Q_PROPERTY(int top READ top WRITE setTop FINAL)
Q_PROPERTY(int bottom READ bottom WRITE setBottom FINAL)
QML_FOREIGN(QMargins)
QML_EXTENDED(ExtQMargins)
public:
ExtQMargins(const QMargins &margins);
int left() const { return m_margins.left(); }
void setLeft(int left) { m_margins.setLeft(left); }
int right() const { return m_margins.right(); }
void setRight(int right) { m_margins.setRight(right); }
int top() const { return m_margins.top(); }
void setTop(int top) { m_margins.setTop(top); }
int bottom() const { return m_margins.bottom(); }
void setBottom(int bottom) { m_margins.setBottom(bottom); }
};
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");
qmlRegisterExtendedUncreatableType<QMargins, ExtQMargins>(uri, 1, 0, "ExtQMargins", QStringLiteral("Only created from C++"));
}
};
#include "layershellqtplugin.moc"

49
src/declarative/types.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleix.pol_gonzalez@mercedes-benz.com>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "types.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 1)
int QQmlMarginsValueType::left() const
{
return m.left();
}
int QQmlMarginsValueType::top() const
{
return m.top();
}
int QQmlMarginsValueType::right() const
{
return m.right();
}
int QQmlMarginsValueType::bottom() const
{
return m.bottom();
}
void QQmlMarginsValueType::setLeft(int left)
{
m.setLeft(left);
}
void QQmlMarginsValueType::setTop(int top)
{
m.setTop(top);
}
void QQmlMarginsValueType::setRight(int right)
{
m.setRight(right);
}
void QQmlMarginsValueType::setBottom(int bottom)
{
m.setBottom(bottom);
}
#endif

55
src/declarative/types.h Normal file
View File

@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleix.pol_gonzalez@mercedes-benz.com>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "../interfaces/window.h"
#include <qqml.h>
QML_DECLARE_TYPEINFO(LayerShellQt::Window, QML_HAS_ATTACHED_PROPERTIES)
class WindowForeign
{
Q_GADGET
QML_NAMED_ELEMENT(Window)
QML_FOREIGN(LayerShellQt::Window)
QML_UNCREATABLE("")
QML_ATTACHED(LayerShellQt::Window)
};
// available upstream since https://invent.kde.org/qt/qt/qtdeclarative/-/commit/a398101f715bfc447aa889fc9c58b13bfe75ab47
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 1)
struct Q_QML_EXPORT QQmlMarginsValueType {
QMargins m;
Q_PROPERTY(int left READ left WRITE setLeft FINAL)
Q_PROPERTY(int right READ right WRITE setRight FINAL)
Q_PROPERTY(int top READ top WRITE setTop FINAL)
Q_PROPERTY(int bottom READ bottom WRITE setBottom FINAL)
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QMargins)
QML_EXTENDED(QQmlMarginsValueType)
QML_STRUCTURED_VALUE
public:
QQmlMarginsValueType() = default;
Q_INVOKABLE QQmlMarginsValueType(const QMarginsF &margins)
: m(margins.toMargins())
{
}
int left() const;
int right() const;
int top() const;
int bottom() const;
void setLeft(int);
void setRight(int);
void setTop(int);
void setBottom(int);
operator QMargins() const
{
return m;
}
};
#endif

View File

@ -32,8 +32,10 @@ public:
Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityOnDemand;
Window::Layer layer = Window::LayerTop;
QMargins margins;
QSize desiredSize = QSize(0, 0);
Window::ScreenConfiguration screenConfiguration = Window::ScreenFromQWindow;
bool closeOnDismissed = true;
bool activateOnShow = true;
};
static QMap<QWindow *, Window *> s_map;
@ -97,6 +99,21 @@ QMargins Window::margins() const
return d->margins;
}
void Window::setDesiredSize(const QSize &size)
{
if (size == d->desiredSize) {
return;
}
d->desiredSize = size;
Q_EMIT desiredSizeChanged();
}
QSize Window::desiredSize() const
{
return d->desiredSize;
}
void Window::setKeyboardInteractivity(KeyboardInteractivity interactivity)
{
if (d->keyboardInteractivity != interactivity) {
@ -154,6 +171,16 @@ void Window::setCloseOnDismissed(bool close)
d->closeOnDismissed = close;
}
bool Window::activateOnShow() const
{
return d->activateOnShow;
}
void Window::setActivateOnShow(bool activateOnShow)
{
d->activateOnShow = activateOnShow;
}
Window::Window(QWindow *window)
: QObject(window)
, d(new WindowPrivate(window))

View File

@ -28,6 +28,7 @@ class LAYERSHELLQT_EXPORT Window : public QObject
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)
Q_PROPERTY(bool activateOnShow READ activateOnShow WRITE setActivateOnShow)
public:
~Window() override;
@ -39,8 +40,8 @@ public:
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)
Q_FLAG(Anchors)
/**
* This enum type is used to specify the layer where a surface can be put in.
@ -86,6 +87,9 @@ public:
void setMargins(const QMargins &margins);
QMargins margins() const;
void setDesiredSize(const QSize &size);
QSize desiredSize() const;
void setKeyboardInteractivity(KeyboardInteractivity interactivity);
KeyboardInteractivity keyboardInteractivity() const;
@ -114,6 +118,18 @@ public:
void setCloseOnDismissed(bool close);
bool closeOnDismissed() const;
/**
* Whether the window should requestActivate on show.
*
* Normally, you want this enabled but in case of e.g. a desktop window, this can be disabled.
*
* It does nothing when KeyboardInteractivity is KeyboardInteractivityNone.
*
* The default is true.
*/
void setActivateOnShow(bool activateOnShow);
bool activateOnShow() const;
/**
* Gets the LayerShell Window for a given Qt Window
* Ownership is not transferred
@ -127,6 +143,7 @@ Q_SIGNALS:
void exclusionZoneChanged();
void exclusiveEdgeChanged();
void marginsChanged();
void desiredSizeChanged();
void keyboardInteractivityChanged();
void layerChanged();

View File

@ -44,7 +44,11 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
setAnchor(m_interface->anchors());
connect(m_interface, &Window::anchorsChanged, this, [this]() {
setAnchor(m_interface->anchors());
setDesiredSize(m_window->windowContentGeometry().size());
if (m_interface->desiredSize().isNull()) {
setDesiredSize(m_window->windowContentGeometry().size());
} else {
setDesiredSize(m_interface->desiredSize());
}
});
setExclusiveZone(m_interface->exclusionZone());
@ -61,12 +65,22 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
setMargins(m_interface->margins());
});
connect(m_interface, &Window::desiredSizeChanged, this, [this]() {
if (!m_interface->desiredSize().isNull()) {
setDesiredSize(m_interface->desiredSize());
}
});
setKeyboardInteractivity(m_interface->keyboardInteractivity());
connect(m_interface, &Window::keyboardInteractivityChanged, this, [this]() {
setKeyboardInteractivity(m_interface->keyboardInteractivity());
});
setDesiredSize(window->windowContentGeometry().size());
if (m_interface->desiredSize().isNull()) {
setDesiredSize(window->windowContentGeometry().size());
} else {
setDesiredSize(m_interface->desiredSize());
}
}
QWaylandLayerSurface::~QWaylandLayerSurface()
@ -174,12 +188,16 @@ void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry)
return;
}
setDesiredSize(geometry.size());
if (m_interface->desiredSize().isNull()) {
setDesiredSize(geometry.size());
}
}
#else
void QWaylandLayerSurface::setWindowSize(const QSize &size)
{
setDesiredSize(size);
if (m_interface->desiredSize().isNull()) {
setDesiredSize(size);
}
}
#endif
@ -193,6 +211,10 @@ bool QWaylandLayerSurface::requestActivate()
activation->activate(m_activationToken, window()->wlSurface());
m_activationToken = {};
return true;
} else if (const auto token = qEnvironmentVariable("XDG_ACTIVATION_TOKEN"); !token.isEmpty()) {
activation->activate(token, window()->wlSurface());
qunsetenv("XDG_ACTIVATION_TOKEN");
return true;
} else {
const auto focusWindow = QGuiApplication::focusWindow();
const auto wlWindow = focusWindow ? static_cast<QtWaylandClient::QWaylandWindow *>(focusWindow->handle()) : window();
@ -208,6 +230,23 @@ bool QWaylandLayerSurface::requestActivate()
return false;
}
bool QWaylandLayerSurface::requestActivateOnShow()
{
if (!m_interface->activateOnShow()) {
return false;
}
if (m_interface->keyboardInteractivity() == Window::KeyboardInteractivityNone) {
return false;
}
if (m_window->window()->property("_q_showWithoutActivating").toBool()) {
return false;
}
return requestActivate();
}
void QWaylandLayerSurface::setXdgActivationToken(const QString &token)
{
m_activationToken = token;

View File

@ -50,6 +50,7 @@ public:
#endif
bool requestActivate() override;
bool requestActivateOnShow() override;
void setXdgActivationToken(const QString &token) override;
void requestXdgActivationToken(quint32 serial) override;

View File

@ -53,7 +53,7 @@ int main(int argc, char **argv)
QGuiApplication app(argc, argv);
const auto layerMetaEnum = QMetaEnum::fromType<Window::Layer>();
const auto anchorMetaEnum = QMetaEnum::fromType<Window::Anchor>();
const auto anchorMetaEnum = QMetaEnum::fromType<Window::Anchors>();
QCommandLineParser parser;
QCommandLineOption marginsOption(QStringLiteral("margins"), QStringLiteral("Window margins"), QStringLiteral("pixels"), QStringLiteral("0"));