Scaled decorations in QPainter mode

Summary:
Under wayland we support high DPI putting by putting a separation
between the logical co-ordinate system and the resolution of rendered
assets.

I didn't include window decorations in the previous wayland scaling
patchset. They were drawn them at a standard resolution, which is
implicitly scaled up.

This uses the Qt scaling, meaning oxygen and breeze (and others) get
perfect high DPI support with zero client changes.

Like the window scaling this handles any combination of a 2x scaled
decoration being rendered on a 1x screen or vice versa.

CCBUG: 384765

Test Plan:
export KWIN_COMPOSE=Q
Had two screens of different scales
It was the right size on both (as before)
Was super-sharp on the fancy screen

Reviewers: #plasma, hetzenecker, graesslin

Reviewed By: #plasma, graesslin

Subscribers: ngraham, graesslin, plasma-devel, kwin, #kwin

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D8504
icc-effect-5.14.5
David Edmundson 2017-10-30 13:27:48 +00:00
parent 2e371f9634
commit 7e6721ece0
2 changed files with 19 additions and 7 deletions

View File

@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "decorationrenderer.h"
#include "decoratedclient.h"
#include "deleted.h"
#include "abstract_client.h"
#include <KDecoration2/Decoration>
#include <KDecoration2/DecoratedClient>
@ -38,6 +39,9 @@ Renderer::Renderer(DecoratedClientImpl *client)
, m_imageSizesDirty(true)
{
auto markImageSizesDirty = [this]{ m_imageSizesDirty = true; };
if (kwinApp()->operationMode() != Application::OperationModeX11) {
connect(client->client(), &AbstractClient::screenChanged, this, markImageSizesDirty);
}
connect(client->decoration(), &KDecoration2::Decoration::bordersChanged, this, markImageSizesDirty);
connect(client->decoratedClient(), &KDecoration2::DecoratedClient::widthChanged, this, markImageSizesDirty);
connect(client->decoratedClient(), &KDecoration2::DecoratedClient::heightChanged, this, markImageSizesDirty);

View File

@ -594,10 +594,14 @@ void SceneQPainterDecorationRenderer::render()
resetImageSizesDirty();
}
const QRect top(QPoint(0, 0), m_images[int(DecorationPart::Top)].size());
const QRect left(QPoint(0, top.height()), m_images[int(DecorationPart::Left)].size());
const QRect right(QPoint(top.width() - m_images[int(DecorationPart::Right)].size().width(), top.height()), m_images[int(DecorationPart::Right)].size());
const QRect bottom(QPoint(0, left.y() + left.height()), m_images[int(DecorationPart::Bottom)].size());
auto imageSize = [this](DecorationPart part) {
return m_images[int(part)].size() / m_images[int(part)].devicePixelRatio();
};
const QRect top(QPoint(0, 0), imageSize(DecorationPart::Top));
const QRect left(QPoint(0, top.height()), imageSize(DecorationPart::Left));
const QRect right(QPoint(top.width() - imageSize(DecorationPart::Right).width(), top.height()), imageSize(DecorationPart::Right));
const QRect bottom(QPoint(0, left.y() + left.height()), imageSize(DecorationPart::Bottom));
const QRect geometry = scheduled.boundingRect();
auto renderPart = [this](const QRect &rect, const QRect &partRect, int index) {
@ -606,7 +610,7 @@ void SceneQPainterDecorationRenderer::render()
}
QPainter painter(&m_images[index]);
painter.setRenderHint(QPainter::Antialiasing);
painter.setWindow(partRect);
painter.setWindow(QRect(partRect.topLeft(), partRect.size() * m_images[index].devicePixelRatio()));
painter.setClipRect(rect);
painter.save();
// clear existing part
@ -628,8 +632,12 @@ void SceneQPainterDecorationRenderer::resizeImages()
client()->client()->layoutDecorationRects(left, top, right, bottom);
auto checkAndCreate = [this](int index, const QSize &size) {
if (m_images[index].size() != size) {
m_images[index] = QImage(size, QImage::Format_ARGB32_Premultiplied);
auto dpr = screens()->scale(client()->client()->screen());
if (m_images[index].size() != size * dpr ||
m_images[index].devicePixelRatio() != dpr)
{
m_images[index] = QImage(size * dpr, QImage::Format_ARGB32_Premultiplied);
m_images[index].setDevicePixelRatio(dpr);
m_images[index].fill(Qt::transparent);
}
};