Try to invalidate quad cache when shadow is changed

Summary:
213239a0ea tried to address the case when
a wayland client gets shadow after it was mapped, but because of poor
testing from my side, another bug was introduced. If a decoration tooltip
or the user actions popup is shown, then in some cases it can be blank.

Usually, SurfaceInterface::shadowChanged proceeds SurfaceInterface::sizeChanged,
so when the shadow is installed, window quads cache is rebuilt. But
because shell client already knows the geometry of the internal client,
goemetryShapeChanged is not emitted, thus the cache is not updated.

It would be better just to invalidate the cache when the shadow is
installed, uninstalled, or updated. This reduces the number of
unnecessary invocations of Scene::Window::buildQuads and also moves
handling of the window quads cache away from the Shadow class.

BUG: 399490
FIXED-IN: 5.15.0

Test Plan: Decoration tooltips are no longer blank.

Reviewers: #kwin, davidedmundson

Reviewed By: #kwin, davidedmundson

Subscribers: davidedmundson, graesslin, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D17215
This commit is contained in:
Vlad Zagorodniy 2018-11-27 15:25:22 +02:00
parent 6f982e88a0
commit 90a26e2e8d
4 changed files with 34 additions and 19 deletions

View file

@ -405,6 +405,11 @@ void Scene::windowAdded(Toplevel *c)
c->effectWindow()->setSceneWindow(w);
c->getShadow();
w->updateShadow(c->shadow());
connect(c, &Toplevel::shadowChanged, this,
[w] {
w->invalidateQuadsCache();
}
);
}
void Scene::windowClosed(Toplevel *c, Deleted *deleted)
@ -732,7 +737,7 @@ void Scene::Window::discardShape()
// it is created on-demand and cached, simply
// reset the flag
shape_valid = false;
cached_quad_list.reset();
invalidateQuadsCache();
}
// Find out the shape of the window using the XShape extension
@ -936,6 +941,11 @@ WindowQuadList Scene::Window::makeDecorationQuads(const QRect *rects, const QReg
return list;
}
void Scene::Window::invalidateQuadsCache()
{
cached_quad_list.reset();
}
WindowQuadList Scene::Window::makeQuads(WindowQuadType type, const QRegion& reg, const QPoint &textureOffset, qreal scale) const
{
WindowQuadList ret;

View file

@ -336,6 +336,7 @@ public:
Shadow* shadow();
void referencePreviousPixmap();
void unreferencePreviousPixmap();
void invalidateQuadsCache();
protected:
WindowQuadList makeQuads(WindowQuadType type, const QRegion& reg, const QPoint &textureOffset = QPoint(0, 0), qreal textureScale = 1.0) const;
WindowQuadList makeDecorationQuads(const QRect *rects, const QRegion &region, qreal textureScale = 1.0) const;

View file

@ -65,9 +65,7 @@ Shadow *Shadow::createShadow(Toplevel *toplevel)
}
if (toplevel->effectWindow() && toplevel->effectWindow()->sceneWindow()) {
toplevel->effectWindow()->sceneWindow()->updateShadow(shadow);
}
if (toplevel->effectWindow()) {
toplevel->effectWindow()->buildQuads(true);
emit toplevel->shadowChanged();
}
return shadow;
}
@ -333,21 +331,24 @@ void Shadow::buildQuads()
bool Shadow::updateShadow()
{
auto clear = [this]() {
if (m_topLevel && m_topLevel->effectWindow() && m_topLevel->effectWindow()->sceneWindow() &&
m_topLevel->effectWindow()->sceneWindow()->shadow()) {
auto clear = [this] {
if (m_topLevel && m_topLevel->shadow()) {
auto w = m_topLevel->effectWindow();
// this also deletes the shadow
w->sceneWindow()->updateShadow(nullptr);
w->buildQuads(true);
emit m_topLevel->shadowChanged();
}
};
if (!m_topLevel) {
return false;
}
if (m_decorationShadow) {
if (AbstractClient *c = qobject_cast<AbstractClient*>(m_topLevel)) {
if (c->decoration()) {
if (init(c->decoration())) {
if (m_topLevel && m_topLevel->effectWindow())
m_topLevel->effectWindow()->buildQuads(true);
emit m_topLevel->shadowChanged();
return true;
}
}
@ -355,30 +356,27 @@ bool Shadow::updateShadow()
clear();
return false;
}
if (waylandServer()) {
if (m_topLevel && m_topLevel->surface()) {
if (const auto &s = m_topLevel->surface()->shadow()) {
if (init(s)) {
if (m_topLevel->effectWindow()) {
m_topLevel->effectWindow()->buildQuads(true);
}
emit m_topLevel->shadowChanged();
return true;
}
}
}
}
if (!m_topLevel) {
clear();
return false;
}
auto data = Shadow::readX11ShadowProperty(m_topLevel->window());
if (data.isEmpty()) {
clear();
return false;
}
init(data);
if (m_topLevel && m_topLevel->effectWindow())
m_topLevel->effectWindow()->buildQuads(true);
emit m_topLevel->shadowChanged();
return true;
}

View file

@ -527,6 +527,12 @@ Q_SIGNALS:
*/
void screenScaleChanged();
/**
* Emitted whenever the client's shadow changes.
* @since 5.15
**/
void shadowChanged();
protected Q_SLOTS:
/**
* Checks whether the screen number for this Toplevel changed and updates if needed.