You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
9.7 KiB
332 lines
9.7 KiB
/* |
|
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> |
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
*/ |
|
|
|
#include "scene/windowitem.h" |
|
#include "effect/effecthandler.h" |
|
#include "internalwindow.h" |
|
#include "scene/decorationitem.h" |
|
#include "scene/shadowitem.h" |
|
#include "scene/surfaceitem_internal.h" |
|
#include "scene/surfaceitem_wayland.h" |
|
#include "scene/surfaceitem_x11.h" |
|
#include "virtualdesktops.h" |
|
#include "wayland_server.h" |
|
#include "window.h" |
|
#include "workspace.h" |
|
#include "x11window.h" |
|
|
|
#include <KDecoration2/Decoration> |
|
|
|
namespace KWin |
|
{ |
|
|
|
WindowItem::WindowItem(Window *window, Scene *scene, Item *parent) |
|
: Item(scene, parent) |
|
, m_window(window) |
|
{ |
|
connect(window, &Window::decorationChanged, this, &WindowItem::updateDecorationItem); |
|
updateDecorationItem(); |
|
|
|
connect(window, &Window::shadowChanged, this, &WindowItem::updateShadowItem); |
|
updateShadowItem(); |
|
|
|
connect(window, &Window::frameGeometryChanged, this, &WindowItem::updatePosition); |
|
updatePosition(); |
|
|
|
if (waylandServer()) { |
|
connect(waylandServer(), &WaylandServer::lockStateChanged, this, &WindowItem::updateVisibility); |
|
} |
|
connect(window, &Window::lockScreenOverlayChanged, this, &WindowItem::updateVisibility); |
|
connect(window, &Window::minimizedChanged, this, &WindowItem::updateVisibility); |
|
connect(window, &Window::hiddenChanged, this, &WindowItem::updateVisibility); |
|
connect(window, &Window::hiddenByShowDesktopChanged, this, &WindowItem::updateVisibility); |
|
connect(window, &Window::activitiesChanged, this, &WindowItem::updateVisibility); |
|
connect(window, &Window::desktopsChanged, this, &WindowItem::updateVisibility); |
|
connect(workspace(), &Workspace::currentActivityChanged, this, &WindowItem::updateVisibility); |
|
connect(workspace(), &Workspace::currentDesktopChanged, this, &WindowItem::updateVisibility); |
|
updateVisibility(); |
|
|
|
connect(window, &Window::opacityChanged, this, &WindowItem::updateOpacity); |
|
updateOpacity(); |
|
|
|
connect(window, &Window::stackingOrderChanged, this, &WindowItem::updateStackingOrder); |
|
updateStackingOrder(); |
|
|
|
m_effectWindow = std::make_unique<EffectWindow>(this); |
|
} |
|
|
|
WindowItem::~WindowItem() |
|
{ |
|
} |
|
|
|
SurfaceItem *WindowItem::surfaceItem() const |
|
{ |
|
return m_surfaceItem.get(); |
|
} |
|
|
|
DecorationItem *WindowItem::decorationItem() const |
|
{ |
|
return m_decorationItem.get(); |
|
} |
|
|
|
ShadowItem *WindowItem::shadowItem() const |
|
{ |
|
return m_shadowItem.get(); |
|
} |
|
|
|
Window *WindowItem::window() const |
|
{ |
|
return m_window; |
|
} |
|
|
|
EffectWindow *WindowItem::effectWindow() const |
|
{ |
|
return m_effectWindow.get(); |
|
} |
|
|
|
void WindowItem::refVisible(int reason) |
|
{ |
|
if (reason & PAINT_DISABLED_BY_HIDDEN) { |
|
m_forceVisibleByHiddenCount++; |
|
} |
|
if (reason & PAINT_DISABLED_BY_DESKTOP) { |
|
m_forceVisibleByDesktopCount++; |
|
} |
|
if (reason & PAINT_DISABLED_BY_MINIMIZE) { |
|
m_forceVisibleByMinimizeCount++; |
|
} |
|
if (reason & PAINT_DISABLED_BY_ACTIVITY) { |
|
m_forceVisibleByActivityCount++; |
|
} |
|
updateVisibility(); |
|
} |
|
|
|
void WindowItem::unrefVisible(int reason) |
|
{ |
|
if (reason & PAINT_DISABLED_BY_HIDDEN) { |
|
Q_ASSERT(m_forceVisibleByHiddenCount > 0); |
|
m_forceVisibleByHiddenCount--; |
|
} |
|
if (reason & PAINT_DISABLED_BY_DESKTOP) { |
|
Q_ASSERT(m_forceVisibleByDesktopCount > 0); |
|
m_forceVisibleByDesktopCount--; |
|
} |
|
if (reason & PAINT_DISABLED_BY_MINIMIZE) { |
|
Q_ASSERT(m_forceVisibleByMinimizeCount > 0); |
|
m_forceVisibleByMinimizeCount--; |
|
} |
|
if (reason & PAINT_DISABLED_BY_ACTIVITY) { |
|
Q_ASSERT(m_forceVisibleByActivityCount > 0); |
|
m_forceVisibleByActivityCount--; |
|
} |
|
updateVisibility(); |
|
} |
|
|
|
void WindowItem::elevate() |
|
{ |
|
// Not ideal, but it's also highly unlikely that there are more than 1000 windows. The |
|
// elevation constantly increases so it's possible to force specific stacking order. It |
|
// can potentially overflow, but it's unlikely to happen because windows are elevated |
|
// rarely. |
|
static int elevation = 1000; |
|
|
|
m_elevation = elevation++; |
|
updateStackingOrder(); |
|
} |
|
|
|
void WindowItem::deelevate() |
|
{ |
|
m_elevation.reset(); |
|
updateStackingOrder(); |
|
} |
|
|
|
bool WindowItem::computeVisibility() const |
|
{ |
|
if (!m_window->readyForPainting()) { |
|
return false; |
|
} |
|
if (waylandServer() && waylandServer()->isScreenLocked()) { |
|
return m_window->isLockScreen() || m_window->isInputMethod() || m_window->isLockScreenOverlay(); |
|
} |
|
if (!m_window->isOnCurrentDesktop()) { |
|
if (m_forceVisibleByDesktopCount == 0) { |
|
return false; |
|
} |
|
} |
|
if (!m_window->isOnCurrentActivity()) { |
|
if (m_forceVisibleByActivityCount == 0) { |
|
return false; |
|
} |
|
} |
|
if (m_window->isMinimized()) { |
|
if (m_forceVisibleByMinimizeCount == 0) { |
|
return false; |
|
} |
|
} |
|
if (m_window->isHidden() || m_window->isHiddenByShowDesktop()) { |
|
if (m_forceVisibleByHiddenCount == 0) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
void WindowItem::updateVisibility() |
|
{ |
|
const bool visible = computeVisibility(); |
|
setVisible(visible); |
|
|
|
if (m_window->readyForPainting()) { |
|
m_window->setSuspended(!visible); |
|
} |
|
} |
|
|
|
void WindowItem::updatePosition() |
|
{ |
|
setPosition(m_window->pos()); |
|
} |
|
|
|
void WindowItem::addSurfaceItemDamageConnects(Item *item) |
|
{ |
|
auto surfaceItem = static_cast<SurfaceItem *>(item); |
|
connect(surfaceItem, &SurfaceItem::damaged, this, &WindowItem::markDamaged); |
|
connect(surfaceItem, &SurfaceItem::childAdded, this, &WindowItem::addSurfaceItemDamageConnects); |
|
const auto childItems = item->childItems(); |
|
for (const auto &child : childItems) { |
|
addSurfaceItemDamageConnects(child); |
|
} |
|
} |
|
|
|
void WindowItem::updateSurfaceItem(std::unique_ptr<SurfaceItem> &&surfaceItem) |
|
{ |
|
m_surfaceItem = std::move(surfaceItem); |
|
|
|
if (m_surfaceItem) { |
|
connect(m_window, &Window::shadeChanged, this, &WindowItem::updateSurfaceVisibility); |
|
connect(m_window, &Window::bufferGeometryChanged, this, &WindowItem::updateSurfacePosition); |
|
connect(m_window, &Window::frameGeometryChanged, this, &WindowItem::updateSurfacePosition); |
|
addSurfaceItemDamageConnects(m_surfaceItem.get()); |
|
|
|
updateSurfacePosition(); |
|
updateSurfaceVisibility(); |
|
} else { |
|
disconnect(m_window, &Window::shadeChanged, this, &WindowItem::updateSurfaceVisibility); |
|
disconnect(m_window, &Window::bufferGeometryChanged, this, &WindowItem::updateSurfacePosition); |
|
disconnect(m_window, &Window::frameGeometryChanged, this, &WindowItem::updateSurfacePosition); |
|
} |
|
} |
|
|
|
void WindowItem::updateSurfacePosition() |
|
{ |
|
const QRectF bufferGeometry = m_window->bufferGeometry(); |
|
const QRectF frameGeometry = m_window->frameGeometry(); |
|
|
|
m_surfaceItem->setPosition(bufferGeometry.topLeft() - frameGeometry.topLeft()); |
|
} |
|
|
|
void WindowItem::updateSurfaceVisibility() |
|
{ |
|
m_surfaceItem->setVisible(!m_window->isShade()); |
|
} |
|
|
|
void WindowItem::updateShadowItem() |
|
{ |
|
Shadow *shadow = m_window->shadow(); |
|
if (shadow) { |
|
if (!m_shadowItem || m_shadowItem->shadow() != shadow) { |
|
m_shadowItem = std::make_unique<ShadowItem>(shadow, m_window, scene(), this); |
|
} |
|
if (m_decorationItem) { |
|
m_shadowItem->stackBefore(m_decorationItem.get()); |
|
} else if (m_surfaceItem) { |
|
m_shadowItem->stackBefore(m_surfaceItem.get()); |
|
} |
|
markDamaged(); |
|
} else { |
|
m_shadowItem.reset(); |
|
} |
|
} |
|
|
|
void WindowItem::updateDecorationItem() |
|
{ |
|
if (m_window->isDeleted()) { |
|
return; |
|
} |
|
if (m_window->decoration()) { |
|
m_decorationItem = std::make_unique<DecorationItem>(m_window->decoration(), m_window, scene(), this); |
|
if (m_shadowItem) { |
|
m_decorationItem->stackAfter(m_shadowItem.get()); |
|
} else if (m_surfaceItem) { |
|
m_decorationItem->stackBefore(m_surfaceItem.get()); |
|
} |
|
connect(m_window->decoration(), &KDecoration2::Decoration::damaged, this, &WindowItem::markDamaged); |
|
markDamaged(); |
|
} else { |
|
m_decorationItem.reset(); |
|
} |
|
} |
|
|
|
void WindowItem::updateOpacity() |
|
{ |
|
setOpacity(m_window->opacity()); |
|
} |
|
|
|
void WindowItem::updateStackingOrder() |
|
{ |
|
if (m_elevation.has_value()) { |
|
setZ(m_elevation.value()); |
|
} else { |
|
setZ(m_window->stackingOrder()); |
|
} |
|
} |
|
|
|
void WindowItem::markDamaged() |
|
{ |
|
Q_EMIT m_window->damaged(m_window); |
|
} |
|
|
|
WindowItemX11::WindowItemX11(X11Window *window, Scene *scene, Item *parent) |
|
: WindowItem(window, scene, parent) |
|
{ |
|
initialize(); |
|
|
|
// Xwayland windows and Wayland surfaces are associated asynchronously. |
|
connect(window, &Window::surfaceChanged, this, &WindowItemX11::initialize); |
|
} |
|
|
|
void WindowItemX11::initialize() |
|
{ |
|
switch (kwinApp()->operationMode()) { |
|
case Application::OperationModeX11: |
|
updateSurfaceItem(std::make_unique<SurfaceItemX11>(static_cast<X11Window *>(window()), scene(), this)); |
|
break; |
|
case Application::OperationModeXwayland: |
|
if (!window()->surface()) { |
|
updateSurfaceItem(nullptr); |
|
} else { |
|
updateSurfaceItem(std::make_unique<SurfaceItemXwayland>(static_cast<X11Window *>(window()), scene(), this)); |
|
} |
|
break; |
|
case Application::OperationModeWaylandOnly: |
|
Q_UNREACHABLE(); |
|
} |
|
} |
|
|
|
WindowItemWayland::WindowItemWayland(Window *window, Scene *scene, Item *parent) |
|
: WindowItem(window, scene, parent) |
|
{ |
|
updateSurfaceItem(std::make_unique<SurfaceItemWayland>(window->surface(), scene, this)); |
|
} |
|
|
|
WindowItemInternal::WindowItemInternal(InternalWindow *window, Scene *scene, Item *parent) |
|
: WindowItem(window, scene, parent) |
|
{ |
|
updateSurfaceItem(std::make_unique<SurfaceItemInternal>(window, scene, this)); |
|
} |
|
|
|
} // namespace KWin |
|
|
|
#include "moc_windowitem.cpp"
|
|
|