File indexing completed on 2024-11-10 04:57:50
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 "layershellv1integration.h" 0010 #include "screenedge.h" 0011 #include "wayland/layershell_v1.h" 0012 #include "wayland/output.h" 0013 #include "wayland/screenedge_v1.h" 0014 #include "wayland/surface.h" 0015 #include "wayland_server.h" 0016 #include "workspace.h" 0017 0018 namespace KWin 0019 { 0020 0021 static NET::WindowType scopeToType(const QString &scope) 0022 { 0023 static const QHash<QString, NET::WindowType> scopeToType{ 0024 {QStringLiteral("desktop"), NET::Desktop}, 0025 {QStringLiteral("dock"), NET::Dock}, 0026 {QStringLiteral("crititical-notification"), NET::CriticalNotification}, 0027 {QStringLiteral("notification"), NET::Notification}, 0028 {QStringLiteral("tooltip"), NET::Tooltip}, 0029 {QStringLiteral("on-screen-display"), NET::OnScreenDisplay}, 0030 {QStringLiteral("dialog"), NET::Dialog}, 0031 {QStringLiteral("splash"), NET::Splash}, 0032 {QStringLiteral("utility"), NET::Utility}, 0033 }; 0034 return scopeToType.value(scope.toLower(), NET::Normal); 0035 } 0036 0037 LayerShellV1Window::LayerShellV1Window(LayerSurfaceV1Interface *shellSurface, 0038 Output *output, 0039 LayerShellV1Integration *integration) 0040 : WaylandWindow(shellSurface->surface()) 0041 , m_desiredOutput(output) 0042 , m_integration(integration) 0043 , m_shellSurface(shellSurface) 0044 , m_windowType(scopeToType(shellSurface->scope())) 0045 { 0046 setSkipSwitcher(!isDesktop()); 0047 setSkipPager(true); 0048 setSkipTaskbar(true); 0049 0050 connect(shellSurface, &LayerSurfaceV1Interface::aboutToBeDestroyed, 0051 this, &LayerShellV1Window::destroyWindow); 0052 connect(shellSurface->surface(), &SurfaceInterface::aboutToBeDestroyed, 0053 this, &LayerShellV1Window::destroyWindow); 0054 0055 connect(output, &Output::geometryChanged, 0056 this, &LayerShellV1Window::scheduleRearrange); 0057 connect(output, &Output::enabledChanged, 0058 this, &LayerShellV1Window::handleOutputEnabledChanged); 0059 0060 connect(shellSurface->surface(), &SurfaceInterface::sizeChanged, 0061 this, &LayerShellV1Window::handleSizeChanged); 0062 connect(shellSurface->surface(), &SurfaceInterface::unmapped, 0063 this, &LayerShellV1Window::handleUnmapped); 0064 connect(shellSurface->surface(), &SurfaceInterface::committed, 0065 this, &LayerShellV1Window::handleCommitted); 0066 0067 connect(shellSurface, &LayerSurfaceV1Interface::desiredSizeChanged, 0068 this, &LayerShellV1Window::scheduleRearrange); 0069 connect(shellSurface, &LayerSurfaceV1Interface::layerChanged, 0070 this, &LayerShellV1Window::scheduleRearrange); 0071 connect(shellSurface, &LayerSurfaceV1Interface::marginsChanged, 0072 this, &LayerShellV1Window::scheduleRearrange); 0073 connect(shellSurface, &LayerSurfaceV1Interface::anchorChanged, 0074 this, &LayerShellV1Window::scheduleRearrange); 0075 connect(shellSurface, &LayerSurfaceV1Interface::exclusiveZoneChanged, 0076 this, &LayerShellV1Window::scheduleRearrange); 0077 connect(shellSurface, &LayerSurfaceV1Interface::acceptsFocusChanged, 0078 this, &LayerShellV1Window::handleAcceptsFocusChanged); 0079 } 0080 0081 LayerSurfaceV1Interface *LayerShellV1Window::shellSurface() const 0082 { 0083 return m_shellSurface; 0084 } 0085 0086 Output *LayerShellV1Window::desiredOutput() const 0087 { 0088 return m_desiredOutput; 0089 } 0090 0091 void LayerShellV1Window::scheduleRearrange() 0092 { 0093 m_integration->scheduleRearrange(); 0094 } 0095 0096 NET::WindowType LayerShellV1Window::windowType() const 0097 { 0098 return m_windowType; 0099 } 0100 0101 bool LayerShellV1Window::isPlaceable() const 0102 { 0103 return false; 0104 } 0105 0106 bool LayerShellV1Window::isCloseable() const 0107 { 0108 return true; 0109 } 0110 0111 bool LayerShellV1Window::isMovable() const 0112 { 0113 return false; 0114 } 0115 0116 bool LayerShellV1Window::isMovableAcrossScreens() const 0117 { 0118 return false; 0119 } 0120 0121 bool LayerShellV1Window::isResizable() const 0122 { 0123 return false; 0124 } 0125 0126 bool LayerShellV1Window::takeFocus() 0127 { 0128 if (acceptsFocus()) { 0129 setActive(true); 0130 } 0131 return true; 0132 } 0133 0134 bool LayerShellV1Window::wantsInput() const 0135 { 0136 return acceptsFocus() && readyForPainting(); 0137 } 0138 0139 bool LayerShellV1Window::dockWantsInput() const 0140 { 0141 return wantsInput(); 0142 } 0143 0144 StrutRect LayerShellV1Window::strutRect(StrutArea area) const 0145 { 0146 switch (area) { 0147 case StrutAreaLeft: 0148 if (m_shellSurface->exclusiveEdge() == Qt::LeftEdge) { 0149 return StrutRect(x(), y(), m_shellSurface->exclusiveZone(), height(), StrutAreaLeft); 0150 } 0151 return StrutRect(); 0152 case StrutAreaRight: 0153 if (m_shellSurface->exclusiveEdge() == Qt::RightEdge) { 0154 return StrutRect(x() + width() - m_shellSurface->exclusiveZone(), y(), 0155 m_shellSurface->exclusiveZone(), height(), StrutAreaRight); 0156 } 0157 return StrutRect(); 0158 case StrutAreaTop: 0159 if (m_shellSurface->exclusiveEdge() == Qt::TopEdge) { 0160 return StrutRect(x(), y(), width(), m_shellSurface->exclusiveZone(), StrutAreaTop); 0161 } 0162 return StrutRect(); 0163 case StrutAreaBottom: 0164 if (m_shellSurface->exclusiveEdge() == Qt::BottomEdge) { 0165 return StrutRect(x(), y() + height() - m_shellSurface->exclusiveZone(), 0166 width(), m_shellSurface->exclusiveZone(), StrutAreaBottom); 0167 } 0168 return StrutRect(); 0169 default: 0170 return StrutRect(); 0171 } 0172 } 0173 0174 bool LayerShellV1Window::hasStrut() const 0175 { 0176 return m_shellSurface->exclusiveZone() > 0; 0177 } 0178 0179 void LayerShellV1Window::destroyWindow() 0180 { 0181 if (m_screenEdge) { 0182 m_screenEdge->disconnect(this); 0183 } 0184 m_shellSurface->disconnect(this); 0185 m_shellSurface->surface()->disconnect(this); 0186 m_desiredOutput->disconnect(this); 0187 0188 markAsDeleted(); 0189 cleanTabBox(); 0190 Q_EMIT closed(); 0191 StackingUpdatesBlocker blocker(workspace()); 0192 cleanGrouping(); 0193 waylandServer()->removeWindow(this); 0194 scheduleRearrange(); 0195 unref(); 0196 } 0197 0198 void LayerShellV1Window::closeWindow() 0199 { 0200 m_shellSurface->sendClosed(); 0201 } 0202 0203 Layer LayerShellV1Window::belongsToLayer() const 0204 { 0205 switch (m_shellSurface->layer()) { 0206 case LayerSurfaceV1Interface::BackgroundLayer: 0207 return DesktopLayer; 0208 case LayerSurfaceV1Interface::BottomLayer: 0209 return BelowLayer; 0210 case LayerSurfaceV1Interface::TopLayer: 0211 return AboveLayer; 0212 case LayerSurfaceV1Interface::OverlayLayer: 0213 return OverlayLayer; 0214 default: 0215 Q_UNREACHABLE(); 0216 } 0217 } 0218 0219 bool LayerShellV1Window::acceptsFocus() const 0220 { 0221 return !isDeleted() && m_shellSurface->acceptsFocus(); 0222 } 0223 0224 void LayerShellV1Window::moveResizeInternal(const QRectF &rect, MoveResizeMode mode) 0225 { 0226 if (areGeometryUpdatesBlocked()) { 0227 setPendingMoveResizeMode(mode); 0228 return; 0229 } 0230 0231 const QSizeF requestedClientSize = frameSizeToClientSize(rect.size()); 0232 if (requestedClientSize != clientSize()) { 0233 m_shellSurface->sendConfigure(rect.size().toSize()); 0234 } else { 0235 updateGeometry(rect); 0236 return; 0237 } 0238 0239 // The surface position is updated synchronously. 0240 QRectF updateRect = m_frameGeometry; 0241 updateRect.moveTopLeft(rect.topLeft()); 0242 updateGeometry(updateRect); 0243 } 0244 0245 void LayerShellV1Window::handleSizeChanged() 0246 { 0247 updateGeometry(QRectF(pos(), clientSizeToFrameSize(surface()->size()))); 0248 scheduleRearrange(); 0249 } 0250 0251 void LayerShellV1Window::handleUnmapped() 0252 { 0253 m_integration->recreateWindow(shellSurface()); 0254 } 0255 0256 void LayerShellV1Window::handleCommitted() 0257 { 0258 if (surface()->buffer()) { 0259 markAsMapped(); 0260 } 0261 } 0262 0263 void LayerShellV1Window::handleAcceptsFocusChanged() 0264 { 0265 switch (m_shellSurface->layer()) { 0266 case LayerSurfaceV1Interface::TopLayer: 0267 case LayerSurfaceV1Interface::OverlayLayer: 0268 if (wantsInput()) { 0269 workspace()->activateWindow(this); 0270 } 0271 break; 0272 case LayerSurfaceV1Interface::BackgroundLayer: 0273 case LayerSurfaceV1Interface::BottomLayer: 0274 break; 0275 } 0276 } 0277 0278 void LayerShellV1Window::handleOutputEnabledChanged() 0279 { 0280 if (!m_desiredOutput->isEnabled()) { 0281 closeWindow(); 0282 destroyWindow(); 0283 } 0284 } 0285 0286 void LayerShellV1Window::setVirtualKeyboardGeometry(const QRectF &geo) 0287 { 0288 if (m_virtualKeyboardGeometry == geo) { 0289 return; 0290 } 0291 0292 m_virtualKeyboardGeometry = geo; 0293 scheduleRearrange(); 0294 } 0295 0296 void LayerShellV1Window::showOnScreenEdge() 0297 { 0298 // ShowOnScreenEdge can be called by an Edge, and setHidden could destroy the Edge 0299 // Use the singleshot to avoid use-after-free 0300 QTimer::singleShot(0, this, &LayerShellV1Window::deactivateScreenEdge); 0301 } 0302 0303 void LayerShellV1Window::installAutoHideScreenEdgeV1(AutoHideScreenEdgeV1Interface *edge) 0304 { 0305 m_screenEdge = edge; 0306 0307 connect(edge, &AutoHideScreenEdgeV1Interface::destroyed, 0308 this, &LayerShellV1Window::deactivateScreenEdge); 0309 connect(edge, &AutoHideScreenEdgeV1Interface::activateRequested, 0310 this, &LayerShellV1Window::activateScreenEdge); 0311 connect(edge, &AutoHideScreenEdgeV1Interface::deactivateRequested, 0312 this, &LayerShellV1Window::deactivateScreenEdge); 0313 0314 connect(this, &LayerShellV1Window::frameGeometryChanged, edge, [this]() { 0315 if (m_screenEdgeActive) { 0316 reserveScreenEdge(); 0317 } 0318 }); 0319 } 0320 0321 void LayerShellV1Window::reserveScreenEdge() 0322 { 0323 if (workspace()->screenEdges()->reserve(this, m_screenEdge->border())) { 0324 setHidden(true); 0325 } else { 0326 setHidden(false); 0327 } 0328 } 0329 0330 void LayerShellV1Window::unreserveScreenEdge() 0331 { 0332 setHidden(false); 0333 workspace()->screenEdges()->reserve(this, ElectricNone); 0334 } 0335 0336 void LayerShellV1Window::activateScreenEdge() 0337 { 0338 m_screenEdgeActive = true; 0339 reserveScreenEdge(); 0340 } 0341 0342 void LayerShellV1Window::deactivateScreenEdge() 0343 { 0344 m_screenEdgeActive = false; 0345 unreserveScreenEdge(); 0346 } 0347 0348 } // namespace KWin 0349 0350 #include "moc_layershellv1window.cpp"