File indexing completed on 2024-11-10 04:57:16
0001 /* 0002 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "scene/windowitem.h" 0008 #include "effect/effecthandler.h" 0009 #include "internalwindow.h" 0010 #include "scene/decorationitem.h" 0011 #include "scene/shadowitem.h" 0012 #include "scene/surfaceitem_internal.h" 0013 #include "scene/surfaceitem_wayland.h" 0014 #include "scene/surfaceitem_x11.h" 0015 #include "virtualdesktops.h" 0016 #include "wayland_server.h" 0017 #include "window.h" 0018 #include "workspace.h" 0019 #include "x11window.h" 0020 0021 #include <KDecoration2/Decoration> 0022 0023 namespace KWin 0024 { 0025 0026 WindowItem::WindowItem(Window *window, Scene *scene, Item *parent) 0027 : Item(scene, parent) 0028 , m_window(window) 0029 { 0030 connect(window, &Window::decorationChanged, this, &WindowItem::updateDecorationItem); 0031 updateDecorationItem(); 0032 0033 connect(window, &Window::shadowChanged, this, &WindowItem::updateShadowItem); 0034 updateShadowItem(); 0035 0036 connect(window, &Window::frameGeometryChanged, this, &WindowItem::updatePosition); 0037 updatePosition(); 0038 0039 if (waylandServer()) { 0040 connect(waylandServer(), &WaylandServer::lockStateChanged, this, &WindowItem::updateVisibility); 0041 } 0042 if (!window->readyForPainting()) { 0043 connect(window, &Window::readyForPaintingChanged, this, &WindowItem::updateVisibility); 0044 } 0045 connect(window, &Window::lockScreenOverlayChanged, this, &WindowItem::updateVisibility); 0046 connect(window, &Window::minimizedChanged, this, &WindowItem::updateVisibility); 0047 connect(window, &Window::hiddenChanged, this, &WindowItem::updateVisibility); 0048 connect(window, &Window::hiddenByShowDesktopChanged, this, &WindowItem::updateVisibility); 0049 connect(window, &Window::activitiesChanged, this, &WindowItem::updateVisibility); 0050 connect(window, &Window::desktopsChanged, this, &WindowItem::updateVisibility); 0051 connect(workspace(), &Workspace::currentActivityChanged, this, &WindowItem::updateVisibility); 0052 connect(workspace(), &Workspace::currentDesktopChanged, this, &WindowItem::updateVisibility); 0053 updateVisibility(); 0054 0055 connect(window, &Window::opacityChanged, this, &WindowItem::updateOpacity); 0056 updateOpacity(); 0057 0058 connect(window, &Window::stackingOrderChanged, this, &WindowItem::updateStackingOrder); 0059 updateStackingOrder(); 0060 0061 connect(window, &Window::closed, this, &WindowItem::freeze); 0062 0063 m_effectWindow = std::make_unique<EffectWindow>(this); 0064 } 0065 0066 WindowItem::~WindowItem() 0067 { 0068 } 0069 0070 SurfaceItem *WindowItem::surfaceItem() const 0071 { 0072 return m_surfaceItem.get(); 0073 } 0074 0075 DecorationItem *WindowItem::decorationItem() const 0076 { 0077 return m_decorationItem.get(); 0078 } 0079 0080 ShadowItem *WindowItem::shadowItem() const 0081 { 0082 return m_shadowItem.get(); 0083 } 0084 0085 Window *WindowItem::window() const 0086 { 0087 return m_window; 0088 } 0089 0090 EffectWindow *WindowItem::effectWindow() const 0091 { 0092 return m_effectWindow.get(); 0093 } 0094 0095 void WindowItem::refVisible(int reason) 0096 { 0097 if (reason & PAINT_DISABLED_BY_HIDDEN) { 0098 m_forceVisibleByHiddenCount++; 0099 } 0100 if (reason & PAINT_DISABLED_BY_DESKTOP) { 0101 m_forceVisibleByDesktopCount++; 0102 } 0103 if (reason & PAINT_DISABLED_BY_MINIMIZE) { 0104 m_forceVisibleByMinimizeCount++; 0105 } 0106 if (reason & PAINT_DISABLED_BY_ACTIVITY) { 0107 m_forceVisibleByActivityCount++; 0108 } 0109 updateVisibility(); 0110 } 0111 0112 void WindowItem::unrefVisible(int reason) 0113 { 0114 if (reason & PAINT_DISABLED_BY_HIDDEN) { 0115 Q_ASSERT(m_forceVisibleByHiddenCount > 0); 0116 m_forceVisibleByHiddenCount--; 0117 } 0118 if (reason & PAINT_DISABLED_BY_DESKTOP) { 0119 Q_ASSERT(m_forceVisibleByDesktopCount > 0); 0120 m_forceVisibleByDesktopCount--; 0121 } 0122 if (reason & PAINT_DISABLED_BY_MINIMIZE) { 0123 Q_ASSERT(m_forceVisibleByMinimizeCount > 0); 0124 m_forceVisibleByMinimizeCount--; 0125 } 0126 if (reason & PAINT_DISABLED_BY_ACTIVITY) { 0127 Q_ASSERT(m_forceVisibleByActivityCount > 0); 0128 m_forceVisibleByActivityCount--; 0129 } 0130 updateVisibility(); 0131 } 0132 0133 void WindowItem::elevate() 0134 { 0135 // Not ideal, but it's also highly unlikely that there are more than 1000 windows. The 0136 // elevation constantly increases so it's possible to force specific stacking order. It 0137 // can potentially overflow, but it's unlikely to happen because windows are elevated 0138 // rarely. 0139 static int elevation = 1000; 0140 0141 m_elevation = elevation++; 0142 updateStackingOrder(); 0143 } 0144 0145 void WindowItem::deelevate() 0146 { 0147 m_elevation.reset(); 0148 updateStackingOrder(); 0149 } 0150 0151 bool WindowItem::computeVisibility() const 0152 { 0153 if (!m_window->readyForPainting()) { 0154 return false; 0155 } 0156 if (waylandServer() && waylandServer()->isScreenLocked()) { 0157 return m_window->isLockScreen() || m_window->isInputMethod() || m_window->isLockScreenOverlay(); 0158 } 0159 if (!m_window->isOnCurrentDesktop()) { 0160 if (m_forceVisibleByDesktopCount == 0) { 0161 return false; 0162 } 0163 } 0164 if (!m_window->isOnCurrentActivity()) { 0165 if (m_forceVisibleByActivityCount == 0) { 0166 return false; 0167 } 0168 } 0169 if (m_window->isMinimized()) { 0170 if (m_forceVisibleByMinimizeCount == 0) { 0171 return false; 0172 } 0173 } 0174 if (m_window->isHidden() || m_window->isHiddenByShowDesktop()) { 0175 if (m_forceVisibleByHiddenCount == 0) { 0176 return false; 0177 } 0178 } 0179 return true; 0180 } 0181 0182 void WindowItem::updateVisibility() 0183 { 0184 const bool visible = computeVisibility(); 0185 setVisible(visible); 0186 0187 if (m_window->readyForPainting()) { 0188 m_window->setSuspended(!visible); 0189 } 0190 } 0191 0192 void WindowItem::updatePosition() 0193 { 0194 setPosition(m_window->pos()); 0195 } 0196 0197 void WindowItem::addSurfaceItemDamageConnects(Item *item) 0198 { 0199 auto surfaceItem = static_cast<SurfaceItem *>(item); 0200 connect(surfaceItem, &SurfaceItem::damaged, this, &WindowItem::markDamaged); 0201 connect(surfaceItem, &SurfaceItem::childAdded, this, &WindowItem::addSurfaceItemDamageConnects); 0202 const auto childItems = item->childItems(); 0203 for (const auto &child : childItems) { 0204 addSurfaceItemDamageConnects(child); 0205 } 0206 } 0207 0208 void WindowItem::updateSurfaceItem(std::unique_ptr<SurfaceItem> &&surfaceItem) 0209 { 0210 m_surfaceItem = std::move(surfaceItem); 0211 0212 if (m_surfaceItem) { 0213 connect(m_window, &Window::shadeChanged, this, &WindowItem::updateSurfaceVisibility); 0214 connect(m_window, &Window::bufferGeometryChanged, this, &WindowItem::updateSurfacePosition); 0215 connect(m_window, &Window::frameGeometryChanged, this, &WindowItem::updateSurfacePosition); 0216 addSurfaceItemDamageConnects(m_surfaceItem.get()); 0217 0218 updateSurfacePosition(); 0219 updateSurfaceVisibility(); 0220 } else { 0221 disconnect(m_window, &Window::shadeChanged, this, &WindowItem::updateSurfaceVisibility); 0222 disconnect(m_window, &Window::bufferGeometryChanged, this, &WindowItem::updateSurfacePosition); 0223 disconnect(m_window, &Window::frameGeometryChanged, this, &WindowItem::updateSurfacePosition); 0224 } 0225 } 0226 0227 void WindowItem::updateSurfacePosition() 0228 { 0229 const QRectF bufferGeometry = m_window->bufferGeometry(); 0230 const QRectF frameGeometry = m_window->frameGeometry(); 0231 0232 m_surfaceItem->setPosition(bufferGeometry.topLeft() - frameGeometry.topLeft()); 0233 } 0234 0235 void WindowItem::updateSurfaceVisibility() 0236 { 0237 m_surfaceItem->setVisible(!m_window->isShade()); 0238 } 0239 0240 void WindowItem::updateShadowItem() 0241 { 0242 Shadow *shadow = m_window->shadow(); 0243 if (shadow) { 0244 if (!m_shadowItem || m_shadowItem->shadow() != shadow) { 0245 m_shadowItem = std::make_unique<ShadowItem>(shadow, m_window, scene(), this); 0246 } 0247 if (m_decorationItem) { 0248 m_shadowItem->stackBefore(m_decorationItem.get()); 0249 } else if (m_surfaceItem) { 0250 m_shadowItem->stackBefore(m_surfaceItem.get()); 0251 } 0252 markDamaged(); 0253 } else { 0254 m_shadowItem.reset(); 0255 } 0256 } 0257 0258 void WindowItem::updateDecorationItem() 0259 { 0260 if (m_window->isDeleted()) { 0261 return; 0262 } 0263 if (m_window->decoration()) { 0264 m_decorationItem = std::make_unique<DecorationItem>(m_window->decoration(), m_window, scene(), this); 0265 if (m_shadowItem) { 0266 m_decorationItem->stackAfter(m_shadowItem.get()); 0267 } else if (m_surfaceItem) { 0268 m_decorationItem->stackBefore(m_surfaceItem.get()); 0269 } 0270 connect(m_window->decoration(), &KDecoration2::Decoration::damaged, this, &WindowItem::markDamaged); 0271 markDamaged(); 0272 } else { 0273 m_decorationItem.reset(); 0274 } 0275 } 0276 0277 void WindowItem::updateOpacity() 0278 { 0279 setOpacity(m_window->opacity()); 0280 } 0281 0282 void WindowItem::updateStackingOrder() 0283 { 0284 if (m_elevation.has_value()) { 0285 setZ(m_elevation.value()); 0286 } else { 0287 setZ(m_window->stackingOrder()); 0288 } 0289 } 0290 0291 void WindowItem::markDamaged() 0292 { 0293 Q_EMIT m_window->damaged(m_window); 0294 } 0295 0296 void WindowItem::freeze() 0297 { 0298 if (m_surfaceItem) { 0299 m_surfaceItem->freeze(); 0300 } 0301 } 0302 0303 WindowItemX11::WindowItemX11(X11Window *window, Scene *scene, Item *parent) 0304 : WindowItem(window, scene, parent) 0305 { 0306 initialize(); 0307 0308 // Xwayland windows and Wayland surfaces are associated asynchronously. 0309 connect(window, &Window::surfaceChanged, this, &WindowItemX11::initialize); 0310 } 0311 0312 void WindowItemX11::initialize() 0313 { 0314 switch (kwinApp()->operationMode()) { 0315 case Application::OperationModeX11: 0316 updateSurfaceItem(std::make_unique<SurfaceItemX11>(static_cast<X11Window *>(window()), scene(), this)); 0317 break; 0318 case Application::OperationModeXwayland: 0319 if (!window()->surface()) { 0320 updateSurfaceItem(nullptr); 0321 } else { 0322 updateSurfaceItem(std::make_unique<SurfaceItemXwayland>(static_cast<X11Window *>(window()), scene(), this)); 0323 } 0324 break; 0325 case Application::OperationModeWaylandOnly: 0326 Q_UNREACHABLE(); 0327 } 0328 } 0329 0330 WindowItemWayland::WindowItemWayland(Window *window, Scene *scene, Item *parent) 0331 : WindowItem(window, scene, parent) 0332 { 0333 updateSurfaceItem(std::make_unique<SurfaceItemWayland>(window->surface(), scene, this)); 0334 } 0335 0336 WindowItemInternal::WindowItemInternal(InternalWindow *window, Scene *scene, Item *parent) 0337 : WindowItem(window, scene, parent) 0338 { 0339 updateSurfaceItem(std::make_unique<SurfaceItemInternal>(window, scene, this)); 0340 } 0341 0342 } // namespace KWin 0343 0344 #include "moc_windowitem.cpp"