feat: GTK3-only theming overhaul—new theme service (discover/import/inherits), layered CSS+settings.ini apply w/ safe rollback + caching; widget/xtext palette mapping + all-colors editor; lots of win32/CI libarchive plumbing + installer assets;

This commit is contained in:
2026-03-04 23:28:01 -07:00
parent 43374f4fae
commit 50346683a1
56 changed files with 5642 additions and 754 deletions

View File

@@ -13,11 +13,16 @@ struct session *lastact_sess;
struct zoitechatprefs prefs;
static gboolean stub_dark_active;
static gboolean stub_gtk3_active;
static ThemeSemanticToken stub_last_color_token;
static int stub_runtime_get_color_calls;
static int stub_runtime_widget_calls;
static int stub_runtime_xtext_calls;
static int stub_runtime_xtext_mapped_calls;
static size_t stub_runtime_xtext_last_len;
static ThemeGtkPaletteMap stub_last_gtk_map;
static gboolean stub_last_gtk_map_valid;
static gboolean gtk_available;
static GdkRGBA stub_light_colors[THEME_TOKEN_COUNT];
static GdkRGBA stub_dark_colors[THEME_TOKEN_COUNT];
@@ -70,6 +75,13 @@ theme_runtime_dark_set_color (ThemeSemanticToken token, const GdkRGBA *col)
(void) col;
}
gboolean
theme_runtime_mode_has_user_colors (gboolean dark_mode)
{
(void) dark_mode;
return FALSE;
}
gboolean
theme_runtime_get_color (ThemeSemanticToken token, GdkRGBA *out_rgba)
{
@@ -109,6 +121,36 @@ theme_runtime_is_dark_active (void)
return stub_dark_active;
}
void
theme_runtime_get_widget_style_values_mapped (const ThemeGtkPaletteMap *gtk_map, ThemeWidgetStyleValues *out_values)
{
(void) gtk_map;
theme_runtime_get_widget_style_values (out_values);
}
void
theme_runtime_get_xtext_colors_mapped (const ThemeGtkPaletteMap *gtk_map, XTextColor *palette, size_t palette_len)
{
size_t i;
stub_runtime_xtext_mapped_calls++;
stub_last_gtk_map = *gtk_map;
stub_last_gtk_map_valid = TRUE;
stub_runtime_xtext_last_len = palette_len;
for (i = 0; i < palette_len; i++)
{
palette[i].red = (unsigned short) (100 + i);
palette[i].green = (unsigned short) (200 + i);
palette[i].blue = (unsigned short) (300 + i);
}
}
gboolean
theme_gtk3_is_active (void)
{
return stub_gtk3_active;
}
static gboolean
rgba_equal (const GdkRGBA *a, const GdkRGBA *b)
{
@@ -127,7 +169,10 @@ reset_stubs (void)
stub_runtime_get_color_calls = 0;
stub_runtime_widget_calls = 0;
stub_runtime_xtext_calls = 0;
stub_runtime_xtext_mapped_calls = 0;
stub_runtime_xtext_last_len = 0;
stub_last_gtk_map_valid = FALSE;
stub_gtk3_active = FALSE;
for (i = 0; i < THEME_TOKEN_COUNT; i++)
{
g_snprintf (light, sizeof (light), "#%02x%02x%02x", (unsigned int) (i + 1), 0x11, 0x22);
@@ -137,6 +182,15 @@ reset_stubs (void)
}
}
static gboolean
rgba_close (const GdkRGBA *a, const GdkRGBA *b)
{
return fabs (a->red - b->red) < 0.0001 &&
fabs (a->green - b->green) < 0.0001 &&
fabs (a->blue - b->blue) < 0.0001 &&
fabs (a->alpha - b->alpha) < 0.0001;
}
static void
test_access_semantic_token_routes_directly (void)
{
@@ -204,6 +258,62 @@ test_access_widget_style_forwarding (void)
g_assert_true (fabs (values.foreground.green - (0xfc / 255.0)) < 0.0001);
}
static void
test_access_xtext_palette_widget_mapping_when_gtk3_active (void)
{
GtkWidget *window;
GtkWidget *label;
GtkStyleContext *context;
GtkCssProvider *provider;
XTextColor palette[2] = { 0 };
GdkRGBA expected;
if (!gtk_available)
{
g_test_skip ("GTK display not available");
return;
}
reset_stubs ();
stub_gtk3_active = TRUE;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
label = gtk_label_new ("mapped");
gtk_container_add (GTK_CONTAINER (window), label);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider,
"label { color: #112233; background-color: #445566; }"
"label:selected { color: #778899; background-color: #aabbcc; }"
"label:link { color: #123456; }",
-1,
NULL);
context = gtk_widget_get_style_context (label);
gtk_style_context_add_provider (context,
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
gtk_widget_realize (window);
theme_get_xtext_colors_for_widget (label, palette, G_N_ELEMENTS (palette));
g_assert_cmpint (stub_runtime_xtext_mapped_calls, ==, 1);
g_assert_cmpint (stub_runtime_xtext_calls, ==, 0);
g_assert_true (stub_last_gtk_map_valid);
g_assert_true (gdk_rgba_parse (&expected, "#112233"));
g_assert_true (rgba_close (&stub_last_gtk_map.text_foreground, &expected));
g_assert_true (gdk_rgba_parse (&expected, "#445566"));
g_assert_true (rgba_close (&stub_last_gtk_map.text_background, &expected));
g_assert_true (gdk_rgba_parse (&expected, "#778899"));
g_assert_true (rgba_close (&stub_last_gtk_map.selection_foreground, &expected));
g_assert_true (gdk_rgba_parse (&expected, "#aabbcc"));
g_assert_true (rgba_close (&stub_last_gtk_map.selection_background, &expected));
g_assert_true (gdk_rgba_parse (&expected, "#123456"));
g_assert_true (rgba_close (&stub_last_gtk_map.accent, &expected));
g_assert_cmpuint (palette[0].red, ==, 100);
g_assert_cmpuint (palette[1].green, ==, 201);
gtk_widget_destroy (window);
g_object_unref (provider);
}
static void
test_access_dark_light_switch_affects_token_consumers (void)
{
@@ -229,8 +339,11 @@ main (int argc, char **argv)
g_test_add_func ("/theme/access/semantic_token_routes_directly", test_access_semantic_token_routes_directly);
g_test_add_func ("/theme/access/token_routes_without_legacy_accessor", test_access_token_routes_without_legacy_accessor);
g_test_add_func ("/theme/access/xtext_palette_forwarding", test_access_xtext_palette_forwarding);
g_test_add_func ("/theme/access/xtext_palette_widget_mapping_when_gtk3_active",
test_access_xtext_palette_widget_mapping_when_gtk3_active);
g_test_add_func ("/theme/access/widget_style_forwarding", test_access_widget_style_forwarding);
g_test_add_func ("/theme/access/dark_light_switch_affects_token_consumers",
test_access_dark_light_switch_affects_token_consumers);
gtk_available = gtk_init_check (&argc, &argv);
return g_test_run ();
}