kwin/src/surfaceitem_wayland.cpp
Vlad Zahorodnii 47113e09b8 scene: Introduce window items
Currently, dealing with sub-surfaces is very difficult due to the scene
design being heavily influenced by X11 requirements.

The goal of this change is to re-work scene abstractions to make improving
the wayland support easier.

The Item class is based on the QQuickItem class. My hope is that one day
we will be able to transition to QtQuick for painting scene, but in
meanwhile it makes more sense to have a minimalistic internal item class.

The WindowItem class represents a window. The SurfaceItem class represents
the contents of either an X11, or a Wayland, or an internal surface. The
DecorationItem and the ShadowItem class represent the server-side deco and
drop-shadow, respectively.

At the moment, the SurfaceItem is bound to the scene window, but the long
term plan is to break that connection so we could re-use the SurfaceItem
for things such as software cursors and drag-and-drop additional icons.

One of the responsibilities of the Item is to schedule repaints as needed.
Ideally, there shouldn't be any addRepaint() calls in the core code. The
Item class schedules repaints on geometry updates. In the future, it also
has to request an update if its opacity or visibility changes.
2021-03-31 13:56:55 +00:00

151 lines
4.6 KiB
C++

/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "surfaceitem_wayland.h"
#include <KWaylandServer/subcompositor_interface.h>
#include <KWaylandServer/surface_interface.h>
namespace KWin
{
SurfaceItemWayland::SurfaceItemWayland(KWaylandServer::SurfaceInterface *surface,
Scene::Window *window, Item *parent)
: SurfaceItem(window, parent)
, m_surface(surface)
{
connect(surface, &KWaylandServer::SurfaceInterface::surfaceToBufferMatrixChanged,
this, &SurfaceItemWayland::discardQuads);
connect(surface, &KWaylandServer::SurfaceInterface::surfaceToBufferMatrixChanged,
this, &SurfaceItemWayland::discardPixmap);
connect(surface, &KWaylandServer::SurfaceInterface::sizeChanged,
this, &SurfaceItemWayland::handleSurfaceSizeChanged);
connect(surface, &KWaylandServer::SurfaceInterface::bufferSizeChanged,
this, &SurfaceItemWayland::discardPixmap);
connect(surface, &KWaylandServer::SurfaceInterface::childSubSurfacesChanged,
this, &SurfaceItemWayland::handleChildSubSurfacesChanged);
connect(surface, &KWaylandServer::SurfaceInterface::committed,
this, &SurfaceItemWayland::handleSurfaceCommitted);
connect(surface, &KWaylandServer::SurfaceInterface::damaged,
this, &SurfaceItemWayland::addDamage);
connect(surface, &KWaylandServer::SurfaceInterface::childSubSurfaceAdded,
this, &SurfaceItemWayland::handleChildSubSurfaceAdded);
connect(surface, &KWaylandServer::SurfaceInterface::childSubSurfaceRemoved,
this, &SurfaceItemWayland::handleChildSubSurfaceRemoved);
KWaylandServer::SubSurfaceInterface *subsurface = surface->subSurface();
if (subsurface) {
connect(subsurface, &KWaylandServer::SubSurfaceInterface::positionChanged,
this, &SurfaceItemWayland::handleSubSurfacePositionChanged);
setPosition(subsurface->position());
}
const QList<KWaylandServer::SubSurfaceInterface *> children = surface->childSubSurfaces();
for (KWaylandServer::SubSurfaceInterface *subsurface : children) {
handleChildSubSurfaceAdded(subsurface);
}
setSize(surface->size());
}
QPointF SurfaceItemWayland::mapToBuffer(const QPointF &point) const
{
if (m_surface) {
return m_surface->mapToBuffer(point);
}
return point;
}
QRegion SurfaceItemWayland::shape() const
{
return QRegion(0, 0, width(), height());
}
QRegion SurfaceItemWayland::opaque() const
{
if (m_surface) {
return m_surface->opaque();
}
return QRegion();
}
KWaylandServer::SurfaceInterface *SurfaceItemWayland::surface() const
{
return m_surface;
}
void SurfaceItemWayland::handleSurfaceSizeChanged()
{
setSize(m_surface->size());
}
void SurfaceItemWayland::handleSurfaceCommitted()
{
if (m_surface->hasFrameCallbacks()) {
scheduleRepaint();
}
}
void SurfaceItemWayland::handleChildSubSurfaceAdded(KWaylandServer::SubSurfaceInterface *child)
{
SurfaceItemWayland *subsurfaceItem = new SurfaceItemWayland(child->surface(), window());
subsurfaceItem->setParent(this);
subsurfaceItem->setParentItem(this);
m_subsurfaces.insert(child, subsurfaceItem);
}
void SurfaceItemWayland::handleChildSubSurfaceRemoved(KWaylandServer::SubSurfaceInterface *child)
{
delete m_subsurfaces.take(child);
}
void SurfaceItemWayland::handleChildSubSurfacesChanged()
{
const QList<KWaylandServer::SubSurfaceInterface *> stackingOrder = m_surface->childSubSurfaces();
QList<Item *> items;
items.reserve(stackingOrder.count());
for (KWaylandServer::SubSurfaceInterface *subsurface : stackingOrder) {
items.append(m_subsurfaces[subsurface]);
}
stackChildren(items);
}
void SurfaceItemWayland::handleSubSurfacePositionChanged()
{
setPosition(m_surface->subSurface()->position());
}
WindowPixmap *SurfaceItemWayland::createPixmap()
{
WindowPixmap *pixmap = window()->createWindowPixmap();
pixmap->setSurface(m_surface);
return pixmap;
}
SurfaceItemXwayland::SurfaceItemXwayland(Scene::Window *window, Item *parent)
: SurfaceItemWayland(window->window()->surface(), window, parent)
{
}
QRegion SurfaceItemXwayland::shape() const
{
const Toplevel *toplevel = window()->window();
if (window()->isShaded()) {
return QRegion();
}
const QRect clipRect = toplevel->clientGeometry().translated(-toplevel->bufferGeometry().topLeft());
const QRegion shape = toplevel->shapeRegion();
return shape & clipRect;
}
} // namespace KWin