Fixed the GTK3 dropdown regression by switching from combo-box ID/path behavior to an explicit internal index→full-path mapping (gtk3_theme_paths) while keeping user-facing theme names in the dropdown text. This preserves internal full path mapping without relying on active-id lookups.

Kept GTK3 discovery restricted to the app-local install directory (get_xdir()/gtk3-themes) and only included directories containing gtk-3.0/gtk.css.

Ensured theme selection is restored/saved correctly by matching saved pref name against discovered entries and applying via the selected internal path, then persisting prefs.hex_gui_gtk3_theme_name with save_config().

Preserved/updated empty-invalid status behavior to show “No valid GTK3 themes found.” when no usable themes exist (or saved selection is invalid).

Added proper cleanup for the new internal mapping via setup_theme_ui_free and wired it into g_object_set_data_full.
This commit is contained in:
2026-02-26 00:56:17 -07:00
parent 1c1110847c
commit 607faa80ca

View File

@@ -74,8 +74,24 @@ typedef struct
GtkWidget *gtk3_apply_button; GtkWidget *gtk3_apply_button;
GtkWidget *gtk3_use_system_button; GtkWidget *gtk3_use_system_button;
GtkWidget *gtk3_status_label; GtkWidget *gtk3_status_label;
GPtrArray *gtk3_theme_paths;
} setup_theme_ui; } setup_theme_ui;
static void
setup_theme_ui_free (gpointer data)
{
setup_theme_ui *ui = data;
if (!ui)
return;
if (ui->gtk3_theme_paths)
g_ptr_array_free (ui->gtk3_theme_paths, TRUE);
g_free (ui);
}
enum enum
{ {
ST_END, ST_END,
@@ -2001,105 +2017,94 @@ cleanup:
} }
static void static void
setup_theme_populate_gtk3 (setup_theme_ui *ui) setup_gtk3_theme_populate (setup_theme_ui *ui)
{ {
const char *theme_dirs[] = { char *themes_dir;
NULL,
g_get_home_dir (),
NULL,
"/usr/local/share/themes",
"/usr/share/themes",
NULL
};
GHashTable *seen;
GPtrArray *names;
GtkTreeModel *model; GtkTreeModel *model;
GtkTreeIter iter; GtkTreeIter iter;
GtkSettings *settings; GDir *dir;
char *current_theme = NULL; const char *name;
gboolean have_valid_theme = FALSE;
gint active = -1;
guint i; guint i;
theme_dirs[1] = g_build_filename (g_get_home_dir (), ".local", "share", "themes", NULL); themes_dir = g_build_filename (get_xdir (), "gtk3-themes", NULL);
theme_dirs[0] = g_build_filename (get_xdir (), "gtk3-themes", NULL); g_mkdir_with_parents (themes_dir, 0700);
seen = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->gtk3_combo));
names = g_ptr_array_new_with_free_func (g_free); while (gtk_tree_model_get_iter_first (model, &iter))
gtk_combo_box_text_remove (GTK_COMBO_BOX_TEXT (ui->gtk3_combo), 0);
for (i = 0; i < G_N_ELEMENTS (theme_dirs); i++) if (!ui->gtk3_theme_paths)
ui->gtk3_theme_paths = g_ptr_array_new_with_free_func (g_free);
else
g_ptr_array_set_size (ui->gtk3_theme_paths, 0);
dir = g_dir_open (themes_dir, 0, NULL);
if (dir)
{ {
const char *dir_path = theme_dirs[i];
GDir *dir;
const char *name;
if (!dir_path || !g_file_test (dir_path, G_FILE_TEST_IS_DIR))
continue;
dir = g_dir_open (dir_path, 0, NULL);
if (!dir)
continue;
while ((name = g_dir_read_name (dir))) while ((name = g_dir_read_name (dir)))
{ {
char *theme_path; char *theme_path;
char *gtk3_path; char *gtk_css_path;
theme_path = g_build_filename (themes_dir, name, NULL);
gtk_css_path = g_build_filename (theme_path, "gtk-3.0", "gtk.css", NULL);
theme_path = g_build_filename (dir_path, name, NULL);
gtk3_path = g_build_filename (theme_path, "gtk-3.0", NULL);
if (g_file_test (theme_path, G_FILE_TEST_IS_DIR) if (g_file_test (theme_path, G_FILE_TEST_IS_DIR)
&& g_file_test (gtk3_path, G_FILE_TEST_IS_DIR) && g_file_test (gtk_css_path, G_FILE_TEST_IS_REGULAR))
&& !g_hash_table_contains (seen, name))
{ {
g_hash_table_add (seen, g_strdup (name)); gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (ui->gtk3_combo), name);
g_ptr_array_add (names, g_strdup (name)); g_ptr_array_add (ui->gtk3_theme_paths, theme_path);
have_valid_theme = TRUE;
theme_path = NULL;
} }
g_free (gtk3_path);
g_free (gtk_css_path);
g_free (theme_path); g_free (theme_path);
} }
g_dir_close (dir); g_dir_close (dir);
} }
g_ptr_array_sort (names, (GCompareFunc) g_ascii_strcasecmp); if (!have_valid_theme)
model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->gtk3_combo));
while (gtk_tree_model_get_iter_first (model, &iter))
gtk_combo_box_text_remove (GTK_COMBO_BOX_TEXT (ui->gtk3_combo), 0);
for (i = 0; i < names->len; i++)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (ui->gtk3_combo), g_ptr_array_index (names, i));
settings = gtk_settings_get_default ();
if (prefs.hex_gui_gtk3_theme_name[0] != '\0')
current_theme = g_strdup (prefs.hex_gui_gtk3_theme_name);
else if (settings)
g_object_get (settings, "gtk-theme-name", &current_theme, NULL);
if (names->len > 0)
{ {
gtk_combo_box_set_active (GTK_COMBO_BOX (ui->gtk3_combo), -1); gtk_label_set_text (GTK_LABEL (ui->gtk3_status_label), _("No valid GTK3 themes found."));
if (current_theme) }
else
{
for (i = 0; i < ui->gtk3_theme_paths->len; i++)
{ {
for (i = 0; i < names->len; i++) const char *theme_path = g_ptr_array_index (ui->gtk3_theme_paths, i);
char *theme_name = g_path_get_basename (theme_path);
if (g_strcmp0 (prefs.hex_gui_gtk3_theme_name, theme_name) == 0)
{ {
if (g_strcmp0 (current_theme, g_ptr_array_index (names, i)) == 0) active = (gint) i;
{ g_free (theme_name);
gtk_combo_box_set_active (GTK_COMBO_BOX (ui->gtk3_combo), i); break;
break;
}
} }
g_free (theme_name);
} }
if (active >= 0)
gtk_combo_box_set_active (GTK_COMBO_BOX (ui->gtk3_combo), active);
else if (prefs.hex_gui_gtk3_theme_name[0] == '\0')
gtk_combo_box_set_active (GTK_COMBO_BOX (ui->gtk3_combo), 0);
else
gtk_combo_box_set_active (GTK_COMBO_BOX (ui->gtk3_combo), -1);
if (gtk_combo_box_get_active (GTK_COMBO_BOX (ui->gtk3_combo)) >= 0)
gtk_label_set_text (GTK_LABEL (ui->gtk3_status_label), _("Select a GTK3 theme to apply."));
else
gtk_label_set_text (GTK_LABEL (ui->gtk3_status_label), _("No valid GTK3 themes found."));
} }
gtk_widget_set_sensitive (ui->gtk3_apply_button, gtk_widget_set_sensitive (ui->gtk3_apply_button,
gtk_combo_box_get_active (GTK_COMBO_BOX (ui->gtk3_combo)) >= 0); gtk_combo_box_get_active (GTK_COMBO_BOX (ui->gtk3_combo)) >= 0);
gtk_label_set_text (GTK_LABEL (ui->gtk3_status_label),
names->len > 0 ? _("Select a GTK3 theme to activate from the dropdown, or use the system GTK theme.") : _("No GTK3 themes found."));
g_ptr_array_free (names, TRUE); g_free (themes_dir);
g_hash_table_destroy (seen);
g_free (current_theme);
g_free ((char *) theme_dirs[1]);
g_free ((char *) theme_dirs[0]);
} }
static void static void
@@ -2160,7 +2165,7 @@ setup_theme_gtk3_import_cb (GtkWidget *button, gpointer user_data)
} }
else else
{ {
setup_theme_populate_gtk3 (ui); setup_gtk3_theme_populate (ui);
gtk_label_set_text (GTK_LABEL (ui->gtk3_status_label), _("GTK3 theme archive imported successfully.")); gtk_label_set_text (GTK_LABEL (ui->gtk3_status_label), _("GTK3 theme archive imported successfully."));
setup_theme_show_message (GTK_MESSAGE_INFO, _("GTK3 theme archive imported successfully.")); setup_theme_show_message (GTK_MESSAGE_INFO, _("GTK3 theme archive imported successfully."));
} }
@@ -2170,16 +2175,26 @@ setup_theme_gtk3_import_cb (GtkWidget *button, gpointer user_data)
static void static void
setup_theme_gtk3_apply_cb (GtkWidget *button, gpointer user_data) setup_theme_apply_gtk3_cb (GtkWidget *button, gpointer user_data)
{ {
setup_theme_ui *ui = user_data; setup_theme_ui *ui = user_data;
gint active;
const char *theme_path;
char *theme; char *theme;
GError *error = NULL; GError *error = NULL;
theme = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (ui->gtk3_combo)); active = gtk_combo_box_get_active (GTK_COMBO_BOX (ui->gtk3_combo));
if (!theme) if (active < 0 || !ui->gtk3_theme_paths || (guint) active >= ui->gtk3_theme_paths->len)
return; return;
theme_path = g_ptr_array_index (ui->gtk3_theme_paths, active);
theme = g_path_get_basename (theme_path);
if (!theme || !*theme)
{
g_free (theme);
return;
}
if (!fe_apply_gtk3_theme (theme, &error)) if (!fe_apply_gtk3_theme (theme, &error))
{ {
setup_theme_show_message (GTK_MESSAGE_ERROR, setup_theme_show_message (GTK_MESSAGE_ERROR,
@@ -2301,7 +2316,7 @@ setup_create_theme_page (void)
ui->gtk3_apply_button = gtk_button_new_with_mnemonic (_("Apply GTK_3 Theme")); ui->gtk3_apply_button = gtk_button_new_with_mnemonic (_("Apply GTK_3 Theme"));
gtk_box_pack_start (GTK_BOX (button_box), ui->gtk3_apply_button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (button_box), ui->gtk3_apply_button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (ui->gtk3_apply_button), "clicked", g_signal_connect (G_OBJECT (ui->gtk3_apply_button), "clicked",
G_CALLBACK (setup_theme_gtk3_apply_cb), ui); G_CALLBACK (setup_theme_apply_gtk3_cb), ui);
ui->gtk3_use_system_button = gtk_button_new_with_mnemonic (_("Use _System GTK Theme")); ui->gtk3_use_system_button = gtk_button_new_with_mnemonic (_("Use _System GTK Theme"));
gtk_box_pack_start (GTK_BOX (button_box), ui->gtk3_use_system_button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (button_box), ui->gtk3_use_system_button, FALSE, FALSE, 0);
@@ -2314,9 +2329,9 @@ setup_create_theme_page (void)
gtk_box_pack_start (GTK_BOX (hbox), ui->gtk3_status_label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), ui->gtk3_status_label, FALSE, FALSE, 0);
setup_theme_populate (ui); setup_theme_populate (ui);
setup_theme_populate_gtk3 (ui); setup_gtk3_theme_populate (ui);
g_object_set_data_full (G_OBJECT (box), "setup-theme-ui", ui, g_free); g_object_set_data_full (G_OBJECT (box), "setup-theme-ui", ui, setup_theme_ui_free);
return box; return box;
} }