detached a5abb19

fix(theme): avoid redundant GTK font resets

Skip resetting gtk-font-name when the effective scaled font has not changed. This keeps repeated theme reapplies from doing unnecessary display-wide font work.
commit
a5abb190af008a52ec412389d1c990a483144832
author
brice · · 2026-04-08 05:33 UTC
parent
c8834e5
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +15 -1
M internal/ui/theme/manager.go +9 -1
@@ -23,6 +23,7 @@ type Manager struct {
2323 fonts FontConfig
2424 modeColors ModeColors // Modal mode indicator colors
2525 cssProvider *gtk.CssProvider
26+ appliedFont string
2627 colorResolver port.ColorSchemeResolver // Resolver for dynamic detection
2728 }
2829
@@ -169,6 +170,10 @@ func formatGTKFontName(family string, uiScale float64) string {
169170 return fmt.Sprintf("%s %d", family, size)
170171 }
171172
173+func shouldApplyGTKFontName(current, next string) bool {
174+ return next != "" && next != current
175+}
176+
172177 // ApplyToDisplay loads the theme CSS into the display.
173178 func (m *Manager) ApplyToDisplay(ctx context.Context, display *gdk.Display) {
174179 log := logging.FromContext(ctx)
@@ -186,8 +191,11 @@ func (m *Manager) ApplyToDisplay(ctx context.Context, display *gdk.Display) {
186191 settings := gtk.SettingsGetForDisplay(display)
187192 if settings == nil {
188193 log.Warn().Msg("cannot apply theme font scaling: settings unavailable")
189- } else {
194+ } else if shouldApplyGTKFontName(m.appliedFont, fontName) {
190195 settings.SetPropertyGtkFontName(fontName)
196+ m.appliedFont = fontName
197+ settings.Unref()
198+ } else {
191199 settings.Unref()
192200 }
193201
@@ -23,6 +23,7 @@ type Manager struct {
23 fonts FontConfig23 fonts FontConfig
24 modeColors ModeColors // Modal mode indicator colors24 modeColors ModeColors // Modal mode indicator colors
25 cssProvider *gtk.CssProvider25 cssProvider *gtk.CssProvider
26+ appliedFont string
26 colorResolver port.ColorSchemeResolver // Resolver for dynamic detection27 colorResolver port.ColorSchemeResolver // Resolver for dynamic detection
27 }28 }
28 29
@@ -169,6 +170,10 @@ func formatGTKFontName(family string, uiScale float64) string {
169 return fmt.Sprintf("%s %d", family, size)170 return fmt.Sprintf("%s %d", family, size)
170 }171 }
171 172
173+func shouldApplyGTKFontName(current, next string) bool {
174+ return next != "" && next != current
175+}
176+
172 // ApplyToDisplay loads the theme CSS into the display.177 // ApplyToDisplay loads the theme CSS into the display.
173 func (m *Manager) ApplyToDisplay(ctx context.Context, display *gdk.Display) {178 func (m *Manager) ApplyToDisplay(ctx context.Context, display *gdk.Display) {
174 log := logging.FromContext(ctx)179 log := logging.FromContext(ctx)
@@ -186,8 +191,11 @@ func (m *Manager) ApplyToDisplay(ctx context.Context, display *gdk.Display) {
186 settings := gtk.SettingsGetForDisplay(display)191 settings := gtk.SettingsGetForDisplay(display)
187 if settings == nil {192 if settings == nil {
188 log.Warn().Msg("cannot apply theme font scaling: settings unavailable")193 log.Warn().Msg("cannot apply theme font scaling: settings unavailable")
189- } else {194+ } else if shouldApplyGTKFontName(m.appliedFont, fontName) {
190 settings.SetPropertyGtkFontName(fontName)195 settings.SetPropertyGtkFontName(fontName)
196+ m.appliedFont = fontName
197+ settings.Unref()
198+ } else {
191 settings.Unref()199 settings.Unref()
192 }200 }
193 201
M internal/ui/theme/manager_test.go +6 -0
@@ -322,3 +322,9 @@ func TestFormatGTKFontName_DefaultsScaleAndRoundsToNearestPoint(t *testing.T) {
322322 assert.Equal(t, "Inter 11", formatGTKFontName("Inter", 0))
323323 assert.Equal(t, "Inter 12", formatGTKFontName("Inter", 1.05))
324324 }
325+
326+func TestShouldApplyGTKFontName(t *testing.T) {
327+ assert.True(t, shouldApplyGTKFontName("", "Fira Sans 14"))
328+ assert.False(t, shouldApplyGTKFontName("Fira Sans 14", "Fira Sans 14"))
329+ assert.False(t, shouldApplyGTKFontName("Fira Sans 14", ""))
330+}
@@ -322,3 +322,9 @@ func TestFormatGTKFontName_DefaultsScaleAndRoundsToNearestPoint(t *testing.T) {
322 assert.Equal(t, "Inter 11", formatGTKFontName("Inter", 0))322 assert.Equal(t, "Inter 11", formatGTKFontName("Inter", 0))
323 assert.Equal(t, "Inter 12", formatGTKFontName("Inter", 1.05))323 assert.Equal(t, "Inter 12", formatGTKFontName("Inter", 1.05))
324 }324 }
325+
326+func TestShouldApplyGTKFontName(t *testing.T) {
327+ assert.True(t, shouldApplyGTKFontName("", "Fira Sans 14"))
328+ assert.False(t, shouldApplyGTKFontName("Fira Sans 14", "Fira Sans 14"))
329+ assert.False(t, shouldApplyGTKFontName("Fira Sans 14", ""))
330+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close