| Summary: | QWindow gives wrong devicePixelRatio with fractional scales | ||
|---|---|---|---|
| Product: | [Plasma] kwin | Reporter: | vincentv42 |
| Component: | wayland-generic | Assignee: | KWin default assignee <kwin-bugs-null> |
| Status: | CONFIRMED --- | ||
| Severity: | normal | CC: | kde, kdedev, nate, noahadvs, umadeguy, xaver.hugl |
| Priority: | NOR | ||
| Version First Reported In: | 6.4.5 | ||
| Target Milestone: | --- | ||
| Platform: | Arch Linux | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented In: | ||
| Sentry Crash Report: | |||
| Attachments: | wrongfractionalqwindowdpr | ||
|
Description
vincentv42
2025-10-13 17:39:43 UTC
Can confirm. I have a 2880x1800 screen I run at 175% scale. Spectacle says the dimensions are 3291x2057, which is exactly what you would get if you multiplied the native resolution by 2, and then divided by 1.75 The problem is in SelectionEditor::reset(), which sets the devicePixelRatio to qGuiApp->devicePixelRatio(), which in our cases returns a ceil()'ed version of the actual DPR (i.e. 2 instead of 1.25 or 1.75). It should be using QWindow::devicePixelRatio() instead so it can get a more accurate value. (In reply to Nate Graham from comment #2) > The problem is in SelectionEditor::reset(), which sets the devicePixelRatio > to qGuiApp->devicePixelRatio(), which in our cases returns a ceil()'ed > version of the actual DPR (i.e. 2 instead of 1.25 or 1.75). It should be > using QWindow::devicePixelRatio() instead so it can get a more accurate > value. It's actually not supposed to return a ceiled value. It seems that the fundamental issue is that QScreen and QWindow/QQuickWindow/CaptureWindow return the wrong values for the DPR when there are two screens with one set to 1.25x DPR and the other set to 1.75x. It seems that the issue is not fixable from Spectacle's side. Using windows instead of QScreen after ensuring that the windows are created first, which should provide correct DPRs: > const auto windows = CaptureWindow::instances(); > Q_ASSERT(!windows.empty()); > const auto dpr = std::accumulate(windows.cbegin(), windows.cend(), 0.0, [](qreal dpr, CaptureWindow *w) { > qDebug() << w->devicePixelRatio(); > return std::max(dpr, w->devicePixelRatio()); > }); > qDebug() << "max dpr" << dpr; Output with 1.25 and 1.75 DPR screens: > ❯ spectacle -i > 2 > 2 > max dpr 2 It seems that the source of the DPR is KWin since KWin sends a fractional scale to QWaylandWindow (QPlatformWindow subclass, which gives the DPR to QWindow). Perhaps the bug is from there? Created attachment 187457 [details]
wrongfractionalqwindowdpr
I've made a small C++ project that can demonstrate the issue if you are using a fractional scale.
KWin does send the correct fractional scale events, the test app just queries the value at a time where the event hasn't arrived yet. |