/* 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 .
*/
#include "signal.h"
#include
#include
/* 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);
}