How to read theme link color and selection background color programmatically in GTK4

Hi,
I’m writing an WYSIWYG editor with GTK 4 (https://github.com/mmMike/marko-editor). For this I need to set the link color in a GtkTextTag. The gtk4-demo just uses “blue” here but that is not the themed color. The color needs to change e.g. with light and dark themes.

My current test (using Rust) was:

let ctx = textview.get_style_context().clone();
ctx.set_state(gtk::StateFlags::LINK);
println!("{:?}", ctx.lookup_color("color"));

But this only prints None, so not finding the respective color. I use “color” in the lookup, since it is the name of the CSS property. Without setting the flag, the color of the regular text is also not found. Which API call should give the answer, or is this just a bug in https://developer.gnome.org/gtk4/stable/GtkStyleContext.html#gtk-style-context-lookup-color?
The same question for the selection background color.

My version is 4.0.3 on Arch Linux.

Thank you.

This is frequently asked question that sits at the intersection of three issues:

  1. a fundamental misunderstanding of how CSS works
  2. baggage of the old GTK2 theming primitives and concepts
  3. the impedance mismatch between GtkTextTag and CSS styling

There is no such thing as “a color” in CSS: the state of the CSS style depends on the state and classes of a widget, plus its ancestors in the UI structure—hence the “cascading” part of “CSS”. You cannot just set the “LINK” state on a widget and hope for the best: that’s not how CSS works.

In this specific case: GtkTextView has no specific style for the “link” state on its own, and it’s inside a bunch of containers that have no style for the “link” state either, so of course you get nothing. Additionally, lookup_color() is meant to be used with named colors, not with CSS properties; you want get_color() instead.

The only widget with a “link” state is GtkLinkButton, so at the very least you’d have to query the color of that widget—using something like (in Python):

lb = Gtk.LinkButton(uri="https://www.gtk.org", visited=False)
link_color = lb.get_style_context().get_color(Gtk.StateFlags.LINK)
visited_link_color = lb.get_style_context().get_color(Gtk.StateFlags.VISITED)

Of course, this is not really correct; the theme could have some CSS selectors that style the GtkLinkButton very differently if it’s inside a specific container, or it could use a blended stack of gradients and textures for links, and you’d never really know, because you’re asking for a color.

It might be enough of an approximation for your use case.

Again, in CSS there’s no such thing as a “background color”: CSS only has stacks of background textures. A “solid color” is just a 1×1px texture with a single color, stretched out over the background rectangle. Asking for a color is not really possible. If the theme is Adwaita, or has the same named colors, you could ask for theme_selected_bg_color and theme_selected_fg_color:

tv = Gtk.TextView()
selected_bg_color = tv.get_style_context().lookup_color('theme_selected_bg_color')
selected_fg_color = tv.get_style_context().lookup_color('theme_selected_fg_color')

and you’ll get the solid colors used by the theme. Of course, this only applies to themes with named colors.


In either case—link and selection colors—you will need fallback values, and you will need to deal with things looking differently from the user’s own theme. Plus, it’s not like you can know if theme in use is dark or not, which means you have a manual toggle for the “please use dark colors” case.

My personal recommendation is to have your own style for your text view widget, including the link state and/or style classes, and define the link and selection colors you want to use.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.