Compare commits

...

12 Commits

Author SHA1 Message Date
ec1a2d02fb Update Frameworks version requirement to 6.0.0
GIT_SILENT
2024-02-21 14:43:27 +00:00
c902d638ec Port to asynchronous roundtrip
When a resize is driven client side we wait for the compositor to have a
chance to reconfigure us before submitting the next frame.

Using a blocking round trip caused an issue. Instead block isExposed and
trigger an expose event whilst a sync is in progress.
2024-02-16 17:15:50 +00:00
176b7648d4 Synchronise client driven resizing
Qt's resizing is inherently synchronous. When an application calls
QWindow::setGeometry with a new size, we expect it to make that resize.
An expose event of the requested size will be generated.

Wayland is by default async, a client requests a size, and then will be
configured to that size, or potentially another size.

The simplest way to map the two APIs is to roundtrip when the client
wants to resize. This way we can guarantee that a call to
`setGeometry();  update()` will have the server configured size before
the paint.

In practice it's still not perfect due to other issues, but at least
will sort itself out within a frame.


(cherry picked from commit 697c747c58)
2024-02-14 12:10:19 +00:00
cce9896e42 Fix build with Qt 6.7
This also fixes a hypothetical case of a layer shell with subsurfaces
and matches the call made by xdgshell after the first configure.


(cherry picked from commit 6427176da4)
2024-02-08 10:19:13 +00:00
f7fee6e7f6 update version for new release 2024-02-01 09:46:00 +00:00
66ec181e1e Update version number for 5.93.0
GIT_SILENT
2024-01-31 13:01:20 +00:00
1abc1f381f Add a new setExclusiveEdge call in the protocol
This can be used to disambiguate the exclusive edge when the anchors are
on a corner (so there  would be 2 candidates)

it's quite quick and dirty mostly to understand if we do want to push
for something along the lines


(cherry picked from commit ad5246f0d0)
2024-01-26 11:39:06 +00:00
47539db4b3 Update version number for 5.92.90
GIT_SILENT
2024-01-10 14:17:49 +00:00
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
8 changed files with 117 additions and 10 deletions

View File

@ -4,13 +4,13 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(layershellqt) project(layershellqt)
set(PROJECT_VERSION "5.91.0") set(PROJECT_VERSION "6.0.0")
set(PROJECT_VERSION_MAJOR 6) set(PROJECT_VERSION_MAJOR 6)
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
set(QT_MIN_VERSION "6.6.0") set(QT_MIN_VERSION "6.6.0")
set(KF6_MIN_VERSION "5.240.0") set(KF6_MIN_VERSION "6.0.0")
set(KDE_COMPILERSETTINGS_LEVEL "5.82") set(KDE_COMPILERSETTINGS_LEVEL "5.82")
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
@ -30,6 +30,7 @@ include(FeatureSummary)
include(GenerateExportHeader) include(GenerateExportHeader)
include(KDEClangFormat) include(KDEClangFormat)
include(ECMQtDeclareLoggingCategory) include(ECMQtDeclareLoggingCategory)
include(ECMQmlModule)
find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml) find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml)

View File

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

View File

@ -28,6 +28,7 @@ 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::Anchor exclusiveEdge = Window::AnchorNone;
Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityOnDemand; Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityOnDemand;
Window::Layer layer = Window::LayerTop; Window::Layer layer = Window::LayerTop;
QMargins margins; QMargins margins;
@ -68,6 +69,21 @@ int32_t Window::exclusionZone() const
return d->exclusionZone; 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) void Window::setMargins(const QMargins &margins)
{ {
if (d->margins != margins) { if (d->margins != margins) {

View File

@ -33,6 +33,7 @@ public:
~Window() override; ~Window() override;
enum Anchor { enum Anchor {
AnchorNone = 0,
AnchorTop = 1, ///< The top edge of the anchor rectangle AnchorTop = 1, ///< The top edge of the anchor rectangle
AnchorBottom = 2, ///< The bottom edge of the anchor rectangle AnchorBottom = 2, ///< The bottom edge of the anchor rectangle
AnchorLeft = 4, ///< The left edge of the anchor rectangle AnchorLeft = 4, ///< The left edge of the anchor rectangle
@ -79,6 +80,9 @@ public:
void setExclusiveZone(int32_t zone); void setExclusiveZone(int32_t zone);
int32_t exclusionZone() const; int32_t exclusionZone() const;
void setExclusiveEdge(Window::Anchor edge);
Window::Anchor exclusiveEdge() const;
void setMargins(const QMargins &margins); void setMargins(const QMargins &margins);
QMargins margins() const; QMargins margins() const;
@ -121,6 +125,7 @@ public:
Q_SIGNALS: Q_SIGNALS:
void anchorsChanged(); void anchorsChanged();
void exclusionZoneChanged(); void exclusionZoneChanged();
void exclusiveEdgeChanged();
void marginsChanged(); void marginsChanged();
void keyboardInteractivityChanged(); void keyboardInteractivityChanged();
void layerChanged(); void layerChanged();

View File

@ -15,7 +15,7 @@
namespace LayerShellQt namespace LayerShellQt
{ {
QWaylandLayerShellIntegration::QWaylandLayerShellIntegration() QWaylandLayerShellIntegration::QWaylandLayerShellIntegration()
: QWaylandShellIntegrationTemplate<QWaylandLayerShellIntegration>(4) : QWaylandShellIntegrationTemplate<QWaylandLayerShellIntegration>(5)
, m_xdgActivation(new QWaylandXdgActivationV1) , m_xdgActivation(new QWaylandXdgActivationV1)
{ {
} }

View File

@ -23,6 +23,7 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
, QtWayland::zwlr_layer_surface_v1() , QtWayland::zwlr_layer_surface_v1()
, m_shell(shell) , m_shell(shell)
, m_interface(Window::get(window->window())) , m_interface(Window::get(window->window()))
, m_window(window)
{ {
wl_output *output = nullptr; wl_output *output = nullptr;
if (m_interface->screenConfiguration() == Window::ScreenFromQWindow) { if (m_interface->screenConfiguration() == Window::ScreenFromQWindow) {
@ -48,6 +49,10 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
connect(m_interface, &Window::exclusionZoneChanged, this, [this]() { connect(m_interface, &Window::exclusionZoneChanged, this, [this]() {
setExclusiveZone(m_interface->exclusionZone()); setExclusiveZone(m_interface->exclusionZone());
}); });
setExclusiveEdge(m_interface->exclusiveEdge());
connect(m_interface, &Window::exclusiveEdgeChanged, this, [this]() {
setExclusiveEdge(m_interface->exclusiveEdge());
});
setMargins(m_interface->margins()); setMargins(m_interface->margins());
connect(m_interface, &Window::marginsChanged, this, [this]() { connect(m_interface, &Window::marginsChanged, this, [this]() {
@ -74,6 +79,9 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
QWaylandLayerSurface::~QWaylandLayerSurface() QWaylandLayerSurface::~QWaylandLayerSurface()
{ {
if (m_waitForSyncCallback) {
wl_callback_destroy(m_waitForSyncCallback);
}
destroy(); destroy();
} }
@ -92,7 +100,7 @@ void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint
if (!m_configured) { if (!m_configured) {
m_configured = true; m_configured = true;
window()->resizeFromApplyConfigure(m_pendingSize); window()->resizeFromApplyConfigure(m_pendingSize);
window()->handleExpose(QRect(QPoint(), m_pendingSize)); sendExpose();
} else { } else {
// Later configures are resizes, so we have to queue them up for a time when we // Later configures are resizes, so we have to queue them up for a time when we
// are not painting to the window. // are not painting to the window.
@ -119,6 +127,7 @@ void QWaylandLayerSurface::applyConfigure()
void QWaylandLayerSurface::setAnchor(uint anchor) void QWaylandLayerSurface::setAnchor(uint anchor)
{ {
set_anchor(anchor); set_anchor(anchor);
setWindowGeometry(window()->windowContentGeometry());
} }
void QWaylandLayerSurface::setExclusiveZone(int32_t zone) void QWaylandLayerSurface::setExclusiveZone(int32_t zone)
@ -126,6 +135,13 @@ void QWaylandLayerSurface::setExclusiveZone(int32_t zone)
set_exclusive_zone(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) void QWaylandLayerSurface::setMargins(const QMargins &margins)
{ {
set_margin(margins.top(), margins.right(), margins.bottom(), margins.left()); set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
@ -144,8 +160,13 @@ void QWaylandLayerSurface::setLayer(uint32_t layer)
void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry) void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry)
{ {
const bool horizontallyConstrained = m_interface->anchors() & (Window::AnchorLeft & Window::AnchorRight); // if we are setting it to the last size we were configured at, we don't need to do anything
const bool verticallyConstrained = m_interface->anchors() & (Window::AnchorTop & Window::AnchorBottom); 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(); QSize size = geometry.size();
if (horizontallyConstrained) { if (horizontallyConstrained) {
@ -155,6 +176,7 @@ void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry)
size.setHeight(0); size.setHeight(0);
} }
set_size(size.width(), size.height()); set_size(size.width(), size.height());
requestWaylandSync();
} }
bool QWaylandLayerSurface::requestActivate() bool QWaylandLayerSurface::requestActivate()
@ -203,7 +225,43 @@ void QWaylandLayerSurface::requestXdgActivationToken(quint32 serial)
Q_EMIT window()->xdgActivationTokenCreated(token); Q_EMIT window()->xdgActivationTokenCreated(token);
}); });
connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, tokenProvider, &QObject::deleteLater); 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

@ -30,12 +30,13 @@ public:
bool isExposed() const override bool isExposed() const override
{ {
return m_configured; return m_configured && !m_waitForSyncCallback;
} }
void attachPopup(QtWaylandClient::QWaylandShellSurface *popup) override; void attachPopup(QtWaylandClient::QWaylandShellSurface *popup) override;
void setAnchor(uint32_t anchor); void setAnchor(uint32_t anchor);
void setExclusiveZone(int32_t zone); void setExclusiveZone(int32_t zone);
void setExclusiveEdge(uint32_t edge);
void setMargins(const QMargins &margins); void setMargins(const QMargins &margins);
void setKeyboardInteractivity(uint32_t interactivity); void setKeyboardInteractivity(uint32_t interactivity);
void setLayer(uint32_t layer); void setLayer(uint32_t layer);
@ -48,14 +49,22 @@ public:
void requestXdgActivationToken(quint32 serial) override; void requestXdgActivationToken(quint32 serial) override;
private: 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_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; QWaylandLayerShellIntegration *m_shell;
LayerShellQt::Window *m_interface; LayerShellQt::Window *m_interface;
QtWaylandClient::QWaylandWindow *m_window;
QSize m_pendingSize; QSize m_pendingSize;
QString m_activationToken; QString m_activationToken;
bool m_configured = false; bool m_configured = false;
static const wl_callback_listener syncCallbackListener;
struct wl_callback *m_waitForSyncCallback = nullptr;
}; };
} }

View File

@ -25,7 +25,7 @@
THIS SOFTWARE. THIS SOFTWARE.
</copyright> </copyright>
<interface name="zwlr_layer_shell_v1" version="4"> <interface name="zwlr_layer_shell_v1" version="5">
<description summary="create surfaces that are layers of the desktop"> <description summary="create surfaces that are layers of the desktop">
Clients can use this interface to assign the surface_layer role to 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 wl_surfaces. Such surfaces are assigned to a "layer" of the output and
@ -100,7 +100,7 @@
</request> </request>
</interface> </interface>
<interface name="zwlr_layer_surface_v1" version="4"> <interface name="zwlr_layer_surface_v1" version="5">
<description summary="layer metadata interface"> <description summary="layer metadata interface">
An interface that may be implemented by a wl_surface, for surfaces that 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 are designed to be rendered as a layer of a stacked desktop-like
@ -367,6 +367,7 @@
<entry name="invalid_size" value="1" summary="size is invalid"/> <entry name="invalid_size" value="1" summary="size is invalid"/>
<entry name="invalid_anchor" value="2" summary="anchor bitfield 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_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>
<enum name="anchor" bitfield="true"> <enum name="anchor" bitfield="true">
@ -386,5 +387,21 @@
</description> </description>
<arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/> <arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
</request> </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> </interface>
</protocol> </protocol>