/* * SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez * * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "window.h" #include "../qwaylandlayershellintegration_p.h" #include #include #include #include #include #include using namespace LayerShellQt; class LayerShellQt::WindowPrivate { public: WindowPrivate(QWindow *window) : parentWindow(window) { } QWindow *parentWindow; QString scope = QStringLiteral("window"); Window::Anchors anchors = {Window::AnchorTop | Window::AnchorBottom | Window::AnchorLeft | Window::AnchorRight}; int32_t exclusionZone = 0; Window::Anchor exclusiveEdge = Window::AnchorNone; Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityOnDemand; Window::Layer layer = Window::LayerTop; QMargins margins; QSize desiredSize = QSize(0, 0); QPointer screen; bool wantsToBeOnActiveScreen = false; bool closeOnDismissed = true; bool activateOnShow = true; }; static QMap s_map; Window::~Window() { s_map.remove(d->parentWindow); } void Window::setAnchors(Anchors anchors) { if (d->anchors != anchors) { d->anchors = anchors; Q_EMIT anchorsChanged(); } } Window::Anchors Window::anchors() const { return d->anchors; } void Window::setExclusiveZone(int32_t zone) { if (d->exclusionZone != zone) { d->exclusionZone = zone; Q_EMIT exclusionZoneChanged(); } } int32_t Window::exclusionZone() const { return d->exclusionZone; } void Window::setExclusiveEdge(Window::Anchor edge) { if (d->exclusiveEdge == edge) { return; } d->exclusiveEdge = edge; Q_EMIT exclusiveEdgeChanged(); } Window::Anchor Window::exclusiveEdge() const { return d->exclusiveEdge; } void Window::setMargins(const QMargins &margins) { if (d->margins != margins) { d->margins = margins; Q_EMIT marginsChanged(); } } 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) { d->keyboardInteractivity = interactivity; Q_EMIT keyboardInteractivityChanged(); } } Window::KeyboardInteractivity Window::keyboardInteractivity() const { return d->keyboardInteractivity; } void Window::setLayer(Layer layer) { if (d->layer != layer) { d->layer = layer; Q_EMIT layerChanged(); } } void Window::setScope(const QString &scope) { d->scope = scope; // this is static and must be set before the platform window is created } QString Window::scope() const { return d->scope; } 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; } } void Window::setScreenConfiguration(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; } bool Window::closeOnDismissed() const { return d->closeOnDismissed; } 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)) { s_map.insert(d->parentWindow, this); window->installEventFilter(this); if (window->isVisible()) { qCWarning(LAYERSHELLQT) << d->parentWindow << "already has a shell integration. Call QWindow::close() first and show it again."; } if (window->handle()) { initializeShell(); } } bool Window::eventFilter(QObject *watched, QEvent *event) { auto window = qobject_cast(watched); if (!window) { return false; } if (event->type() == QEvent::PlatformSurface) { if (auto pse = static_cast(event); pse->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { initializeShell(); } } return false; } void Window::initializeShell() { auto waylandWindow = dynamic_cast(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(); if (!shellIntegration->initialize(waylandWindow->display())) { delete shellIntegration; shellIntegration = nullptr; qCWarning(LAYERSHELLQT) << "Failed to initialize layer-shell integration, possibly because compositor does not support the layer-shell protocol"; return; } } waylandWindow->setShellIntegration(shellIntegration); } Window *Window::get(QWindow *window) { if (!window) { return nullptr; } auto layerShellWindow = s_map.value(window); if (layerShellWindow) { return layerShellWindow; } return new Window(window); } Window *Window::qmlAttachedProperties(QObject *object) { return get(qobject_cast(object)); }