From ee9bbfc34d86bfcf9384ed93e4300f6464528b9b Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 28 Jul 2014 21:12:51 +0000
Subject: Provided a way to receive a signal in the main thread.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@383 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog               |  12 ++++
 src/glibext/Makefile.am |   1 +
 src/glibext/signal.c    | 171 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/glibext/signal.h    |  37 +++++++++++
 src/project.c           |   5 +-
 5 files changed, 224 insertions(+), 2 deletions(-)
 create mode 100644 src/glibext/signal.c
 create mode 100644 src/glibext/signal.h

diff --git a/ChangeLog b/ChangeLog
index 5eb2020..e604fd4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+14-07-28  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/glibext/Makefile.am:
+	Add the 'signal.[ch]' files to libglibext_la_SOURCES.
+
+	* src/glibext/signal.c:
+	* src/glibext/signal.h:
+	New entries: provide a way to receive a signal in the main thread.
+
+	* src/project.c:
+	Update code.
+
 14-07-22  Cyrille Bagard <nocbos@gmail.com>
 
 	* plugins/pychrysa/gui/editem.c:
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index 50b9902..192587d 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -13,6 +13,7 @@ libglibext_la_SOURCES =					\
 	gbuffersegment.h gbuffersegment.c	\
 	gcodebuffer.h gcodebuffer.c			\
 	gnhash.h gnhash.c					\
+	signal.h signal.c					\
 	proto.h
 
 libglibext_la_LDFLAGS = 
diff --git a/src/glibext/signal.c b/src/glibext/signal.c
new file mode 100644
index 0000000..c7c8fe3
--- /dev/null
+++ b/src/glibext/signal.c
@@ -0,0 +1,171 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * signal.h - prototypes pour un encadrement des signaux supplémentaire par rapport à celui de la GLib
+ *
+ * Copyright (C) 2009-2013 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA 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.
+ *
+ *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "signal.h"
+
+
+#include <malloc.h>
+#include <stdarg.h>
+
+
+
+/* Prototype pour le transfert d'exécution. */
+typedef void (* GSignalCallback) (gpointer, ...);
+
+
+/* Informations concernant une diffusion de signal */
+typedef struct _gsignal_wrapper_info
+{
+    GConnectFlags flags;                    /* Ordre des arguments         */
+
+    GSignalCallback callback;               /* Fonction finale de récept°  */
+    gpointer instance;                      /* Instance GLib initiatrice   */
+    gpointer data;                          /* Donnée utilisateur associée */
+
+    guint n_params;                         /* Nombre de paramètres        */
+    unsigned long params[0];                /* Paramètres récupérés        */
+
+} gsignal_wrapper_info;
+
+
+/* Réceptionne un signal et redirige son exécution. */
+static void carry_signal_to_main_thread(gsignal_wrapper_info *, ...);
+
+/* Transmet un signal dans le contexte principal. */
+static gboolean to_main_wrapper(gsignal_wrapper_info *);
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : info = 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(gsignal_wrapper_info *info)
+{
+    gpointer data1;                         /* Premier argument à envoyer  */
+    gpointer data2;                         /* Dernier argument à envoyer  */
+
+    if (info->flags & G_CONNECT_SWAPPED)
+    {
+        data1 = info->data;
+        data2 = info->instance;
+    }
+    else
+    {
+        data1 = info->instance;
+        data2 = info->data;
+    }
+
+    switch (info->n_params - 1)
+    {
+        case 0:
+            info->callback(data1, data2);
+            break;
+
+    }
+
+    return G_SOURCE_REMOVE;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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 *info, ...)
+{
+    va_list ap;                             /* Liste d'arguments sur pile  */
+    guint i;                                /* Boucle de parcours          */
+
+    va_start(ap, info);
+
+    for (i = 0; i < info->n_params; i++)
+        info->params[i] = va_arg(ap, unsigned long);
+
+    va_end(ap);
+
+    g_idle_add_full(G_PRIORITY_HIGH_IDLE, (GSourceFunc)to_main_wrapper, info, free);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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.     *
+*                                                                             *
+*  Description : Reproduit le comportement de la fonction g_signal_connect(). *
+*                                                                             *
+*  Retour      : Identifiant supérieur zéro en cas de succès.                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gulong g_signal_connect_to_main(gpointer instance, const gchar *signal, GCallback handler, gpointer data)
+{
+    guint signal_id;                        /* Identifiant du signal visé  */
+    GSignalQuery query;                     /* Information sur le signal   */
+    gsignal_wrapper_info *info;             /* Encapsulation des données   */
+
+    /* Collection d'informations */
+
+    signal_id = g_signal_lookup(signal, G_TYPE_FROM_INSTANCE(instance));
+
+    g_signal_query(signal_id, &query);
+
+    /* Allocation adaptée */
+
+    info = (gsignal_wrapper_info *)malloc(sizeof(gsignal_wrapper_info) + sizeof(unsigned long) * ++query.n_params);
+
+    info->flags = 0;
+
+    info->callback = (GSignalCallback)handler;
+    info->instance = instance;
+    info->data = data;
+
+    info->n_params = query.n_params;
+
+    return g_signal_connect_swapped(instance, signal, G_CALLBACK(carry_signal_to_main_thread), info);
+
+}
diff --git a/src/glibext/signal.h b/src/glibext/signal.h
new file mode 100644
index 0000000..8d139a7
--- /dev/null
+++ b/src/glibext/signal.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * signal.h - prototypes pour un encadrement des signaux supplémentaire par rapport à celui de la GLib
+ *
+ * Copyright (C) 2009-2012 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA 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.
+ *
+ *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_SIGNAL_H
+#define _GLIBEXT_SIGNAL_H
+
+
+#include <glib-object.h>
+
+
+
+/* Reproduit le comportement de la fonction g_signal_connect(). */
+gulong g_signal_connect_to_main(gpointer, const gchar *, GCallback, gpointer);
+
+
+
+#endif  /* _GLIBEXT_SIGNAL_H */
diff --git a/src/project.c b/src/project.c
index a555f2d..faf232a 100644
--- a/src/project.c
+++ b/src/project.c
@@ -32,6 +32,7 @@
 #include "analysis/binaries/file.h"
 #include "common/xml.h"
 #include "core/params.h"
+#include "glibext/signal.h"
 #include "gtkext/easygtk.h"
 #include "gtkext/gtkblockview.h"
 #include "gtkext/gtkgraphview.h"
@@ -209,8 +210,8 @@ GStudyProject *g_study_project_open(GObject *ref, const char *filename)
 
         if (binary != NULL)
         {
-            g_signal_connect(binary, "disassembly-done",
-                             G_CALLBACK(g_study_project_add_loaded_binary), result);
+            g_signal_connect_to_main(binary, "disassembly-done",
+                                     G_CALLBACK(g_study_project_add_loaded_binary), result);
             g_loaded_binary_analyse(binary);
         }
 
-- 
cgit v0.11.2-87-g4458