kwin/src/windowitem.cpp
Vlad Zahorodnii 935fa6a9e1 Move ownership of Shadow to Toplevel
This decouples the management of Shadow from the scene window and allows
multiple items share the same Shadow.

Currently, kwin has a single scene graph, but it makes sense to create a
scene graph per output as they could have different layers, etc. This
would also allow QtQuick share more textures with kwin, which is worth
doing for optimization purposes in the future.
2021-09-06 10:42:39 +00:00

161 lines
4.3 KiB
C++

/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "windowitem.h"
#include "abstract_client.h"
#include "decorationitem.h"
#include "deleted.h"
#include "shadowitem.h"
#include "surfaceitem_internal.h"
#include "surfaceitem_wayland.h"
#include "surfaceitem_x11.h"
namespace KWin
{
WindowItem::WindowItem(Toplevel *window, Item *parent)
: Item(parent)
, m_window(window)
{
AbstractClient *client = qobject_cast<AbstractClient *>(window);
if (client) {
connect(client, &AbstractClient::decorationChanged, this, &WindowItem::updateDecorationItem);
updateDecorationItem();
}
connect(window, &Toplevel::shadowChanged, this, &WindowItem::updateShadowItem);
updateShadowItem();
connect(window, &Toplevel::windowClosed, this, &WindowItem::handleWindowClosed);
}
SurfaceItem *WindowItem::surfaceItem() const
{
return m_surfaceItem.data();
}
DecorationItem *WindowItem::decorationItem() const
{
return m_decorationItem.data();
}
ShadowItem *WindowItem::shadowItem() const
{
return m_shadowItem.data();
}
Toplevel *WindowItem::window() const
{
return m_window;
}
void WindowItem::handleWindowClosed(Toplevel *original, Deleted *deleted)
{
Q_UNUSED(original)
m_window = deleted;
}
void WindowItem::updateSurfaceItem(SurfaceItem *surfaceItem)
{
m_surfaceItem.reset(surfaceItem);
connect(m_window, &Toplevel::shadeChanged, this, &WindowItem::updateSurfaceVisibility);
connect(m_window, &Toplevel::bufferGeometryChanged, this, &WindowItem::updateSurfacePosition);
connect(m_window, &Toplevel::frameGeometryChanged, this, &WindowItem::updateSurfacePosition);
updateSurfacePosition();
updateSurfaceVisibility();
}
void WindowItem::updateSurfacePosition()
{
const QRect bufferGeometry = m_window->bufferGeometry();
const QRect 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.reset(new ShadowItem(shadow, m_window, this));
}
if (m_decorationItem) {
m_shadowItem->stackBefore(m_decorationItem.data());
} else if (m_surfaceItem) {
m_shadowItem->stackBefore(m_decorationItem.data());
}
} else {
m_shadowItem.reset();
}
}
void WindowItem::updateDecorationItem()
{
AbstractClient *client = qobject_cast<AbstractClient *>(m_window);
if (!client || client->isZombie()) {
return;
}
if (client->decoration()) {
m_decorationItem.reset(new DecorationItem(client->decoration(), client, this));
if (m_shadowItem) {
m_decorationItem->stackAfter(m_shadowItem.data());
} else if (m_surfaceItem) {
m_decorationItem->stackBefore(m_surfaceItem.data());
}
} else {
m_decorationItem.reset();
}
}
WindowItemX11::WindowItemX11(Toplevel *window, Item *parent)
: WindowItem(window, parent)
{
switch (kwinApp()->operationMode()) {
case Application::OperationModeX11:
initialize();
break;
case Application::OperationModeXwayland:
// Xwayland windows and Wayland surfaces are associated asynchronously.
if (window->surface()) {
initialize();
} else {
connect(window, &Toplevel::surfaceChanged, this, &WindowItemX11::initialize);
}
break;
case Application::OperationModeWaylandOnly:
Q_UNREACHABLE();
}
}
void WindowItemX11::initialize()
{
if (!window()->surface()) {
updateSurfaceItem(new SurfaceItemX11(window(), this));
} else {
updateSurfaceItem(new SurfaceItemXwayland(window(), this));
}
}
WindowItemWayland::WindowItemWayland(Toplevel *window, Item *parent)
: WindowItem(window, parent)
{
updateSurfaceItem(new SurfaceItemWayland(window->surface(), window, this));
}
WindowItemInternal::WindowItemInternal(Toplevel *window, Item *parent)
: WindowItem(window, parent)
{
updateSurfaceItem(new SurfaceItemInternal(window, this));
}
} // namespace KWin