Re: Scintilla GTK 4 port

Sergey Bugaev <[email protected]> Fri, 14 Nov 2025 16:57:39 +0300
Newsgroups gmane.comp.lib.scintilla.devel
Message-ID <CAN9u=HfcAiuKR7hA+QpfiJ1YBKPi32h=07V1q-mbMx_r6LpnDQ@mail.gmail.com>
Hello,

On Fri, Nov 14, 2025 at 6:27=E2=80=AFAM 'Neil Hodgson' via scintilla-intere=
st
<[email protected]> wrote:
>
> Sergey Bugaev:
>
> > I'm writing to announce that I have developed a mostly working port of
> > Scintilla to the GTK 4 toolkit.
> =E2=80=A6
> > snapshot of the port, rebased on top of the
> > latest changes from Mercurial (so, the 5.5.8 release), to
> > https://github.com/bugaevc/scintilla on GitHub
>
> I'm a bit confused here. Are you also using the 'xuges' identity responsi=
ble for https://github.com/xuges/scintilla or are these separate or related=
 projects?

uhh, no, that is someone else, and seemingly another GTK 4 port?

From a brief look at it, it looks to be based on the existing GTK 2/3
port. In particular it has the code to render itself using Cairo and
GtkDrawingArea (not even gtk_snapshot_append_cairo). Mine is a whole
new independent port, which also tries to do things better / more
conventionally than the GTK 2/3 port on various fronts, as described.

> > =E2=80=A6 But there are some considerations for applications
> > & widgets as well: in particular Scintilla tries to round extents to
> > physical pixels via a PixelDivisions value, which is, for one thing,
> > an integer, with no way to represent a fractional scale like 2.5 or
> > 1.75.
>
>    The PixelDivisions value is mostly for macOS or similar systems where =
windowing-layer coordinates may not match physical pixels but are always an=
 integral number of physical pixels.
>
>    Win32 provides fractional scaling by allowing the application/thread/w=
indow to enrol as High DPI aware with windowing-layer coordinates then matc=
hing physical pixels. The drawing-layer calls may then use scaling if they =
want. Other behaviour like invalidation is also directed to the windowing-l=
ayer and do not use scaled coordinates.

Yes, I understand that.

Between these two, GTK behaves closer to Cocoa, in that
application/widget level coordinates are in logical pixels/units,
which are then scaled inside the toolkit to get to physical/device
pixels. This way, most of the application code never has to care about
the details of scaling (other than shipping icons with a larger
resolution etc).

Up until GTK 4.11, this only supported integer scaling, so as you're
saying about macOS, a single logical pixel would always correspond to
an integral number of physical pixels. The reality is that there are
displays out there for which e.g. 100% is too small and 200% is too
large (or 200% is too small and 300% is too large, as is the case with
this laptop I'm typing this on), hence, fractional scaling is needed.
The traditional way to implement this has been telling applications to
render at 300% and then downscaling the produced textures by 2x
compositor-side =E2=80=94 this way, you get 150%, but the application/toolk=
it
only has to deal with integer scaling. I believe this is also what
macOS / Cocoa does as well. The downside with that approach of course
is that the toolkit does antialiasing etc for a pixel layout that
doesn't actually match the display.

Newer versions of GTK support full (or "native") fractional scaling
toolkit-side. This is generally much better for sharpness & clarity,
but indeed introduces the issues with seams and other kinds of
misalignment. It's a trade-off.

> > Another issue here is that Scintilla paints the background behind each
> > piece of text individually as its own little rectangle; this for one
> > thing has the downside of producing a lot of render nodes (a lot of
> > small white rectangles, instead of one large white rectangle covering
> > the whole widget area), and therefore a bunch of extra work for the
> > GPU to push through.
>
>    Each text span (commonly associated with a lexeme) may have a differen=
t background colour to other spans. Other features (like highlighting break=
point lines) may also impose a background colour.

Yes, sure. Seams are a lot less visible where the colors are different
along the sides of the seam. It's the case where the colors are the
same that is most visible.

> One common technique is to colour the background of major zones of the fi=
le differently: for HTML, text and tags may have one background but client-=
side and server-side scripts use different background colours.
>
>    Commonly, a view may have 80 lines and less than 10 spans per line, re=
sulting in 800 pieces of text and 800 simple coloured rectangles. GPUs can =
normally draw many million rectangles per second so it's unlikely that 800 =
rectangles will be a major problem. Looking at profiles shows that its draw=
ing text that is slow, not backgrounds.
>
>    A few years back, I thought this may be a worthwhile area to optimize =
so wrote some code that coalesced adjacent background rectangles and only d=
rew when the background changed. While this would often reduce the number o=
f background drawing calls to one per line, it had no effect on speed for D=
irect2D (Win32) or macOS. It's likely the system is batching rectangle draw=
ing or even coalescing itself. If this produces a noticeable benefit on som=
e platform, then it can be added, probably as an option.

Yes, so that sounds like it would help. It would likely make little
difference performance-wise, but the render tree would look tidier,
and there would be less seams visible.

>    A potential addition here is for an optional base fill colour to be us=
ed as the background. Following drawing of text backgrounds can then assume=
 that has already been drawn and refrain from redrawing with the same colou=
r. This may reduce seaming, particularly for applications that have a consi=
stent or mostly consistent background colour.

Yes, exactly, that's what I tried to implement on my side in
gtk4/ScintillaGTK.cxx:RemoveWhiteBackground. But this is a hack, and
only really helps when the background is the default white. It can be
easily removed if a more proper solution would be implemented in
Scintilla core.

> > I had used various tricks to somewhat reconcile Scintilla code's idea
> > of each platform having a single global style with this GTK's idea of
> > style inherently coming from a style sheet and differing per-widget
> > and with time.
>
>    Applications and individual users often want detailed control over sty=
ling issues and it's unlikely they will write GTK style sheets when they wa=
nt documentation comments to be a slightly bluer tone.

Yes, so we of course have to keep compatibility with applications
forcing specific colors and fonts, if they do.

The issue with this (as it's always the case when a specific color is
provided instead of going through the style sheet mechanism) is that
it won't (without additional work on each application's side) follow
system settings like dark mode, accent color, high contrast.

GtkSourceView has pairs of light/dark styles for this, and uses the
accent color for selection.

> > Yet another topic is phases. In GTK, "every frame is perfect". We
> > don't draw bad frames, because... why would we do such a thing? But
> > Scintilla sometimes decides to just *adandon painting* if it discovers
> > it needs to re-style or update something in the middle of painting.
>
>    Some Scintilla features, like syntax styling and word-wrapping are qui=
te slow so are performed as background activities and may slip against inpu=
t to avoid blocking.
>
>    Requiring that the entire document be fully prepared before painting w=
ill not be viable for huge documents. As well as syntax styling and word-wr=
apping, applications may also choose various features like spelling and lin=
ting that will require time.

Certainly, so, we don't have to highlight the entire document to be
able to display one screenful of text, only the visible part. (This is
too of course non-trivial =E2=80=94 how would you know if there's a /* ten
thousand lines above, and everything after that should have been
highlighted as a comment?) If that's still too slow, the work could be
split in chunks, so we do one chunk of work per frame.

It's fine if we initially show the document unhighlighted, and
highlighting catches up later. It's not fine to produce broken/junk
frames, where we just decide to avoid painting altogether.

> > GObject introspection [6] is a cool feature of the GObject type system,=
 where:
>
>    In the past I have had great hopes for language interoperability syste=
ms and they never achieved all that much. Microsoft's COM is the biggest su=
ccess in this space but has still underachieved with users. I was 'the COM =
guy' at one company and have been through all the stages of belief and disa=
ppointment here.

I'm not really familiar with COM (besides some superficial knowledge
about IUnknown/QueryInterface), so I cannot compare how successful it
has been compared to GObject.

But, GObject introspection (& numerous language bindings) certainly
exists and works and is widely adopted; it's not a pipe dream. It's
been a success, technologically and socially; I don't remember seeing
any language interoperability solution succeed to this extent on other
platforms (though again, I just might be uninformed on what COM has
achieved).

The proof is in the pudding. If you take, for example, the *core*
GNOME apps listed on the "Apps for GNOME" page [0], you'll find that:

[0]: https://apps.gnome.org/

* Audio Player (Decibels) is in TypeScript
* Calculator is in Vala
* Calendar is in C
* Camera (Snapshot) is in Rust
* Characters is in JavaScript (with parts in C)
* Clocks is in Vala
* Connections is in Vala
* Console (kgx) is in C
* Contacts is in Vala
* Disk Usage Analyzer (Baobab) is in Vala
* Disks (disk utility) is in C, with newer parts in Rust
* Document Scanner (SimpleScan) is in Vala
* Document Viewer (Papers) is mixed C and (newer parts) in Rust
* Files (Nautilus) is in C
* Fonts is in C
* Help (Yelp) is in C
* Image Viewer (Loupe) is in Rust
* Logs is in C
* Maps is in JavaScript
* Music is in Python
* Settings (Control Center) is in C
* Software is in C
* System Monitor is in C++
* Text Editor is in C
* Tour is in Rust
* Video Player (Showtime) is in Python
* Weather is in TypeScript
* Web (Epiphany) is in C

So, while there is a lot of C (mostly in older apps), and it's not
going anywhere, other languages =E2=80=94 mostly Python, Rust,
JavaScript/TypeScript (GJS), Vala =E2=80=94 are also being used, a lot. Tha=
t's
GNOME core apps; there's even more of non-C language usage in the
GNOME Circle apps, and the wider ecosystem (just to name a few:
Foliate is in JavaScript, rnote is in Rust, Apostrophe is in Python).
The very UI of GNOME Shell is (in)famously written in JavaScript.
elementary OS people are writing all of their code, apps and
otherwise, in Vala [1]. I've recently seen this visualization of
language usage stats [2] (made by Sophie).

[1]: https://blog.elementary.io/why-we-write-elementary-apps-in-vala/
[2]: https://sophie-h.pages.gitlab.gnome.org/app-overview/charts.html

There are libraries in the platform whose API was not designed with
introspection and language bindings in mind, and this is seen as a
deficiency. Pango is an example here, although it is still possible to
use Pango through introspection to a large extent.

So: it's a vibrant and language-diverse ecosystem, and GObject
introspection, which enables language interoperability, is central to
it. I don't think I'm being delusional or overly hopeful here :)

> > There are some bits of this in the GTK 2/3 port already, but for the
> > GTK 4 port, I went all in.
>
>    This isn't a bad feature, especially if you can use it well yourself b=
ut don't expect it to be embraced by many.
>
>    A scripting language tightly integrated into an application with an ob=
ject model customized to the language is much more likely to attract users =
than a generic, automatically translated, API.

I suppose you're thinking of SciTE and Lua?

It is of course possible for an application which uses Scintilla to
bring its own scripting language integration which is based on some
other technology (not GObject introspection). That being said, GObject
introspection makes it pretty easy to do so (bring in a scripting
language), so that opens a bunch of interesting possibilities.

> > It would also be great if distributions (like Debian etc) packaged
> > Scintilla as a normal library, much like GTK or any other, with the
> > compiled library appearing in /lib/libscintilla.so (or such), the
> > headers at /usr/include/ScintillaView.h, and so on. To that end, we
> > might want to write and install a pkg-config file for Scintilla; this
> > would enable others to link to the system build of Scintilla easily,
> > e.g. with just `dependency("scintilla")` in Meson.
>
>    One hassle here is that Scintilla can be built with different GUI tool=
kits like Qt, Tk, and wxWidgets. If it's going to be installed into a globa=
l shared object directory then it may need a toolkit dongle on the name.

Sure, so that'd be libscintilla-gtk4.so and dependency('scintilla-gtk4') th=
en.

> > Included with the port is a little application called Scintilla Demo,
> > which is a very basic text editor, with tabs and menus and a
> > ScintillaView in each tab.
>
>    Unfortunately, I couldn't make this build with a bunch of 'incompatibl=
e pointer type' errors. This is on Ubuntu 25.10.
>
>    For anyone else wanting to experiment, the prerequisites I needed (ove=
r standard Scintilla) to 'apt install' were libgtk-4-dev, gobject-introspec=
tion, valac, and blueprint-compiler.

FWIW, only libgtk-4-dev from this list is required to build
libscintilla.so (i.e. 'make shared'), the rest are for the
introspection, Vala, and the demo.

I just tried building this on Ubuntu 25.10, using their provided
toolchain, and the packages you listed, and I only get some
"-Wincompatible-pointer-types" warnings (when building the demo, not
Scintilla itself). These warnings are unfortunately an issue with the
C code generated by Vala (it messes up things like 'const char * const
*' vs 'char **', which the compilers then warn about); I actually had
some work that attempted to fix that on the Vala compiler side. While
it's unfortunate, those are warnings, not erros, and can be ignored,
the build should still succeed, leaving you with an executable at
gtk4/ScintillaDemo/demo, does it not?

> > Could we host the HTML documentation autogenerated using gi-docgen
> > somewhere on scintilla.org? Is there a CI process?
>
>    There is no CI easily available on SourceForge. If the documentation i=
s easy to generate then it can go on scintilla.org <http://scintilla.org/>.

Please try 'make doc' (after installing gi-docgen), then see the
gtk4/doc/Scintilla-5/ directory (start at index.html).

In addition to actually writing more of the documentation, there are
some configuration improvements to be made there as well. We should
fill out more metadata for the project (see gi-docgen doc page [3])
such as authors and license.

Assuming Scintilla GTK 4 will eventually be upstream, for the
'source-location' feature, what's the appropriate way to link to a
specific line of code in a file on SourceForge? On GitHub and GitLab
(and many others), this is done with #L<line-number> suffix, e.g.
clicking on [4] should bring you directly to the definition of
gtk_accessible_set_accessible_parent in the GTK code base. How would I
do the same on SourceForge?

[3]: https://gnome.pages.gitlab.gnome.org/gi-docgen/project-configuration.h=
tml
[4]: https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gtk/gtkaccessible.c#L16=
3

Sergey

--=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/CAN9u%3DHfcAiuKR7hA%2BQpfiJ1YBKPi32h%3D07V1q-mbMx_r6LpnDQ%40mail.gm=
ail.com.