File indexing completed on 2023-11-26 12:08:26

0001 /*
0002  *   SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003  *   SPDX-FileCopyrightText: 2018 Drew DeVault <sir@cmpwn.com>
0004  *
0005  *   SPDX-License-Identifier: LGPL-3.0-or-later
0006  */
0007 
0008 #include "interfaces/window.h"
0009 #include "layershellqt_logging.h"
0010 #include "qwaylandlayersurface_p.h"
0011 
0012 #include <QtWaylandClient/private/qwaylandscreen_p.h>
0013 #include <QtWaylandClient/private/qwaylandsurface_p.h>
0014 #include <QtWaylandClient/private/qwaylandwindow_p.h>
0015 
0016 namespace LayerShellQt
0017 {
0018 QWaylandLayerSurface::QWaylandLayerSurface(QtWayland::zwlr_layer_shell_v1 *shell, QtWaylandClient::QWaylandWindow *window)
0019     : QtWaylandClient::QWaylandShellSurface(window)
0020     , QtWayland::zwlr_layer_surface_v1()
0021     , m_interface(Window::get(window->window()))
0022 {
0023     wl_output *output = nullptr;
0024     if (m_interface->screenConfiguration() == Window::ScreenFromQWindow) {
0025         auto waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen *>(window->window()->screen()->handle());
0026         // Qt will always assign a screen to a window, but if the compositor has no screens available a dummy QScreen object is created
0027         // this will not cast to a QWaylandScreen
0028         if (!waylandScreen) {
0029             qCWarning(LAYERSHELLQT) << "Creating a layer shell for placeholder screen. This will be positioned incorrectly";
0030         } else {
0031             output = waylandScreen->output();
0032         }
0033     }
0034     init(shell->get_layer_surface(window->waylandSurface()->object(), output, m_interface->layer(), m_interface->scope()));
0035     connect(m_interface, &Window::layerChanged, this, [this]() {
0036         setLayer(m_interface->layer());
0037     });
0038 
0039     set_anchor(m_interface->anchors());
0040     connect(m_interface, &Window::anchorsChanged, this, [this]() {
0041         set_anchor(m_interface->anchors());
0042     });
0043     setExclusiveZone(m_interface->exclusionZone());
0044     connect(m_interface, &Window::exclusionZoneChanged, this, [this]() {
0045         setExclusiveZone(m_interface->exclusionZone());
0046     });
0047 
0048     setMargins(m_interface->margins());
0049     connect(m_interface, &Window::marginsChanged, this, [this]() {
0050         setMargins(m_interface->margins());
0051     });
0052 
0053     setKeyboardInteractivity(m_interface->keyboardInteractivity());
0054     connect(m_interface, &Window::keyboardInteractivityChanged, this, [this]() {
0055         setKeyboardInteractivity(m_interface->keyboardInteractivity());
0056     });
0057 
0058     QSize size = window->surfaceSize();
0059     const Window::Anchors anchors = m_interface->anchors();
0060     if ((anchors & Window::AnchorLeft) && (anchors & Window::AnchorRight)) {
0061         size.setWidth(0);
0062     }
0063     if ((anchors & Window::AnchorTop) && (anchors & Window::AnchorBottom)) {
0064         size.setHeight(0);
0065     }
0066     if (size.isValid() && size != QSize(0, 0)) {
0067         set_size(size.width(), size.height());
0068     }
0069 }
0070 
0071 QWaylandLayerSurface::~QWaylandLayerSurface()
0072 {
0073     destroy();
0074 }
0075 
0076 void QWaylandLayerSurface::zwlr_layer_surface_v1_closed()
0077 {
0078     if (m_interface->closeOnDismissed()) {
0079         window()->window()->close();
0080     }
0081 }
0082 
0083 void QWaylandLayerSurface::zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height)
0084 {
0085     ack_configure(serial);
0086     m_pendingSize = QSize(width, height);
0087 
0088     if (!m_configured) {
0089         m_configured = true;
0090         window()->resizeFromApplyConfigure(m_pendingSize);
0091         window()->handleExpose(QRect(QPoint(), m_pendingSize));
0092     } else {
0093         // Later configures are resizes, so we have to queue them up for a time when we
0094         // are not painting to the window.
0095         window()->applyConfigureWhenPossible();
0096     }
0097 }
0098 
0099 #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
0100 void QWaylandLayerSurface::attachPopup(QtWaylandClient::QWaylandShellSurface *popup)
0101 {
0102     std::any anyRole = popup->surfaceRole();
0103 
0104     if (auto role = std::any_cast<::xdg_popup *>(&anyRole)) {
0105         get_popup(*role);
0106     } else {
0107         qCWarning(LAYERSHELLQT) << "Cannot attach popup of unknown type";
0108     }
0109 }
0110 #endif
0111 
0112 void QWaylandLayerSurface::applyConfigure()
0113 {
0114     window()->resizeFromApplyConfigure(m_pendingSize);
0115 }
0116 
0117 void QWaylandLayerSurface::setAnchor(uint anchor)
0118 {
0119     set_anchor(anchor);
0120 }
0121 
0122 void QWaylandLayerSurface::setExclusiveZone(int32_t zone)
0123 {
0124     set_exclusive_zone(zone);
0125 }
0126 
0127 void QWaylandLayerSurface::setMargins(const QMargins &margins)
0128 {
0129     set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
0130 }
0131 
0132 void QWaylandLayerSurface::setKeyboardInteractivity(uint32_t interactivity)
0133 {
0134     set_keyboard_interactivity(interactivity);
0135 }
0136 
0137 void QWaylandLayerSurface::setLayer(uint32_t layer)
0138 {
0139     if (zwlr_layer_surface_v1_get_version(object()) >= ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION)
0140         set_layer(layer);
0141 }
0142 
0143 void QWaylandLayerSurface::setWindowGeometry(const QRect &geometry)
0144 {
0145     const bool horizontallyConstrained = m_interface->anchors() & (Window::AnchorLeft & Window::AnchorRight);
0146     const bool verticallyConstrained = m_interface->anchors() & (Window::AnchorTop & Window::AnchorBottom);
0147 
0148     QSize size = geometry.size();
0149     if (horizontallyConstrained) {
0150         size.setWidth(0);
0151     }
0152     if (verticallyConstrained) {
0153         size.setHeight(0);
0154     }
0155     set_size(size.width(), size.height());
0156 }
0157 
0158 }