summaryrefslogtreecommitdiff
path: root/src/glibext/sigredir.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glibext/sigredir.c')
-rw-r--r--src/glibext/sigredir.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/src/glibext/sigredir.c b/src/glibext/sigredir.c
new file mode 100644
index 0000000..67e8563
--- /dev/null
+++ b/src/glibext/sigredir.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sigredir.c - encadrement des signaux supplémentaire par rapport à celui de la GLib
+ *
+ * Copyright (C) 2014-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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "sigredir.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <gobject/gclosure.h>
+#include <gobject/gvaluecollector.h>
+
+
+
+/* Informations utiles à l'appel final */
+typedef struct _gsignal_wrapper_params_t
+{
+ GClosure *closure; /* Glue pour les appels */
+
+ guint n_params; /* Nombre de paramètres */
+ GValue instance_and_params[0]; /* Instance & paramètres */
+
+} gsignal_wrapper_params_t;
+
+/* Transmet un signal dans le contexte principal. */
+static gboolean to_main_wrapper(gpointer);
+
+/* Supprime de la mémoire le transporteur d'informations. */
+static void destroy_wrapper_params(gpointer);
+
+/* Informations concernant une diffusion de signal */
+typedef struct _gsignal_wrapper_info_t
+{
+ gpointer instance; /* Instance GLib initiatrice */
+ gulong id; /* Identifiant de connexion */
+
+ GClosure *closure; /* Glue pour les appels */
+
+ guint n_params; /* Nombre de paramètres */
+ GType param_types[0]; /* Type des paramètres associés*/
+
+} gsignal_wrapper_info_t;
+
+/* Réceptionne un signal et redirige son exécution. */
+static void carry_signal_to_main_thread(gsignal_wrapper_info_t *, ...);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : data = collecteur d'informations sur la diffusion. *
+* *
+* Description : Transmet un signal dans le contexte principal. *
+* *
+* Retour : FALSE / G_SOURCE_REMOVE pour arrêter la transmission. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static gboolean to_main_wrapper(gpointer data)
+{
+ gsignal_wrapper_params_t *params; /* Informations d'appel */
+
+ params = (gsignal_wrapper_params_t *)data;
+
+ g_closure_invoke(params->closure,
+ NULL /* return_value */,
+ params->n_params + 1,
+ params->instance_and_params,
+ NULL /* invocation_hint */);
+
+ return G_SOURCE_REMOVE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : data = collecteur d'informations à supprimer. *
+* *
+* Description : Supprime de la mémoire le transporteur d'informations. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void destroy_wrapper_params(gpointer data)
+{
+ gsignal_wrapper_params_t *params; /* Informations d'appel */
+ guint i; /* Boucle de parcours */
+
+ params = (gsignal_wrapper_params_t *)data;
+
+ g_closure_unref(params->closure);
+
+ for (i = 0; i < (params->n_params + 1); i++)
+ g_value_unset(params->instance_and_params + i);
+
+ free(params);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = collecteur d'informations sur la diffusion. *
+* ... = arguments poussés par la GLib sur la pile. *
+* *
+* Description : Réceptionne un signal et redirige son exécution. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void carry_signal_to_main_thread(gsignal_wrapper_info_t *info, ...)
+{
+ gsignal_wrapper_params_t *params; /* Informations d'appel */
+ GValue *param_values; /* Paramètres d'appel */
+ va_list ap; /* Liste d'arguments sur pile */
+ guint i; /* Boucle de parcours */
+ bool static_scope; /* Portée des arguments */
+ gchar *error; /* Eventuelle erreur inattendue*/
+
+ params = calloc(1, sizeof(gsignal_wrapper_params_t) + sizeof(GValue) * (info->n_params + 1));
+
+ params->closure = info->closure;
+ g_closure_ref(info->closure);
+
+ params->n_params = info->n_params;
+
+ g_value_init(params->instance_and_params, G_TYPE_FROM_INSTANCE(info->instance));
+ g_value_set_instance(params->instance_and_params, info->instance);
+
+ param_values = params->instance_and_params + 1;
+
+ va_start(ap, info);
+
+ error = NULL;
+
+ for (i = 0; i < info->n_params; i++)
+ {
+ static_scope = info->param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE;
+
+ G_VALUE_COLLECT_INIT(param_values + i,
+ info->param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE,
+ ap, static_scope ? G_VALUE_NOCOPY_CONTENTS : 0,
+ &error);
+
+ if (error != NULL)
+ {
+ fprintf(stderr, "%s: %s", G_STRLOC, error);
+ g_free(error);
+ break;
+ }
+
+ }
+
+ va_end(ap);
+
+ if (error == NULL)
+ g_idle_add_full(G_PRIORITY_HIGH_IDLE, to_main_wrapper, params, destroy_wrapper_params);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : info = collecteur d'informations à supprimer. *
+* *
+* Description : Déconnecte un signal redirigé vers le contexte principal. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_signal_disconnect_from_main(gsignal_wrapper_info_t *info)
+{
+ g_signal_handler_disconnect(info->instance, info->id);
+
+ free(info);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : instance = object GLib à l'origine de l'émission. *
+* signal = identification du signal à réceptionner. *
+* handler = fonction C servant de réceptacle. *
+* data = éventuelle donnée de l'utilisateur à ajouter. *
+* marshal = précise la fonction de transfert des arguments. *
+* flags = fournit quelques indications supplémentaires. *
+* *
+* Description : Reproduit le comportement de la fonction g_signal_connect(). *
+* *
+* Retour : Identifiant supérieur zéro en cas de succès. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gsignal_wrapper_info_t *_g_signal_connect_to_main(gpointer instance, const gchar *signal, GCallback handler, gpointer data, GClosureMarshal marshal, GConnectFlags flags)
+{
+ gsignal_wrapper_info_t *result; /* Structure à renvoyer */
+ guint signal_id; /* Identifiant du signal visé */
+ GSignalQuery query; /* Information sur le signal */
+
+ /* Collection d'informations */
+
+ signal_id = g_signal_lookup(signal, G_TYPE_FROM_INSTANCE(instance));
+
+ g_signal_query(signal_id, &query);
+
+ assert(query.signal_id != 0);
+ assert(query.return_type == G_TYPE_NONE);
+
+ /* Allocation adaptée */
+
+ result = malloc(sizeof(gsignal_wrapper_info_t) + sizeof(GType) * query.n_params);
+
+ result->instance = instance;
+
+ if (flags & G_CONNECT_SWAPPED)
+ result->closure = g_cclosure_new_swap(handler, data, NULL);
+ else
+ result->closure = g_cclosure_new(handler, data, NULL);
+
+ g_closure_ref(result->closure);
+ g_closure_sink(result->closure);
+
+ g_closure_set_marshal(result->closure, marshal);
+
+ result->n_params = query.n_params;
+ memcpy(result->param_types, query.param_types, sizeof(GType) * query.n_params);
+
+ /* Connexion au signal */
+
+ result->id = g_signal_connect_swapped(instance, signal, G_CALLBACK(carry_signal_to_main_thread), result);
+
+ return result;
+
+}