File indexing completed on 2024-05-19 16:34:47

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 "deleted.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 "wayland_server.h"
0016 #include "window.h"
0017 #include "workspace.h"
0018 
0019 #include <KDecoration2/Decoration>
0020 
0021 namespace KWin
0022 {
0023 
0024 WindowItem::WindowItem(Window *window, Scene *scene, Item *parent)
0025     : Item(scene, parent)
0026     , m_window(window)
0027 {
0028     connect(window, &Window::decorationChanged, this, &WindowItem::updateDecorationItem);
0029     updateDecorationItem();
0030 
0031     connect(window, &Window::shadowChanged, this, &WindowItem::updateShadowItem);
0032     updateShadowItem();
0033 
0034     connect(window, &Window::frameGeometryChanged, this, &WindowItem::updatePosition);
0035     updatePosition();
0036 
0037     if (waylandServer()) {
0038         connect(waylandServer(), &WaylandServer::lockStateChanged, this, &WindowItem::updateVisibility);
0039     }
0040     connect(window, &Window::lockScreenOverlayChanged, this, &WindowItem::updateVisibility);
0041     connect(window, &Window::minimizedChanged, this, &WindowItem::updateVisibility);
0042     connect(window, &Window::hiddenChanged, this, &WindowItem::updateVisibility);
0043     connect(window, &Window::activitiesChanged, this, &WindowItem::updateVisibility);
0044     connect(window, &Window::desktopChanged, this, &WindowItem::updateVisibility);
0045     connect(workspace(), &Workspace::currentActivityChanged, this, &WindowItem::updateVisibility);
0046     connect(workspace(), &Workspace::currentDesktopChanged, this, &WindowItem::updateVisibility);
0047     updateVisibility();
0048 
0049     connect(window, &Window::opacityChanged, this, &WindowItem::updateOpacity);
0050     updateOpacity();
0051 
0052     connect(window, &Window::windowClosed, this, &WindowItem::handleWindowClosed);
0053 }
0054 
0055 WindowItem::~WindowItem()
0056 {
0057 }
0058 
0059 SurfaceItem *WindowItem::surfaceItem() const
0060 {
0061     return m_surfaceItem.get();
0062 }
0063 
0064 DecorationItem *WindowItem::decorationItem() const
0065 {
0066     return m_decorationItem.get();
0067 }
0068 
0069 ShadowItem *WindowItem::shadowItem() const
0070 {
0071     return m_shadowItem.get();
0072 }
0073 
0074 Window *WindowItem::window() const
0075 {
0076     return m_window;
0077 }
0078 
0079 void WindowItem::refVisible(int reason)
0080 {
0081     if (reason & PAINT_DISABLED_BY_HIDDEN) {
0082         m_forceVisibleByHiddenCount++;
0083     }
0084     if (reason & PAINT_DISABLED_BY_DELETE) {
0085         m_forceVisibleByDeleteCount++;
0086     }
0087     if (reason & PAINT_DISABLED_BY_DESKTOP) {
0088         m_forceVisibleByDesktopCount++;
0089     }
0090     if (reason & PAINT_DISABLED_BY_MINIMIZE) {
0091         m_forceVisibleByMinimizeCount++;
0092     }
0093     if (reason & PAINT_DISABLED_BY_ACTIVITY) {
0094         m_forceVisibleByActivityCount++;
0095     }
0096     updateVisibility();
0097 }
0098 
0099 void WindowItem::unrefVisible(int reason)
0100 {
0101     if (reason & PAINT_DISABLED_BY_HIDDEN) {
0102         Q_ASSERT(m_forceVisibleByHiddenCount > 0);
0103         m_forceVisibleByHiddenCount--;
0104     }
0105     if (reason & PAINT_DISABLED_BY_DELETE) {
0106         Q_ASSERT(m_forceVisibleByDeleteCount > 0);
0107         m_forceVisibleByDeleteCount--;
0108     }
0109     if (reason & PAINT_DISABLED_BY_DESKTOP) {
0110         Q_ASSERT(m_forceVisibleByDesktopCount > 0);
0111         m_forceVisibleByDesktopCount--;
0112     }
0113     if (reason & PAINT_DISABLED_BY_MINIMIZE) {
0114         Q_ASSERT(m_forceVisibleByMinimizeCount > 0);
0115         m_forceVisibleByMinimizeCount--;
0116     }
0117     if (reason & PAINT_DISABLED_BY_ACTIVITY) {
0118         Q_ASSERT(m_forceVisibleByActivityCount > 0);
0119         m_forceVisibleByActivityCount--;
0120     }
0121     updateVisibility();
0122 }
0123 
0124 void WindowItem::handleWindowClosed(Window *original, Deleted *deleted)
0125 {
0126     m_window = deleted;
0127 }
0128 
0129 bool WindowItem::computeVisibility() const
0130 {
0131     if (!m_window->readyForPainting()) {
0132         return false;
0133     }
0134     if (waylandServer() && waylandServer()->isScreenLocked()) {
0135         return m_window->isLockScreen() || m_window->isInputMethod() || m_window->isLockScreenOverlay();
0136     }
0137     if (m_window->isDeleted()) {
0138         if (m_forceVisibleByDeleteCount == 0) {
0139             return false;
0140         }
0141     }
0142     if (!m_window->isOnCurrentDesktop()) {
0143         if (m_forceVisibleByDesktopCount == 0) {
0144             return false;
0145         }
0146     }
0147     if (!m_window->isOnCurrentActivity()) {
0148         if (m_forceVisibleByActivityCount == 0) {
0149             return false;
0150         }
0151     }
0152     if (m_window->isMinimized()) {
0153         if (m_forceVisibleByMinimizeCount == 0) {
0154             return false;
0155         }
0156     }
0157     if (m_window->isHiddenInternal()) {
0158         if (m_forceVisibleByHiddenCount == 0) {
0159             return false;
0160         }
0161     }
0162     return true;
0163 }
0164 
0165 void WindowItem::updateVisibility()
0166 {
0167     setVisible(computeVisibility());
0168 }
0169 
0170 void WindowItem::updatePosition()
0171 {
0172     setPosition(m_window->pos());
0173 }
0174 
0175 void WindowItem::addSurfaceItemDamageConnects(Item *item)
0176 {
0177     auto surfaceItem = static_cast<SurfaceItem *>(item);
0178     connect(surfaceItem, &SurfaceItem::damaged, this, &WindowItem::markDamaged);
0179     connect(surfaceItem, &SurfaceItem::childAdded, this, &WindowItem::addSurfaceItemDamageConnects);
0180     const auto childItems = item->childItems();
0181     for (const auto &child : childItems) {
0182         addSurfaceItemDamageConnects(child);
0183     }
0184 }
0185 
0186 void WindowItem::updateSurfaceItem(SurfaceItem *surfaceItem)
0187 {
0188     m_surfaceItem.reset(surfaceItem);
0189 
0190     if (m_surfaceItem) {
0191         connect(m_window, &Window::shadeChanged, this, &WindowItem::updateSurfaceVisibility);
0192         connect(m_window, &Window::bufferGeometryChanged, this, &WindowItem::updateSurfacePosition);
0193         connect(m_window, &Window::frameGeometryChanged, this, &WindowItem::updateSurfacePosition);
0194         addSurfaceItemDamageConnects(surfaceItem);
0195 
0196         updateSurfacePosition();
0197         updateSurfaceVisibility();
0198     } else {
0199         disconnect(m_window, &Window::shadeChanged, this, &WindowItem::updateSurfaceVisibility);
0200         disconnect(m_window, &Window::bufferGeometryChanged, this, &WindowItem::updateSurfacePosition);
0201         disconnect(m_window, &Window::frameGeometryChanged, this, &WindowItem::updateSurfacePosition);
0202     }
0203 }
0204 
0205 void WindowItem::updateSurfacePosition()
0206 {
0207     const QRectF bufferGeometry = m_window->bufferGeometry();
0208     const QRectF frameGeometry = m_window->frameGeometry();
0209 
0210     m_surfaceItem->setPosition(bufferGeometry.topLeft() - frameGeometry.topLeft());
0211 }
0212 
0213 void WindowItem::updateSurfaceVisibility()
0214 {
0215     m_surfaceItem->setVisible(!m_window->isShade());
0216 }
0217 
0218 void WindowItem::updateShadowItem()
0219 {
0220     Shadow *shadow = m_window->shadow();
0221     if (shadow) {
0222         if (!m_shadowItem || m_shadowItem->shadow() != shadow) {
0223             m_shadowItem.reset(new ShadowItem(shadow, m_window, scene(), this));
0224         }
0225         if (m_decorationItem) {
0226             m_shadowItem->stackBefore(m_decorationItem.get());
0227         } else if (m_surfaceItem) {
0228             m_shadowItem->stackBefore(m_surfaceItem.get());
0229         }
0230         markDamaged();
0231     } else {
0232         m_shadowItem.reset();
0233     }
0234 }
0235 
0236 void WindowItem::updateDecorationItem()
0237 {
0238     if (m_window->isDeleted() || m_window->isZombie()) {
0239         return;
0240     }
0241     if (m_window->decoration()) {
0242         m_decorationItem.reset(new DecorationItem(m_window->decoration(), m_window, scene(), this));
0243         if (m_shadowItem) {
0244             m_decorationItem->stackAfter(m_shadowItem.get());
0245         } else if (m_surfaceItem) {
0246             m_decorationItem->stackBefore(m_surfaceItem.get());
0247         }
0248         connect(m_window->decoration(), &KDecoration2::Decoration::damaged, this, &WindowItem::markDamaged);
0249         markDamaged();
0250     } else {
0251         m_decorationItem.reset();
0252     }
0253 }
0254 
0255 void WindowItem::updateOpacity()
0256 {
0257     setOpacity(m_window->opacity());
0258 }
0259 
0260 void WindowItem::markDamaged()
0261 {
0262     Q_EMIT m_window->damaged(m_window);
0263 }
0264 
0265 WindowItemX11::WindowItemX11(Window *window, Scene *scene, Item *parent)
0266     : WindowItem(window, scene, parent)
0267 {
0268     initialize();
0269 
0270     // Xwayland windows and Wayland surfaces are associated asynchronously.
0271     connect(window, &Window::surfaceChanged, this, &WindowItemX11::initialize);
0272 }
0273 
0274 void WindowItemX11::initialize()
0275 {
0276     switch (kwinApp()->operationMode()) {
0277     case Application::OperationModeX11:
0278         updateSurfaceItem(new SurfaceItemX11(window(), scene(), this));
0279         break;
0280     case Application::OperationModeXwayland:
0281         if (!window()->surface()) {
0282             updateSurfaceItem(nullptr);
0283         } else {
0284             updateSurfaceItem(new SurfaceItemXwayland(window(), scene(), this));
0285         }
0286         break;
0287     case Application::OperationModeWaylandOnly:
0288         Q_UNREACHABLE();
0289     }
0290 }
0291 
0292 WindowItemWayland::WindowItemWayland(Window *window, Scene *scene, Item *parent)
0293     : WindowItem(window, scene, parent)
0294 {
0295     updateSurfaceItem(new SurfaceItemWayland(window->surface(), scene, this));
0296 }
0297 
0298 WindowItemInternal::WindowItemInternal(InternalWindow *window, Scene *scene, Item *parent)
0299     : WindowItem(window, scene, parent)
0300 {
0301     updateSurfaceItem(new SurfaceItemInternal(window, scene, this));
0302 }
0303 
0304 } // namespace KWin