diff --git a/autotests/integration/internal_window.cpp b/autotests/integration/internal_window.cpp --- a/autotests/integration/internal_window.cpp +++ b/autotests/integration/internal_window.cpp @@ -33,6 +33,8 @@ #include #include +#include + #include using namespace KWayland::Client; @@ -64,6 +66,7 @@ void testModifierClickUnrestrictedMove(); void testModifierScroll(); void testPopup(); + void testScale(); }; class HelperWindow : public QRasterWindow @@ -687,6 +690,29 @@ QCOMPARE(internalClient->isPopupWindow(), true); } +void InternalWindowTest::testScale() +{ + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, + Q_ARG(int, 2), + Q_ARG(QVector, QVector({QRect(0,0,1280, 1024), QRect(1280/2, 0, 1280, 1024)})), + Q_ARG(QVector, QVector({2,2}))); + + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + HelperWindow win; + win.setGeometry(0, 0, 100, 100); + win.setFlags(win.flags() | Qt::Popup); + win.show(); + QCOMPARE(win.devicePixelRatio(), 2.0); + QVERIFY(clientAddedSpy.wait()); + QCOMPARE(clientAddedSpy.count(), 1); + auto internalClient = clientAddedSpy.first().first().value(); + QCOMPARE(internalClient->surface()->scale(), 2); + + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2)); +} + + } WAYLANDTEST_MAIN(KWin::InternalWindowTest) diff --git a/autotests/integration/kwin_wayland_test.h b/autotests/integration/kwin_wayland_test.h --- a/autotests/integration/kwin_wayland_test.h +++ b/autotests/integration/kwin_wayland_test.h @@ -207,9 +207,9 @@ } #ifdef NO_XWAYLAND -#define WAYLANDTEST_MAIN(TestObject) WAYLANDTEST_MAIN_HELPER(TestObject, QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling), KWin::Application::OperationModeWaylandOnly) +#define WAYLANDTEST_MAIN(TestObject) WAYLANDTEST_MAIN_HELPER(TestObject, QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps), KWin::Application::OperationModeWaylandOnly) #else -#define WAYLANDTEST_MAIN(TestObject) WAYLANDTEST_MAIN_HELPER(TestObject, QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling), KWin::Application::OperationModeXwayland) +#define WAYLANDTEST_MAIN(TestObject) WAYLANDTEST_MAIN_HELPER(TestObject, QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps), KWin::Application::OperationModeXwayland) #endif #endif diff --git a/main_wayland.cpp b/main_wayland.cpp --- a/main_wayland.cpp +++ b/main_wayland.cpp @@ -553,7 +553,7 @@ qunsetenv("QT_DEVICE_PIXEL_RATIO"); qputenv("QT_IM_MODULE", "qtvirtualkeyboard"); qputenv("QSG_RENDER_LOOP", "basic"); - QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); KWin::ApplicationWayland a(argc, argv); a.setupTranslator(); // reset QT_QPA_PLATFORM to a sane value for any processes started from KWin diff --git a/plugins/qpa/backingstore.h b/plugins/qpa/backingstore.h --- a/plugins/qpa/backingstore.h +++ b/plugins/qpa/backingstore.h @@ -48,6 +48,7 @@ void beginPaint(const QRegion &) override; private: + int scale() const; KWayland::Client::ShmPool *m_shm; QWeakPointer m_buffer; QImage m_backBuffer; diff --git a/plugins/qpa/backingstore.cpp b/plugins/qpa/backingstore.cpp --- a/plugins/qpa/backingstore.cpp +++ b/plugins/qpa/backingstore.cpp @@ -47,6 +47,7 @@ } const QSize size = m_backBuffer.size(); m_backBuffer = QImage(b->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied); + m_backBuffer.setDevicePixelRatio(scale()); } ); } @@ -61,7 +62,7 @@ void BackingStore::resize(const QSize &size, const QRegion &staticContents) { Q_UNUSED(staticContents) - m_size = size; + m_size = size * scale(); if (!m_buffer) { return; } @@ -73,13 +74,15 @@ { Q_UNUSED(region) Q_UNUSED(offset) - auto s = static_cast(window->handle())->surface(); + + auto w = static_cast(window->handle()); + auto s = w->surface(); if (!s) { return; } s->attachBuffer(m_buffer); // TODO: proper damage region - s->damage(QRect(QPoint(0, 0), m_backBuffer.size())); + s->damage(QRect(QPoint(0, 0), m_backBuffer.size() / scale())); s->commit(KWayland::Client::Surface::CommitFlag::None); waylandServer()->internalClientConection()->flush(); waylandServer()->dispatch(); @@ -108,12 +111,18 @@ auto b = m_buffer.toStrongRef(); b->setUsed(true); m_backBuffer = QImage(b->address(), m_size.width(), m_size.height(), QImage::Format_ARGB32_Premultiplied); + m_backBuffer.setDevicePixelRatio(scale()); if (oldBuffer) { b->copy(oldBuffer->address()); } else { m_backBuffer.fill(Qt::transparent); } } +int BackingStore::scale() const +{ + return static_cast(window()->handle())->scale(); +} + } } diff --git a/plugins/qpa/window.h b/plugins/qpa/window.h --- a/plugins/qpa/window.h +++ b/plugins/qpa/window.h @@ -74,6 +74,9 @@ } void createEglSurface(EGLDisplay dpy, EGLConfig config); + int scale() const; + qreal devicePixelRatio() const override; + void bindContentFBO(); const QSharedPointer &contentFBO() const { return m_contentFBO; @@ -96,6 +99,7 @@ #endif quint32 m_windowId; const Integration *m_integration; + int m_scale = 1; }; } diff --git a/plugins/qpa/window.cpp b/plugins/qpa/window.cpp --- a/plugins/qpa/window.cpp +++ b/plugins/qpa/window.cpp @@ -20,6 +20,7 @@ #define WL_EGL_PLATFORM 1 #include "integration.h" #include "window.h" +#include "screens.h" #include "../../shell_client.h" #include "../../wayland_server.h" #include @@ -44,7 +45,10 @@ , m_shellSurface(shellSurface) , m_windowId(++s_windowId) , m_integration(integration) + , m_scale(screens()->maxScale()) { + m_surface->setScale(m_scale); + QObject::connect(m_surface, &QObject::destroyed, window, [this] { m_surface = nullptr;}); QObject::connect(m_shellSurface, &QObject::destroyed, window, [this] { m_shellSurface = nullptr;}); waylandServer()->internalClientConection()->flush(); @@ -94,14 +98,17 @@ if (rect.height() != oldRect.height()) { emit window()->heightChanged(rect.height()); } + + const QSize nativeSize = rect.size() * m_scale; + if (m_contentFBO) { - if (m_contentFBO->width() != geometry().width() || m_contentFBO->height() != geometry().height()) { + if (m_contentFBO->size() != nativeSize) { m_resized = true; } } #if HAVE_WAYLAND_EGL if (m_eglWaylandWindow) { - wl_egl_window_resize(m_eglWaylandWindow, geometry().width(), geometry().height(), 0, 0); + wl_egl_window_resize(m_eglWaylandWindow, nativeSize.width(), nativeSize.height(), 0, 0); } #endif QWindowSystemInterface::handleGeometryChange(window(), geometry()); @@ -124,7 +131,7 @@ void Window::createEglSurface(EGLDisplay dpy, EGLConfig config) { #if HAVE_WAYLAND_EGL - const QSize size = window()->size(); + const QSize size = window()->size() * m_scale; m_eglWaylandWindow = wl_egl_window_create(*m_surface, size.width(), size.height()); if (!m_eglWaylandWindow) { return; @@ -158,7 +165,8 @@ if (m_contentFBO && r.size().isEmpty()) { return; } - m_contentFBO.reset(new QOpenGLFramebufferObject(r.width(), r.height(), QOpenGLFramebufferObject::CombinedDepthStencil)); + const QSize nativeSize = r.size() * m_scale; + m_contentFBO.reset(new QOpenGLFramebufferObject(nativeSize.width(), nativeSize.height(), QOpenGLFramebufferObject::CombinedDepthStencil)); if (!m_contentFBO->isValid()) { qCWarning(KWIN_QPA) << "Content FBO is not valid"; } @@ -174,5 +182,15 @@ return m_shellClient; } +int Window::scale() const +{ + return m_scale; +} + +qreal Window::devicePixelRatio() const +{ + return m_scale; +} + } } diff --git a/shell_client.cpp b/shell_client.cpp --- a/shell_client.cpp +++ b/shell_client.cpp @@ -510,9 +510,7 @@ return; } - //Kwin currently scales internal windows to 1, so this is currently always correct - //when that changes, this needs adjusting - m_clientSize = fbo->size(); + m_clientSize = fbo->size() / surface()->scale(); markAsMapped(); doSetGeometry(QRect(geom.topLeft(), m_clientSize)); Toplevel::setInternalFramebufferObject(fbo);