Re: Decreasing seams in scaled windows
John Ehresman <[email protected]> Fri, 19 Jun 2026 11:08:58 +0100
| Newsgroups | gmane.comp.lib.scintilla.devel |
|---|---|
| Message-ID | <[email protected]> |
--Apple-Mail=_772A1E51-5D79-42C4-AABC-F2C7D36ED746 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" Here=E2=80=99s a version that always snaps. Haven=E2=80=99t tried it with d= efault scaling technique but should work. Also added a define to disable it= =E2=80=94 I do have the start of a patch to Qt that seems to work for scin= tilla and for other widgets. The backing store has a grid of what is dirty = and that grid is only half the size of the backing store on retina displays= . Making it full size seems to fix the one pixel lines. [I wrote this before seeing Neil=E2=80=99s followup message. I agree that s= caling on macOS is less important (other than the default 2x), but it=E2=80= =99s nice to know that the bug is not in scintilla and it actually works we= ll when fixed] John --=20 You received this message because you are subscribed to the Google Groups "= scintilla-interest" group. To unsubscribe from this group and stop receiving emails from it, send an e= mail to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/scintilla-i= nterest/4A409030-1FB4-4859-AF72-465C48263135%40wingware.com. --Apple-Mail=_772A1E51-5D79-42C4-AABC-F2C7D36ED746 Content-Disposition: attachment; filename=QtScale-PlatQt.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="QtScale-PlatQt.patch" Content-Transfer-Encoding: 7bit diff -r 7d5e2d6cf92c qt/ScintillaEditBase/PlatQt.cpp --- a/qt/ScintillaEditBase/PlatQt.cpp Tue Jun 16 11:23:34 2026 +0100 +++ b/qt/ScintillaEditBase/PlatQt.cpp Thu Jun 18 20:20:21 2026 +0100 @@ -223,6 +223,50 @@ return variant.toDouble(); } +// Define SCINTILLA_QT_BACKINGSTORE_FIXED when building against a Qt whose +// backing store tracks dirty state at device-pixel resolution; that makes the +// fractional-scaling workarounds below compile out entirely. + +#if defined(Q_OS_APPLE) && !defined(SCINTILLA_QT_BACKINGSTORE_FIXED) +// Grow a logical update rect so its coordinates translate into even device +// pixels w/o rounding. The coordinates need to be even because there's +// a dirty grid that's 1/2 the size of the device pixel grid on Retina +// displays. This may grow the rect more than needed on non-Retina displays +static QRect SnapToDevicePixelGrid(QRect upd, qreal scale, QSize widgetSize) +{ + const int backing = (scale >= 2.0) ? 2 : 1; + if (backing == 1) + return upd; // grid is already device-pixel resolution; nothing to snap + + // q logical pixels span q * (scale/backing) grid cells. The smallest q + // that makes this whole is the snap period whose multiples put logical + // edges on the device-pixel grid. (scale/backing is the fractional + // QT_SCALE_FACTOR, e.g. 1.5 -> q == 2, 1.25 -> q == 4.) + const double zoom = scale / backing; + int q = 0; + for (int n = 1; n <= 8; ++n) { + if (std::fabs(zoom * n - std::round(zoom * n)) < 1e-4) { + q = n; + break; + } + } + if (q == 0) + return QRect(); // not a simple ratio + if (q == 1) + return upd; // already on the grid + + auto floorTo = [](int v, int n) { int r = v % n; if (r < 0) r += n; return v - r; }; + const int l = floorTo(upd.left(), q); + const int t = floorTo(upd.top(), q); + const int r = floorTo(upd.right() + q, q) - 1; // ceil the exclusive edge + const int b = floorTo(upd.bottom() + q, q) - 1; + const QRect snapped(QPoint(l, t), QPoint(r, b)); + if (snapped.width() >= widgetSize.width() && snapped.height() >= widgetSize.height()) + return QRect(); // would cover the whole widget + return snapped; +} +#endif + double ScaleToMultiply(WindowID wid) { const qreal scale = ScaleOfWindow(wid); @@ -934,18 +978,34 @@ { if (wid) { const qreal scale = ScaleOfWindow(wid); - if (scale) { + QRect upd; + + if (!scale) { + upd = QRectFromPRect(rc); + } + else { #if !defined(Q_OS_WIN) && !defined(Q_OS_APPLE) // Using X11 or Wayland, likely Linux but may be a BSD or similar if (scale != 1.0 && scale != 2.0) { - // Fractional scaling leaves repaint debris, so redraw completely window(wid)->update(); return; } #endif - rc = rc / scale; + + upd = QRectFFromPRect(rc / scale).toAlignedRect(); } - window(wid)->update(QRectFromPRect(rc)); + +#if defined(Q_OS_APPLE) && !defined(SCINTILLA_QT_BACKINGSTORE_FIXED) + // macOS: snap the update to the backing store's device-pixel grid. + const QRect snapped = SnapToDevicePixelGrid(upd, scale, window(wid)->size()); + if (snapped.isNull()) { + window(wid)->update(); + return; + } + upd = snapped; +#endif + + window(wid)->update(upd); } } --Apple-Mail=_772A1E51-5D79-42C4-AABC-F2C7D36ED746 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" > On Jun 18, 2026, at 1:43=E2=80=AFAM, 'Neil Hodgson' via scintilla-interes= t <[email protected]> wrote: >=20 > John: >=20 >> Attached is a patch that seems to work =E2=80=94 note that on some ratio= s, it will revert to a full redraw. I have only tried this on macOS but pla= n to try it on the other platforms soon. >=20 > This does appear to help when scale is turned on. >=20 > However, it may also be needed for ScaleTechnique::Default. Here is an = image when QT_SCALE_FACTOR=3D1.5. > https://www.scintilla.org/MacOS-Seam-150.jpg >=20 > Neil >=20 > --=20 > You received this message because you are subscribed to the Google Groups= "scintilla-interest" group. > To unsubscribe from this group and stop receiving emails from it, send an= email to [email protected]. > To view this discussion visit https://groups.google.com/d/msgid/scintilla= -interest/9D1C1081-19AE-4845-AD70-D78C0A700D85%40me.com. --=20 You received this message because you are subscribed to the Google Groups "= scintilla-interest" group. To unsubscribe from this group and stop receiving emails from it, send an e= mail to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/scintilla-i= nterest/4A409030-1FB4-4859-AF72-465C48263135%40wingware.com. --Apple-Mail=_772A1E51-5D79-42C4-AABC-F2C7D36ED746--