File indexing completed on 2025-02-16 11:23:13
0001 /* 0002 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "layershellv1window.h" 0008 #include "core/output.h" 0009 #include "deleted.h" 0010 #include "layershellv1integration.h" 0011 #include "wayland/layershell_v1_interface.h" 0012 #include "wayland/output_interface.h" 0013 #include "wayland/surface_interface.h" 0014 #include "wayland_server.h" 0015 #include "workspace.h" 0016 0017 using namespace KWaylandServer; 0018 0019 namespace KWin 0020 { 0021 0022 static NET::WindowType scopeToType(const QString &scope) 0023 { 0024 static const QHash<QString, NET::WindowType> scopeToType{ 0025 {QStringLiteral("desktop"), NET::Desktop}, 0026 {QStringLiteral("dock"), NET::Dock}, 0027 {QStringLiteral("crititical-notification"), NET::CriticalNotification}, 0028 {QStringLiteral("notification"), NET::Notification}, 0029 {QStringLiteral("tooltip"), NET::Tooltip}, 0030 {QStringLiteral("on-screen-display"), NET::OnScreenDisplay}, 0031 {QStringLiteral("dialog"), NET::Dialog}, 0032 {QStringLiteral("splash"), NET::Splash}, 0033 {QStringLiteral("utility"), NET::Utility}, 0034 }; 0035 return scopeToType.value(scope.toLower(), NET::Normal); 0036 } 0037 0038 LayerShellV1Window::LayerShellV1Window(LayerSurfaceV1Interface *shellSurface, 0039 Output *output, 0040 LayerShellV1Integration *integration) 0041 : WaylandWindow(shellSurface->surface()) 0042 , m_desiredOutput(output) 0043 , m_integration(integration) 0044 , m_shellSurface(shellSurface) 0045 , m_windowType(scopeToType(shellSurface->scope())) 0046 { 0047 setSkipSwitcher(!isDesktop()); 0048 setSkipPager(true); 0049 setSkipTaskbar(true); 0050 0051 connect(shellSurface, &LayerSurfaceV1Interface::aboutToBeDestroyed, 0052 this, &LayerShellV1Window::destroyWindow); 0053 connect(shellSurface->surface(), &SurfaceInterface::aboutToBeDestroyed, 0054 this, &LayerShellV1Window::destroyWindow); 0055 0056 connect(output, &Output::geometryChanged, 0057 this, &LayerShellV1Window::scheduleRearrange); 0058 connect(output, &Output::enabledChanged, 0059 this, &LayerShellV1Window::handleOutputEnabledChanged); 0060 connect(output, &Output::destroyed, 0061 this, &LayerShellV1Window::handleOutputDestroyed); 0062 0063 connect(shellSurface->surface(), &SurfaceInterface::sizeChanged, 0064 this, &LayerShellV1Window::handleSizeChanged); 0065 connect(shellSurface->surface(), &SurfaceInterface::unmapped, 0066 this, &LayerShellV1Window::handleUnmapped); 0067 connect(shellSurface->surface(), &SurfaceInterface::committed, 0068 this, &LayerShellV1Window::handleCommitted); 0069 0070 connect(shellSurface, &LayerSurfaceV1Interface::desiredSizeChanged, 0071 this, &LayerShellV1Window::scheduleRearrange); 0072 connect(shellSurface, &LayerSurfaceV1Interface::layerChanged, 0073 this, &LayerShellV1Window::scheduleRearrange); 0074 connect(shellSurface, &LayerSurfaceV1Interface::marginsChanged, 0075 this, &LayerShellV1Window::scheduleRearrange); 0076 connect(shellSurface, &LayerSurfaceV1Interface::anchorChanged, 0077 this, &LayerShellV1Window::scheduleRearrange); 0078 connect(shellSurface, &LayerSurfaceV1Interface::exclusiveZoneChanged, 0079 this, &LayerShellV1Window::scheduleRearrange); 0080 connect(shellSurface, &LayerSurfaceV1Interface::acceptsFocusChanged, 0081 this, &LayerShellV1Window::handleAcceptsFocusChanged); 0082 } 0083 0084 LayerSurfaceV1Interface *LayerShellV1Window::shellSurface() const 0085 { 0086 return m_shellSurface; 0087 } 0088 0089 Output *LayerShellV1Window::desiredOutput() const 0090 { 0091 return m_desiredOutput; 0092 } 0093 0094 void LayerShellV1Window::scheduleRearrange() 0095 { 0096 m_integration->scheduleRearrange(); 0097 } 0098 0099 NET::WindowType LayerShellV1Window::windowType(bool, int) const 0100 { 0101 return m_windowType; 0102 } 0103 0104 bool LayerShellV1Window::isPlaceable() const 0105 { 0106 return false; 0107 } 0108 0109 bool LayerShellV1Window::isCloseable() const 0110 { 0111 return true; 0112 } 0113 0114 bool LayerShellV1Window::isMovable() const 0115 { 0116 return false; 0117 } 0118 0119 bool LayerShellV1Window::isMovableAcrossScreens() const 0120 { 0121 return false; 0122 } 0123 0124 bool LayerShellV1Window::isResizable() const 0125 { 0126 return false; 0127 } 0128 0129 bool LayerShellV1Window::takeFocus() 0130 { 0131 setActive(true); 0132 return true; 0133 } 0134 0135 bool LayerShellV1Window::wantsInput() const 0136 { 0137 return acceptsFocus() && readyForPainting(); 0138 } 0139 0140 StrutRect LayerShellV1Window::strutRect(StrutArea area) const 0141 { 0142 switch (area) { 0143 case StrutAreaLeft: 0144 if (m_shellSurface->exclusiveEdge() == Qt::LeftEdge) { 0145 return StrutRect(x(), y(), m_shellSurface->exclusiveZone(), height(), StrutAreaLeft); 0146 } 0147 return StrutRect(); 0148 case StrutAreaRight: 0149 if (m_shellSurface->exclusiveEdge() == Qt::RightEdge) { 0150 return StrutRect(x() + width() - m_shellSurface->exclusiveZone(), y(), 0151 m_shellSurface->exclusiveZone(), height(), StrutAreaRight); 0152 } 0153 return StrutRect(); 0154 case StrutAreaTop: 0155 if (m_shellSurface->exclusiveEdge() == Qt::TopEdge) { 0156 return StrutRect(x(), y(), width(), m_shellSurface->exclusiveZone(), StrutAreaTop); 0157 } 0158 return StrutRect(); 0159 case StrutAreaBottom: 0160 if (m_shellSurface->exclusiveEdge() == Qt::BottomEdge) { 0161 return StrutRect(x(), y() + height() - m_shellSurface->exclusiveZone(), 0162 width(), m_shellSurface->exclusiveZone(), StrutAreaBottom); 0163 } 0164 return StrutRect(); 0165 default: 0166 return StrutRect(); 0167 } 0168 } 0169 0170 bool LayerShellV1Window::hasStrut() const 0171 { 0172 return m_shellSurface->exclusiveZone() > 0; 0173 } 0174 0175 void LayerShellV1Window::destroyWindow() 0176 { 0177 markAsZombie(); 0178 cleanTabBox(); 0179 Deleted *deleted = Deleted::create(this); 0180 Q_EMIT windowClosed(this, deleted); 0181 StackingUpdatesBlocker blocker(workspace()); 0182 cleanGrouping(); 0183 waylandServer()->removeWindow(this); 0184 deleted->unrefWindow(); 0185 scheduleRearrange(); 0186 delete this; 0187 } 0188 0189 void LayerShellV1Window::closeWindow() 0190 { 0191 m_shellSurface->sendClosed(); 0192 } 0193 0194 Layer LayerShellV1Window::belongsToLayer() const 0195 { 0196 if (!isNormalWindow()) { 0197 return WaylandWindow::belongsToLayer(); 0198 } 0199 switch (m_shellSurface->layer()) { 0200 case LayerSurfaceV1Interface::BackgroundLayer: 0201 return DesktopLayer; 0202 case LayerSurfaceV1Interface::BottomLayer: 0203 return BelowLayer; 0204 case LayerSurfaceV1Interface::TopLayer: 0205 return AboveLayer; 0206 case LayerSurfaceV1Interface::OverlayLayer: 0207 return UnmanagedLayer; 0208 default: 0209 Q_UNREACHABLE(); 0210 } 0211 } 0212 0213 bool LayerShellV1Window::acceptsFocus() const 0214 { 0215 return !isDeleted() && m_shellSurface->acceptsFocus(); 0216 } 0217 0218 void LayerShellV1Window::moveResizeInternal(const QRectF &rect, MoveResizeMode mode) 0219 { 0220 if (areGeometryUpdatesBlocked()) { 0221 setPendingMoveResizeMode(mode); 0222 return; 0223 } 0224 0225 const QSizeF requestedClientSize = frameSizeToClientSize(rect.size()); 0226 if (requestedClientSize != clientSize()) { 0227 m_shellSurface->sendConfigure(rect.size().toSize()); 0228 } else { 0229 updateGeometry(rect); 0230 return; 0231 } 0232 0233 // The surface position is updated synchronously. 0234 QRectF updateRect = m_frameGeometry; 0235 updateRect.moveTopLeft(rect.topLeft()); 0236 updateGeometry(updateRect); 0237 } 0238 0239 void LayerShellV1Window::handleSizeChanged() 0240 { 0241 updateGeometry(QRectF(pos(), clientSizeToFrameSize(surface()->size()))); 0242 scheduleRearrange(); 0243 } 0244 0245 void LayerShellV1Window::handleUnmapped() 0246 { 0247 m_integration->recreateWindow(shellSurface()); 0248 } 0249 0250 void LayerShellV1Window::handleCommitted() 0251 { 0252 if (surface()->buffer()) { 0253 updateDepth(); 0254 setReadyForPainting(); 0255 } 0256 } 0257 0258 void LayerShellV1Window::handleAcceptsFocusChanged() 0259 { 0260 switch (m_shellSurface->layer()) { 0261 case LayerSurfaceV1Interface::TopLayer: 0262 case LayerSurfaceV1Interface::OverlayLayer: 0263 if (wantsInput()) { 0264 workspace()->activateWindow(this); 0265 } 0266 break; 0267 case LayerSurfaceV1Interface::BackgroundLayer: 0268 case LayerSurfaceV1Interface::BottomLayer: 0269 break; 0270 } 0271 } 0272 0273 void LayerShellV1Window::handleOutputEnabledChanged() 0274 { 0275 if (!m_desiredOutput->isEnabled()) { 0276 closeWindow(); 0277 destroyWindow(); 0278 } 0279 } 0280 0281 void LayerShellV1Window::handleOutputDestroyed() 0282 { 0283 closeWindow(); 0284 destroyWindow(); 0285 } 0286 0287 void LayerShellV1Window::setVirtualKeyboardGeometry(const QRectF &geo) 0288 { 0289 if (m_virtualKeyboardGeometry == geo) { 0290 return; 0291 } 0292 0293 m_virtualKeyboardGeometry = geo; 0294 scheduleRearrange(); 0295 } 0296 0297 } // namespace KWin