Compare commits

..

1 Commits

Author SHA1 Message Date
38e36e8131 Allow specifying margins as fraactions
Absolute margin values pose a problem if you want to place a surface
certain distance away from a screen edge (in percents) but you also want
the compositor to place the surface on the active output.

At the moment, this issue is worked around by using kwin dbus api to
query the active output. This is not good.

This change is a take on allowing to specify margin values in fractions.
It can be used to drop a dbus call in krunner and assist us with porting
other components to layer shell, e.g. OSDs, they also need to be placed
one third away the bottom screen edge.
2025-12-08 10:01:32 +02:00
12 changed files with 448 additions and 210 deletions

View File

@ -4,13 +4,13 @@
cmake_minimum_required(VERSION 3.16)
project(layershellqt)
set(PROJECT_VERSION "6.6.80")
set(PROJECT_VERSION "6.5.80")
set(PROJECT_VERSION_MAJOR 6)
set(CMAKE_C_STANDARD 99)
set(QT_MIN_VERSION "6.10.0")
set(KF6_MIN_VERSION "6.22.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)
@ -32,7 +32,6 @@ include(KDEClangFormat)
include(ECMQtDeclareLoggingCategory)
include(ECMQmlModule)
include(KDEGitCommitHooks)
include(ECMGenerateExportHeader)
find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS WaylandClient Qml)

View File

@ -64,12 +64,10 @@ ecm_generate_headers(LayerShellQt_HEADERS
)
ecm_generate_export_header(LayerShellQtInterface
generate_export_header(LayerShellQtInterface
BASE_NAME LayerShellQtInterface
EXPORT_MACRO_NAME LAYERSHELLQT_EXPORT
EXPORT_FILE_NAME LayerShellQt/layershellqt_export.h
VERSION ${LAYERSHELLQT_VERSION}
DEPRECATION_VERSIONS 6.6
)
install(TARGETS layer-shell

View File

@ -5,9 +5,6 @@
*/
#include "shell.h"
#if LAYERSHELLQTINTERFACE_BUILD_DEPRECATED_SINCE(6, 6)
#include <QByteArray>
#include <layershellqt_logging.h>
#include <qglobal.h>
@ -21,4 +18,3 @@ void Shell::useLayerShell()
qCDebug(LAYERSHELLQT) << "Unable to set QT_WAYLAND_SHELL_INTEGRATION=layer-shell";
}
}
#endif

View File

@ -8,9 +8,7 @@
#define LAYERSHELLQTSHELL_H
#include "layershellqt_export.h"
#if LAYERSHELLQTINTERFACE_ENABLE_DEPRECATED_SINCE(6, 6)
#include "window.h"
#include <QString>
namespace LayerShellQt
@ -21,11 +19,9 @@ namespace LayerShellQt
class LAYERSHELLQT_EXPORT Shell
{
public:
LAYERSHELLQTINTERFACE_DEPRECATED_VERSION(6, 6, "Calling useLayerShell is not needed since Qt 6.5")
static void useLayerShell();
};
}
#endif
#endif

View File

@ -7,16 +7,59 @@
#include "window.h"
#include "../qwaylandlayershellintegration_p.h"
#include <QtWaylandClient/private/qwaylandclientshellapi_p.h>
#include <layershellqt_logging.h>
#include <QPlatformSurfaceEvent>
#include <QPointer>
#include <mutex>
#include <optional>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
using namespace LayerShellQt;
Margin::Margin()
: m_value(0)
{
}
Margin::Margin(int pixels)
: m_value(pixels)
{
}
Margin::Margin(qreal fraction)
: m_value(fraction)
{
}
Margin Margin::fromPixels(int pixels)
{
return Margin(pixels);
}
Margin Margin::fromFraction(qreal fraction)
{
return Margin(fraction);
}
std::optional<int> Margin::pixels() const
{
if (std::holds_alternative<int>(m_value)) {
return std::get<int>(m_value);
} else {
return std::nullopt;
}
}
std::optional<qreal> Margin::fraction() const
{
if (std::holds_alternative<qreal>(m_value)) {
return std::get<qreal>(m_value);
} else {
return std::nullopt;
}
}
class LayerShellQt::WindowPrivate
{
public:
@ -32,10 +75,12 @@ public:
Window::Anchor exclusiveEdge = Window::AnchorNone;
Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityOnDemand;
Window::Layer layer = Window::LayerTop;
QMargins margins;
Margin leftMargin;
Margin topMargin;
Margin rightMargin;
Margin bottomMargin;
QSize desiredSize = QSize(0, 0);
QPointer<QScreen> screen;
bool wantsToBeOnActiveScreen = false;
Window::ScreenConfiguration screenConfiguration = Window::ScreenFromQWindow;
bool closeOnDismissed = true;
bool activateOnShow = true;
};
@ -90,15 +135,74 @@ Window::Anchor Window::exclusiveEdge() const
void Window::setMargins(const QMargins &margins)
{
if (d->margins != margins) {
d->margins = margins;
Q_EMIT marginsChanged();
}
setLeftMargin(Margin::fromPixels(margins.left()));
setTopMargin(Margin::fromPixels(margins.top()));
setRightMargin(Margin::fromPixels(margins.right()));
setBottomMargin(Margin::fromPixels(margins.bottom()));
}
QMargins Window::margins() const
{
return d->margins;
return QMargins(d->leftMargin.pixels().value_or(0),
d->topMargin.pixels().value_or(0),
d->rightMargin.pixels().value_or(0),
d->bottomMargin.pixels().value_or(0));
}
void Window::setLeftMargin(Margin margin)
{
if (d->leftMargin != margin) {
d->leftMargin = margin;
Q_EMIT leftMarginChanged();
Q_EMIT marginsChanged();
}
}
Margin Window::leftMargin() const
{
return d->leftMargin;
}
void Window::setTopMargin(Margin margin)
{
if (d->topMargin != margin) {
d->topMargin = margin;
Q_EMIT topMarginChanged();
Q_EMIT marginsChanged();
}
}
Margin Window::topMargin() const
{
return d->topMargin;
}
void Window::setRightMargin(Margin margin)
{
if (d->rightMargin != margin) {
d->rightMargin = margin;
Q_EMIT rightMarginChanged();
Q_EMIT marginsChanged();
}
}
Margin Window::rightMargin() const
{
return d->rightMargin;
}
void Window::setBottomMargin(Margin margin)
{
if (d->bottomMargin != margin) {
d->bottomMargin = margin;
Q_EMIT bottomMarginChanged();
Q_EMIT marginsChanged();
}
}
Margin Window::bottomMargin() const
{
return d->bottomMargin;
}
void Window::setDesiredSize(const QSize &size)
@ -153,73 +257,14 @@ Window::Layer Window::layer() const
return d->layer;
}
#if LAYERSHELLQTINTERFACE_BUILD_DEPRECATED_SINCE(6, 6)
Window::ScreenConfiguration Window::screenConfiguration() const
{
if (wantsToBeOnActiveScreen()) {
return ScreenFromCompositor;
} else {
// If an explicit screen is set, it's quite inaccurate but it should be fine.
return ScreenFromQWindow;
}
return d->screenConfiguration;
}
void Window::setScreenConfiguration(ScreenConfiguration screenConfiguration)
void Window::setScreenConfiguration(Window::ScreenConfiguration screenConfiguration)
{
static std::once_flag deprecationFlag;
std::call_once(deprecationFlag, []() {
qWarning() << "LayerShellQt.Window.screenConfiguration is deprecated use screen and wantsToBeOnActiveScreen instead";
});
if (screenConfiguration == ScreenFromCompositor) {
setWantsToBeOnActiveScreen(true);
} else {
setWantsToBeOnActiveScreen(false);
setScreen(nullptr);
}
}
#endif
void Window::setWantsToBeOnActiveScreen(bool set)
{
if (d->wantsToBeOnActiveScreen == set) {
return;
}
d->wantsToBeOnActiveScreen = set;
if (d->wantsToBeOnActiveScreen && d->screen) {
d->screen = nullptr;
Q_EMIT screenChanged();
}
Q_EMIT wantsToBeOnActiveScreenChanged();
}
bool Window::wantsToBeOnActiveScreen() const
{
return d->wantsToBeOnActiveScreen;
}
void Window::setScreen(QScreen *screen)
{
if (d->screen == screen) {
return;
}
d->screen = screen;
if (d->screen && d->wantsToBeOnActiveScreen) {
d->wantsToBeOnActiveScreen = false;
Q_EMIT wantsToBeOnActiveScreenChanged();
}
Q_EMIT screenChanged();
}
QScreen *Window::screen() const
{
return d->screen;
d->screenConfiguration = screenConfiguration;
}
bool Window::closeOnDismissed() const
@ -273,27 +318,23 @@ bool Window::eventFilter(QObject *watched, QEvent *event)
void Window::initializeShell()
{
// FIXME
// auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow *>(d->parentWindow->handle());
// if (!waylandWindow) {
// qCWarning(LAYERSHELLQT) << d->parentWindow << "is not a wayland window. Not creating zwlr_layer_surface";
// return;
// }
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow *>(d->parentWindow->handle());
if (!waylandWindow) {
qCWarning(LAYERSHELLQT) << d->parentWindow << "is not a wayland window. Not creating zwlr_layer_surface";
return;
}
static QWaylandLayerShellIntegration *shellIntegration = nullptr;
if (!shellIntegration) {
shellIntegration = new QWaylandLayerShellIntegration();
// Why does it take a display that is unused
if (!shellIntegration->initialize(nullptr)) {
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;
}
}
// FIXME this is relevant when the plugin is not the default shell integration
// Something like QWaylandShellIntegration::assignToWindow(QPlatformWindow *)?
// waylandWindow->setShellIntegration(shellIntegration);
waylandWindow->setShellIntegration(shellIntegration);
}
Window *Window::get(QWindow *window)

View File

@ -18,6 +18,34 @@ namespace LayerShellQt
{
class WindowPrivate;
/**
* The Margin type provides a way to specify how far a layer surface should be away from a screen edge.
*
* A margin can have an absolute value or a percent value. An absolute value indicates the distance
* in pixels. A percent value indicates the distance as a percentage of the output size, for example
* this can be used to tell the compositor that the surface should be one third of the output height from
* a screen edge, etc.
*/
class LAYERSHELLQT_EXPORT Margin
{
public:
static Margin fromPixels(int pixels);
static Margin fromFraction(qreal fraction);
Margin();
std::optional<int> pixels() const;
std::optional<qreal> fraction() const;
auto operator<=>(const Margin &other) const = default;
private:
Margin(int pixels);
Margin(qreal fraction);
std::variant<int, qreal> m_value;
};
class LAYERSHELLQT_EXPORT Window : public QObject
{
Q_OBJECT
@ -27,12 +55,8 @@ class LAYERSHELLQT_EXPORT Window : public QObject
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(bool activateOnShow READ activateOnShow WRITE setActivateOnShow)
Q_PROPERTY(bool wantsToBeOnActiveScreen READ wantsToBeOnActiveScreen WRITE setWantsToBeOnActiveScreen NOTIFY wantsToBeOnActiveScreenChanged)
Q_PROPERTY(QScreen *screen READ screen WRITE setScreen NOTIFY screenChanged)
#if LAYERSHELLQTINTERFACE_ENABLE_DEPRECATED_SINCE(6, 6)
Q_PROPERTY(ScreenConfiguration screenConfiguration READ screenConfiguration WRITE setScreenConfiguration)
#endif
Q_PROPERTY(bool activateOnShow READ activateOnShow WRITE setActivateOnShow)
public:
~Window() override;
@ -68,6 +92,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;
@ -80,6 +115,18 @@ public:
void setMargins(const QMargins &margins);
QMargins margins() const;
void setLeftMargin(Margin margin);
Margin leftMargin() const;
void setTopMargin(Margin margin);
Margin topMargin() const;
void setRightMargin(Margin margin);
Margin rightMargin() const;
void setBottomMargin(Margin margin);
Margin bottomMargin() const;
void setDesiredSize(const QSize &size);
QSize desiredSize() const;
@ -89,48 +136,8 @@ public:
void setLayer(Layer layer);
Layer layer() const;
#if LAYERSHELLQTINTERFACE_ENABLE_DEPRECATED_SINCE(6, 6)
/**
* 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.
*/
LAYERSHELLQTINTERFACE_DEPRECATED_VERSION(6, 6, "Use wantsToBeOnActiveScreen and screen instead")
enum ScreenConfiguration {
ScreenFromQWindow = 0,
ScreenFromCompositor = 1,
};
Q_ENUM(ScreenConfiguration)
LAYERSHELLQTINTERFACE_DEPRECATED_VERSION(6, 6, "Use wantsToBeOnActiveScreen and screen instead")
void setScreenConfiguration(ScreenConfiguration screenConfiguration);
LAYERSHELLQTINTERFACE_DEPRECATED_VERSION(6, 6, "Use wantsToBeOnActiveScreen and screen instead")
ScreenConfiguration screenConfiguration() const;
#endif
/**
* Indicates whether the layer shell surface should be placed on the active screen based on @a set.
*
* The active screen depends on the compositor policies.
*
* If the screen() is @c null and the wantsToBeOnActiveScreen() is @c false, then the
* QWindow::screen() will be used to decide what screen the layer shell surface should be placed on.
*
* The screen() will be reset if @a set is @c true.
*/
void setWantsToBeOnActiveScreen(bool set);
bool wantsToBeOnActiveScreen() const;
/**
* Indicates that the layer shell surface should be placed on the specified @a screen.
*
* If the screen() is @c null and the wantsToBeOnActiveScreen() is @c false, then the
* QWindow::screen() will be used to decide what screen the layer shell surface should be placed on.
*
* The wantsToBeOnActiveScreen() will be reset to @c false after calling this function.
*/
void setScreen(QScreen *screen);
QScreen *screen() const;
/**
* Sets a string based identifier for this window.
@ -178,11 +185,13 @@ Q_SIGNALS:
void exclusionZoneChanged();
void exclusiveEdgeChanged();
void marginsChanged();
void leftMarginChanged();
void topMarginChanged();
void rightMarginChanged();
void bottomMarginChanged();
void desiredSizeChanged();
void keyboardInteractivityChanged();
void layerChanged();
void wantsToBeOnActiveScreenChanged();
void screenChanged();
private:
void initializeShell();

View File

@ -9,10 +9,13 @@
#include "qwaylandlayersurface_p.h"
#include "qwaylandxdgactivationv1_p.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandwindow_p.h>
namespace LayerShellQt
{
QWaylandLayerShellIntegration::QWaylandLayerShellIntegration()
: QWaylandShellIntegrationTemplate<QWaylandLayerShellIntegration>(5)
: QWaylandShellIntegrationTemplate<QWaylandLayerShellIntegration>(6)
, m_xdgActivation(new QWaylandXdgActivationV1)
{
}

View File

@ -10,10 +10,11 @@
#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>
#include <QScreen>
#include <qpa/qplatformwindow.h>
#include <qpa/qplatformwindow_p.h> // private native interface
namespace LayerShellQt
{
@ -21,19 +22,12 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
: QtWaylandClient::QWaylandShellSurface(window)
, QtWayland::zwlr_layer_surface_v1()
, m_shell(shell)
// FIXME reverse lookup would a QWindow getter make sense, also below a bunch
// QWindow * QWaylandShellSurface::window
, m_interface(Window::get(platformWindow()->window()))
, m_interface(Window::get(window->window()))
, m_window(window)
{
wl_output *output = nullptr;
if (!m_interface->wantsToBeOnActiveScreen()) {
QScreen *desiredScreen = m_interface->screen();
if (!desiredScreen) {
desiredScreen = platformWindow()->window()->screen();
}
auto waylandScreen = platformWindow()->window()->screen()->nativeInterface<QNativeInterface::QWaylandScreen>();
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) {
@ -42,7 +36,7 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
output = waylandScreen->output();
}
}
init(shell->get_layer_surface(wlSurface(), output, m_interface->layer(), m_interface->scope()));
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());
});
@ -51,7 +45,7 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
connect(m_interface, &Window::anchorsChanged, this, [this]() {
setAnchor(m_interface->anchors());
if (m_interface->desiredSize().isNull()) {
setDesiredSize(m_lastContentGeometry.size());
setDesiredSize(m_window->windowContentGeometry().size());
} else {
setDesiredSize(m_interface->desiredSize());
}
@ -66,9 +60,24 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
setExclusiveEdge(m_interface->exclusiveEdge());
});
setMargins(m_interface->margins());
connect(m_interface, &Window::marginsChanged, this, [this]() {
setMargins(m_interface->margins());
setLeftMargin(m_interface->leftMargin());
connect(m_interface, &Window::leftMarginChanged, this, [this]() {
setLeftMargin(m_interface->leftMargin());
});
setTopMargin(m_interface->topMargin());
connect(m_interface, &Window::topMarginChanged, this, [this]() {
setTopMargin(m_interface->topMargin());
});
setRightMargin(m_interface->rightMargin());
connect(m_interface, &Window::rightMarginChanged, this, [this]() {
setRightMargin(m_interface->rightMargin());
});
setBottomMargin(m_interface->bottomMargin());
connect(m_interface, &Window::bottomMarginChanged, this, [this]() {
setBottomMargin(m_interface->bottomMargin());
});
connect(m_interface, &Window::desiredSizeChanged, this, [this]() {
@ -83,22 +92,12 @@ QWaylandLayerSurface::QWaylandLayerSurface(QWaylandLayerShellIntegration *shell,
});
if (m_interface->desiredSize().isNull()) {
// FIXME QWaylandWindow should call setWindowContentGeometry when creating the shell surface
// / Does a setWindowContentGeometry call arrive early enough?
// setDesiredSize(window->windowContentGeometry().size());
setDesiredSize(window->windowContentGeometry().size());
} else {
setDesiredSize(m_interface->desiredSize());
}
}
void QWaylandLayerSurface::setContentGeometry(const QRect &rect)
{
m_lastContentGeometry = rect;
if (m_interface->desiredSize().isNull()) {
setDesiredSize(rect.size());
}
}
QWaylandLayerSurface::~QWaylandLayerSurface()
{
destroy();
@ -107,7 +106,7 @@ QWaylandLayerSurface::~QWaylandLayerSurface()
void QWaylandLayerSurface::zwlr_layer_surface_v1_closed()
{
if (m_interface->closeOnDismissed()) {
platformWindow()->close();
window()->window()->close();
}
}
@ -123,7 +122,7 @@ void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint
} else {
// Later configures are resizes, so we have to queue them up for a time when we
// are not painting to the window.
applyConfigureWhenPossible();
window()->applyConfigureWhenPossible();
}
}
@ -140,7 +139,7 @@ void QWaylandLayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface *po
void QWaylandLayerSurface::applyConfigure()
{
resizeFromApplyConfigure(m_pendingSize);
window()->resizeFromApplyConfigure(m_pendingSize);
}
void QWaylandLayerSurface::setDesiredSize(const QSize &size)
@ -175,9 +174,68 @@ void QWaylandLayerSurface::setExclusiveEdge(uint32_t edge)
}
}
void QWaylandLayerSurface::setMargins(const QMargins &margins)
void QWaylandLayerSurface::setLeftMargin(const Margin &margin)
{
set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
if (zwlr_layer_surface_v1_get_version(object()) >= 6) {
if (const auto pixels = margin.pixels()) {
set_left_margin_units(*pixels);
} else if (const auto fraction = margin.fraction()) {
set_left_margin_fraction(wl_fixed_from_double(*fraction));
} else {
qCWarning(LAYERSHELLQT) << "Unspecified left margin for" << m_window->window();
}
} else {
const QMargins margins = m_interface->margins();
set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
}
}
void QWaylandLayerSurface::setTopMargin(const Margin &margin)
{
if (zwlr_layer_surface_v1_get_version(object()) >= 6) {
if (const auto pixels = margin.pixels()) {
set_top_margin_units(*pixels);
} else if (const auto fraction = margin.fraction()) {
set_top_margin_fraction(wl_fixed_from_double(*fraction));
} else {
qCWarning(LAYERSHELLQT) << "Unspecified top margin for" << m_window->window();
}
} else {
const QMargins margins = m_interface->margins();
set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
}
}
void QWaylandLayerSurface::setRightMargin(const Margin &margin)
{
if (zwlr_layer_surface_v1_get_version(object()) >= 6) {
if (const auto pixels = margin.pixels()) {
set_right_margin_units(*pixels);
} else if (const auto fraction = margin.fraction()) {
set_right_margin_fraction(wl_fixed_from_double(*fraction));
} else {
qCWarning(LAYERSHELLQT) << "Unspecified right margin for" << m_window->window();
}
} else {
const QMargins margins = m_interface->margins();
set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
}
}
void QWaylandLayerSurface::setBottomMargin(const Margin &margin)
{
if (zwlr_layer_surface_v1_get_version(object()) >= 6) {
if (const auto pixels = margin.pixels()) {
set_bottom_margin_units(*pixels);
} else if (const auto fraction = margin.fraction()) {
set_bottom_margin_fraction(wl_fixed_from_double(*fraction));
} else {
qCWarning(LAYERSHELLQT) << "Unspecified bottom margin for" << m_window->window();
}
} else {
const QMargins margins = m_interface->margins();
set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
}
}
void QWaylandLayerSurface::setKeyboardInteractivity(uint32_t interactivity)
@ -205,21 +263,20 @@ bool QWaylandLayerSurface::requestActivate()
return false;
}
if (!m_activationToken.isEmpty()) {
activation->activate(m_activationToken, wlSurface());
activation->activate(m_activationToken, window()->wlSurface());
m_activationToken = {};
return true;
} else if (const auto token = qEnvironmentVariable("XDG_ACTIVATION_TOKEN"); !token.isEmpty()) {
activation->activate(token, wlSurface());
activation->activate(token, window()->wlSurface());
qunsetenv("XDG_ACTIVATION_TOKEN");
return true;
} else {
const auto focusWindow = QGuiApplication::focusWindow();
const auto waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
const auto surface = focusWindow ? focusWindow->nativeInterface<QNativeInterface::Private::QWaylandWindow>()->surface() : wlSurface();
if (const auto seat = waylandApp->lastInputSeat()) {
const auto tokenProvider = activation->requestXdgActivationToken(seat, surface, waylandApp->lastInputSerial(), QString());
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, wlSurface());
m_shell->activation()->activate(token, window()->wlSurface());
});
connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, tokenProvider, &QObject::deleteLater);
return true;
@ -238,7 +295,7 @@ bool QWaylandLayerSurface::requestActivateOnShow()
return false;
}
if (platformWindow()->window()->property("_q_showWithoutActivating").toBool()) {
if (m_window->window()->property("_q_showWithoutActivating").toBool()) {
return false;
}
@ -256,21 +313,16 @@ void QWaylandLayerSurface::requestXdgActivationToken(quint32 serial)
if (!activation->isActive()) {
return;
}
const auto waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
auto tokenProvider = activation->requestXdgActivationToken(waylandApp->lastInputSeat(), wlSurface(), serial, QString());
auto tokenProvider = activation->requestXdgActivationToken(window()->display(), window()->wlSurface(), serial, QString());
connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, this, [this](const QString &token) {
// FIXME No way to do this without knowing QWaylandWindow because QPlatofrmWindow is not QObject
// But we wanted to make a better API as well or alternatively the signal needs to be on QWaylandShellSurface as well
// Q_EMIT window()->xdgActivationTokenCreated(token);
// QMetaObject::invokeMethod(window(), "xdgActivationTokenCreated", token);
Q_EMIT window()->xdgActivationTokenCreated(token);
});
connect(tokenProvider, &QWaylandXdgActivationTokenV1::done, tokenProvider, &QObject::deleteLater);
}
void QWaylandLayerSurface::sendExpose()
{
// FIXME No way to call this, needs wrapper in QWaylandShellSurface
// window()->updateExposure();
window()->updateExposure();
}
}

View File

@ -8,7 +8,6 @@
#ifndef _LAYERSURFACE_H
#define _LAYERSURFACE_H
#include <QRect>
#include <wayland-client.h>
#include "qwaylandlayershellintegration_p.h"
@ -20,6 +19,7 @@
namespace LayerShellQt
{
class Margin;
class Window;
class LAYERSHELLQT_EXPORT QWaylandLayerSurface : public QtWaylandClient::QWaylandShellSurface, public QtWayland::zwlr_layer_surface_v1
@ -39,10 +39,13 @@ public:
void setAnchor(uint32_t anchor);
void setExclusiveZone(int32_t zone);
void setExclusiveEdge(uint32_t edge);
void setMargins(const QMargins &margins);
void setLeftMargin(const Margin &margin);
void setTopMargin(const Margin &margin);
void setRightMargin(const Margin &margin);
void setBottomMargin(const Margin &margin);
void setKeyboardInteractivity(uint32_t interactivity);
void setLayer(uint32_t layer);
void setContentGeometry(const QRect &rect) override;
void applyConfigure() override;
void setWindowSize(const QSize &size) override;
@ -61,7 +64,6 @@ private:
QtWaylandClient::QWaylandWindow *m_window;
QSize m_pendingSize;
QString m_activationToken;
QRect m_lastContentGeometry;
bool m_configured = false;
};

View File

@ -3,6 +3,8 @@
*/
#include "qwaylandxdgactivationv1_p.h"
#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/private/qwaylandinputdevice_p.h>
QWaylandXdgActivationV1::QWaylandXdgActivationV1()
: QWaylandClientExtensionTemplate<QWaylandXdgActivationV1>(1)
@ -17,8 +19,10 @@ QWaylandXdgActivationV1::~QWaylandXdgActivationV1()
}
}
QWaylandXdgActivationTokenV1 *
QWaylandXdgActivationV1::requestXdgActivationToken(::wl_seat *seat, struct ::wl_surface *surface, std::optional<uint32_t> serial, const QString &app_id)
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;
@ -30,8 +34,8 @@ QWaylandXdgActivationV1::requestXdgActivationToken(::wl_seat *seat, struct ::wl_
if (!app_id.isEmpty()) {
provider->set_app_id(app_id);
}
if (serial && seat) {
provider->set_serial(*serial, seat);
if (serial && display->lastInputDevice()) {
provider->set_serial(*serial, display->lastInputDevice()->wl_seat());
}
provider->commit();
return provider;

View File

@ -42,7 +42,7 @@ public:
~QWaylandXdgActivationV1() override;
QWaylandXdgActivationTokenV1 *
requestXdgActivationToken(::wl_seat *seat, struct ::wl_surface *surface, std::optional<uint32_t> serial, const QString &app_id);
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="6">
<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="6">
<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
@ -187,7 +187,7 @@
<arg name="zone" type="int"/>
</request>
<request name="set_margin">
<request name="set_margin" deprecated-since="6">
<description summary="sets a margin from the anchor point">
Requests that the surface be placed some distance away from the anchor
point on the output, in surface-local coordinates. Setting this value
@ -196,6 +196,10 @@
The exclusive zone includes the margin.
Margin is double-buffered, see wl_surface.commit.
This request is deprecated since version 6. Use set_left_margin_{units,fraction},
set_top_margin_{units,fraction}, set_right_margin_{units,fraction}, and
set_bottom_margin_{units,fraction} requests instead.
</description>
<arg name="top" type="int"/>
<arg name="right" type="int"/>
@ -401,7 +405,141 @@
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"/>
<arg name="edge" type="uint" enum="anchor"/>
</request>
<!-- Version 6 additions -->
<request name="set_left_margin_units" since="6">
<description summary="set the left margin in surface local coordinates">
Sets the left margin in surface-local coordinates.
Margins specify that the surface should be placed some distance away
from the anchor point on the output. Setting a margin for an edge
you are not anchored to has no effect.
The left margin specified using set_left_margin_fraction will be
overwritten by this request.
Margins are double-buffered, see wl_surface.commit.
</description>
<arg name="margin" type="int"/>
</request>
<request name="set_left_margin_fraction" since="6">
<description summary="set the left margin as a fraction">
Sets the left margin as a fraction of the available area width. The
margin value is a number between 0 and 1.
Margins specify that the surface should be placed some distance away
from the anchor point on the output. Setting a margin for an edge
you are not anchored to has no effect.
The left margin specified using set_left_margin_units will be
overwritten by this request.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="margin" type="fixed"/>
</request>
<request name="set_top_margin_units" since="6">
<description summary="set the top margin in surface local coordinates">
Sets the top margin in surface-local coordinates.
Margins specify that the surface should be placed some distance away
from the anchor point on the output. Setting a margin for an edge
you are not anchored to has no effect.
The top margin specified using set_top_margin_fraction will be
overwritten by this request.
Margins are double-buffered, see wl_surface.commit.
</description>
<arg name="margin" type="int"/>
</request>
<request name="set_top_margin_fraction" since="6">
<description summary="set the top margin as a fraction">
Sets the top margin as a fraction of the available area height. The
margin value is a number between 0 and 1.
Margins specify that the surface should be placed some distance away
from the anchor point on the output. Setting a margin for an edge
you are not anchored to has no effect.
The top margin specified using set_top_margin_units will be
overwritten by this request.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="margin" type="fixed"/>
</request>
<request name="set_right_margin_units" since="6">
<description summary="set the right margin in surface local coordinates">
Sets the right margin in surface-local coordinates.
Margins specify that the surface should be placed some distance away
from the anchor point on the output. Setting a margin for an edge
you are not anchored to has no effect.
The right margin specified using set_right_margin_fraction will be
overwritten by this request.
Margins are double-buffered, see wl_surface.commit.
</description>
<arg name="margin" type="int"/>
</request>
<request name="set_right_margin_fraction" since="6">
<description summary="set the right margin as a fraction">
Sets the right margin as a fraction of the available area width. The
margin value is a number between 0 and 1.
Margins specify that the surface should be placed some distance away
from the anchor point on the output. Setting a margin for an edge
you are not anchored to has no effect.
The right margin specified using set_right_margin_units will be
overwritten by this request.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="margin" type="fixed"/>
</request>
<request name="set_bottom_margin_units" since="6">
<description summary="set the bottom margin in surface local coordinates">
Sets the bottom margin in surface-local coordinates.
Margins specify that the surface should be placed some distance away
from the anchor point on the output. Setting a margin for an edge
you are not anchored to has no effect.
The bottom margin specified using set_bottom_margin_fraction will be
overwritten by this request.
Margins are double-buffered, see wl_surface.commit.
</description>
<arg name="margin" type="int"/>
</request>
<request name="set_bottom_margin_fraction" since="6">
<description summary="set the bottom margin as a fraction">
Sets the bottom margin as a fraction of the available area height. The
margin value is a number between 0 and 1.
Margins specify that the surface should be placed some distance away
from the anchor point on the output. Setting a margin for an edge
you are not anchored to has no effect.
The bottom margin specified using set_bottom_margin_units will be
overwritten by this request.
Margin is double-buffered, see wl_surface.commit.
</description>
<arg name="margin" type="fixed"/>
</request>
</interface>
</protocol>