Commit d70bd243 authored by David Edmundson's avatar David Edmundson
Browse files

Introduce client level scale overrides

This allows for compositor managed different co-ordinate space between kwin's
logical co-ordinate space and a client's logical co-ordinate space.

When combined with a modified !1959 this allows us to set a DPI in xrdb and
mark all xwayland windows as being 2x (or other) and avoid upscales for xwayland
clients in a way that doesn't impact other wayland clients or require
third-party changes. Any use of fractional values is in layers we control
instead of over the wire. kwayland-server is the right place for this
abstraction as we need Outputs to differ on a per resource basis. Something we
can't control from within kwin.

Right now only protocols used by Xwayland are covered. If we covered
remaining protocols we can offer user-control on all remaining clients which
could open up other possibilities such as a user controlled dynamic resizing,
or adapt to possible future protocol changes with wayland scaling.
parent 51999dea
......@@ -27,6 +27,8 @@ public:
gid_t group = 0;
QString executablePath;
qreal scaleOverride = 1.0;
private:
static void destroyListenerCallback(wl_listener *listener, void *data);
ClientConnection *q;
......@@ -145,4 +147,13 @@ QString ClientConnection::executablePath() const
return d->executablePath;
}
void ClientConnection::setScaleOverride(qreal scaleOveride)
{
d->scaleOverride = scaleOveride;
}
qreal ClientConnection::scaleOverride() const
{
return d->scaleOverride;
}
}
......@@ -109,6 +109,21 @@ public:
*/
void destroy();
/**
* Set an additional mapping between kwin's logical co-ordinate space and
* the client's logical co-ordinate space.
*
* This is used in the same way as if the client was setting the
* surface.buffer_scale on every surface i.e a value of 2.0 will make
* the windows appear smaller on a regular DPI monitor.
*
* Only the minimal set of protocols used by xwayland have support.
*
* Buffer sizes are unaffected.
*/
void setScaleOverride(qreal scaleOverride);
qreal scaleOverride() const;
Q_SIGNALS:
/**
* This signal is emitted when the client is about to be destroyed.
......@@ -119,6 +134,8 @@ Q_SIGNALS:
*/
void disconnected(KWaylandServer::ClientConnection *);
void scaleOverrideChanged();
private:
friend class Display;
explicit ClientConnection(wl_client *c, Display *parent);
......
......@@ -412,4 +412,9 @@ OutputInterface *OutputInterface::get(wl_resource *native)
return nullptr;
}
Display *OutputInterface::display() const
{
return d->display;
}
} // namespace KWaylandServer
......@@ -104,6 +104,8 @@ public:
static OutputInterface *get(wl_resource *native);
Display *display() const;
Q_SIGNALS:
void physicalSizeChanged(const QSize &);
void globalPositionChanged(const QPoint &);
......
......@@ -174,7 +174,7 @@ void PointerInterface::sendEnter(SurfaceInterface *surface, const QPointF &posit
Q_EMIT focusedSurfaceChanged();
});
d->sendEnter(position, serial);
d->sendEnter(d->focusedSurface->toSurfaceLocal(position), serial);
d->sendFrame();
d->lastPosition = position;
......@@ -262,9 +262,11 @@ void PointerInterface::sendMotion(const QPointF &position)
return;
}
const QPointF localPos = d->focusedSurface->toSurfaceLocal(position);
const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
for (PointerInterfacePrivate::Resource *resource : pointerResources) {
d->send_motion(resource->handle, d->seat->timestamp(), wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y()));
d->send_motion(resource->handle, d->seat->timestamp(), wl_fixed_from_double(localPos.x()), wl_fixed_from_double(localPos.y()));
}
}
......
......@@ -76,6 +76,8 @@ void RelativePointerV1Interface::sendRelativeMotion(const QSizeF &delta, const Q
return;
}
auto scaleOverride = pointer->focusedSurface()->scaleOverride();
ClientConnection *focusedClient = pointer->focusedSurface()->client();
const QList<Resource *> pointerResources = resourceMap().values(focusedClient->client());
for (Resource *pointerResource : pointerResources) {
......@@ -83,10 +85,10 @@ void RelativePointerV1Interface::sendRelativeMotion(const QSizeF &delta, const Q
send_relative_motion(pointerResource->handle,
microseconds >> 32,
microseconds & 0xffffffff,
wl_fixed_from_double(delta.width()),
wl_fixed_from_double(delta.height()),
wl_fixed_from_double(deltaNonAccelerated.width()),
wl_fixed_from_double(deltaNonAccelerated.height()));
wl_fixed_from_double(delta.width() * scaleOverride),
wl_fixed_from_double(delta.height() * scaleOverride),
wl_fixed_from_double(deltaNonAccelerated.width() * scaleOverride),
wl_fixed_from_double(deltaNonAccelerated.height() * scaleOverride));
}
}
}
......
......@@ -526,9 +526,13 @@ void SeatInterface::setDragTarget(AbstractDropHandler *dropTarget,
} else if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->globalTouch.focus.firstTouchPos != globalPosition) {
notifyTouchMotion(d->globalTouch.ids.first(), globalPosition);
}
QMatrix4x4 surfaceInputTransformation = inputTransformation;
surfaceInputTransformation.scale(surface->scaleOverride());
if (d->drag.target) {
d->drag.surface = surface;
d->drag.transformation = inputTransformation;
d->drag.transformation = surfaceInputTransformation;
d->drag.target->updateDragTarget(surface, serial);
} else {
d->drag.surface = nullptr;
......
......@@ -25,6 +25,16 @@
namespace KWaylandServer
{
static QRegion map_helper(const QMatrix4x4 &matrix, const QRegion &region)
{
QRegion result;
for (const QRect &rect : region) {
result += matrix.mapRect(rect);
}
return result;
}
SurfaceInterfacePrivate::SurfaceInterfacePrivate(SurfaceInterface *q)
: q(q)
{
......@@ -346,6 +356,12 @@ SurfaceInterface::SurfaceInterface(CompositorInterface *compositor, wl_resource
d->compositor = compositor;
d->init(resource);
d->client = compositor->display()->getConnection(d->resource()->client());
d->scaleOverride = d->client->scaleOverride();
connect(d->client, &ClientConnection::scaleOverrideChanged, this, [this]() {
d->scaleOverride = d->client->scaleOverride();
// TODO before merging we should do some applyState() with the current state
});
}
SurfaceInterface::~SurfaceInterface()
......@@ -407,6 +423,7 @@ QMatrix4x4 SurfaceInterfacePrivate::buildSurfaceToBufferMatrix()
}
surfaceToBufferMatrix.scale(current.bufferScale, current.bufferScale);
surfaceToBufferMatrix.scale(scaleOverride, scaleOverride);
switch (current.bufferTransform) {
case KWin::Output::Transform::Normal:
......@@ -590,6 +607,7 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
} else {
surfaceSize = implicitSurfaceSize;
}
surfaceSize = implicitSurfaceSize;
const QRect surfaceRect(QPoint(0, 0), surfaceSize);
inputRegion = current.input & surfaceRect;
......@@ -599,6 +617,13 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
} else {
opaqueRegion = current.opaque & surfaceRect;
}
const QMatrix4x4 scaleOverrideMatrix(QTransform::fromScale(1. / scaleOverride, 1. / scaleOverride));
opaqueRegion = map_helper(scaleOverrideMatrix, opaqueRegion);
inputRegion = map_helper(scaleOverrideMatrix, inputRegion);
surfaceSize = surfaceSize / scaleOverride;
implicitSurfaceSize = implicitSurfaceSize / scaleOverride;
} else {
surfaceSize = QSize();
implicitSurfaceSize = QSize();
......@@ -765,7 +790,7 @@ ClientBuffer *SurfaceInterface::buffer() const
QPoint SurfaceInterface::offset() const
{
return d->current.offset;
return d->current.offset / d->scaleOverride;
}
SurfaceInterface *SurfaceInterface::get(wl_resource *native)
......@@ -992,15 +1017,6 @@ QPointF SurfaceInterface::mapFromBuffer(const QPointF &point) const
return d->bufferToSurfaceMatrix.map(point);
}
static QRegion map_helper(const QMatrix4x4 &matrix, const QRegion &region)
{
QRegion result;
for (const QRect &rect : region) {
result += matrix.mapRect(rect);
}
return result;
}
QRegion SurfaceInterface::mapToBuffer(const QRegion &region) const
{
return map_helper(d->surfaceToBufferMatrix, region);
......@@ -1043,4 +1059,19 @@ QSize SurfaceInterface::bufferSize() const
return d->bufferSize;
}
qreal SurfaceInterface::scaleOverride() const
{
return d->scaleOverride;
}
QPoint SurfaceInterface::toSurfaceLocal(const QPoint &point) const
{
return QPoint(point.x() * d->scaleOverride, point.y() * d->scaleOverride);
}
QPointF SurfaceInterface::toSurfaceLocal(const QPointF &point) const
{
return QPointF(point.x() * d->scaleOverride, point.y() * d->scaleOverride);
}
} // namespace KWaylandServer
......@@ -315,6 +315,21 @@ public:
*/
static SurfaceInterface *get(quint32 id, const ClientConnection *client);
/**
* @see ClientConnection::setScaleOverride
*/
qreal scaleOverride() const;
/**
* Convert a co-ordinate from kwin logical space to surface logical space
* @internal
*/
QPoint toSurfaceLocal(const QPoint &point) const;
/**
* Convert a co-ordinate from kwin logical space to surface logical space
* @internal
*/
QPointF toSurfaceLocal(const QPointF &point) const;
Q_SIGNALS:
/**
* This signal is emitted when the underlying wl_surface resource is about to be freed.
......
......@@ -113,6 +113,7 @@ public:
ClientBuffer *bufferRef = nullptr;
bool mapped = false;
bool hasCacheState = false;
qreal scaleOverride = 1.;
QVector<OutputInterface *> outputs;
......
......@@ -259,7 +259,8 @@ void TabletToolV2Interface::sendButton(uint32_t button, bool pressed)
void TabletToolV2Interface::sendMotion(const QPointF &pos)
{
d->send_motion(d->targetResource(), wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
const QPointF surfacePos = d->m_surface->toSurfaceLocal(pos);
d->send_motion(d->targetResource(), wl_fixed_from_double(surfacePos.x()), wl_fixed_from_double(surfacePos.y()));
}
void TabletToolV2Interface::sendDistance(uint32_t distance)
......
......@@ -84,9 +84,11 @@ void TouchInterface::sendMotion(qint32 id, const QPointF &localPos)
return;
}
QPointF pos = d->focusedSurface->toSurfaceLocal(localPos);
const auto touchResources = d->touchesForClient(d->focusedSurface->client());
for (TouchInterfacePrivate::Resource *resource : touchResources) {
d->send_motion(resource->handle, d->seat->timestamp(), id, wl_fixed_from_double(localPos.x()), wl_fixed_from_double(localPos.y()));
d->send_motion(resource->handle, d->seat->timestamp(), id, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
}
}
......@@ -108,6 +110,8 @@ void TouchInterface::sendDown(qint32 id, quint32 serial, const QPointF &localPos
return;
}
QPointF pos = d->focusedSurface->toSurfaceLocal(localPos);
const auto touchResources = d->touchesForClient(d->focusedSurface->client());
for (TouchInterfacePrivate::Resource *resource : touchResources) {
d->send_down(resource->handle,
......@@ -115,8 +119,8 @@ void TouchInterface::sendDown(qint32 id, quint32 serial, const QPointF &localPos
d->seat->timestamp(),
d->focusedSurface->resource(),
id,
wl_fixed_from_double(localPos.x()),
wl_fixed_from_double(localPos.y()));
wl_fixed_from_double(pos.x()),
wl_fixed_from_double(pos.y()));
}
}
......
......@@ -47,6 +47,9 @@ public:
bool doneOnce = false;
QPointer<OutputInterface> output;
void sendLogicalPosition(Resource *resource, const QPoint &position);
void sendLogicalSize(Resource *resource, const QSize &size);
protected:
void zxdg_output_v1_bind_resource(Resource *resource) override;
void zxdg_output_v1_destroy(Resource *resource) override;
......@@ -125,7 +128,7 @@ void XdgOutputV1Interface::setLogicalSize(const QSize &size)
const auto outputResources = d->resourceMap();
for (auto resource : outputResources) {
d->send_logical_size(resource->handle, size.width(), size.height());
d->sendLogicalSize(resource, size);
}
}
......@@ -144,7 +147,7 @@ void XdgOutputV1Interface::setLogicalPosition(const QPoint &pos)
const auto outputResources = d->resourceMap();
for (auto resource : outputResources) {
d->send_logical_position(resource->handle, pos.x(), pos.y());
d->sendLogicalPosition(resource, pos);
}
}
......@@ -188,8 +191,8 @@ void XdgOutputV1InterfacePrivate::zxdg_output_v1_destroy(Resource *resource)
void XdgOutputV1InterfacePrivate::zxdg_output_v1_bind_resource(Resource *resource)
{
send_logical_position(resource->handle, pos.x(), pos.y());
send_logical_size(resource->handle, size.width(), size.height());
sendLogicalPosition(resource, pos);
sendLogicalSize(resource, size);
if (resource->version() >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
send_name(resource->handle, name);
}
......@@ -208,4 +211,24 @@ void XdgOutputV1InterfacePrivate::zxdg_output_v1_bind_resource(Resource *resourc
}
}
void XdgOutputV1InterfacePrivate::sendLogicalSize(Resource *resource, const QSize &size)
{
if (!output) {
return;
}
ClientConnection *connection = output->display()->getConnection(resource->client());
qreal scaleOverride = connection->scaleOverride();
send_logical_size(resource->handle, size.width() * scaleOverride, size.height() * scaleOverride);
}
void XdgOutputV1InterfacePrivate::sendLogicalPosition(Resource *resource, const QPoint &pos)
{
if (!output) {
return;
}
ClientConnection *connection = output->display()->getConnection(resource->client());
qreal scaleOverride = connection->scaleOverride();
send_logical_position(resource->handle, pos.x() * scaleOverride, pos.y() * scaleOverride);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment