/* Chrysalide - Outil d'analyse de fichiers binaires * preferences.c - boîte de dialogue d'édition des préférences de l'utilisateur * * Copyright (C) 2019-2025 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "preferences.h" #include #include #include #include #include #include "preferences-int.h" #include "prefs/security.h" #include "../../common/cpp.h" #include "../../gtkext/tweak.h" /* --------------------------- BASES DE BOITE DE DIALOGUE --------------------------- */ /* Procède à l'initialisation de la fenêtre des paramètres. */ static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *); /* Procède à l'initialisation de la fenêtre des paramètres. */ static void gtk_preferences_dialog_init(GtkPreferencesDialog *); /* Supprime toutes les références externes. */ static void gtk_preferences_dialog_dispose(GObject *); /* Procède à la libération totale de la mémoire. */ static void gtk_preferences_dialog_finalize(GObject *); /* Fournit la liste de section désignée par un nom. */ static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *, const char *, bool); /* Réagit à un changement de sélection dans les sections. */ static void gtk_preferences_dialog_on_row_selected(GtkListBox *, GtkListBoxRow *, GtkPreferencesDialog *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ /* ---------------------------------------------------------------------------------- */ /* BASES DE BOITE DE DIALOGUE */ /* ---------------------------------------------------------------------------------- */ /* Détermine le type du composant d'affichage générique. */ G_DEFINE_TYPE(GtkPreferencesDialog, gtk_preferences_dialog, GTK_TYPE_WINDOW); /****************************************************************************** * * * Paramètres : class = classe GTK à initialiser. * * * * Description : Procède à l'initialisation de la fenêtre des paramètres. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_preferences_dialog_class_init(GtkPreferencesDialogClass *class) { GObjectClass *object; /* Plus haut niveau équivalent */ GtkWidgetClass *widget; /* Classe de haut niveau */ object = G_OBJECT_CLASS(class); object->dispose = gtk_preferences_dialog_dispose; object->finalize = gtk_preferences_dialog_finalize; widget = GTK_WIDGET_CLASS(class); gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gui/dialogs/preferences.ui"); gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, side_title); gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, side_content); gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, main_title); gtk_widget_class_bind_template_child(widget, GtkPreferencesDialog, main_content); /* Active une action native (cf. https://docs.gtk.org/gtk4/class.Window.html#actions) */ gtk_widget_class_add_binding_action(widget, GDK_KEY_Escape, 0 /* GDK 4.14 : GDK_NO_MODIFIER_MASK */, "window.close", NULL); } /****************************************************************************** * * * Paramètres : dialog = composant GTK à initialiser. * * * * Description : Procède à l'initialisation de la fenêtre des paramètres. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_preferences_dialog_init(GtkPreferencesDialog *dialog) { size_t i; /* Boucle de parcours */ const tweak_info_t *info; /* Informations à considérer */ GtkListBox *navigation; /* Liste de sections à afficher*/ GtkTweakSection *section; /* Nouvelle section à présenter*/ tweak_info_t infos[] = { TWEAK_SIMPLE_DEF("root", "Basics", "security-high-symbolic", "security", "Security", GTK_TYPE_SECURITY_TWEAK_PANEL), }; gtk_widget_init_template(GTK_WIDGET(dialog)); dialog->navigations = g_hash_table_new_full(g_str_hash, g_str_equal, free, g_object_unref); /* Chargement des sections fixes */ for (i = 0; i < ARRAY_SIZE(infos); i++) { info = &infos[i]; navigation = gtk_preferences_dialog_get_navigation(dialog, info->parent, true); assert(navigation != NULL); section = gtk_tweak_section_new(info); gtk_list_box_append(navigation, GTK_WIDGET(section)); } /* Affichage de la liste racine */ navigation = gtk_preferences_dialog_get_navigation(dialog, "root", false); assert(navigation != NULL); g_signal_connect(navigation, "row-selected", G_CALLBACK(gtk_preferences_dialog_on_row_selected), dialog); gtk_scrolled_window_set_child(dialog->side_content, GTK_WIDGET(navigation)); unref_object(navigation); } /****************************************************************************** * * * Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_preferences_dialog_dispose(GObject *object) { GtkPreferencesDialog *dialog; /* Version spécialisée */ dialog = GTK_PREFERENCES_DIALOG(object); if (dialog->navigations != NULL) { /** * Cf. documentation de g_hash_table_new_full(). */ g_hash_table_remove_all(dialog->navigations); g_hash_table_unref(dialog->navigations); dialog->navigations = NULL; } gtk_widget_dispose_template(GTK_WIDGET(dialog), GTK_TYPE_PREFERENCES_DIALOG); G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->dispose(object); } /****************************************************************************** * * * Paramètres : object = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_preferences_dialog_finalize(GObject *object) { G_OBJECT_CLASS(gtk_preferences_dialog_parent_class)->finalize(object); } /****************************************************************************** * * * Paramètres : parent = fenêtre parente à surpasser. * * * * Description : Construit une boîte de dialogue pour les préférences. * * * * Retour : Adresse de la fenêtre mise en place. * * * * Remarques : - * * * ******************************************************************************/ GtkWindow *gtk_preferences_dialog_new(GtkWindow *parent) { GtkWindow *result; /* Boite de dialogue à renvoyer*/ result = g_object_new(GTK_TYPE_PREFERENCES_DIALOG, NULL); if (!gtk_preferences_dialog_create(GTK_PREFERENCES_DIALOG(result), parent)) g_clear_object(&result); return result; } /****************************************************************************** * * * Paramètres : dialog = boîte de dialogue à initialiser pleinement. * * parent = fenêtre parente à surpasser. * * * * Description : Met en place la boîte de dialogue pour les préférences. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool gtk_preferences_dialog_create(GtkPreferencesDialog *dialog, GtkWindow *parent) { bool result; /* Bilan à retourner */ result = true; gtk_window_set_transient_for(GTK_WINDOW(dialog), parent); return result; } /****************************************************************************** * * * Paramètres : dialog = boîte de dialogue à initialiser pleinement. * * key = désignation de la liste à fournir. * * create = autorisation d'une création si besoin est. * * * * Description : Fournit la liste de section désignée par un nom. * * * * Retour : Composant graphique à utiliser. * * * * Remarques : - * * * ******************************************************************************/ static GtkListBox *gtk_preferences_dialog_get_navigation(GtkPreferencesDialog *dialog, const char *key, bool create) { GtkListBox *result; /* Instance à retourner */ #ifndef NDEBUG gboolean status; /* Bilan d'une insertion */ #endif result = g_hash_table_lookup(dialog->navigations, key); if (result == NULL && create) { result = GTK_LIST_BOX(gtk_list_box_new()); g_object_ref_sink(G_OBJECT(result)); gtk_list_box_set_selection_mode(result, GTK_SELECTION_BROWSE); gtk_widget_add_css_class(GTK_WIDGET(result), "navigation-sidebar"); #ifndef NDEBUG status = g_hash_table_insert(dialog->navigations, strdup(key), result); assert(status); #else g_hash_table_insert(dialog->navigations, key, result); #endif } if (result != NULL) ref_object(result); return result; } /****************************************************************************** * * * Paramètres : navigation = liste concernée par l'événement. * * selected = élément sélectionné (voire NULL). * * dialog = boîte de dialogue à initialiser pleinement. * * * * Description : Réagit à un changement de sélection dans les sections. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_preferences_dialog_on_row_selected(GtkListBox *navigation, GtkListBoxRow *selected, GtkPreferencesDialog *dialog) { GtkTweakSection *section; /* Nature réelle sélectionnée */ GType type; /* Type de panneau de config. */ GtkWidget *panel; /* Nouveau panneau à présenter */ if (selected != NULL) { if (!gtk_tweak_section_has_sub_section(GTK_TWEAK_SECTION(selected))) { section = GTK_TWEAK_SECTION(selected); gtk_label_set_text(dialog->main_title, gtk_tweak_section_get_label(section)); type = gtk_tweak_section_get_panel(section); panel = g_object_new(type, NULL); gtk_scrolled_window_set_child(dialog->main_content, panel); } else { // TODO } } } /* ---------------------------------------------------------------------------------- */ /* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */