From 4f2938d957b3187e04962ca0e2cabda6d24c926e Mon Sep 17 00:00:00 2001 From: deepend-tildeclub Date: Wed, 8 Apr 2026 17:47:51 -0600 Subject: [PATCH] Add .hct support to colors.conf import --- src/common/gtk3-theme-service.c | 88 +++++++++++++++++++ src/common/gtk3-theme-service.h | 1 + .../test-theme-preferences-gtk3-populate.c | 10 +++ src/fe-gtk/theme/theme-preferences.c | 40 ++++++--- 4 files changed, 129 insertions(+), 10 deletions(-) diff --git a/src/common/gtk3-theme-service.c b/src/common/gtk3-theme-service.c index 83be71f7..26bfe5cd 100644 --- a/src/common/gtk3-theme-service.c +++ b/src/common/gtk3-theme-service.c @@ -1221,6 +1221,94 @@ extract_archive (const char *source, GError **error) #endif } +static char * +path_find_first_file_recursive (const char *root, const char *name, int depth) +{ + GDir *dir; + const char *entry; + + if (!root || !name || depth < 0 || !g_file_test (root, G_FILE_TEST_IS_DIR)) + return NULL; + + { + char *candidate = g_build_filename (root, name, NULL); + if (g_file_test (candidate, G_FILE_TEST_IS_REGULAR)) + return candidate; + g_free (candidate); + } + + if (depth == 0) + return NULL; + + dir = g_dir_open (root, 0, NULL); + if (!dir) + return NULL; + + while ((entry = g_dir_read_name (dir)) != NULL) + { + char *child = g_build_filename (root, entry, NULL); + char *found = NULL; + + if (g_file_test (child, G_FILE_TEST_IS_DIR)) + found = path_find_first_file_recursive (child, name, depth - 1); + g_free (child); + if (found) + { + g_dir_close (dir); + return found; + } + } + + g_dir_close (dir); + return NULL; +} + +gboolean +zoitechat_gtk3_theme_service_read_archive_text_file (const char *archive_path, const char *name, char **contents, GError **error) +{ + char *root; + char *path; + gboolean ok; + GError *local_error = NULL; + + if (contents) + *contents = NULL; + if (!archive_path || !*archive_path) + return g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "No archive path provided."), FALSE; + if (!name || !*name) + return g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "No file name provided."), FALSE; + if (!contents) + return g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "No output buffer provided."), FALSE; + + root = extract_archive (archive_path, error); + if (!root) + return FALSE; + + path = path_find_first_file_recursive (root, name, 8); + if (!path) + { + remove_tree (root); + g_free (root); + return g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Requested file was not found in archive."), FALSE; + } + + ok = g_file_get_contents (path, contents, NULL, &local_error); + g_free (path); + remove_tree (root); + g_free (root); + + if (!ok) + { + if (error) + *error = local_error; + else + g_clear_error (&local_error); + return FALSE; + } + + return TRUE; +} + gboolean zoitechat_gtk3_theme_service_import (const char *source_path, char **imported_id, GError **error) { diff --git a/src/common/gtk3-theme-service.h b/src/common/gtk3-theme-service.h index 4ba56ad4..e92a9d56 100644 --- a/src/common/gtk3-theme-service.h +++ b/src/common/gtk3-theme-service.h @@ -48,5 +48,6 @@ gboolean zoitechat_gtk3_theme_service_remove_user_theme (const char *theme_id, G char *zoitechat_gtk3_theme_pick_css_dir_for_minor (const char *theme_root, int preferred_minor); char *zoitechat_gtk3_theme_pick_css_dir (const char *theme_root); GPtrArray *zoitechat_gtk3_theme_build_inheritance_chain (const char *theme_root); +gboolean zoitechat_gtk3_theme_service_read_archive_text_file (const char *archive_path, const char *name, char **contents, GError **error); #endif diff --git a/src/fe-gtk/theme/tests/test-theme-preferences-gtk3-populate.c b/src/fe-gtk/theme/tests/test-theme-preferences-gtk3-populate.c index f4834e87..13ffcd01 100644 --- a/src/fe-gtk/theme/tests/test-theme-preferences-gtk3-populate.c +++ b/src/fe-gtk/theme/tests/test-theme-preferences-gtk3-populate.c @@ -188,6 +188,16 @@ zoitechat_gtk3_theme_service_import (const char *source_path, char **imported_id return FALSE; } +gboolean +zoitechat_gtk3_theme_service_read_archive_text_file (const char *archive_path, const char *name, char **contents, GError **error) +{ + (void)archive_path; + (void)name; + (void)contents; + (void)error; + return FALSE; +} + gboolean zoitechat_gtk3_theme_service_remove_user_theme (const char *theme_id, GError **error) { diff --git a/src/fe-gtk/theme/theme-preferences.c b/src/fe-gtk/theme/theme-preferences.c index 97c8458e..95296471 100644 --- a/src/fe-gtk/theme/theme-preferences.c +++ b/src/fe-gtk/theme/theme-preferences.c @@ -1038,40 +1038,60 @@ static void theme_preferences_import_colors_conf_cb (GtkWidget *button, gpointer user_data) { gboolean *color_change_flag = user_data; - GtkWidget *dialog; + GtkFileChooserNative *dialog; char *path; + char *lower_path; char *cfg; GError *error = NULL; gboolean any_imported = FALSE; ThemeSemanticToken token; + GtkFileFilter *filter; - dialog = gtk_file_chooser_dialog_new (_("Import colors.conf colors"), + dialog = gtk_file_chooser_native_new (_("Import colors.conf colors"), GTK_WINDOW (gtk_widget_get_toplevel (button)), GTK_FILE_CHOOSER_ACTION_OPEN, - _("_Cancel"), GTK_RESPONSE_CANCEL, - _("_Import"), GTK_RESPONSE_ACCEPT, - NULL); - gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE); + _("_Import"), + _("_Cancel")); gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE); + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("Theme colors (*.conf, *.hct)")); + gtk_file_filter_add_pattern (filter, "*.conf"); + gtk_file_filter_add_pattern (filter, "*.hct"); + gtk_file_filter_add_pattern (filter, "*.HCT"); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT) + if (gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT) { - gtk_widget_destroy (dialog); + g_object_unref (dialog); return; } path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); - gtk_widget_destroy (dialog); + g_object_unref (dialog); if (!path) return; - if (!g_file_get_contents (path, &cfg, NULL, &error)) + lower_path = g_ascii_strdown (path, -1); + if (g_str_has_suffix (lower_path, ".hct")) + { + if (!zoitechat_gtk3_theme_service_read_archive_text_file (path, "colors.conf", &cfg, &error)) + { + theme_preferences_show_import_error (button, _("Failed to read colors.conf from .hct file.")); + g_clear_error (&error); + g_free (lower_path); + g_free (path); + return; + } + } + else if (!g_file_get_contents (path, &cfg, NULL, &error)) { theme_preferences_show_import_error (button, _("Failed to read colors.conf file.")); g_clear_error (&error); + g_free (lower_path); g_free (path); return; } + g_free (lower_path); for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++) {