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.
This commit is contained in:
Vlad Zahorodnii 2021-09-03 13:24:17 +03:00
parent b40fb76c71
commit 935fa6a9e1
11 changed files with 47 additions and 17 deletions

View file

@ -48,6 +48,7 @@ Deleted::~Deleted()
workspace()->removeDeleted(this);
}
deleteEffectWindow();
deleteShadow();
}
Deleted* Deleted::create(Toplevel* c)

View file

@ -466,7 +466,6 @@ void Scene::addToplevel(Toplevel *c)
connect(c, &Toplevel::windowClosed, this, &Scene::windowClosed);
c->effectWindow()->setSceneWindow(w);
c->updateShadow();
}
void Scene::removeToplevel(Toplevel *toplevel)
@ -486,9 +485,6 @@ void Scene::windowClosed(Toplevel *toplevel, Deleted *deleted)
Q_ASSERT(m_windows.contains(toplevel));
Window *window = m_windows.take(toplevel);
window->updateToplevel(deleted);
if (window->shadowItem()) {
window->shadowItem()->shadow()->setToplevel(deleted);
}
m_windows[deleted] = window;
}

View file

@ -325,6 +325,11 @@ bool Shadow::updateShadow()
return true;
}
Toplevel *Shadow::toplevel() const
{
return m_topLevel;
}
void Shadow::setToplevel(Toplevel *topLevel)
{
m_topLevel = topLevel;

View file

@ -73,6 +73,7 @@ public:
*/
static Shadow *createShadow(Toplevel *toplevel);
Toplevel *toplevel() const;
/**
* Reparents the shadow to @p toplevel.
* Used when a window is deleted.

View file

@ -32,7 +32,7 @@ ShadowItem::~ShadowItem()
Shadow *ShadowItem::shadow() const
{
return m_shadow.data();
return m_shadow;
}
void ShadowItem::updateGeometry()

View file

@ -38,7 +38,7 @@ private Q_SLOTS:
private:
Toplevel *m_window;
QScopedPointer<Shadow> m_shadow;
Shadow *m_shadow = nullptr;
};
} // namespace KWin

View file

@ -118,6 +118,10 @@ void Toplevel::copyToDeleted(Toplevel* c)
effect_window = c->effect_window;
if (effect_window != nullptr)
effect_window->setWindow(this);
m_shadow = c->m_shadow;
if (m_shadow) {
m_shadow->setToplevel(this);
}
resource_name = c->resourceName();
resource_class = c->resourceClass();
m_clientMachine = c->m_clientMachine;
@ -271,6 +275,7 @@ bool Toplevel::setupCompositing()
return false;
effect_window = new EffectWindowImpl(this);
updateShadow();
Compositor::self()->scene()->addToplevel(this);
connect(windowItem(), &WindowItem::positionChanged, this, &Toplevel::visibleGeometryChanged);
@ -287,6 +292,9 @@ void Toplevel::finishCompositing(ReleaseReason releaseReason)
item->destroyDamage();
}
}
if (m_shadow && m_shadow->toplevel() == this) { // otherwise it's already passed to Deleted, don't free data
deleteShadow();
}
if (effect_window && effect_window->window() == this) { // otherwise it's already passed to Deleted, don't free data
deleteEffectWindow();
}
@ -359,6 +367,12 @@ void Toplevel::setReadyForPainting()
}
}
void Toplevel::deleteShadow()
{
delete m_shadow;
m_shadow = nullptr;
}
void Toplevel::deleteEffectWindow()
{
delete effect_window;
@ -425,21 +439,24 @@ bool Toplevel::isOnOutput(AbstractOutput *output) const
return output->geometry().intersects(frameGeometry());
}
Shadow *Toplevel::shadow() const
{
return m_shadow;
}
void Toplevel::updateShadow()
{
WindowItem *windowItem = this->windowItem();
if (!windowItem) {
if (!Compositor::compositing()) {
return;
}
if (auto shadowItem = windowItem->shadowItem()) {
if (!shadowItem->shadow()->updateShadow()) {
windowItem->setShadow(nullptr);
if (m_shadow) {
if (!m_shadow->updateShadow()) {
deleteShadow();
}
Q_EMIT shadowChanged();
} else {
Shadow *shadow = Shadow::createShadow(this);
if (shadow) {
windowItem->setShadow(shadow);
m_shadow = Shadow::createShadow(this);
if (m_shadow) {
Q_EMIT shadowChanged();
}
}

View file

@ -466,6 +466,10 @@ public:
*/
void elevate(bool elevate);
/**
* Returns the Shadow associated with this Toplevel or @c null if it has no shadow.
*/
Shadow *shadow() const;
/**
* Updates the Shadow associated with this Toplevel from X11 Property.
* Call this method when the Property changes or Compositing is started.
@ -692,6 +696,7 @@ protected:
void getSkipCloseAnimation();
void copyToDeleted(Toplevel* c);
void disownDataPassedToDeleted();
void deleteShadow();
void deleteEffectWindow();
void setDepth(int depth);
QRect m_frameGeometry;
@ -713,6 +718,7 @@ private:
Xcb::Window m_client;
bool is_shape;
EffectWindowImpl* effect_window;
Shadow *m_shadow = nullptr;
QByteArray resource_name;
QByteArray resource_class;
ClientMachine *m_clientMachine;

View file

@ -25,6 +25,9 @@ WindowItem::WindowItem(Toplevel *window, Item *parent)
connect(client, &AbstractClient::decorationChanged, this, &WindowItem::updateDecorationItem);
updateDecorationItem();
}
connect(window, &Toplevel::shadowChanged, this, &WindowItem::updateShadowItem);
updateShadowItem();
connect(window, &Toplevel::windowClosed, this, &WindowItem::handleWindowClosed);
}
@ -79,8 +82,9 @@ void WindowItem::updateSurfaceVisibility()
m_surfaceItem->setVisible(!m_window->isShade());
}
void WindowItem::setShadow(Shadow *shadow)
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));

View file

@ -38,8 +38,6 @@ public:
ShadowItem *shadowItem() const;
Toplevel *window() const;
void setShadow(Shadow *shadow);
protected:
explicit WindowItem(Toplevel *window, Item *parent = nullptr);
void updateSurfaceItem(SurfaceItem *surfaceItem);
@ -47,6 +45,7 @@ protected:
private Q_SLOTS:
void handleWindowClosed(Toplevel *original, Deleted *deleted);
void updateDecorationItem();
void updateShadowItem();
void updateSurfacePosition();
void updateSurfaceVisibility();

View file

@ -493,6 +493,7 @@ Workspace::~Workspace()
for (auto it = deleted.begin(); it != deleted.end();) {
Q_EMIT deletedRemoved(*it);
(*it)->finishCompositing();
it = deleted.erase(it);
}