The venerable GtkSourceView project provides a
GtkWidget for various code languages. It has a number of features including the most basic, showing a line number next to your line of text.
It turns out that takes a lot more effort than you might think, particularly when you want to do it at 240hz with kinetic scrolling on crappy hardware that may barely have enough engine for the GL driver.
First, you need to have the line number as a string to be rendered. For a few years now, GtkSourceView has code which will optimizes the translation from number to strings with minimal overhead. If you
g_snprintf(), you’re gonna be slow.
After that you need to know the X,Y coordinate of the particular line within the gutter and it’s line height when wrapped. Then you need to know the measured pixel width of the line number string. Further still you need the xalign/yalign and xpad/ypad to apply proper alignments based on application needs. You may even want to align based on first line, last wrapped line, or the entire cell.
In the GtkSourceView 5.x port I created GtkSourceGutterLines which can cache some of that information. It’s still extremely expensive to calculate but at least we only have to do it once per-frame now no matter how many
GtkSourceGutterRenderer are packed into the
After that, we can create (well recycle) a
PangoLayout to setup what we want to render. Except, that is also extremely expensive because you need to measure the contents and go through a
PangoRenderer for each line you render.
If you are kinetic scrolling through a
GtkSourceView with something like a touch pad there is a good chance that a decent chunk of CPU is wasted on line numbers. Nicht gut.
Astute readers will remember that I spent a little time making VTE render faster this cycle and one of the ways to do that was to avoid
PangoLayout. We can do the same here as it’s extremely simple and controlled input. Just cache the
0..9 and use that to build a suitable
PangoGlyphString. Armed with a
PangoFont and said string, we can use
gtk_snapshot_append_node() instead of
A quick hour or so later I have given you back double digit CPU percentages but more importantly, smoother and lower latency input.
Sysprof makes it easy to locate, triage, and verify performance fixes.
That said, in the future, if I were redesigning something to replace all of this I’d probably just use widgets for each line number and recycle them like
GtkListView. Then you get
GtkWidget render node caching for free. C’est la vie.