File indexing completed on 2024-09-29 04:54:08

0001 /*
0002  *   SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003  *
0004  *   SPDX-License-Identifier: LGPL-3.0-or-later
0005  */
0006 
0007 #include "window.h"
0008 #include "../qwaylandlayershellintegration_p.h"
0009 
0010 #include <layershellqt_logging.h>
0011 
0012 #include <QPointer>
0013 #include <optional>
0014 
0015 #include <QtWaylandClient/private/qwaylandwindow_p.h>
0016 
0017 using namespace LayerShellQt;
0018 
0019 class LayerShellQt::WindowPrivate
0020 {
0021 public:
0022     WindowPrivate(QWindow *window)
0023         : parentWindow(window)
0024     {
0025     }
0026 
0027     QWindow *parentWindow;
0028     QString scope = QStringLiteral("window");
0029     Window::Anchors anchors = {Window::AnchorTop | Window::AnchorBottom | Window::AnchorLeft | Window::AnchorRight};
0030     int32_t exclusionZone = 0;
0031     Window::Anchor exclusiveEdge = Window::AnchorNone;
0032     Window::KeyboardInteractivity keyboardInteractivity = Window::KeyboardInteractivityOnDemand;
0033     Window::Layer layer = Window::LayerTop;
0034     QMargins margins;
0035     Window::ScreenConfiguration screenConfiguration = Window::ScreenFromQWindow;
0036     bool closeOnDismissed = true;
0037 };
0038 
0039 static QMap<QWindow *, Window *> s_map;
0040 
0041 Window::~Window()
0042 {
0043     s_map.remove(d->parentWindow);
0044 }
0045 
0046 void Window::setAnchors(Anchors anchors)
0047 {
0048     if (d->anchors != anchors) {
0049         d->anchors = anchors;
0050         Q_EMIT anchorsChanged();
0051     }
0052 }
0053 
0054 Window::Anchors Window::anchors() const
0055 {
0056     return d->anchors;
0057 }
0058 
0059 void Window::setExclusiveZone(int32_t zone)
0060 {
0061     if (d->exclusionZone != zone) {
0062         d->exclusionZone = zone;
0063         Q_EMIT exclusionZoneChanged();
0064     }
0065 }
0066 
0067 int32_t Window::exclusionZone() const
0068 {
0069     return d->exclusionZone;
0070 }
0071 
0072 void Window::setExclusiveEdge(Window::Anchor edge)
0073 {
0074     if (d->exclusiveEdge == edge) {
0075         return;
0076     }
0077 
0078     d->exclusiveEdge = edge;
0079     Q_EMIT exclusiveEdgeChanged();
0080 }
0081 
0082 Window::Anchor Window::exclusiveEdge() const
0083 {
0084     return d->exclusiveEdge;
0085 }
0086 
0087 void Window::setMargins(const QMargins &margins)
0088 {
0089     if (d->margins != margins) {
0090         d->margins = margins;
0091         Q_EMIT marginsChanged();
0092     }
0093 }
0094 
0095 QMargins Window::margins() const
0096 {
0097     return d->margins;
0098 }
0099 
0100 void Window::setKeyboardInteractivity(KeyboardInteractivity interactivity)
0101 {
0102     if (d->keyboardInteractivity != interactivity) {
0103         d->keyboardInteractivity = interactivity;
0104         Q_EMIT keyboardInteractivityChanged();
0105     }
0106 }
0107 
0108 Window::KeyboardInteractivity Window::keyboardInteractivity() const
0109 {
0110     return d->keyboardInteractivity;
0111 }
0112 
0113 void Window::setLayer(Layer layer)
0114 {
0115     if (d->layer != layer) {
0116         d->layer = layer;
0117         Q_EMIT layerChanged();
0118     }
0119 }
0120 
0121 void Window::setScope(const QString &scope)
0122 {
0123     d->scope = scope;
0124     // this is static and must be set before the platform window is created
0125 }
0126 
0127 QString Window::scope() const
0128 {
0129     return d->scope;
0130 }
0131 
0132 Window::Layer Window::layer() const
0133 {
0134     return d->layer;
0135 }
0136 
0137 Window::ScreenConfiguration Window::screenConfiguration() const
0138 {
0139     return d->screenConfiguration;
0140 }
0141 
0142 void Window::setScreenConfiguration(Window::ScreenConfiguration screenConfiguration)
0143 {
0144     d->screenConfiguration = screenConfiguration;
0145 }
0146 
0147 bool Window::closeOnDismissed() const
0148 {
0149     return d->closeOnDismissed;
0150 }
0151 
0152 void Window::setCloseOnDismissed(bool close)
0153 {
0154     d->closeOnDismissed = close;
0155 }
0156 
0157 Window::Window(QWindow *window)
0158     : QObject(window)
0159     , d(new WindowPrivate(window))
0160 {
0161     s_map.insert(d->parentWindow, this);
0162 
0163     window->create();
0164 
0165     auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow *>(window->handle());
0166     if (!waylandWindow) {
0167         qCWarning(LAYERSHELLQT) << window << "is not a wayland window. Not creating zwlr_layer_surface";
0168         return;
0169     }
0170 
0171     static QWaylandLayerShellIntegration *shellIntegration = nullptr;
0172     if (!shellIntegration) {
0173         shellIntegration = new QWaylandLayerShellIntegration();
0174         if (!shellIntegration->initialize(waylandWindow->display())) {
0175             delete shellIntegration;
0176             shellIntegration = nullptr;
0177             qCWarning(LAYERSHELLQT) << "Failed to initialize layer-shell integration, possibly because compositor does not support the layer-shell protocol";
0178             return;
0179         }
0180     }
0181 
0182     waylandWindow->setShellIntegration(shellIntegration);
0183 }
0184 
0185 Window *Window::get(QWindow *window)
0186 {
0187     if (!window) {
0188         return nullptr;
0189     }
0190 
0191     auto layerShellWindow = s_map.value(window);
0192     if (layerShellWindow) {
0193         return layerShellWindow;
0194     }
0195     return new Window(window);
0196 }
0197 
0198 Window *Window::qmlAttachedProperties(QObject *object)
0199 {
0200     return get(qobject_cast<QWindow *>(object));
0201 }