Fix window shadow on Linux for translucent windows.

This commit is contained in:
John Preston 2023-02-17 10:35:02 +04:00
parent c4838f5899
commit eb4d44ecd3
2 changed files with 87 additions and 3 deletions

View file

@ -31,6 +31,86 @@ namespace {
return st::callRadius;
}
[[nodiscard]] std::array<QImage, 4> PrepareSides(
const style::Shadow &shadow) {
auto result = std::array<QImage, 4>();
const auto extend = shadow.extend;
const auto make = [&](
int index,
const style::icon &icon,
auto &&postprocess) {
result[index] = icon.instance(st::windowShadowFg->c);
auto p = QPainter(&result[index]);
p.setCompositionMode(QPainter::CompositionMode_Source);
postprocess(p, icon.width(), icon.height());
};
make(0, shadow.left, [&](QPainter &p, int width, int height) {
const auto skip = extend.left();
p.fillRect(skip, 0, width - skip, height, Qt::transparent);
});
make(1, shadow.top, [&](QPainter &p, int width, int height) {
const auto skip = extend.top();
p.fillRect(0, skip, width, height - skip, Qt::transparent);
});
make(2, shadow.right, [&](QPainter &p, int width, int height) {
const auto skip = extend.right();
p.fillRect(0, 0, width - skip, height, Qt::transparent);
});
make(3, shadow.bottom, [&](QPainter &p, int width, int height) {
const auto skip = extend.bottom();
p.fillRect(0, 0, width, height - skip, Qt::transparent);
});
return result;
}
[[nodiscard]] std::array<QImage, 4> PrepareCorners(
const style::Shadow &shadow,
int radius) {
auto result = std::array<QImage, 4>();
const auto extend = shadow.extend;
const auto make = [&](
int index,
const style::icon &icon,
auto &&postprocess) {
result[index] = icon.instance(st::windowShadowFg->c);
auto p = QPainter(&result[index]);
auto hq = PainterHighQualityEnabler(p);
p.setCompositionMode(QPainter::CompositionMode_Source);
p.setBrush(Qt::transparent);
p.setPen(Qt::NoPen);
postprocess(p, icon.width(), icon.height());
};
make(0, shadow.topLeft, [&](QPainter &p, int width, int height) {
const auto skipx = extend.left();
const auto skipy = extend.top();
width += 2 * radius;
height += 2 * radius;
p.drawRoundedRect(skipx, skipy, width, height, radius, radius);
});
make(1, shadow.bottomLeft, [&](QPainter &p, int width, int height) {
const auto skipx = extend.left();
const auto skipy = extend.bottom() + 2 * radius;
width += 2 * radius;
height += 2 * radius;
p.drawRoundedRect(skipx, -skipy, width, height, radius, radius);
});
make(2, shadow.topRight, [&](QPainter &p, int width, int height) {
const auto skipx = extend.right() + 2 * radius;
const auto skipy = extend.top();
width += 2 * radius;
height += 2 * radius;
p.drawRoundedRect(-skipx, skipy, width, height, radius, radius);
});
make(3, shadow.bottomRight, [&](QPainter &p, int width, int height) {
const auto skipx = extend.right() + 2 * radius;
const auto skipy = extend.bottom() + 2 * radius;
width += 2 * radius;
height += 2 * radius;
p.drawRoundedRect(-skipx, -skipy, width, height, radius, radius);
});
return result;
}
} // namespace
BasicWindowHelper::BasicWindowHelper(not_null<RpWidget*> window)
@ -187,7 +267,9 @@ DefaultWindowHelper::DefaultWindowHelper(not_null<RpWidget*> window)
: BasicWindowHelper(window)
, _title(Ui::CreateChild<DefaultTitleWidget>(window.get()))
, _body(Ui::CreateChild<RpWidget>(window.get()))
, _roundRect(Radius(), st::windowBg) {
, _roundRect(Radius(), st::windowBg)
, _sides(PrepareSides(Shadow()))
, _corners(PrepareCorners(Shadow(), Radius())) {
init();
}
@ -323,8 +405,8 @@ void DefaultWindowHelper::updateRoundingOverlay() {
const auto rect = window()->rect().marginsRemoved(resizeArea());
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
_roundRect.paint(p, rect, RectPart::AllCorners);
p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
Shadow::paint(p, rect, window()->width(), Shadow());
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
Shadow::paint(p, rect, window()->width(), Shadow(), _sides, _corners);
}, _roundingOverlay->lifetime());
}

View file

@ -110,6 +110,8 @@ private:
const not_null<DefaultTitleWidget*> _title;
const not_null<RpWidget*> _body;
RoundRect _roundRect;
std::array<QImage, 4> _sides;
std::array<QImage, 4> _corners;
object_ptr<RpWidget> _roundingOverlay = { nullptr };
bool _extentsSet = false;
rpl::variable<Qt::WindowStates> _windowState = Qt::WindowNoState;