Skip to content

Commit

Permalink
Drop theme color usage for GTK4 migration
Browse files Browse the repository at this point in the history
  • Loading branch information
lwindolf committed Jun 21, 2024
1 parent b0b1d89 commit eb0ce63
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 220 deletions.
214 changes: 15 additions & 199 deletions src/render.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @file render.c generic GTK theme and XSLT rendering handling
*
* Copyright (C) 2006-2023 Lars Windolf <[email protected]>
* Copyright (C) 2006-2024 Lars Windolf <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -42,9 +42,10 @@
#include "xml.h"

/* Liferea renders items and feed info using self-generated HTML in a WebkitGTK
widget. While this provides rendering flexibility it also requires us to do
CSS color theming to match the GTK theme and localization of HTML rendered
UI literals.
widget. While this provides rendering flexibility. Starting with GTK 4 there
is no access to theme colors anymore. So Liferea has to rely one the color
defaults provided by WebkitGTK and to refrain from any background color
effects.
To separate code and layout and to easily localize the layout it is
provided in the form of automake XSL stylesheet templates.
Expand Down Expand Up @@ -141,218 +142,33 @@ render_load_stylesheet (const gchar *xsltName)
}

/** cached CSS definitions */
static GString *css = NULL;
static GString *userCss = NULL;

/** widget background theme colors as 8bit HTML RGB code */
typedef struct themeColor {
const gchar *name;
gchar *value;
} *themeColorPtr;

static GSList *themeColors = NULL;

/* Determining of theme colors, to be inserted in CSS */
static themeColorPtr
render_calculate_theme_color (const gchar *name, GdkColor themeColor)
{
themeColorPtr tc;
gushort r, g, b;

r = themeColor.red / 256;
g = themeColor.green / 256;
b = themeColor.blue / 256;

tc = g_new0 (struct themeColor, 1);
tc->name = name;
tc->value = g_strdup_printf ("%.2X%.2X%.2X", r, g, b);
debug (DEBUG_HTML, "theme color \"%s\" is %s", tc->name, tc->value);

return tc;
}

static void
render_theme_color_free (themeColorPtr tc)
{
g_free (tc->value);
g_free (tc);
}

static gint
render_get_rgb_distance (GdkColor *c1, GdkColor *c2)
{
return abs(
(299 * c1->red/256 +
587 * c1->green/256 +
114 * c1->blue/256) -
(299 * c2->red/256 +
587 * c2->green/256 +
114 * c2->blue/256)
) / 1000;
}

static void
rgba_to_color (GdkColor *color, GdkRGBA *rgba)
{
color->red = lrint (rgba->red * 65535);
color->green = lrint (rgba->green * 65535);
color->blue = lrint (rgba->blue * 65535);
}

void
render_init_theme_colors (GtkWidget *widget)
{
GtkStyle *style;
GtkStyleContext *sctxt;
GdkColor color;
GdkRGBA rgba;

/* Clear cached previous stylesheet */
if (css) {
g_string_free (css, TRUE);
css = NULL;
}
if (userCss) {
g_string_free (userCss, TRUE);
userCss = NULL;
}
if (themeColors) {
g_slist_free_full (themeColors, (GDestroyNotify)render_theme_color_free);
themeColors = NULL;
}

style = gtk_widget_get_style (widget);
sctxt = gtk_widget_get_style_context (widget);

themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-FG", style->fg[GTK_STATE_NORMAL]));
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-BG", style->bg[GTK_STATE_NORMAL]));
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-LIGHT", style->light[GTK_STATE_NORMAL]));
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-DARK", style->dark[GTK_STATE_NORMAL]));
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-MID", style->mid[GTK_STATE_NORMAL]));

/* Sanity check text+base color as this causes many problems on dark
themes. If brightness distance is not enough we set text to fg/bg
which is always safe. */
if (render_get_rgb_distance (&style->base[GTK_STATE_NORMAL], &style->text[GTK_STATE_NORMAL]) > 150) {
// FIXME: Use theme labels instead of GTK-COLOR-<something> (e.g. CSS-BACKGROUND)
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-BASE", style->base[GTK_STATE_NORMAL]));
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-TEXT", style->text[GTK_STATE_NORMAL]));
} else {
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-BASE", style->bg[GTK_STATE_NORMAL]));
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-TEXT", style->fg[GTK_STATE_NORMAL]));
}

gtk_style_context_get_color (sctxt, GTK_STATE_FLAG_LINK, &rgba);
rgba_to_color (&color, &rgba);
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-NORMAL-LINK", color));

gtk_style_context_get_color (sctxt, GTK_STATE_FLAG_VISITED, &rgba);
rgba_to_color (&color, &rgba);
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("GTK-COLOR-VISITED-LINK", color));

if (conf_get_dark_theme()) {
debug (DEBUG_HTML, "Dark GTK theme detected.");

themeColors = g_slist_append (themeColors, render_calculate_theme_color ("FEEDLIST_UNREAD_BG", style->text[GTK_STATE_NORMAL]));
/* Try nice foreground with 'fg' color (note: distance 50 is enough because it should be non-intrusive) */
if (render_get_rgb_distance (&style->text[GTK_STATE_NORMAL], &style->fg[GTK_STATE_NORMAL]) > 50)
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("FEEDLIST_UNREAD_FG", style->fg[GTK_STATE_NORMAL]));
else
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("FEEDLIST_UNREAD_FG", style->bg[GTK_STATE_NORMAL]));
} else {
debug (DEBUG_HTML, "Light GTK theme detected.");

themeColors = g_slist_append (themeColors, render_calculate_theme_color ("FEEDLIST_UNREAD_FG", style->bg[GTK_STATE_NORMAL]));
/* Try nice foreground with 'dark' color (note: distance 50 is enough because it should be non-intrusive) */
if (render_get_rgb_distance (&style->dark[GTK_STATE_NORMAL], &style->bg[GTK_STATE_NORMAL]) > 50)
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("FEEDLIST_UNREAD_BG", style->dark[GTK_STATE_NORMAL]));
else
themeColors = g_slist_append (themeColors, render_calculate_theme_color ("FEEDLIST_UNREAD_BG", style->fg[GTK_STATE_NORMAL]));
}
}

static gchar *
render_set_theme_colors (gchar *css)
{
GSList *iter = themeColors;

while (iter) {
themeColorPtr tc = (themeColorPtr)iter->data;
css = common_strreplace (css, tc->name, tc->value);
iter = g_slist_next (iter);
}

return css;
}

const gchar *
render_get_theme_color (const gchar *name)
{
GSList *iter;

g_return_val_if_fail (themeColors != NULL, NULL);

iter = themeColors;
while (iter) {
themeColorPtr tc = (themeColorPtr)iter->data;
if (g_str_equal (name, tc->name))
return tc->value;
iter = g_slist_next (iter);
}

return NULL;
}
static gchar *css = NULL;
static gchar *userCss = NULL;

const gchar *
render_get_default_css (void)
{
if (!css) {
gchar *defaultStyleSheetFile;
gchar *tmp;

g_return_val_if_fail (themeColors != NULL, NULL);

css = g_string_new(NULL);

defaultStyleSheetFile = g_build_filename (PACKAGE_DATA_DIR, PACKAGE, "css", "liferea.css", NULL);

if (g_file_get_contents(defaultStyleSheetFile, &tmp, NULL, NULL)) {
tmp = render_set_theme_colors(tmp);
g_string_append(css, tmp);
g_free(tmp);
} else {
g_error ("Loading %s failed.", defaultStyleSheetFile);
}
gchar *filename = g_build_filename (PACKAGE_DATA_DIR, PACKAGE, "css", "liferea.css", NULL);

g_free(defaultStyleSheetFile);
g_file_get_contents (filename, &css, NULL, NULL);
g_free (filename);
}

return css->str;
return css;
}

const gchar *
render_get_user_css (void)
{
if (!userCss) {
gchar *userStyleSheetFile;
gchar *tmp;

g_return_val_if_fail (themeColors != NULL, NULL);

userCss = g_string_new (NULL);

userStyleSheetFile = common_create_config_filename ("liferea.css");

if (g_file_get_contents (userStyleSheetFile, &tmp, NULL, NULL)) {
tmp = render_set_theme_colors (tmp);
g_string_append (userCss, tmp);
g_free (tmp);
}
gchar *filename = common_create_config_filename ("liferea.css");

g_free (userStyleSheetFile);
g_file_get_contents (filename, &userCss, NULL, NULL);
g_free (filename);
}

return userCss->str;
return userCss;
}

gchar *
Expand Down
34 changes: 16 additions & 18 deletions src/ui/feed_list_view.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @file feed_list_view.c the feed list in a GtkTreeView
*
* Copyright (C) 2004-2022 Lars Windolf <[email protected]>
* Copyright (C) 2004-2024 Lars Windolf <[email protected]>
* Copyright (C) 2004-2006 Nathan J. Conrad <[email protected]>
* Copyright (C) 2005 Raphael Slinckx <[email protected]>
*
Expand Down Expand Up @@ -33,7 +33,6 @@
#include "folder.h"
#include "net_monitor.h"
#include "newsbin.h"
#include "render.h"
#include "vfolder.h"
#include "ui/icons.h"
#include "ui/liferea_dialog.h"
Expand Down Expand Up @@ -777,26 +776,25 @@ feed_list_view_update_node (const gchar *nodeId)
gchar *label, *count = NULL;
guint labeltype;
nodePtr node;

static gchar *countColor = NULL;
static gchar *countColor = NULL;

/* Until GTK3 we used real theme colors here. Nowadays GTK simply knows
that we do not need to know about them and helpfully prevents us from
accessing them. So we use hard-coded colors that hopefully fit all the
themes out there.
And yes of course with to much time on my hand I could implement
my own renderer widget... */
if (conf_get_dark_theme ())
countColor = "foreground='#ddd' background='#444'";
else
countColor = "foreground='#fff' background='#aaa'";

node = node_from_id (nodeId);
iter = feed_list_view_to_iter (nodeId);
if (!iter)
return;

/* Initialize unread item color Pango CSS */
if (!countColor) {
const gchar *bg = NULL, *fg = NULL;

bg = render_get_theme_color ("FEEDLIST_UNREAD_BG");
fg = render_get_theme_color ("FEEDLIST_UNREAD_FG");
if (fg && bg) {
countColor = g_strdup_printf ("foreground='#%s' background='#%s'", fg, bg);
debug (DEBUG_HTML, "Feed list unread CSS: %s", countColor);
}
}

labeltype = NODE_TYPE (node)->capabilities;
labeltype &= (NODE_CAPABILITY_SHOW_UNREAD_COUNT |
NODE_CAPABILITY_SHOW_ITEM_COUNT);
Expand All @@ -810,10 +808,10 @@ feed_list_view_update_node (const gchar *nodeId)
NODE_CAPABILITY_SHOW_ITEM_COUNT:
/* treat like show unread count */
case NODE_CAPABILITY_SHOW_UNREAD_COUNT:
count = g_strdup_printf ("<span weight='bold' %s> %u </span>", countColor?countColor:"", node->unreadCount);
count = g_strdup_printf ("<span weight='bold' %s> %u </span>", countColor, node->unreadCount);
break;
case NODE_CAPABILITY_SHOW_ITEM_COUNT:
count = g_strdup_printf ("<span weight='bold' %s> %u </span>", countColor?countColor:"", node->itemCount);
count = g_strdup_printf ("<span weight='bold' %s> %u </span>", countColor, node->itemCount);
break;
default:
break;
Expand Down
3 changes: 0 additions & 3 deletions src/ui/liferea_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
#include "net_monitor.h"
#include "newsbin.h"
#include "plugins_engine.h"
#include "render.h"
#include "social.h"
#include "vfolder.h"
#include "fl_sources/node_source.h"
Expand Down Expand Up @@ -1359,7 +1358,6 @@ liferea_shell_create (GtkApplication *app, const gchar *overrideWindowState, gin
gtk_grid_attach_next_to (GTK_GRID (liferea_shell_lookup ("vbox1")), shell->toolbar, NULL, GTK_POS_TOP, 1,1);

gtk_widget_show_all(GTK_WIDGET(shell->toolbar));
render_init_theme_colors (GTK_WIDGET (shell->window));
g_signal_connect (G_OBJECT (shell->window), "style-updated", G_CALLBACK(liferea_shell_rebuild_css), NULL);

/* 3.) setup status bar */
Expand Down Expand Up @@ -1541,7 +1539,6 @@ liferea_shell_get_window (void)
void
liferea_shell_rebuild_css (void)
{
render_init_theme_colors (GTK_WIDGET (shell->window));
itemview_style_update ();
}

0 comments on commit eb0ce63

Please sign in to comment.