diff --git a/plugins/scenes/opengl/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp --- a/plugins/scenes/opengl/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -2137,16 +2137,18 @@ void SceneOpenGLShadow::buildQuads() { - // prepare window quads - m_shadowQuads.clear(); const QSizeF top(elementSize(ShadowElementTop)); const QSizeF topRight(elementSize(ShadowElementTopRight)); const QSizeF right(elementSize(ShadowElementRight)); const QSizeF bottomRight(elementSize(ShadowElementBottomRight)); const QSizeF bottom(elementSize(ShadowElementBottom)); const QSizeF bottomLeft(elementSize(ShadowElementBottomLeft)); const QSizeF left(elementSize(ShadowElementLeft)); const QSizeF topLeft(elementSize(ShadowElementTopLeft)); + + // TODO: Do we need this? Turning shadows off when a window is too small + // is not the best KWin could do. + // KDecoration or KWin could mask out inner shadow rect. if ((left.width() - leftOffset() > topLevel()->width()) || (right.width() - rightOffset() > topLevel()->width()) || (top.height() - topOffset() > topLevel()->height()) || @@ -2157,95 +2159,176 @@ } const QRectF outerRect(QPointF(-leftOffset(), -topOffset()), - QPointF(topLevel()->width() + rightOffset(), topLevel()->height() + bottomOffset())); + QPointF(topLevel()->width() + rightOffset(), + topLevel()->height() + bottomOffset())); + + const int width = std::max({topLeft.width(), left.width(), bottomLeft.width()}) + + std::max(top.width(), bottom.width()) + + std::max({topRight.width(), right.width(), bottomRight.width()}); + const int height = std::max({topLeft.height(), top.height(), topRight.height()}) + + std::max(left.height(), right.height()) + + std::max({bottomLeft.height(), bottom.height(), bottomRight.height()}); + + QRectF topLeftRect(outerRect.topLeft(), topLeft); + QRectF topRightRect(outerRect.topRight() - QPointF(topRight.width(), 0), topRight); + QRectF bottomRightRect( + outerRect.bottomRight() - QPointF(bottomRight.width(), bottomRight.height()), + bottomRight); + QRectF bottomLeftRect(outerRect.bottomLeft() - QPointF(0, bottomLeft.height()), bottomLeft); + + // Re-distribute the corner tiles so no one of them is overlapping with others. + // By doing this, we assume that shadow's corner tiles are symmetric + // and it is OK to not draw top/right/bottom/left tile between corners. + // For example, let's say top-left and top-right tiles are overlapping. + // In that case, the right side of the top-left tile will be shifted to left, + // the left side of the top-right tile will shifted to right, and the top + // tile won't be rendered. + bool drawTop = true; + if (topLeftRect.right() > topRightRect.left()) { + const float halfOverlap = qAbs(topLeftRect.right() - topRightRect.left()) / 2; + topLeftRect.setRight(topLeftRect.right() - halfOverlap); + topRightRect.setLeft(topRightRect.left() + halfOverlap); + drawTop = false; + } + + bool drawRight = true; + if (topRightRect.bottom() > bottomRightRect.top()) { + const float halfOverlap = qAbs(topRightRect.bottom() - bottomRightRect.top()) / 2; + topRightRect.setBottom(topRightRect.bottom() - halfOverlap); + bottomRightRect.setTop(bottomRightRect.top() + halfOverlap); + drawRight = false; + } + + bool drawBottom = true; + if (bottomLeftRect.right() > bottomRightRect.left()) { + const float halfOverlap = qAbs(bottomLeftRect.right() - bottomRightRect.left()) / 2; + bottomLeftRect.setRight(bottomLeftRect.right() - halfOverlap); + bottomRightRect.setLeft(bottomRightRect.left() + halfOverlap); + drawBottom = false; + } + + bool drawLeft = true; + if (topLeftRect.bottom() > bottomLeftRect.top()) { + const float halfOverlap = qAbs(topLeftRect.bottom() - bottomLeftRect.top()) / 2; + topLeftRect.setBottom(topLeftRect.bottom() - halfOverlap); + bottomLeftRect.setTop(bottomLeftRect.top() + halfOverlap); + drawLeft = false; + } + + qreal tx1 = 0.0, + tx2 = 0.0, + ty1 = 0.0, + ty2 = 0.0; - const int width = std::max({topLeft.width(), left.width(), bottomLeft.width()}) + - std::max(top.width(), bottom.width()) + - std::max({topRight.width(), right.width(), bottomRight.width()}); - const int height = std::max({topLeft.height(), top.height(), topRight.height()}) + - std::max(left.height(), right.height()) + - std::max({bottomLeft.height(), bottom.height(), bottomRight.height()}); - - qreal tx1(0.0), tx2(0.0), ty1(0.0), ty2(0.0); + m_shadowQuads.clear(); - tx2 = topLeft.width()/width; - ty2 = topLeft.height()/height; + tx1 = 0.0; + ty1 = 0.0; + tx2 = topLeftRect.width() / width; + ty2 = topLeftRect.height() / height; WindowQuad topLeftQuad(WindowQuadShadow); - topLeftQuad[ 0 ] = WindowVertex(outerRect.x(), outerRect.y(), tx1, ty1); - topLeftQuad[ 1 ] = WindowVertex(outerRect.x() + topLeft.width(), outerRect.y(), tx2, ty1); - topLeftQuad[ 2 ] = WindowVertex(outerRect.x() + topLeft.width(), outerRect.y() + topLeft.height(), tx2, ty2); - topLeftQuad[ 3 ] = WindowVertex(outerRect.x(), outerRect.y() + topLeft.height(), tx1, ty2); + topLeftQuad[0] = WindowVertex(topLeftRect.left(), topLeftRect.top(), tx1, ty1); + topLeftQuad[1] = WindowVertex(topLeftRect.right(), topLeftRect.top(), tx2, ty1); + topLeftQuad[2] = WindowVertex(topLeftRect.right(), topLeftRect.bottom(), tx2, ty2); + topLeftQuad[3] = WindowVertex(topLeftRect.left(), topLeftRect.bottom(), tx1, ty2); m_shadowQuads.append(topLeftQuad); - tx1 = tx2; - tx2 = (topLeft.width() + top.width())/width; - ty2 = top.height()/height; - WindowQuad topQuad(WindowQuadShadow); - topQuad[ 0 ] = WindowVertex(outerRect.x() + topLeft.width(), outerRect.y(), tx1, ty1); - topQuad[ 1 ] = WindowVertex(outerRect.right() - topRight.width(), outerRect.y(), tx2, ty1); - topQuad[ 2 ] = WindowVertex(outerRect.right() - topRight.width(), outerRect.y() + top.height(),tx2, ty2); - topQuad[ 3 ] = WindowVertex(outerRect.x() + topLeft.width(), outerRect.y() + top.height(), tx1, ty2); - m_shadowQuads.append(topQuad); - - tx1 = tx2; + tx1 = 1.0 - topRightRect.width() / width; + ty1 = 0.0; tx2 = 1.0; - ty2 = topRight.height()/height; + ty2 = topRightRect.height() / height; WindowQuad topRightQuad(WindowQuadShadow); - topRightQuad[ 0 ] = WindowVertex(outerRect.right() - topRight.width(), outerRect.y(), tx1, ty1); - topRightQuad[ 1 ] = WindowVertex(outerRect.right(), outerRect.y(), tx2, ty1); - topRightQuad[ 2 ] = WindowVertex(outerRect.right(), outerRect.y() + topRight.height(), tx2, ty2); - topRightQuad[ 3 ] = WindowVertex(outerRect.right() - topRight.width(), outerRect.y() + topRight.height(), tx1, ty2); + topRightQuad[0] = WindowVertex(topRightRect.left(), topRightRect.top(), tx1, ty1); + topRightQuad[1] = WindowVertex(topRightRect.right(), topRightRect.top(), tx2, ty1); + topRightQuad[2] = WindowVertex(topRightRect.right(), topRightRect.bottom(), tx2, ty2); + topRightQuad[3] = WindowVertex(topRightRect.left(), topRightRect.bottom(), tx1, ty2); m_shadowQuads.append(topRightQuad); - tx1 = (width - right.width())/width; - ty1 = topRight.height()/height; - ty2 = (topRight.height() + right.height())/height; - WindowQuad rightQuad(WindowQuadShadow); - rightQuad[ 0 ] = WindowVertex(outerRect.right() - right.width(), outerRect.y() + topRight.height(), tx1, ty1); - rightQuad[ 1 ] = WindowVertex(outerRect.right(), outerRect.y() + topRight.height(), tx2, ty1); - rightQuad[ 2 ] = WindowVertex(outerRect.right(), outerRect.bottom() - bottomRight.height(), tx2, ty2); - rightQuad[ 3 ] = WindowVertex(outerRect.right() - right.width(), outerRect.bottom() - bottomRight.height(), tx1, ty2); - m_shadowQuads.append(rightQuad); - - tx1 = (width - bottomRight.width())/width; - ty1 = ty2; + tx1 = 1.0 - bottomRightRect.width() / width; + tx2 = 1.0; + ty1 = 1.0 - bottomRightRect.height() / height; ty2 = 1.0; WindowQuad bottomRightQuad(WindowQuadShadow); - bottomRightQuad[ 0 ] = WindowVertex(outerRect.right() - bottomRight.width(), outerRect.bottom() - bottomRight.height(), tx1, ty1); - bottomRightQuad[ 1 ] = WindowVertex(outerRect.right(), outerRect.bottom() - bottomRight.height(), tx2, ty1); - bottomRightQuad[ 2 ] = WindowVertex(outerRect.right(), outerRect.bottom(), tx2, ty2); - bottomRightQuad[ 3 ] = WindowVertex(outerRect.right() - bottomRight.width(), outerRect.bottom(), tx1, ty2); + bottomRightQuad[0] = WindowVertex(bottomRightRect.left(), bottomRightRect.top(), tx1, ty1); + bottomRightQuad[1] = WindowVertex(bottomRightRect.right(), bottomRightRect.top(), tx2, ty1); + bottomRightQuad[2] = WindowVertex(bottomRightRect.right(), bottomRightRect.bottom(), tx2, ty2); + bottomRightQuad[3] = WindowVertex(bottomRightRect.left(), bottomRightRect.bottom(), tx1, ty2); m_shadowQuads.append(bottomRightQuad); - tx2 = tx1; - tx1 = bottomLeft.width()/width; - ty1 = (height - bottom.height())/height; - WindowQuad bottomQuad(WindowQuadShadow); - bottomQuad[ 0 ] = WindowVertex(outerRect.x() + bottomLeft.width(), outerRect.bottom() - bottom.height(), tx1, ty1); - bottomQuad[ 1 ] = WindowVertex(outerRect.right() - bottomRight.width(), outerRect.bottom() - bottom.height(), tx2, ty1); - bottomQuad[ 2 ] = WindowVertex(outerRect.right() - bottomRight.width(), outerRect.bottom(), tx2, ty2); - bottomQuad[ 3 ] = WindowVertex(outerRect.x() + bottomLeft.width(), outerRect.bottom(), tx1, ty2); - m_shadowQuads.append(bottomQuad); - tx1 = 0.0; - tx2 = bottomLeft.width()/width; - ty1 = (height - bottomLeft.height())/height; + tx2 = bottomLeftRect.width() / width; + ty1 = 1.0 - bottomLeftRect.height() / height; + ty2 = 1.0; WindowQuad bottomLeftQuad(WindowQuadShadow); - bottomLeftQuad[ 0 ] = WindowVertex(outerRect.x(), outerRect.bottom() - bottomLeft.height(), tx1, ty1); - bottomLeftQuad[ 1 ] = WindowVertex(outerRect.x() + bottomLeft.width(), outerRect.bottom() - bottomLeft.height(), tx2, ty1); - bottomLeftQuad[ 2 ] = WindowVertex(outerRect.x() + bottomLeft.width(), outerRect.bottom(), tx2, ty2); - bottomLeftQuad[ 3 ] = WindowVertex(outerRect.x(), outerRect.bottom(), tx1, ty2); + bottomLeftQuad[0] = WindowVertex(bottomLeftRect.left(), bottomLeftRect.top(), tx1, ty1); + bottomLeftQuad[1] = WindowVertex(bottomLeftRect.right(), bottomLeftRect.top(), tx2, ty1); + bottomLeftQuad[2] = WindowVertex(bottomLeftRect.right(), bottomLeftRect.bottom(), tx2, ty2); + bottomLeftQuad[3] = WindowVertex(bottomLeftRect.left(), bottomLeftRect.bottom(), tx1, ty2); m_shadowQuads.append(bottomLeftQuad); - tx2 = left.width()/width; - ty2 = ty1; - ty1 = topLeft.height()/height; - WindowQuad leftQuad(WindowQuadShadow); - leftQuad[ 0 ] = WindowVertex(outerRect.x(), outerRect.y() + topLeft.height(), tx1, ty1); - leftQuad[ 1 ] = WindowVertex(outerRect.x() + left.width(), outerRect.y() + topLeft.height(), tx2, ty1); - leftQuad[ 2 ] = WindowVertex(outerRect.x() + left.width(), outerRect.bottom() - bottomLeft.height(), tx2, ty2); - leftQuad[ 3 ] = WindowVertex(outerRect.x(), outerRect.bottom() - bottomLeft.height(), tx1, ty2); - m_shadowQuads.append(leftQuad); + if (drawTop) { + QRectF topRect( + topLeftRect.topRight(), + topRightRect.topLeft() + QPointF(0, top.height())); + tx1 = topLeft.width() / width; + ty1 = 0.0; + tx2 = 1.0 - topRight.width() / width; + ty2 = top.height() / height; + WindowQuad topQuad(WindowQuadShadow); + topQuad[0] = WindowVertex(topRect.left(), topRect.top(), tx1, ty1); + topQuad[1] = WindowVertex(topRect.right(), topRect.top(), tx2, ty1); + topQuad[2] = WindowVertex(topRect.right(), topRect.bottom(), tx2, ty2); + topQuad[3] = WindowVertex(topRect.left(), topRect.bottom(), tx1, ty2); + m_shadowQuads.append(topQuad); + } + + if (drawRight) { + QRectF rightRect( + topRightRect.bottomRight() - QPointF(right.width(), 0), + bottomRightRect.topRight()); + tx1 = 1.0 - right.width() / width; + ty1 = topRight.height() / height; + tx2 = 1.0; + ty2 = 1.0 - bottomRight.height() / height; + WindowQuad rightQuad(WindowQuadShadow); + rightQuad[0] = WindowVertex(rightRect.left(), rightRect.top(), tx1, ty1); + rightQuad[1] = WindowVertex(rightRect.right(), rightRect.top(), tx2, ty1); + rightQuad[2] = WindowVertex(rightRect.right(), rightRect.bottom(), tx2, ty2); + rightQuad[3] = WindowVertex(rightRect.left(), rightRect.bottom(), tx1, ty2); + m_shadowQuads.append(rightQuad); + } + + if (drawBottom) { + QRectF bottomRect( + bottomLeftRect.bottomRight() - QPointF(0, bottom.height()), + bottomRightRect.bottomLeft()); + tx1 = bottomLeft.width() / width; + ty1 = 1.0 - bottom.height() / height; + tx2 = 1.0 - bottomRight.width() / width; + ty2 = 1.0; + WindowQuad bottomQuad(WindowQuadShadow); + bottomQuad[0] = WindowVertex(bottomRect.left(), bottomRect.top(), tx1, ty1); + bottomQuad[1] = WindowVertex(bottomRect.right(), bottomRect.top(), tx2, ty1); + bottomQuad[2] = WindowVertex(bottomRect.right(), bottomRect.bottom(), tx2, ty2); + bottomQuad[3] = WindowVertex(bottomRect.left(), bottomRect.bottom(), tx1, ty2); + m_shadowQuads.append(bottomQuad); + } + + if (drawLeft) { + QRectF leftRect( + topLeftRect.bottomLeft(), + bottomLeftRect.topLeft() + QPointF(left.width(), 0)); + tx1 = 0.0; + ty1 = topLeft.height() / height; + tx2 = left.width() / width; + ty2 = 1.0 - bottomRight.height() / height; + WindowQuad leftQuad(WindowQuadShadow); + leftQuad[0] = WindowVertex(leftRect.left(), leftRect.top(), tx1, ty1); + leftQuad[1] = WindowVertex(leftRect.right(), leftRect.top(), tx2, ty1); + leftQuad[2] = WindowVertex(leftRect.right(), leftRect.bottom(), tx2, ty2); + leftQuad[3] = WindowVertex(leftRect.left(), leftRect.bottom(), tx1, ty2); + m_shadowQuads.append(leftQuad); + } } bool SceneOpenGLShadow::prepareBackend()