File indexing completed on 2024-05-19 05:32:21

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"