summaryrefslogtreecommitdiff
path: root/src/gtkext/statusstack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gtkext/statusstack.c')
-rw-r--r--src/gtkext/statusstack.c1383
1 files changed, 1383 insertions, 0 deletions
diff --git a/src/gtkext/statusstack.c b/src/gtkext/statusstack.c
new file mode 100644
index 0000000..92c296a
--- /dev/null
+++ b/src/gtkext/statusstack.c
@@ -0,0 +1,1383 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * statusstack.c - empilement d'informations de statut
+ *
+ * Copyright (C) 2015-2024 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "statusstack.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include "helpers.h"
+#include "statusstack-int.h"
+#include "../core/global.h"
+
+
+
+/* -------------------------- GESTION GENERALE DES STATUTS -------------------------- */
+
+
+/* Liste des propriétés */
+
+typedef enum _StatusStackProperty {
+
+ PROP_0, /* Réservé */
+
+ PROP_SHOW_BOTTOM, /* Affichage de la zone inf. */
+
+ N_PROPERTIES
+
+} StatusStackProperty;
+
+static GParamSpec *_status_stack_properties[N_PROPERTIES] = { NULL, };
+
+
+/* Source d'affichage par défaut */
+#define gtk_status_stack_default_source gtk_status_stack_show_simple_message
+
+
+/* Initialise la classe des barres de statut améliorées. */
+static void gtk_status_stack_class_init(GtkStatusStackClass *);
+
+/* Initialise une instance de barre de statut améliorée. */
+static void gtk_status_stack_init(GtkStatusStack *);
+
+/* Supprime toutes les références externes. */
+static void gtk_status_stack_dispose(GtkStatusStack *);
+
+/* Procède à la libération totale de la mémoire. */
+static void gtk_status_stack_finalize(GtkStatusStack *);
+
+/* Note le changement de verrouillage du stockage sécurisé. */
+static void gtk_status_stack_on_secret_storage_lock_update(GSecretStorage *, GtkStatusStack *);
+
+/* Met à jour dans la barre les débits réseau observés. */
+static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Met à jour une propriété d'instance GObject. */
+static void gtk_status_stack_set_property(GObject *, guint, const GValue *, GParamSpec *);
+
+/* Fournit la valeur d'une propriété d'instance GObject. */
+static void gtk_status_stack_get_property(GObject *, guint, GValue *, GParamSpec *);
+
+
+
+/* ----------------------- MISE EN AVANT DES MESSAGES SIMPLES ----------------------- */
+
+
+/* S'assure de l'affichage à jour de la partie "default". */
+static gboolean gtk_status_stack_show_simple_message(gpointer);
+
+
+
+/* -------------------- STATUT DES INFORMATIONS DE DESASSEMBLAGE -------------------- */
+
+
+/* Navigation au sein d'assemblage */
+struct _navigation_info_t
+{
+ char *segment; /* Segment d'appartenance */
+
+ mrange_t current; /* Emplacement correspondant */
+
+ VMPA_BUFFER(phys); /* Localisation physique */
+ VMPA_BUFFER(virt); /* Localisation virtuelle */
+
+ char *symbol; /* Eventuel symbole concerné */
+
+ char *format; /* Architecture et format */
+ char *details; /* Encodage de l'instruction */
+
+};
+
+
+/* Met en place le suivi d'informations de navigation. */
+static void init_navigation_info(navigation_info_t *);
+
+/* Supprime l'empreinte mémoire d'informations de navigation. */
+static void fini_navigation_info(navigation_info_t *);
+
+/* S'assure de l'affichage à jour de la partie "navigation". */
+static gboolean gtk_status_stack_show_current_location(gpointer);
+
+/* Réagit à un clic sur l'icône de zoom. */
+static void gtk_status_stack_on_zoom_icon_press(GtkEntry *, GtkEntryIconPosition, GtkStatusStack *);
+
+
+
+/* -------------------------- STATUT DES SUIVIS D'ACTIVITE -------------------------- */
+
+
+/* Informations de progression */
+typedef struct _activity_status_t
+{
+ activity_id_t id; /* Identifiant unique */
+
+ char *message; /* Indication à faire valoir */
+
+ unsigned long current; /* Position courante */
+ unsigned long max; /* Couverture à parcourir */
+
+ double last_updated; /* Dernière valeur poussée */
+
+} activity_status_t;
+
+
+/* Mémorisation des progressions au sein d'activités */
+struct _activity_info_t
+{
+ GMutex access; /* Accès à la pile */
+
+ activity_id_t generator; /* Générateur de séquence */
+
+ activity_status_t *statuses; /* Statuts de progression */
+ size_t count; /* Nombre de ces statuts */
+
+ guint tag; /* Identifiant de mise à jour */
+
+};
+
+
+/* Met en place le suivi d'informations d'activité. */
+static void init_activity_info(activity_info_t *);
+
+/* Supprime l'empreinte mémoire d'informations d'activité. */
+static void fini_activity_info(activity_info_t *);
+
+/* Recherche les indications de statut d'une activité donnée. */
+static activity_status_t *find_activity_status_by_id(activity_info_t *, activity_id_t);
+
+/* S'assure de l'affichage à jour de la partie "activité". */
+static gboolean gtk_status_stack_show_current_activity(gpointer);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GESTION GENERALE DES STATUTS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Détermine le type du composant d'affichage générique. */
+G_DEFINE_TYPE(GtkStatusStack, gtk_status_stack, GTK_TYPE_BOX);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe GTK à initialiser. *
+* *
+* Description : Initialise la classe des barres de statut améliorées. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_class_init(GtkStatusStackClass *class)
+{
+ GObjectClass *object; /* Plus haut niveau équivalent */
+ GtkWidgetClass *widget; /* Classe de haut niveau */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)gtk_status_stack_dispose;
+ object->finalize = (GObjectFinalizeFunc)gtk_status_stack_finalize;
+ object->set_property = gtk_status_stack_set_property;
+ object->get_property = gtk_status_stack_get_property;
+
+ _status_stack_properties[PROP_SHOW_BOTTOM] =
+ g_param_spec_boolean("show-bottom", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(object, N_PROPERTIES, _status_stack_properties);
+
+ widget = GTK_WIDGET_CLASS(class);
+
+ gtk_widget_class_set_template_from_resource(widget, "/re/chrysalide/framework/gtkext/statusstack.ui");
+
+ gtk_widget_class_bind_template_callback_full(widget, BUILDER_CB(gtk_status_stack_on_zoom_icon_press));
+
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, main);
+
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, def_label);
+
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_segment);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_phys);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_virt);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_offset);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_format);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, nav_details);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, zoom);
+
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, activity_message);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, activity_progress);
+
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, lock_update);
+
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_recv_speed);
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, net_send_speed);
+
+ gtk_widget_class_bind_template_child(widget, GtkStatusStack, bottom_toggler);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = composant GTK à initialiser. *
+* *
+* Description : Initialise une instance de barre de statut améliorée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_init(GtkStatusStack *stack)
+{
+ gtk_widget_init_template(GTK_WIDGET(stack));
+
+ stack->def_source = gtk_status_stack_default_source;
+
+ stack->msg = NULL;
+
+ stack->nav_info = calloc(1, sizeof(navigation_info_t));
+ init_navigation_info(stack->nav_info);
+
+ stack->activity_info = calloc(1, sizeof(activity_info_t));
+ init_activity_info(stack->activity_info);
+
+ /* Suivi des évolutions relatives au stockage sécurisé */
+
+ stack->storage = get_secret_storage();
+
+ g_signal_connect(stack->storage, "lock-update",
+ G_CALLBACK(gtk_status_stack_on_secret_storage_lock_update), stack);
+
+ gtk_status_stack_on_secret_storage_lock_update(stack->storage, stack);
+
+ /* Suivi des débits de connexion */
+
+ stack->next_index = 0;
+
+ stack->network_update_tag = g_timeout_add(NETWORK_UPDATE_INTERVAL,
+ G_SOURCE_FUNC(gtk_status_stack_update_network_stats), stack);
+
+ /* Premier affichage... */
+
+ gtk_status_stack_reset_to_default(stack);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_dispose(GtkStatusStack *stack)
+{
+ if (stack->storage != NULL)
+ g_signal_handlers_disconnect_by_func(stack->storage,
+ gtk_status_stack_on_secret_storage_lock_update, stack);
+
+ g_clear_object(&stack->storage);
+
+ g_source_remove(stack->network_update_tag);
+
+ gtk_widget_dispose_template(GTK_WIDGET(stack), GTK_TYPE_STATUS_STACK);
+
+ G_OBJECT_CLASS(gtk_status_stack_parent_class)->dispose(G_OBJECT(stack));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_finalize(GtkStatusStack *stack)
+{
+ if (stack->msg != NULL)
+ free(stack->msg);
+
+ fini_navigation_info(stack->nav_info);
+ free(stack->nav_info);
+
+ fini_activity_info(stack->activity_info);
+ free(stack->activity_info);
+
+ G_OBJECT_CLASS(gtk_status_stack_parent_class)->finalize(G_OBJECT(stack));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée une nouvelle instance de barre de statut. *
+* *
+* Retour : Composant GTK mis en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GtkStatusStack *gtk_status_stack_new(void)
+{
+ GtkStatusStack *result; /* Instance à retourner */
+
+ result = g_object_new(GTK_TYPE_STATUS_STACK, NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* *
+* Description : Réinitialise la barre de statut à son stade par défaut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_reset_to_default(GtkStatusStack *stack)
+{
+ /**
+ * Une amélioration possible serait de passer à g_idle_add_once(),
+ * et de s'affranchir des retours G_SOURCE_REMOVE systématiques,
+ * mais la fonction n'est disponible qu'à partir de la GLib 2.74.
+ */
+
+ g_idle_add(stack->def_source, stack);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : storage = gardien des secrets impliqué. *
+* stack = barre de statut à actualiser. *
+* *
+* Description : Note le changement de verrouillage du stockage sécurisé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_on_secret_storage_lock_update(GSecretStorage *storage, GtkStatusStack *stack)
+{
+ if (!g_secret_storage_has_key(stack->storage))
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(stack->lock_update), false);
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "nolock-symbolic");
+ }
+ else
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(stack->lock_update), true);
+
+ if (g_secret_storage_is_locked(stack->storage))
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "locked-symbolic");
+ else
+ gtk_button_set_icon_name(GTK_BUTTON(stack->lock_update), "unlocked-symbolic");
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* *
+* Description : Met à jour dans la barre les débits réseau observés. *
+* *
+* Retour : G_SOURCE_CONTINUE pour poursuivre les mises à jour. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_status_stack_update_network_stats(GtkStatusStack *stack)
+{
+ gboolean result; /* Indication à retourner */
+ gint64 timestamp; /* Position temporelle */
+ size_t received; /* Quantité d'octets reçus */
+ size_t sent; /* Quantité d'octets émis */
+ gint64 diff_time; /* Différentiel de temps */
+ size_t diff_bytes; /* Différentiel de volume */
+ double speed; /* Débit de transfert constaté */
+ size_t i; /* Boucle de parcours */
+ char *value; /* Valeur à afficher */
+
+ const char *units[] = { _("b/s"), _("kb/s"), _("Mb/s"), _("Gb/s"), _("Tb/s") };
+
+ result = G_SOURCE_CONTINUE;
+
+ /* Mémorisation des données */
+
+ timestamp = g_get_monotonic_time();
+
+ get_network_stats(&received, &sent);
+
+ if (stack->next_index < NETWORK_UPDATE_COUNT)
+ {
+ stack->last_bytes_received[stack->next_index] = received;
+ stack->last_bytes_sent[stack->next_index] = sent;
+ stack->last_timestamps[stack->next_index] = timestamp;
+
+ stack->next_index++;
+
+ }
+ else
+ {
+ memcpy(stack->last_bytes_received, stack->last_bytes_received + 1,
+ (NETWORK_UPDATE_COUNT - 1) * sizeof(size_t));
+
+ memcpy(stack->last_bytes_sent, stack->last_bytes_sent + 1,
+ (NETWORK_UPDATE_COUNT - 1) * sizeof(size_t));
+
+ memcpy(stack->last_timestamps, stack->last_timestamps + 1,
+ (NETWORK_UPDATE_COUNT - 1) * sizeof(gint64));
+
+ stack->last_bytes_received[NETWORK_UPDATE_COUNT - 1] = received;
+ stack->last_bytes_sent[NETWORK_UPDATE_COUNT - 1] = sent;
+ stack->last_timestamps[NETWORK_UPDATE_COUNT - 1] = timestamp;
+
+ }
+
+ if (stack->next_index < NETWORK_UPDATE_COUNT)
+ goto done;
+
+ diff_time = stack->last_timestamps[NETWORK_UPDATE_COUNT - 1] - stack->last_timestamps[0];
+
+ /* Débit de réception */
+
+ diff_bytes = stack->last_bytes_received[NETWORK_UPDATE_COUNT - 1] - stack->last_bytes_received[0];
+
+ speed = (diff_bytes * 1000000) / diff_time;
+
+ for (i = 0; i < G_N_ELEMENTS(units); i++)
+ {
+ if (speed < 1024)
+ break;
+
+ speed /= 1024;
+
+ }
+
+ if (i == 0)
+ asprintf(&value, "%d %s", (int)speed, units[i]);
+ else
+ asprintf(&value, "%.1f %s", speed, units[i]);
+
+ gtk_label_set_label(stack->net_recv_speed, value);
+
+ free(value);
+
+ /* Débit de émission */
+
+ diff_bytes = stack->last_bytes_sent[NETWORK_UPDATE_COUNT - 1] - stack->last_bytes_sent[0];
+
+ speed = (diff_bytes * 1000000) / diff_time;
+
+ for (i = 0; i < G_N_ELEMENTS(units); i++)
+ {
+ if (speed < 1024)
+ break;
+
+ speed /= 1024;
+
+ }
+
+ if (i == 0)
+ asprintf(&value, "%d %s", (int)speed, units[i]);
+ else
+ asprintf(&value, "%.1f %s", speed, units[i]);
+
+ gtk_label_set_label(stack->net_send_speed, value);
+
+ free(value);
+
+ done:
+
+ return result;
+
+}
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à prendre en compte. *
+* pspec = définition de la propriété. *
+* *
+* Description : Met à jour une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(object);
+
+ switch (prop_id)
+ {
+ case PROP_SHOW_BOTTOM:
+ gtk_toggle_button_set_active(stack->bottom_toggler, g_value_get_boolean(value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : object = instance d'objet GLib à mamnipuler. *
+* prop_id = identifiant de la propriété visée. *
+* value = valeur à transmettre. [OUT] *
+* pspec = définition de la propriété. *
+* *
+* Description : Fournit la valeur d'une propriété d'instance GObject. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(object);
+
+ switch (prop_id)
+ {
+ case PROP_SHOW_BOTTOM:
+ g_value_set_boolean(value, gtk_toggle_button_get_active(stack->bottom_toggler));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+
+ }
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MISE EN AVANT DES MESSAGES SIMPLES */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* msg = simple message à faire paraître. *
+* *
+* Description : Inscrit un message simple dans la barre de statut. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_display_message(GtkStatusStack *stack, const char *msg)
+{
+ if (stack->msg != NULL)
+ free(stack->msg);
+
+ if (msg != NULL)
+ stack->msg = strdup(msg);
+ else
+ stack->msg = NULL;
+
+ gtk_status_stack_show_simple_message(stack);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = pile de statuts à manipuler. *
+* *
+* Description : S'assure de l'affichage à jour de la partie "default". *
+* *
+* Retour : G_SOURCE_REMOVE pour une exécution unique. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_status_stack_show_simple_message(gpointer data)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+
+ stack = GTK_STATUS_STACK(data);
+
+ stack->def_source = gtk_status_stack_show_simple_message;
+
+ gtk_label_set_text(stack->def_label, stack->msg != NULL ? stack->msg : "");
+
+ gtk_stack_set_visible_child_name(stack->main, "default");
+
+ return G_SOURCE_REMOVE;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* STATUT DES INFORMATIONS DE DESASSEMBLAGE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations à initialiser. *
+* *
+* Description : Met en place le suivi d'informations de navigation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_navigation_info(navigation_info_t *info)
+{
+ info->segment = NULL;
+
+ info->symbol = NULL;
+
+ info->format = NULL;
+ info->details = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations à libérer de la mémoire. *
+* *
+* Description : Supprime l'empreinte mémoire d'informations de navigation. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void fini_navigation_info(navigation_info_t *info)
+{
+ if (info->segment != NULL)
+ free(info->segment);
+
+ if (info->symbol != NULL)
+ free(info->symbol);
+
+ if (info->format != NULL)
+ free(info->format);
+
+ if (info->details != NULL)
+ free(info->details);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* range = emplacement à mettre en valeur. *
+* segment = zone de binaire d'appartenance. *
+* symbol = éventuelle position par rapport à un symbole. *
+* format = format du binaire manipulé *
+* details = détails supplémentaires (liés à l'encodage ?) *
+* *
+* Description : Actualise les informations liées une position d'assemblage. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_update_current_location(GtkStatusStack *stack, const mrange_t *range, const char *segment, const char *symbol, const char *format, const char *details)
+{
+ navigation_info_t *info; /* Informations à constituer */
+ const vmpa2t *addr; /* Localisation de départ */
+
+ info = stack->nav_info;
+
+ if (cmp_mrange(&info->current, range) == 0)
+ goto useless;
+
+ /* Zone d'appartenance */
+
+ if (segment != NULL)
+ info->segment = strdup(segment);
+ else
+ info->segment = NULL;
+
+ /* Adresses de base */
+
+ copy_mrange(&info->current, range);
+
+ addr = get_mrange_addr(range);
+
+ vmpa2_phys_to_string(addr, MDS_UNDEFINED, info->phys, NULL);
+
+ vmpa2_virt_to_string(addr, MDS_UNDEFINED, info->virt, NULL);
+
+ /* Symbole concerné */
+
+ if (symbol != NULL)
+ info->symbol = strdup(symbol);
+ else
+ info->symbol = NULL;
+
+ /* Architecture & format */
+
+ info->format = strdup(format);
+
+ if (details != NULL)
+ info->details = strdup(details);
+ else
+ info->details = NULL;
+
+ /* Nettoyage et conclusion */
+
+ gtk_status_stack_show_current_location(stack);
+
+ useless:
+
+ ;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = pile de statuts à manipuler. *
+* *
+* Description : S'assure de l'affichage à jour de la partie "navigation". *
+* *
+* Retour : G_SOURCE_REMOVE pour une exécution unique. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_status_stack_show_current_location(gpointer data)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+ navigation_info_t *info; /* Informations à constituer */
+ char raw_pos[6 + VMPA_MAX_LEN + 1]; /* Formatage final en direct */
+
+ stack = GTK_STATUS_STACK(data);
+
+ stack->def_source = gtk_status_stack_show_current_location;
+
+ info = stack->nav_info;
+
+ /* Première partie : navigation */
+
+ gtk_label_set_text(stack->nav_segment, info->segment != NULL ? info->segment : "");
+
+ snprintf(raw_pos, sizeof(raw_pos), "phys: %s", info->phys);
+
+ gtk_label_set_text(stack->nav_phys, raw_pos);
+
+ snprintf(raw_pos, sizeof(raw_pos), "virt: %s", info->virt);
+
+ gtk_label_set_text(stack->nav_virt, raw_pos);
+
+ gtk_label_set_text(stack->nav_offset, info->symbol != NULL ? info->symbol : "");
+
+ /* Seconde partie : format & architecture */
+
+ gtk_label_set_text(stack->nav_format, info->format);
+
+ gtk_label_set_text(stack->nav_details, info->details != NULL ? info->details : "");
+
+ /* Conclusion */
+
+ gtk_stack_set_visible_child_name(stack->main, "navigation");
+
+ return G_SOURCE_REMOVE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : entry = zone de texte visée par la procédure. *
+* icon_pos = position de l'image associée à l'entrée. *
+* stack = composant graphique de gestion des statuts. *
+* *
+* Description : Réagit à un clic sur l'icône de zoom. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void gtk_status_stack_on_zoom_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GtkStatusStack *stack)
+{
+#if 0
+ GtkWidget *popup; /* Popup à faire surgir */
+ GdkRectangle rect; /* Zone précise à cibler */
+
+ popup = gtk_popover_new();
+
+ gtk_entry_get_icon_area(entry, GTK_ENTRY_ICON_SECONDARY, &rect);
+ gtk_popover_set_pointing_to(GTK_POPOVER(popup), &rect);
+
+ gtk_widget_show(popup);
+#endif
+}
+
+
+/* ---------------------------------------------------------------------------------- */
+/* STATUT DES SUIVIS D'ACTIVITE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations à initialiser. *
+* *
+* Description : Met en place le suivi d'informations d'activité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_activity_info(activity_info_t *info)
+{
+ g_mutex_init(&info->access);
+
+ info->generator = NO_ACTIVITY_ID;
+
+ info->statuses = NULL;
+ info->count = 0;
+
+ info->tag = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations à libérer de la mémoire. *
+* *
+* Description : Supprime l'empreinte mémoire d'informations d'activité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void fini_activity_info(activity_info_t *info)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (info->tag != 0)
+ g_source_remove(info->tag);
+
+ info->tag = 0;
+
+ for (i = 0; i < info->count; i++)
+ {
+ if (info->statuses[i].message != NULL)
+ free(info->statuses[i].message);
+ }
+
+ if (info->statuses != NULL)
+ {
+ free(info->statuses);
+ info->statuses = NULL;
+ }
+
+ info->count = 0;
+
+ g_mutex_clear(&info->access);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = informations relatives aux activités à consulter. *
+* id = identifiant de l'activité à cibler. *
+* *
+* Description : Recherche les indications de statut d'une activité donnée. *
+* *
+* Retour : Structure d'encadrement trouvée ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static activity_status_t *find_activity_status_by_id(activity_info_t *info, activity_id_t id)
+{
+ activity_status_t *result; /* Statut trouvé à renvoyer */
+ size_t i; /* Boucle de parcours */
+
+ result = NULL;
+
+ assert(!g_mutex_trylock(&info->access));
+
+ for (i = 0; i < info->count; i++)
+ if (info->statuses[i].id == id)
+ {
+ result = info->statuses + i;
+ break;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* msg = nouveau message de statut à copier. *
+* max = taille de la plage à parcourir. *
+* *
+* Description : Démarre le suivi d'une nouvelle activité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+activity_id_t gtk_status_stack_add_activity(GtkStatusStack *stack, const char *msg, unsigned long max)
+{
+ activity_id_t result; /* Numéro unique à renvoyer */
+ activity_info_t *info; /* Informations à consulter */
+ activity_status_t *new; /* Nouveau suivi d'activité */
+
+ info = stack->activity_info;
+
+ g_mutex_lock(&info->access);
+
+ while (1)
+ {
+ result = ++info->generator;
+
+ if (find_activity_status_by_id(info, result) == NULL)
+ break;
+
+ }
+ while (0);
+
+ info->statuses = realloc(info->statuses, ++info->count * sizeof(activity_status_t));
+
+ new = info->statuses + info->count - 1;
+
+ /* Identifiant */
+
+ new->id = result;
+
+ /* Intitulé */
+
+ if (msg == NULL)
+ new->message = NULL;
+ else
+ new->message = strdup(msg);
+
+ /* Valeur */
+
+ new->current = 0;
+ new->max = max;
+ new->last_updated = 0;
+
+ /* Actualisation */
+
+ if (info->tag != 0)
+ g_source_remove(info->tag);
+
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
+
+ g_mutex_unlock(&info->access);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* id = identifiant de l'activité à cibler. *
+* msg = nouveau message de statut à copier. *
+* *
+* Description : Actualise les informations concernant une activité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_update_activity_message(GtkStatusStack *stack, activity_id_t id, const char *msg)
+{
+ activity_info_t *info; /* Informations à consulter */
+ activity_status_t *status; /* Suivi d'activité à traiter */
+ bool msg_changed; /* Changement d'intitulé */
+
+ info = stack->activity_info;
+
+ g_mutex_lock(&info->access);
+
+ status = find_activity_status_by_id(info, id);
+
+ assert(status != NULL);
+
+ if (status == NULL)
+ goto exit;
+
+ /* Intitulé */
+
+ if (status->message != NULL)
+ {
+ if (msg == NULL)
+ msg_changed = true;
+ else
+ msg_changed = (strcmp(status->message, msg) != 0);
+
+ free(status->message);
+
+ }
+ else
+ msg_changed = (msg != NULL);
+
+ if (msg == NULL)
+ status->message = NULL;
+ else
+ status->message = strdup(msg);
+
+ /* On n'actualise que le sommet de la pile */
+
+ if ((status - info->statuses + 1) == info->count && msg_changed)
+ {
+ if (info->tag != 0)
+ g_source_remove(info->tag);
+
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
+
+ }
+
+ exit:
+
+ g_mutex_unlock(&info->access);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* id = identifiant de l'activité à cibler. *
+* inc = nouvelle valeur pour une progression donnée. *
+* *
+* Description : Actualise la progression d'une activité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_update_activity_value(GtkStatusStack *stack, activity_id_t id, unsigned long inc)
+{
+ activity_info_t *info; /* Informations à consulter */
+ activity_status_t *status; /* Suivi d'activité à traiter */
+ double new; /* Nouvelle progression */
+
+ info = stack->activity_info;
+
+ g_mutex_lock(&info->access);
+
+ status = find_activity_status_by_id(info, id);
+
+ assert(status != NULL);
+
+ if (status == NULL)
+ goto exit;
+
+ /* Valeur */
+
+ status->current += inc;
+
+ new = (status->current * 1.0) / status->max;
+
+ /* On n'actualise que le sommet de la pile */
+
+ if ((status - info->statuses + 1) == info->count && (new - status->last_updated) > 0.1)
+ {
+ status->last_updated = new;
+
+ if (info->tag != 0)
+ g_source_remove(info->tag);
+
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
+
+ }
+
+ exit:
+
+ g_mutex_unlock(&info->access);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* id = identifiant de l'activité à cibler. *
+* extra = nouvelle échéance supplémentaire des traitements. *
+* *
+* Description : Etend la portée des travaux d'une nouvelle activité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_extend_activity_max(GtkStatusStack *stack, activity_id_t id, unsigned long extra)
+{
+ activity_info_t *info; /* Informations à consulter */
+ activity_status_t *status; /* Suivi d'activité à traiter */
+
+ info = stack->activity_info;
+
+ g_mutex_lock(&info->access);
+
+ status = find_activity_status_by_id(info, id);
+
+ assert(status != NULL);
+
+ if (status == NULL)
+ goto exit;
+
+ /* Valeur */
+
+ status->max += extra;
+
+ /* On n'actualise que le sommet de la pile */
+
+ if ((status - info->statuses + 1) == info->count)
+ {
+ if (info->tag != 0)
+ g_source_remove(info->tag);
+
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
+
+ }
+
+ exit:
+
+ g_mutex_unlock(&info->access);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : stack = barre de statut à actualiser. *
+* *
+* Description : Met fin au suivi d'une activité donnée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void gtk_status_stack_remove_activity(GtkStatusStack *stack, activity_id_t id)
+{
+ activity_info_t *info; /* Informations à consulter */
+ activity_status_t *status; /* Suivi d'activité à traiter */
+ bool is_last; /* Dernière position ? */
+
+ info = stack->activity_info;
+
+ g_mutex_lock(&info->access);
+
+ status = find_activity_status_by_id(info, id);
+
+ assert(status != NULL);
+
+ if (status == NULL)
+ goto exit;
+
+ is_last = ((status - info->statuses + 1) == info->count);
+
+ /* Suppression des données */
+
+ if (is_last)
+ {
+ if (info->tag != 0)
+ g_source_remove(info->tag);
+ }
+
+ if (status->message != NULL)
+ free(status->message);
+
+ /* Réajustement des enregistrements */
+
+ if (!is_last)
+ memmove(status, status + 1,
+ (((info->statuses + info->count) - status) - 1) * sizeof(activity_status_t));
+
+ info->statuses = realloc(info->statuses, --info->count * sizeof(activity_status_t));
+
+ /* Bascule vers un autre affichage ou actualisation ? */
+
+ if (info->count == 0)
+ {
+ info->tag = 0;
+ gtk_status_stack_reset_to_default(stack);
+ }
+ else if (is_last)
+ info->tag = g_idle_add(gtk_status_stack_show_current_activity, stack);
+
+ exit:
+
+ g_mutex_unlock(&info->access);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = pile de statuts à manipuler. *
+* *
+* Description : S'assure de l'affichage à jour de la partie "activité". *
+* *
+* Retour : G_SOURCE_REMOVE pour une exécution unique. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean gtk_status_stack_show_current_activity(gpointer data)
+{
+ GtkStatusStack *stack; /* Version spécialisée */
+ activity_info_t *info; /* Informations à consulter */
+ activity_status_t *last; /* Dernier statut à traiter */
+
+ stack = GTK_STATUS_STACK(data);
+
+ info = stack->activity_info;
+
+ g_mutex_lock(&info->access);
+
+ if (!g_source_is_destroyed(g_main_current_source()))
+ {
+ if (info->count > 0)
+ {
+ last = &info->statuses[info->count - 1];
+
+ gtk_label_set_text(stack->activity_message, last->message);
+
+ gtk_progress_bar_set_fraction(stack->activity_progress, (last->current * 1.0) / last->max);
+
+ gtk_stack_set_visible_child_name(stack->main, "activity");
+
+ }
+
+ info->tag = 0;
+
+ }
+
+ g_mutex_unlock(&info->access);
+
+ return G_SOURCE_REMOVE;
+
+}