diff --git a/src/decorationitem.cpp b/src/decorationitem.cpp index e38919eb20..473a32322b 100644 --- a/src/decorationitem.cpp +++ b/src/decorationitem.cpp @@ -148,16 +148,21 @@ DecorationItem::DecorationItem(KDecoration2::Decoration *decoration, Window *win handleOutputChanged(); } -QRegion DecorationItem::shape() const +QVector DecorationItem::shape() const { QRectF left, top, right, bottom; m_window->layoutDecorationRects(left, top, right, bottom); - return QRegion(left.toRect()).united(top.toRect()).united(right.toRect()).united(bottom.toRect()); + return {left, top, right, bottom}; } QRegion DecorationItem::opaque() const { - return m_window->decorationHasAlpha() ? QRegion() : shape(); + if (m_window->decorationHasAlpha()) { + return QRegion(); + } + QRectF left, top, right, bottom; + m_window->layoutDecorationRects(left, top, right, bottom); + return QRegion(left.toRect()).united(top.toRect()).united(right.toRect()).united(bottom.toRect()); } void DecorationItem::preprocess() diff --git a/src/decorationitem.h b/src/decorationitem.h index 4e3f380202..86a42969fd 100644 --- a/src/decorationitem.h +++ b/src/decorationitem.h @@ -83,7 +83,7 @@ public: DecorationRenderer *renderer() const; Window *window() const; - QRegion shape() const override final; + QVector shape() const override final; QRegion opaque() const override final; private Q_SLOTS: diff --git a/src/item.cpp b/src/item.cpp index fc11a7da2e..1254f2e4aa 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -169,9 +169,9 @@ void Item::updateBoundingRect() } } -QRegion Item::shape() const +QVector Item::shape() const { - return rect().toAlignedRect(); + return QVector(); } QRegion Item::opaque() const diff --git a/src/item.h b/src/item.h index 80393b57ee..b3db8c9319 100644 --- a/src/item.h +++ b/src/item.h @@ -11,6 +11,7 @@ #include #include +#include #include @@ -51,7 +52,7 @@ public: */ QRectF boundingRect() const; - virtual QRegion shape() const; + virtual QVector shape() const; virtual QRegion opaque() const; /** diff --git a/src/scenes/opengl/scene_opengl.cpp b/src/scenes/opengl/scene_opengl.cpp index 4883471b05..8141c8e2b4 100644 --- a/src/scenes/opengl/scene_opengl.cpp +++ b/src/scenes/opengl/scene_opengl.cpp @@ -386,8 +386,18 @@ void SceneOpenGL::createRenderNode(Item *item, RenderContext *context) SurfacePixmap *pixmap = surfaceItem->pixmap(); if (pixmap) { if (!geometry.isEmpty()) { + bool hasAlpha = pixmap->hasAlphaChannel(); + bool isCompletelyOpaque = true; // Don't bother with blending if the entire surface is opaque - bool hasAlpha = pixmap->hasAlphaChannel() && !surfaceItem->shape().subtracted(surfaceItem->opaque()).isEmpty(); + const QVector shape = surfaceItem->shape(); + for (const QRectF &shapePart : shape) { + if (!item->opaque().contains(shapePart.toRect())) { + isCompletelyOpaque = false; + break; + } + } + hasAlpha &= !isCompletelyOpaque; + context->renderNodes.append(RenderNode{ .texture = bindSurfaceTexture(surfaceItem), .geometry = geometry, diff --git a/src/scenes/qpainter/scene_qpainter.cpp b/src/scenes/qpainter/scene_qpainter.cpp index 282ab880d8..76e31eb9e8 100644 --- a/src/scenes/qpainter/scene_qpainter.cpp +++ b/src/scenes/qpainter/scene_qpainter.cpp @@ -167,7 +167,7 @@ void SceneQPainter::renderSurfaceItem(QPainter *painter, SurfaceItem *surfaceIte } surfaceItem->resetDamage(); - const QRegion shape = surfaceItem->shape(); + const QVector shape = surfaceItem->shape(); for (const QRectF rect : shape) { const QMatrix4x4 matrix = surfaceItem->surfaceToBufferMatrix(); const QPointF bufferTopLeft = matrix.map(rect.topLeft()); diff --git a/src/surfaceitem.cpp b/src/surfaceitem.cpp index fa6eaaecc8..43c4ad349f 100644 --- a/src/surfaceitem.cpp +++ b/src/surfaceitem.cpp @@ -130,11 +130,11 @@ WindowQuadList SurfaceItem::buildQuads() const return {}; } - const QRegion region = shape(); + const QVector region = shape(); const auto size = pixmap()->size(); WindowQuadList quads; - quads.reserve(region.rectCount()); + quads.reserve(region.count()); for (const QRectF rect : region) { WindowQuad quad; diff --git a/src/surfaceitem_internal.cpp b/src/surfaceitem_internal.cpp index 29bb9a7a70..16141ea8d7 100644 --- a/src/surfaceitem_internal.cpp +++ b/src/surfaceitem_internal.cpp @@ -28,9 +28,9 @@ SurfaceItemInternal::SurfaceItemInternal(InternalWindow *window, Item *parent) setSurfaceToBufferMatrix(surfaceToBufferMatrix); } -QRegion SurfaceItemInternal::shape() const +QVector SurfaceItemInternal::shape() const { - return QRegion(rect().toAlignedRect()); + return {rect()}; } std::unique_ptr SurfaceItemInternal::createPixmap() diff --git a/src/surfaceitem_internal.h b/src/surfaceitem_internal.h index 58349338a5..9a49fb35e6 100644 --- a/src/surfaceitem_internal.h +++ b/src/surfaceitem_internal.h @@ -25,7 +25,7 @@ class KWIN_EXPORT SurfaceItemInternal : public SurfaceItem public: explicit SurfaceItemInternal(InternalWindow *window, Item *parent = nullptr); - QRegion shape() const override; + QVector shape() const override; private Q_SLOTS: void handleBufferGeometryChanged(Window *window, const QRectF &old); diff --git a/src/surfaceitem_wayland.cpp b/src/surfaceitem_wayland.cpp index e8853953cd..b2375de6a2 100644 --- a/src/surfaceitem_wayland.cpp +++ b/src/surfaceitem_wayland.cpp @@ -53,9 +53,9 @@ SurfaceItemWayland::SurfaceItemWayland(KWaylandServer::SurfaceInterface *surface setSurfaceToBufferMatrix(surface->surfaceToBufferMatrix()); } -QRegion SurfaceItemWayland::shape() const +QVector SurfaceItemWayland::shape() const { - return QRegion(rect().toAlignedRect()); + return {rect()}; } QRegion SurfaceItemWayland::opaque() const @@ -208,12 +208,16 @@ SurfaceItemXwayland::SurfaceItemXwayland(Window *window, Item *parent) connect(window, &Window::geometryShapeChanged, this, &SurfaceItemXwayland::discardQuads); } -QRegion SurfaceItemXwayland::shape() const +QVector SurfaceItemXwayland::shape() const { const QRectF clipRect = rect() & window()->clientGeometry().translated(-window()->bufferGeometry().topLeft()); - const QRegion shape = window()->shapeRegion(); + QVector shape = window()->shapeRegion(); - return shape & clipRect.toRect(); + // bounded to clipRect + for (QRectF &shapePart : shape) { + shapePart = shapePart.intersected(clipRect); + } + return shape; } } // namespace KWin diff --git a/src/surfaceitem_wayland.h b/src/surfaceitem_wayland.h index 53e5da76e3..4483fdee55 100644 --- a/src/surfaceitem_wayland.h +++ b/src/surfaceitem_wayland.h @@ -29,7 +29,7 @@ public: explicit SurfaceItemWayland(KWaylandServer::SurfaceInterface *surface, Window *window, Item *parent = nullptr); - QRegion shape() const override; + QVector shape() const override; QRegion opaque() const override; ContentType contentType() const override; @@ -88,7 +88,7 @@ class KWIN_EXPORT SurfaceItemXwayland : public SurfaceItemWayland public: explicit SurfaceItemXwayland(Window *window, Item *parent = nullptr); - QRegion shape() const override; + QVector shape() const override; }; } // namespace KWin diff --git a/src/surfaceitem_x11.cpp b/src/surfaceitem_x11.cpp index f68f9b0765..ddd12282ab 100644 --- a/src/surfaceitem_x11.cpp +++ b/src/surfaceitem_x11.cpp @@ -138,21 +138,29 @@ void SurfaceItemX11::handleGeometryShapeChanged() discardQuads(); } -QRegion SurfaceItemX11::shape() const +QVector SurfaceItemX11::shape() const { const QRectF clipRect = window()->clientGeometry().translated(-window()->bufferGeometry().topLeft()); - const QRegion shape = window()->shapeRegion(); - - return shape & clipRect.toAlignedRect(); + QVector shape = window()->shapeRegion(); + // bounded to clipRect + for (QRectF &shapePart : shape) { + shapePart = shapePart.intersected(clipRect); + } + return shape; } QRegion SurfaceItemX11::opaque() const { - if (!window()->hasAlpha()) { - return shape(); - } else { - return window()->opaqueRegion() & shape(); + QRegion shapeRegion; + for (const QRectF &shapePart : shape()) { + shapeRegion |= shapePart.toRect(); } + if (!window()->hasAlpha()) { + return shapeRegion; + } else { + return window()->opaqueRegion() & shapeRegion; + } + return QRegion(); } std::unique_ptr SurfaceItemX11::createPixmap() diff --git a/src/surfaceitem_x11.h b/src/surfaceitem_x11.h index 343c82dbbb..71e04d0aca 100644 --- a/src/surfaceitem_x11.h +++ b/src/surfaceitem_x11.h @@ -32,7 +32,7 @@ public: void waitForDamage(); void destroyDamage(); - QRegion shape() const override; + QVector shape() const override; QRegion opaque() const override; private Q_SLOTS: diff --git a/src/window.cpp b/src/window.cpp index 692f80b3b1..981b08b2a5 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -483,13 +483,12 @@ void Window::getWmOpaqueRegion() const auto rects = info->opaqueRegion(); QRegion new_opaque_region; for (const auto &r : rects) { - new_opaque_region += Xcb::fromXNative(QRect(r.pos.x, r.pos.y, r.size.width, r.size.height)).toAlignedRect(); + new_opaque_region |= Xcb::fromXNative(QRect(r.pos.x, r.pos.y, r.size.width, r.size.height)).toRect(); } - opaque_region = new_opaque_region; } -QRegion Window::shapeRegion() const +QVector Window::shapeRegion() const { if (m_shapeRegionIsValid) { return m_shapeRegion; @@ -501,19 +500,21 @@ QRegion Window::shapeRegion() const auto cookie = xcb_shape_get_rectangles_unchecked(kwinApp()->x11Connection(), frameId(), XCB_SHAPE_SK_BOUNDING); UniqueCPtr reply(xcb_shape_get_rectangles_reply(kwinApp()->x11Connection(), cookie, nullptr)); if (reply) { - m_shapeRegion = QRegion(); + m_shapeRegion.clear(); const xcb_rectangle_t *rects = xcb_shape_get_rectangles_rectangles(reply.get()); const int rectCount = xcb_shape_get_rectangles_rectangles_length(reply.get()); for (int i = 0; i < rectCount; ++i) { - m_shapeRegion += Xcb::fromXNative(QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height)).toAlignedRect(); + QRectF region = Xcb::fromXNative(QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height)).toAlignedRect(); + // make sure the shape is sane (X is async, maybe even XShape is broken) + region = region.intersected(QRectF(QPointF(0, 0), bufferGeometry.size())); + + m_shapeRegion += region; } - // make sure the shape is sane (X is async, maybe even XShape is broken) - m_shapeRegion &= QRegion(0, 0, bufferGeometry.width(), bufferGeometry.height()); } else { - m_shapeRegion = QRegion(); + m_shapeRegion.clear(); } } else { - m_shapeRegion = QRegion(0, 0, bufferGeometry.width(), bufferGeometry.height()); + m_shapeRegion = {QRectF(0, 0, bufferGeometry.width(), bufferGeometry.height())}; } m_shapeRegionIsValid = true; @@ -523,7 +524,7 @@ QRegion Window::shapeRegion() const void Window::discardShapeRegion() { m_shapeRegionIsValid = false; - m_shapeRegion = QRegion(); + m_shapeRegion.clear(); } bool Window::isClient() const diff --git a/src/window.h b/src/window.h index fcda80c00b..1e05572f5e 100644 --- a/src/window.h +++ b/src/window.h @@ -773,7 +773,7 @@ public: * @see hasAlpha */ const QRegion &opaqueRegion() const; - QRegion shapeRegion() const; + QVector shapeRegion() const; bool skipsCloseAnimation() const; void setSkipCloseAnimation(bool set); @@ -1925,7 +1925,7 @@ private: ClientMachine *m_clientMachine; xcb_window_t m_wmClientLeader; QRegion opaque_region; - mutable QRegion m_shapeRegion; + mutable QVector m_shapeRegion; mutable bool m_shapeRegionIsValid = false; bool m_skipCloseAnimation; quint32 m_pendingSurfaceId = 0;