diff --git a/src/item.cpp b/src/item.cpp index eb7b59883d..ec0ad630d2 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -39,6 +39,23 @@ Item::~Item() } } +int Item::z() const +{ + return m_z; +} + +void Item::setZ(int z) +{ + if (m_z == z) { + return; + } + m_z = z; + if (m_parentItem) { + m_parentItem->markSortedChildItemsDirty(); + } + scheduleRepaint(boundingRect()); +} + Item *Item::parentItem() const { return m_parentItem; @@ -64,6 +81,8 @@ void Item::addChild(Item *item) Q_ASSERT(!m_childItems.contains(item)); m_childItems.append(item); + markSortedChildItemsDirty(); + updateBoundingRect(); scheduleRepaint(item->boundingRect().translated(item->position())); } @@ -74,6 +93,7 @@ void Item::removeChild(Item *item) scheduleRepaint(item->boundingRect().translated(item->position())); m_childItems.removeOne(item); + markSortedChildItemsDirty(); updateBoundingRect(); } @@ -191,6 +211,7 @@ void Item::stackBefore(Item *sibling) } m_parentItem->m_childItems.move(selfIndex, selfIndex > siblingIndex ? siblingIndex : siblingIndex - 1); + markSortedChildItemsDirty(); scheduleRepaint(boundingRect()); sibling->scheduleRepaint(sibling->boundingRect()); @@ -218,6 +239,7 @@ void Item::stackAfter(Item *sibling) } m_parentItem->m_childItems.move(selfIndex, selfIndex > siblingIndex ? siblingIndex + 1 : siblingIndex); + markSortedChildItemsDirty(); scheduleRepaint(boundingRect()); sibling->scheduleRepaint(sibling->boundingRect()); @@ -237,6 +259,8 @@ void Item::stackChildren(const QList &children) #endif m_childItems = children; + discardQuads(); + markSortedChildItemsDirty(); } void Item::scheduleRepaint(const QRegion ®ion) @@ -369,4 +393,24 @@ void Item::updateEffectiveVisibility() } } +static bool compareZ(const Item *a, const Item *b) +{ + return a->z() < b->z(); +} + +QList Item::sortedChildItems() const +{ + if (!m_sortedChildItems.has_value()) { + QList items = m_childItems; + std::stable_sort(items.begin(), items.end(), compareZ); + m_sortedChildItems = items; + } + return m_sortedChildItems.value(); +} + +void Item::markSortedChildItemsDirty() +{ + m_sortedChildItems.reset(); +} + } // namespace KWin diff --git a/src/item.h b/src/item.h index 1c7908553a..e066f40836 100644 --- a/src/item.h +++ b/src/item.h @@ -30,6 +30,9 @@ public: QSize size() const; void setSize(const QSize &size); + int z() const; + void setZ(int z); + /** * Returns the enclosing rectangle of the item. The rect equals QRect(0, 0, width(), height()). */ @@ -46,6 +49,7 @@ public: Item *parentItem() const; void setParentItem(Item *parent); QList childItems() const; + QList sortedChildItems() const; Scene::Window *window() const; QPoint rootPosition() const; @@ -112,6 +116,7 @@ private: void updateBoundingRect(); void scheduleRepaintInternal(const QRegion ®ion); void reallocRepaints(); + void markSortedChildItemsDirty(); bool computeEffectiveVisibility() const; void updateEffectiveVisibility(); @@ -122,10 +127,12 @@ private: QRect m_boundingRect; QPoint m_position; QSize m_size = QSize(0, 0); + int m_z = 0; bool m_visible = true; bool m_effectiveVisible = true; QVector m_repaints; mutable std::optional m_quads; + mutable std::optional> m_sortedChildItems; }; } // namespace KWin diff --git a/src/plugins/scenes/opengl/scene_opengl.cpp b/src/plugins/scenes/opengl/scene_opengl.cpp index 88e3b80b2d..f6208d1ae4 100644 --- a/src/plugins/scenes/opengl/scene_opengl.cpp +++ b/src/plugins/scenes/opengl/scene_opengl.cpp @@ -940,8 +940,18 @@ static WindowQuadList clipQuads(const Item *item, const OpenGLWindow::RenderCont void OpenGLWindow::createRenderNode(Item *item, RenderContext *context) { - item->preprocess(); + const QList sortedChildItems = item->sortedChildItems(); + for (Item *childItem : sortedChildItems) { + if (childItem->z() >= 0) { + break; + } + if (childItem->isVisible()) { + createRenderNode(childItem, context); + } + } + + item->preprocess(); if (auto shadowItem = qobject_cast(item)) { WindowQuadList quads = clipQuads(item, context); if (!quads.isEmpty()) { @@ -985,8 +995,10 @@ void OpenGLWindow::createRenderNode(Item *item, RenderContext *context) } } - const QList childItems = item->childItems(); - for (Item *childItem : childItems) { + for (Item *childItem : sortedChildItems) { + if (childItem->z() < 0) { + continue; + } if (childItem->isVisible()) { createRenderNode(childItem, context); } diff --git a/src/plugins/scenes/qpainter/scene_qpainter.cpp b/src/plugins/scenes/qpainter/scene_qpainter.cpp index 0a7204f5c2..2daa2c5593 100644 --- a/src/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/src/plugins/scenes/qpainter/scene_qpainter.cpp @@ -245,18 +245,31 @@ void SceneQPainter::Window::performPaint(int mask, const QRegion &_region, const void SceneQPainter::Window::renderItem(QPainter *painter, Item *item) const { - item->preprocess(); + const QList sortedChildItems = item->sortedChildItems(); + painter->save(); painter->translate(item->position()); + for (Item *childItem : sortedChildItems) { + if (childItem->z() >= 0) { + break; + } + if (childItem->isVisible()) { + renderItem(painter, childItem); + } + } + + item->preprocess(); if (auto surfaceItem = qobject_cast(item)) { renderSurfaceItem(painter, surfaceItem); } else if (auto decorationItem = qobject_cast(item)) { renderDecorationItem(painter, decorationItem); } - const QList childItems = item->childItems(); - for (Item *childItem : childItems) { + for (Item *childItem : sortedChildItems) { + if (childItem->z() < 0) { + continue; + } if (childItem->isVisible()) { renderItem(painter, childItem); }