mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 07:56:14 +01:00
bbc5a3adac
Sat Feb 17 04:55:35 2001 Tim Janik <timj@gtk.org> * gtype.[hc]: changed collect_format, collect_value() and lcopy_format, lcopy_value() in the GTypeValueTable. the collect functions are now called only once per value, collect_format/lcopy_format are strings that enlist all necessary GTypeCValues to be varargs-collected. * gvalue.h: ranamed STATIC_TAG to G_VALUE_NOCOPY_CONTENTS to indicate that a value shouldn't copy its contents. * gvaluecollector.h: changed G_VALUE_COLLECT() and G_VALUE_LCOPY() macros to carry an additional argument (flags) that can be used to pass G_VALUE_NOCOPY_CONTENTS along to the collection functions. * *.c: adapted collect_value() and lcopy_value() functions to the new prototypes, support G_VALUE_NOCOPY_CONTENTS where apropriate. * gsignal.[hc]: introduced a G_SIGNAL_TYPE_STATIC_SCOPE flag that can be passed along (ORed) with the parameter types, indicating that the emission arguments are to be considered static for the scope of the emission. should be used with care and only if the caller knows that a parameter cannot be destroyed/freed from signal handlers connected to an emission.
2049 lines
56 KiB
C
2049 lines
56 KiB
C
/* GObject - GLib Type, Object, Parameter and Signal Library
|
|
* Copyright (C) 2000 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General
|
|
* Public License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*
|
|
* this code is based on the original GtkSignal implementation
|
|
* for the Gtk+ library by Peter Mattis <petm@xcf.berkeley.edu>
|
|
*/
|
|
|
|
/*
|
|
* MT safe
|
|
*/
|
|
|
|
#include "gsignal.h"
|
|
#include "gbsearcharray.h"
|
|
#include "gvaluecollector.h"
|
|
#include <string.h>
|
|
|
|
|
|
/* pre allocation configurations
|
|
*/
|
|
#define MAX_STACK_VALUES (16)
|
|
#define BSA_PRE_ALLOC (20)
|
|
#define HANDLER_PRE_ALLOC (48)
|
|
#define EMISSION_PRE_ALLOC (16)
|
|
|
|
#define REPORT_BUG "please report occourance circumstances to gtk-devel-list@gnome.org"
|
|
#ifdef G_ENABLE_DEBUG
|
|
#define IF_DEBUG(debug_type, cond) if ((_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) || cond)
|
|
static volatile gpointer *g_trace_instance_signals = NULL;
|
|
static volatile gpointer *g_trap_instance_signals = NULL;
|
|
#endif /* G_ENABLE_DEBUG */
|
|
|
|
|
|
/* --- generic allocation --- */
|
|
/* we special case allocations generically by replacing
|
|
* these functions with more speed/memory aware variants
|
|
*/
|
|
#ifndef DISABLE_MEM_POOLS
|
|
static inline gpointer
|
|
g_generic_node_alloc (GTrashStack **trash_stack_p,
|
|
guint sizeof_node,
|
|
guint nodes_pre_alloc)
|
|
{
|
|
gpointer node = g_trash_stack_pop (trash_stack_p);
|
|
|
|
if (!node)
|
|
{
|
|
guint8 *block;
|
|
|
|
nodes_pre_alloc = MAX (nodes_pre_alloc, 1);
|
|
block = g_malloc (sizeof_node * nodes_pre_alloc);
|
|
while (--nodes_pre_alloc)
|
|
{
|
|
g_trash_stack_push (trash_stack_p, block);
|
|
block += sizeof_node;
|
|
}
|
|
node = block;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
#define g_generic_node_free(trash_stack_p, node) g_trash_stack_push (trash_stack_p, node)
|
|
#else /* !DISABLE_MEM_POOLS */
|
|
#define g_generic_node_alloc(t,sizeof_node,p) g_malloc (sizeof_node)
|
|
#define g_generic_node_free(t,node) g_free (node)
|
|
#endif /* !DISABLE_MEM_POOLS */
|
|
|
|
|
|
/* --- typedefs --- */
|
|
typedef struct _SignalNode SignalNode;
|
|
typedef struct _SignalKey SignalKey;
|
|
typedef struct _Emission Emission;
|
|
typedef struct _Handler Handler;
|
|
typedef struct _HandlerList HandlerList;
|
|
typedef struct _HandlerMatch HandlerMatch;
|
|
typedef enum
|
|
{
|
|
EMISSION_STOP,
|
|
EMISSION_RUN,
|
|
EMISSION_HOOK,
|
|
EMISSION_RESTART
|
|
} EmissionState;
|
|
|
|
|
|
/* --- prototypes --- */
|
|
static inline guint signal_id_lookup (GQuark quark,
|
|
GType itype);
|
|
static void signal_destroy_R (SignalNode *signal_node);
|
|
static inline HandlerList* handler_list_ensure (guint signal_id,
|
|
gpointer instance);
|
|
static inline HandlerList* handler_list_lookup (guint signal_id,
|
|
gpointer instance);
|
|
static inline Handler* handler_new (gboolean after);
|
|
static void handler_insert (guint signal_id,
|
|
gpointer instance,
|
|
Handler *handler);
|
|
static Handler* handler_lookup (gpointer instance,
|
|
guint handler_id,
|
|
guint *signal_id_p);
|
|
static inline HandlerMatch* handler_match_prepend (HandlerMatch *list,
|
|
Handler *handler,
|
|
guint signal_id);
|
|
static inline HandlerMatch* handler_match_free1_R (HandlerMatch *node,
|
|
gpointer instance);
|
|
static HandlerMatch* handlers_find (gpointer instance,
|
|
GSignalMatchType mask,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gpointer func,
|
|
gpointer data,
|
|
gboolean one_and_only);
|
|
static inline void handler_ref (Handler *handler);
|
|
static inline void handler_unref_R (guint signal_id,
|
|
gpointer instance,
|
|
Handler *handler);
|
|
static inline void emission_push (Emission **emission_list_p,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
gpointer instance,
|
|
EmissionState *state_p);
|
|
static inline void emission_pop (Emission **emission_list_p,
|
|
EmissionState *state_p);
|
|
static inline Emission* emission_find (Emission *emission_list,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
gpointer instance);
|
|
static gboolean signal_emit_R (SignalNode *node,
|
|
GQuark detail,
|
|
gpointer instance,
|
|
GValue *return_value,
|
|
const GValue *instance_and_params);
|
|
|
|
|
|
/* --- structures --- */
|
|
struct _SignalNode
|
|
{
|
|
/* permanent portion */
|
|
guint signal_id;
|
|
GType itype;
|
|
gchar *name;
|
|
guint destroyed : 1;
|
|
|
|
/* reinitializable portion */
|
|
guint flags : 8;
|
|
guint n_params : 8;
|
|
GType *param_types; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
|
|
GType return_type; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
|
|
GClosure *class_closure;
|
|
GSignalAccumulator accumulator;
|
|
GSignalCMarshaller c_marshaller;
|
|
GHookList *emission_hooks;
|
|
};
|
|
|
|
struct _SignalKey
|
|
{
|
|
GType itype;
|
|
GQuark quark;
|
|
guint signal_id;
|
|
};
|
|
|
|
struct _Emission
|
|
{
|
|
Emission *next;
|
|
guint signal_id;
|
|
GQuark detail;
|
|
gpointer instance;
|
|
EmissionState *state_p;
|
|
};
|
|
|
|
struct _HandlerList
|
|
{
|
|
guint signal_id;
|
|
Handler *handlers;
|
|
};
|
|
struct _Handler
|
|
{
|
|
guint id;
|
|
Handler *next;
|
|
Handler *prev;
|
|
GQuark detail;
|
|
guint ref_count : 16;
|
|
#define HANDLER_MAX_REF_COUNT (1 << 16)
|
|
guint block_count : 12;
|
|
#define HANDLER_MAX_BLOCK_COUNT (1 << 12)
|
|
guint after : 1;
|
|
GClosure *closure;
|
|
};
|
|
struct _HandlerMatch
|
|
{
|
|
Handler *handler;
|
|
HandlerMatch *next;
|
|
union {
|
|
guint signal_id;
|
|
gpointer dummy;
|
|
} d;
|
|
};
|
|
|
|
|
|
/* --- variables --- */
|
|
static GBSearchArray g_signal_key_bsa = { NULL, 0, 0, 0, NULL };
|
|
static GHashTable *g_handler_list_bsa_ht = NULL;
|
|
static Emission *g_recursive_emissions = NULL;
|
|
static Emission *g_restart_emissions = NULL;
|
|
static GTrashStack *g_bsa_ts = NULL;
|
|
static GTrashStack *g_handler_ts = NULL;
|
|
static GTrashStack *g_emission_ts = NULL;
|
|
G_LOCK_DEFINE_STATIC (g_signal_mutex);
|
|
|
|
|
|
/* --- signal nodes --- */
|
|
static guint g_n_signal_nodes = 0;
|
|
static SignalNode **g_signal_nodes = NULL;
|
|
|
|
static inline SignalNode*
|
|
LOOKUP_SIGNAL_NODE (register guint signal_id)
|
|
{
|
|
if (signal_id < g_n_signal_nodes)
|
|
return g_signal_nodes[signal_id];
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* --- functions --- */
|
|
static inline guint
|
|
signal_id_lookup (GQuark quark,
|
|
GType itype)
|
|
{
|
|
GType *ifaces, type = itype;
|
|
SignalKey key;
|
|
guint n_ifaces;
|
|
|
|
key.quark = quark;
|
|
|
|
/* try looking up signals for this type and its anchestors */
|
|
do
|
|
{
|
|
SignalKey *signal_key;
|
|
|
|
key.itype = type;
|
|
signal_key = g_bsearch_array_lookup (&g_signal_key_bsa, &key);
|
|
|
|
if (signal_key)
|
|
return signal_key->signal_id;
|
|
|
|
type = g_type_parent (type);
|
|
}
|
|
while (type);
|
|
|
|
/* no luck, try interfaces it exports */
|
|
ifaces = g_type_interfaces (itype, &n_ifaces);
|
|
while (n_ifaces--)
|
|
{
|
|
SignalKey *signal_key;
|
|
|
|
key.itype = ifaces[n_ifaces];
|
|
signal_key = g_bsearch_array_lookup (&g_signal_key_bsa, &key);
|
|
|
|
if (signal_key)
|
|
{
|
|
g_free (ifaces);
|
|
return signal_key->signal_id;
|
|
}
|
|
}
|
|
g_free (ifaces);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
handler_lists_cmp (gconstpointer node1,
|
|
gconstpointer node2)
|
|
{
|
|
const HandlerList *hlist1 = node1, *hlist2 = node2;
|
|
|
|
return G_BSEARCH_ARRAY_CMP (hlist1->signal_id, hlist2->signal_id);
|
|
}
|
|
|
|
static inline HandlerList*
|
|
handler_list_ensure (guint signal_id,
|
|
gpointer instance)
|
|
{
|
|
GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
|
|
HandlerList key;
|
|
|
|
if (!hlbsa)
|
|
{
|
|
hlbsa = g_generic_node_alloc (&g_bsa_ts,
|
|
sizeof (GBSearchArray),
|
|
BSA_PRE_ALLOC);
|
|
hlbsa->cmp_func = handler_lists_cmp;
|
|
hlbsa->sizeof_node = sizeof (HandlerList);
|
|
hlbsa->flags = G_BSEARCH_DEFER_SHRINK;
|
|
hlbsa->n_nodes = 0;
|
|
hlbsa->nodes = NULL;
|
|
g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa);
|
|
}
|
|
key.signal_id = signal_id;
|
|
key.handlers = NULL;
|
|
|
|
return g_bsearch_array_insert (hlbsa, &key, FALSE);
|
|
}
|
|
|
|
static inline HandlerList*
|
|
handler_list_lookup (guint signal_id,
|
|
gpointer instance)
|
|
{
|
|
GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
|
|
HandlerList key;
|
|
|
|
key.signal_id = signal_id;
|
|
|
|
return hlbsa ? g_bsearch_array_lookup (hlbsa, &key) : NULL;
|
|
}
|
|
|
|
static Handler*
|
|
handler_lookup (gpointer instance,
|
|
guint handler_id,
|
|
guint *signal_id_p)
|
|
{
|
|
GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
|
|
|
|
if (hlbsa)
|
|
{
|
|
guint i;
|
|
|
|
for (i = 0; i < hlbsa->n_nodes; i++)
|
|
{
|
|
HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
|
|
Handler *handler;
|
|
|
|
for (handler = hlist->handlers; handler; handler = handler->next)
|
|
if (handler->id == handler_id)
|
|
{
|
|
if (signal_id_p)
|
|
*signal_id_p = hlist->signal_id;
|
|
|
|
return handler;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static inline HandlerMatch*
|
|
handler_match_prepend (HandlerMatch *list,
|
|
Handler *handler,
|
|
guint signal_id)
|
|
{
|
|
HandlerMatch *node;
|
|
|
|
/* yeah, we could use our own memchunk here, introducing yet more
|
|
* rarely used cached nodes and extra allocation overhead.
|
|
* instead, we use GList* nodes, since they are exactly the size
|
|
* we need and are already cached. g_signal_init() asserts this.
|
|
*/
|
|
node = (HandlerMatch*) g_list_alloc ();
|
|
node->handler = handler;
|
|
node->next = list;
|
|
node->d.signal_id = signal_id;
|
|
handler_ref (handler);
|
|
|
|
return node;
|
|
}
|
|
static inline HandlerMatch*
|
|
handler_match_free1_R (HandlerMatch *node,
|
|
gpointer instance)
|
|
{
|
|
HandlerMatch *next = node->next;
|
|
|
|
handler_unref_R (node->d.signal_id, instance, node->handler);
|
|
g_list_free_1 ((GList*) node);
|
|
|
|
return next;
|
|
}
|
|
|
|
static HandlerMatch*
|
|
handlers_find (gpointer instance,
|
|
GSignalMatchType mask,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gpointer func,
|
|
gpointer data,
|
|
gboolean one_and_only)
|
|
{
|
|
HandlerMatch *mlist = NULL;
|
|
|
|
if (mask & G_SIGNAL_MATCH_ID)
|
|
{
|
|
HandlerList *hlist = handler_list_lookup (signal_id, instance);
|
|
Handler *handler;
|
|
SignalNode *node = NULL;
|
|
|
|
if (mask & G_SIGNAL_MATCH_FUNC)
|
|
{
|
|
node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
if (!node || !node->c_marshaller)
|
|
return NULL;
|
|
}
|
|
|
|
mask = ~mask;
|
|
for (handler = hlist ? hlist->handlers : NULL; handler; handler = handler->next)
|
|
if (handler->id &&
|
|
((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
|
|
((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
|
|
((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
|
|
((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
|
|
((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
|
|
handler->closure->meta_marshal == 0 &&
|
|
((GCClosure*) handler->closure)->callback == func)))
|
|
{
|
|
mlist = handler_match_prepend (mlist, handler, signal_id);
|
|
if (one_and_only)
|
|
return mlist;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
|
|
|
|
mask = ~mask;
|
|
if (hlbsa)
|
|
{
|
|
guint i;
|
|
|
|
for (i = 0; i < hlbsa->n_nodes; i++)
|
|
{
|
|
HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
|
|
SignalNode *node = NULL;
|
|
Handler *handler;
|
|
|
|
if (!(mask & G_SIGNAL_MATCH_FUNC))
|
|
{
|
|
node = LOOKUP_SIGNAL_NODE (hlist->signal_id);
|
|
if (!node->c_marshaller)
|
|
continue;
|
|
}
|
|
|
|
for (handler = hlist->handlers; handler; handler = handler->next)
|
|
if (handler->id &&
|
|
((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
|
|
((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
|
|
((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
|
|
((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
|
|
((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
|
|
handler->closure->meta_marshal == 0 &&
|
|
((GCClosure*) handler->closure)->callback == func)))
|
|
{
|
|
mlist = handler_match_prepend (mlist, handler, hlist->signal_id);
|
|
if (one_and_only)
|
|
return mlist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return mlist;
|
|
}
|
|
|
|
static inline Handler*
|
|
handler_new (gboolean after)
|
|
{
|
|
static guint handler_id = 1;
|
|
Handler *handler = g_generic_node_alloc (&g_handler_ts,
|
|
sizeof (Handler),
|
|
HANDLER_PRE_ALLOC);
|
|
#ifndef G_DISABLE_CHECKS
|
|
if (handler_id == 0)
|
|
g_error (G_STRLOC ": handler id overflow, %s", REPORT_BUG);
|
|
#endif
|
|
|
|
handler->id = handler_id++;
|
|
handler->prev = NULL;
|
|
handler->next = NULL;
|
|
handler->detail = 0;
|
|
handler->ref_count = 1;
|
|
handler->block_count = 0;
|
|
handler->after = after != FALSE;
|
|
handler->closure = NULL;
|
|
|
|
return handler;
|
|
}
|
|
|
|
static inline void
|
|
handler_ref (Handler *handler)
|
|
{
|
|
g_return_if_fail (handler->ref_count > 0);
|
|
|
|
#ifndef G_DISABLE_CHECKS
|
|
if (handler->ref_count >= HANDLER_MAX_REF_COUNT - 1)
|
|
g_error (G_STRLOC ": handler ref_count overflow, %s", REPORT_BUG);
|
|
#endif
|
|
|
|
handler->ref_count += 1;
|
|
}
|
|
|
|
static inline void
|
|
handler_unref_R (guint signal_id,
|
|
gpointer instance,
|
|
Handler *handler)
|
|
{
|
|
g_return_if_fail (handler->ref_count > 0);
|
|
|
|
handler->ref_count -= 1;
|
|
if (!handler->ref_count)
|
|
{
|
|
if (handler->next)
|
|
handler->next->prev = handler->prev;
|
|
if (handler->prev) /* watch out for g_signal_handlers_destroy()! */
|
|
handler->prev->next = handler->next;
|
|
else
|
|
{
|
|
HandlerList *hlist = handler_list_lookup (signal_id, instance);
|
|
|
|
hlist->handlers = handler->next;
|
|
}
|
|
G_UNLOCK (g_signal_mutex);
|
|
g_closure_unref (handler->closure);
|
|
G_LOCK (g_signal_mutex);
|
|
g_generic_node_free (&g_handler_ts, handler);
|
|
}
|
|
}
|
|
|
|
static void
|
|
handler_insert (guint signal_id,
|
|
gpointer instance,
|
|
Handler *handler)
|
|
{
|
|
HandlerList *hlist;
|
|
|
|
g_assert (handler->prev == NULL && handler->next == NULL); /* paranoid */
|
|
|
|
hlist = handler_list_ensure (signal_id, instance);
|
|
if (!hlist->handlers)
|
|
hlist->handlers = handler;
|
|
else if (hlist->handlers->after && !handler->after)
|
|
{
|
|
handler->next = hlist->handlers;
|
|
hlist->handlers->prev = handler;
|
|
hlist->handlers = handler;
|
|
}
|
|
else
|
|
{
|
|
Handler *tmp = hlist->handlers;
|
|
|
|
if (handler->after)
|
|
while (tmp->next)
|
|
tmp = tmp->next;
|
|
else
|
|
while (tmp->next && !tmp->next->after)
|
|
tmp = tmp->next;
|
|
if (tmp->next)
|
|
tmp->next->prev = handler;
|
|
handler->next = tmp->next;
|
|
handler->prev = tmp;
|
|
tmp->next = handler;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
emission_push (Emission **emission_list_p,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
gpointer instance,
|
|
EmissionState *state_p)
|
|
{
|
|
Emission *emission = g_generic_node_alloc (&g_emission_ts,
|
|
sizeof (Emission),
|
|
EMISSION_PRE_ALLOC);
|
|
emission->next = *emission_list_p;
|
|
emission->signal_id = signal_id;
|
|
emission->detail = detail;
|
|
emission->instance = instance;
|
|
emission->state_p = state_p;
|
|
*emission_list_p = emission;
|
|
}
|
|
|
|
static inline void
|
|
emission_pop (Emission **emission_list_p,
|
|
EmissionState *state_p)
|
|
{
|
|
Emission **loc = emission_list_p, *emission = *loc;
|
|
|
|
while (emission->state_p != state_p)
|
|
{
|
|
loc = &emission->next;
|
|
emission = *loc;
|
|
}
|
|
*loc = emission->next;
|
|
g_generic_node_free (&g_emission_ts, emission);
|
|
}
|
|
|
|
static inline Emission*
|
|
emission_find (Emission *emission_list,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
gpointer instance)
|
|
{
|
|
Emission *emission;
|
|
|
|
for (emission = emission_list; emission; emission = emission->next)
|
|
if (emission->instance == instance &&
|
|
emission->signal_id == signal_id &&
|
|
emission->detail == detail)
|
|
return emission;
|
|
return NULL;
|
|
}
|
|
|
|
static gint
|
|
signal_key_cmp (gconstpointer node1,
|
|
gconstpointer node2)
|
|
{
|
|
const SignalKey *key1 = node1, *key2 = node2;
|
|
|
|
if (key1->itype == key2->itype)
|
|
return G_BSEARCH_ARRAY_CMP (key1->quark, key2->quark);
|
|
else
|
|
return G_BSEARCH_ARRAY_CMP (key1->itype, key2->itype);
|
|
}
|
|
|
|
void
|
|
g_signal_init (void) /* sync with gtype.c */
|
|
{
|
|
G_LOCK (g_signal_mutex);
|
|
if (!g_n_signal_nodes)
|
|
{
|
|
/* handler_id_node_prepend() requires this */
|
|
g_assert (sizeof (GList) == sizeof (HandlerMatch));
|
|
|
|
/* setup signal key array */
|
|
g_signal_key_bsa.cmp_func = signal_key_cmp;
|
|
g_signal_key_bsa.sizeof_node = sizeof (SignalKey);
|
|
g_signal_key_bsa.flags = G_BSEARCH_ALIGN_POWER2; /* alloc-only */
|
|
|
|
/* setup handler list binary searchable array hash table (in german, that'd be one word ;) */
|
|
g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL);
|
|
|
|
/* invalid (0) signal_id */
|
|
g_n_signal_nodes = 1;
|
|
g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
|
|
g_signal_nodes[0] = NULL;
|
|
}
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
void
|
|
_g_signals_destroy (GType itype)
|
|
{
|
|
guint i;
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
for (i = 1; i < g_n_signal_nodes; i++)
|
|
{
|
|
SignalNode *node = g_signal_nodes[i];
|
|
|
|
if (node->itype == itype)
|
|
{
|
|
if (node->destroyed)
|
|
g_warning (G_STRLOC ": signal \"%s\" of type `%s' already destroyed",
|
|
node->name,
|
|
g_type_name (node->itype));
|
|
else
|
|
signal_destroy_R (node);
|
|
}
|
|
}
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
void
|
|
g_signal_stop_emission (gpointer instance,
|
|
guint signal_id,
|
|
GQuark detail)
|
|
{
|
|
SignalNode *node;
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
|
|
g_return_if_fail (signal_id > 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
if (node && detail && !(node->flags & G_SIGNAL_DETAILED))
|
|
{
|
|
g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return;
|
|
}
|
|
if (node && g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
|
|
{
|
|
Emission *emission_list = node->flags & G_SIGNAL_NO_RECURSE ? g_restart_emissions : g_recursive_emissions;
|
|
Emission *emission = emission_find (emission_list, signal_id, detail, instance);
|
|
|
|
if (emission)
|
|
{
|
|
if (*emission->state_p == EMISSION_HOOK)
|
|
g_warning (G_STRLOC ": emission of signal \"%s\" for instance `%p' cannot be stopped from emission hook",
|
|
node->name, instance);
|
|
else if (*emission->state_p == EMISSION_RUN)
|
|
*emission->state_p = EMISSION_STOP;
|
|
}
|
|
else
|
|
g_warning (G_STRLOC ": no emission of signal \"%s\" to stop for instance `%p'",
|
|
node->name, instance);
|
|
}
|
|
else
|
|
g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
static inline guint
|
|
signal_parse_name (const gchar *name,
|
|
GType itype,
|
|
GQuark *detail_p,
|
|
gboolean force_quark)
|
|
{
|
|
const gchar *colon = strchr (name, ':');
|
|
guint signal_id;
|
|
|
|
if (!colon)
|
|
{
|
|
signal_id = signal_id_lookup (g_quark_try_string (name), itype);
|
|
if (signal_id && detail_p)
|
|
*detail_p = 0;
|
|
}
|
|
else if (colon[1] == ':')
|
|
{
|
|
gchar buffer[32];
|
|
guint l = colon - name;
|
|
|
|
if (l < 32)
|
|
{
|
|
memcpy (buffer, name, l);
|
|
buffer[l] = 0;
|
|
signal_id = signal_id_lookup (g_quark_try_string (buffer), itype);
|
|
}
|
|
else
|
|
{
|
|
gchar *signal = g_new (gchar, l + 1);
|
|
|
|
memcpy (signal, name, l);
|
|
signal[l] = 0;
|
|
signal_id = signal_id_lookup (g_quark_try_string (signal), itype);
|
|
g_free (signal);
|
|
}
|
|
|
|
if (signal_id && detail_p)
|
|
*detail_p = colon[2] ? (force_quark ? g_quark_from_string : g_quark_try_string) (colon + 2) : 0;
|
|
}
|
|
else
|
|
signal_id = 0;
|
|
return signal_id;
|
|
}
|
|
|
|
gboolean
|
|
g_signal_parse_name (const gchar *detailed_signal,
|
|
GType itype,
|
|
guint *signal_id_p,
|
|
GQuark *detail_p,
|
|
gboolean force_detail_quark)
|
|
{
|
|
GQuark detail = 0;
|
|
guint signal_id;
|
|
|
|
g_return_val_if_fail (detailed_signal != NULL, FALSE);
|
|
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), FALSE);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
signal_id = signal_parse_name (detailed_signal, itype, &detail, force_detail_quark);
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
if (signal_id)
|
|
{
|
|
if (signal_id_p)
|
|
*signal_id_p = signal_id;
|
|
if (detail_p)
|
|
*detail_p = detail;
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
guint
|
|
g_signal_lookup (const gchar *name,
|
|
GType itype)
|
|
{
|
|
guint signal_id;
|
|
|
|
g_return_val_if_fail (name != NULL, 0);
|
|
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
signal_id = signal_id_lookup (g_quark_try_string (name), itype);
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
return signal_id;
|
|
}
|
|
|
|
gchar*
|
|
g_signal_name (guint signal_id)
|
|
{
|
|
SignalNode *node;
|
|
gchar *name;
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
name = node ? node->name : NULL;
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
return name;
|
|
}
|
|
|
|
void
|
|
g_signal_query (guint signal_id,
|
|
GSignalQuery *query)
|
|
{
|
|
SignalNode *node;
|
|
|
|
g_return_if_fail (query != NULL);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
if (!node || node->destroyed)
|
|
query->signal_id = 0;
|
|
else
|
|
{
|
|
query->signal_id = node->signal_id;
|
|
query->signal_name = node->name;
|
|
query->itype = node->itype;
|
|
query->signal_flags = node->flags;
|
|
query->return_type = node->return_type;
|
|
query->n_params = node->n_params;
|
|
query->param_types = node->param_types;
|
|
}
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
guint*
|
|
g_signal_list_ids (GType itype,
|
|
guint *n_ids)
|
|
{
|
|
SignalKey *keys;
|
|
GArray *result;
|
|
guint n_nodes;
|
|
guint i;
|
|
|
|
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
|
|
g_return_val_if_fail (n_ids != NULL, NULL);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
|
|
keys = g_signal_key_bsa.nodes;
|
|
n_nodes = g_signal_key_bsa.n_nodes;
|
|
result = g_array_new (FALSE, FALSE, sizeof (guint));
|
|
|
|
for (i = 0; i < n_nodes; i++)
|
|
if (keys[i].itype == itype)
|
|
{
|
|
gchar *name = g_quark_to_string (keys[i].quark);
|
|
|
|
/* Signal names with "_" in them are aliases to the same
|
|
* name with "-" instead of "_".
|
|
*/
|
|
if (!strchr (name, '_'))
|
|
g_array_append_val (result, keys[i].signal_id);
|
|
}
|
|
|
|
*n_ids = result->len;
|
|
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
return (guint *) g_array_free (result, FALSE);
|
|
}
|
|
|
|
guint
|
|
g_signal_new_valist (const gchar *signal_name,
|
|
GType itype,
|
|
GSignalFlags signal_flags,
|
|
GClosure *class_closure,
|
|
GSignalAccumulator accumulator,
|
|
GSignalCMarshaller c_marshaller,
|
|
GType return_type,
|
|
guint n_params,
|
|
va_list args)
|
|
{
|
|
GType *param_types;
|
|
guint i;
|
|
guint signal_id;
|
|
|
|
if (n_params > 0)
|
|
{
|
|
param_types = g_new (GType, n_params);
|
|
|
|
for (i = 0; i < n_params; i++)
|
|
param_types[i] = va_arg (args, GType);
|
|
}
|
|
else
|
|
param_types = NULL;
|
|
|
|
signal_id = g_signal_newv (signal_name, itype, signal_flags,
|
|
class_closure, accumulator, c_marshaller,
|
|
return_type, n_params, param_types);
|
|
g_free (param_types);
|
|
|
|
return signal_id;
|
|
}
|
|
|
|
guint
|
|
g_signal_newc (const gchar *signal_name,
|
|
GType itype,
|
|
GSignalFlags signal_flags,
|
|
guint class_offset,
|
|
GSignalAccumulator accumulator,
|
|
GSignalCMarshaller c_marshaller,
|
|
GType return_type,
|
|
guint n_params,
|
|
...)
|
|
{
|
|
va_list args;
|
|
guint signal_id;
|
|
|
|
g_return_val_if_fail (signal_name != NULL, 0);
|
|
|
|
va_start (args, n_params);
|
|
|
|
signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
|
|
g_signal_type_cclosure_new (itype, class_offset),
|
|
accumulator, c_marshaller,
|
|
return_type, n_params, args);
|
|
|
|
va_end (args);
|
|
|
|
return signal_id;
|
|
}
|
|
|
|
guint
|
|
g_signal_newv (const gchar *signal_name,
|
|
GType itype,
|
|
GSignalFlags signal_flags,
|
|
GClosure *class_closure,
|
|
GSignalAccumulator accumulator,
|
|
GSignalCMarshaller c_marshaller,
|
|
GType return_type,
|
|
guint n_params,
|
|
GType *param_types)
|
|
{
|
|
gchar *name;
|
|
guint signal_id, i;
|
|
SignalNode *node;
|
|
|
|
g_return_val_if_fail (signal_name != NULL, 0);
|
|
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
|
|
if (n_params)
|
|
g_return_val_if_fail (param_types != NULL, 0);
|
|
if (return_type != G_TYPE_NONE)
|
|
g_return_val_if_fail (accumulator == NULL, 0);
|
|
|
|
name = g_strdup (signal_name);
|
|
g_strdelimit (name, G_STR_DELIMITERS ":^", '_'); // FIXME do character checks like for types
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
|
|
signal_id = signal_id_lookup (g_quark_try_string (name), itype);
|
|
node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
if (node && !node->destroyed)
|
|
{
|
|
g_warning (G_STRLOC ": signal \"%s\" already exists in the `%s' %s",
|
|
name,
|
|
g_type_name (node->itype),
|
|
G_TYPE_IS_INTERFACE (node->itype) ? "interface" : "class ancestry");
|
|
g_free (name);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return 0;
|
|
}
|
|
if (node && node->itype != itype)
|
|
{
|
|
g_warning (G_STRLOC ": signal \"%s\" for type `%s' was previously created for type `%s'",
|
|
name,
|
|
g_type_name (itype),
|
|
g_type_name (node->itype));
|
|
g_free (name);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return 0;
|
|
}
|
|
for (i = 0; i < n_params; i++)
|
|
if (!G_TYPE_IS_VALUE (param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE) ||
|
|
(param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE) == G_TYPE_ENUM ||
|
|
(param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE) == G_TYPE_FLAGS) /* FIXME: kludge */
|
|
{
|
|
g_warning (G_STRLOC ": parameter %d of type `%s' for signal \"%s::%s\" is not a value type",
|
|
i + 1, g_type_name (param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE), g_type_name (itype), name);
|
|
g_free (name);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return 0;
|
|
}
|
|
if (return_type != G_TYPE_NONE && !G_TYPE_IS_VALUE (return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE))
|
|
{
|
|
g_warning (G_STRLOC ": return value of type `%s' for signal \"%s::%s\" is not a value type",
|
|
g_type_name (return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE), g_type_name (itype), name);
|
|
g_free (name);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return 0;
|
|
}
|
|
|
|
/* setup permanent portion of signal node */
|
|
if (!node)
|
|
{
|
|
SignalKey key;
|
|
|
|
signal_id = g_n_signal_nodes++;
|
|
node = g_new (SignalNode, 1);
|
|
node->signal_id = signal_id;
|
|
g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
|
|
g_signal_nodes[signal_id] = node;
|
|
node->itype = itype;
|
|
node->name = name;
|
|
key.itype = itype;
|
|
key.quark = g_quark_from_string (node->name);
|
|
key.signal_id = signal_id;
|
|
g_bsearch_array_insert (&g_signal_key_bsa, &key, FALSE);
|
|
g_strdelimit (node->name, "_", '-');
|
|
key.quark = g_quark_from_static_string (node->name);
|
|
g_bsearch_array_insert (&g_signal_key_bsa, &key, FALSE);
|
|
}
|
|
node->destroyed = FALSE;
|
|
|
|
/* setup reinitializable portion */
|
|
node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
|
|
node->n_params = n_params;
|
|
node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
|
|
node->return_type = return_type;
|
|
node->class_closure = class_closure ? g_closure_ref (class_closure) : NULL;
|
|
if (class_closure)
|
|
g_closure_sink (class_closure);
|
|
node->accumulator = accumulator;
|
|
node->c_marshaller = c_marshaller;
|
|
node->emission_hooks = NULL;
|
|
if (node->c_marshaller && class_closure && G_CLOSURE_NEEDS_MARSHAL (class_closure))
|
|
g_closure_set_marshal (class_closure, node->c_marshaller);
|
|
|
|
G_UNLOCK (g_signal_mutex);
|
|
return signal_id;
|
|
}
|
|
|
|
static void
|
|
signal_destroy_R (SignalNode *signal_node)
|
|
{
|
|
SignalNode node = *signal_node;
|
|
|
|
signal_node->destroyed = TRUE;
|
|
|
|
/* reentrancy caution, zero out real contents first */
|
|
signal_node->n_params = 0;
|
|
signal_node->param_types = NULL;
|
|
signal_node->return_type = 0;
|
|
signal_node->class_closure = NULL;
|
|
signal_node->accumulator = NULL;
|
|
signal_node->c_marshaller = NULL;
|
|
signal_node->emission_hooks = NULL;
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
/* check current emissions */
|
|
{
|
|
Emission *emission;
|
|
|
|
for (emission = (node.flags & G_SIGNAL_NO_RECURSE) ? g_restart_emissions : g_recursive_emissions;
|
|
emission; emission = emission->next)
|
|
if (emission->signal_id == node.signal_id)
|
|
g_critical (G_STRLOC ": signal \"%s\" being destroyed is currently in emission (instance `%p')",
|
|
node.name, emission->instance);
|
|
}
|
|
#endif
|
|
|
|
/* free contents that need to
|
|
*/
|
|
G_UNLOCK (g_signal_mutex);
|
|
g_free (node.param_types);
|
|
g_closure_unref (node.class_closure);
|
|
if (node.emission_hooks)
|
|
{
|
|
g_hook_list_clear (node.emission_hooks);
|
|
g_free (node.emission_hooks);
|
|
}
|
|
G_LOCK (g_signal_mutex);
|
|
}
|
|
|
|
guint
|
|
g_signal_connect_closure_by_id (gpointer instance,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gboolean after)
|
|
{
|
|
SignalNode *node;
|
|
guint handler_id = 0;
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
|
|
g_return_val_if_fail (signal_id > 0, 0);
|
|
g_return_val_if_fail (closure != NULL, 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
if (node)
|
|
{
|
|
if (detail && !(node->flags & G_SIGNAL_DETAILED))
|
|
g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
|
|
else if (!g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
|
|
g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
|
|
else
|
|
{
|
|
Handler *handler = handler_new (after);
|
|
|
|
handler_id = handler->id;
|
|
handler->detail = detail;
|
|
handler->closure = g_closure_ref (closure);
|
|
g_closure_sink (closure);
|
|
handler_insert (signal_id, instance, handler);
|
|
if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure))
|
|
g_closure_set_marshal (closure, node->c_marshaller);
|
|
}
|
|
}
|
|
else
|
|
g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
return handler_id;
|
|
}
|
|
|
|
guint
|
|
g_signal_connect_closure (gpointer instance,
|
|
const gchar *detailed_signal,
|
|
GClosure *closure,
|
|
gboolean after)
|
|
{
|
|
guint signal_id, handler_id = 0;
|
|
GQuark detail = 0;
|
|
GType itype;
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
|
|
g_return_val_if_fail (detailed_signal != NULL, 0);
|
|
g_return_val_if_fail (closure != NULL, 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
itype = G_TYPE_FROM_INSTANCE (instance);
|
|
signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE);
|
|
if (signal_id)
|
|
{
|
|
SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
|
|
if (detail && !(node->flags & G_SIGNAL_DETAILED))
|
|
g_warning ("%s: signal `%s' does not support details", G_STRLOC, detailed_signal);
|
|
else if (!g_type_is_a (itype, node->itype))
|
|
g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance);
|
|
else
|
|
{
|
|
Handler *handler = handler_new (after);
|
|
|
|
handler_id = handler->id;
|
|
handler->detail = detail;
|
|
handler->closure = g_closure_ref (closure);
|
|
g_closure_sink (closure);
|
|
handler_insert (signal_id, instance, handler);
|
|
if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (handler->closure))
|
|
g_closure_set_marshal (handler->closure, node->c_marshaller);
|
|
}
|
|
}
|
|
else
|
|
g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance);
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
return handler_id;
|
|
}
|
|
|
|
guint
|
|
g_signal_connect_data (gpointer instance,
|
|
const gchar *detailed_signal,
|
|
GCallback c_handler,
|
|
gpointer data,
|
|
GClosureNotify destroy_data,
|
|
gboolean swapped,
|
|
gboolean after)
|
|
{
|
|
guint signal_id, handler_id = 0;
|
|
GQuark detail = 0;
|
|
GType itype;
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
|
|
g_return_val_if_fail (detailed_signal != NULL, 0);
|
|
g_return_val_if_fail (c_handler != NULL, 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
itype = G_TYPE_FROM_INSTANCE (instance);
|
|
signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE);
|
|
if (signal_id)
|
|
{
|
|
SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
|
|
if (detail && !(node->flags & G_SIGNAL_DETAILED))
|
|
g_warning ("%s: signal `%s' does not support details", G_STRLOC, detailed_signal);
|
|
else if (!g_type_is_a (itype, node->itype))
|
|
g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance);
|
|
else
|
|
{
|
|
Handler *handler = handler_new (after);
|
|
|
|
handler_id = handler->id;
|
|
handler->detail = detail;
|
|
handler->closure = g_closure_ref ((swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data));
|
|
g_closure_sink (handler->closure);
|
|
handler_insert (signal_id, instance, handler);
|
|
if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (handler->closure))
|
|
g_closure_set_marshal (handler->closure, node->c_marshaller);
|
|
}
|
|
}
|
|
else
|
|
g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance);
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
return handler_id;
|
|
}
|
|
|
|
void
|
|
g_signal_handler_block (gpointer instance,
|
|
guint handler_id)
|
|
{
|
|
Handler *handler;
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
|
|
g_return_if_fail (handler_id > 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
handler = handler_lookup (instance, handler_id, NULL);
|
|
if (handler)
|
|
{
|
|
#ifndef G_DISABLE_CHECKS
|
|
if (handler->block_count >= HANDLER_MAX_BLOCK_COUNT - 1)
|
|
g_error (G_STRLOC ": handler block_count overflow, %s", REPORT_BUG);
|
|
#endif
|
|
|
|
handler->block_count += 1;
|
|
}
|
|
else
|
|
g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
void
|
|
g_signal_handler_unblock (gpointer instance,
|
|
guint handler_id)
|
|
{
|
|
Handler *handler;
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
|
|
g_return_if_fail (handler_id > 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
handler = handler_lookup (instance, handler_id, NULL);
|
|
if (handler)
|
|
{
|
|
if (handler->block_count)
|
|
handler->block_count -= 1;
|
|
else
|
|
g_warning (G_STRLOC ": handler `%u' of instance `%p' is not blocked", handler_id, instance);
|
|
}
|
|
else
|
|
g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
void
|
|
g_signal_handler_disconnect (gpointer instance,
|
|
guint handler_id)
|
|
{
|
|
Handler *handler;
|
|
guint signal_id;
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
|
|
g_return_if_fail (handler_id > 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
handler = handler_lookup (instance, handler_id, &signal_id);
|
|
if (handler)
|
|
{
|
|
handler->id = 0;
|
|
handler->block_count = 1;
|
|
handler_unref_R (signal_id, instance, handler);
|
|
}
|
|
else
|
|
g_warning ("%s: instance `%p' has no handler with id `%u'", G_STRLOC, instance, handler_id);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
void
|
|
g_signal_handlers_destroy (gpointer instance)
|
|
{
|
|
GBSearchArray *hlbsa;
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
|
|
if (hlbsa)
|
|
{
|
|
guint i;
|
|
|
|
/* reentrancy caution, delete instance trace first */
|
|
g_hash_table_remove (g_handler_list_bsa_ht, instance);
|
|
|
|
for (i = 0; i < hlbsa->n_nodes; i++)
|
|
{
|
|
HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, i);
|
|
Handler *handler = hlist->handlers;
|
|
|
|
while (handler)
|
|
{
|
|
Handler *tmp = handler;
|
|
|
|
handler = tmp->next;
|
|
tmp->block_count = 1;
|
|
/* cruel unlink, this works because _all_ handlers vanish */
|
|
tmp->next = NULL;
|
|
tmp->prev = tmp;
|
|
if (tmp->id)
|
|
{
|
|
tmp->id = 0;
|
|
handler_unref_R (0, NULL, tmp);
|
|
}
|
|
}
|
|
}
|
|
g_free (hlbsa->nodes);
|
|
g_generic_node_free (&g_bsa_ts, hlbsa);
|
|
}
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
guint
|
|
g_signal_handler_find (gpointer instance,
|
|
GSignalMatchType mask,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gpointer func,
|
|
gpointer data)
|
|
{
|
|
guint handler_id = 0;
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
|
|
g_return_val_if_fail ((mask & ~G_SIGNAL_MATCH_MASK) == 0, 0);
|
|
|
|
if (mask & G_SIGNAL_MATCH_MASK)
|
|
{
|
|
HandlerMatch *mlist;
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
mlist = handlers_find (instance, mask, signal_id, detail, closure, func, data, TRUE);
|
|
if (mlist)
|
|
{
|
|
handler_id = mlist->handler->id;
|
|
handler_match_free1_R (mlist, instance);
|
|
}
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
return handler_id;
|
|
}
|
|
|
|
static guint
|
|
signal_handlers_foreach_matched_R (gpointer instance,
|
|
GSignalMatchType mask,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gpointer func,
|
|
gpointer data,
|
|
void (*callback) (gpointer instance,
|
|
guint handler_id))
|
|
{
|
|
HandlerMatch *mlist;
|
|
guint n_handlers = 0;
|
|
|
|
mlist = handlers_find (instance, mask, signal_id, detail, closure, func, data, FALSE);
|
|
while (mlist)
|
|
{
|
|
n_handlers++;
|
|
G_UNLOCK (g_signal_mutex);
|
|
callback (instance, mlist->handler->id);
|
|
G_LOCK (g_signal_mutex);
|
|
mlist = handler_match_free1_R (mlist, instance);
|
|
}
|
|
|
|
return n_handlers;
|
|
}
|
|
|
|
guint
|
|
g_signal_handlers_block_matched (gpointer instance,
|
|
GSignalMatchType mask,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gpointer func,
|
|
gpointer data)
|
|
{
|
|
guint n_handlers = 0;
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
|
|
g_return_val_if_fail ((mask & ~G_SIGNAL_MATCH_MASK) == 0, FALSE);
|
|
|
|
if (mask & (G_SIGNAL_MATCH_CLOSURE | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA))
|
|
{
|
|
G_LOCK (g_signal_mutex);
|
|
n_handlers = signal_handlers_foreach_matched_R (instance, mask, signal_id, detail,
|
|
closure, func, data,
|
|
g_signal_handler_block);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
return n_handlers;
|
|
}
|
|
|
|
guint
|
|
g_signal_handlers_unblock_matched (gpointer instance,
|
|
GSignalMatchType mask,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gpointer func,
|
|
gpointer data)
|
|
{
|
|
guint n_handlers = 0;
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
|
|
g_return_val_if_fail ((mask & ~G_SIGNAL_MATCH_MASK) == 0, FALSE);
|
|
|
|
if (mask & (G_SIGNAL_MATCH_CLOSURE | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA))
|
|
{
|
|
G_LOCK (g_signal_mutex);
|
|
n_handlers = signal_handlers_foreach_matched_R (instance, mask, signal_id, detail,
|
|
closure, func, data,
|
|
g_signal_handler_unblock);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
return n_handlers;
|
|
}
|
|
|
|
guint
|
|
g_signal_handlers_disconnect_matched (gpointer instance,
|
|
GSignalMatchType mask,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GClosure *closure,
|
|
gpointer func,
|
|
gpointer data)
|
|
{
|
|
guint n_handlers = 0;
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
|
|
g_return_val_if_fail ((mask & ~G_SIGNAL_MATCH_MASK) == 0, FALSE);
|
|
|
|
if (mask & (G_SIGNAL_MATCH_CLOSURE | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA))
|
|
{
|
|
G_LOCK (g_signal_mutex);
|
|
n_handlers = signal_handlers_foreach_matched_R (instance, mask, signal_id, detail,
|
|
closure, func, data,
|
|
g_signal_handler_disconnect);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
return n_handlers;
|
|
}
|
|
|
|
gboolean
|
|
g_signal_has_handler_pending (gpointer instance,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
gboolean may_be_blocked)
|
|
{
|
|
HandlerMatch *mlist;
|
|
gboolean has_pending;
|
|
|
|
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), FALSE);
|
|
g_return_val_if_fail (signal_id > 0, FALSE);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
if (detail)
|
|
{
|
|
SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
|
|
if (!(node->flags & G_SIGNAL_DETAILED))
|
|
{
|
|
g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return FALSE;
|
|
}
|
|
}
|
|
mlist = handlers_find (instance,
|
|
(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | (may_be_blocked ? 0 : G_SIGNAL_MATCH_UNBLOCKED)),
|
|
signal_id, detail, NULL, NULL, NULL, TRUE);
|
|
if (mlist)
|
|
{
|
|
has_pending = TRUE;
|
|
handler_match_free1_R (mlist, instance);
|
|
}
|
|
else
|
|
has_pending = FALSE;
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
return has_pending;
|
|
}
|
|
|
|
void
|
|
g_signal_emitv (const GValue *instance_and_params,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
GValue *return_value)
|
|
{
|
|
const GValue *param_values;
|
|
gpointer instance;
|
|
SignalNode *node;
|
|
guint i;
|
|
|
|
g_return_if_fail (instance_and_params != NULL);
|
|
instance = g_value_get_as_pointer (instance_and_params);
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
|
|
g_return_if_fail (signal_id > 0);
|
|
|
|
param_values = instance_and_params + 1;
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
if (!node || !g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
|
|
{
|
|
g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return;
|
|
}
|
|
#ifdef G_ENABLE_DEBUG
|
|
if (detail && !(node->flags & G_SIGNAL_DETAILED))
|
|
{
|
|
g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return;
|
|
}
|
|
for (i = 0; i < node->n_params; i++)
|
|
if (!G_VALUE_HOLDS (param_values + i, node->param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE))
|
|
{
|
|
g_critical ("%s: value for `%s' parameter %u for signal \"%s\" is of type `%s'",
|
|
G_STRLOC,
|
|
g_type_name (node->param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE),
|
|
i,
|
|
node->name,
|
|
G_VALUE_TYPE_NAME (param_values + i));
|
|
G_UNLOCK (g_signal_mutex);
|
|
return;
|
|
}
|
|
if (node->return_type != G_TYPE_NONE)
|
|
{
|
|
if (!return_value)
|
|
{
|
|
g_critical ("%s: return value `%s' for signal \"%s\" is (NULL)",
|
|
G_STRLOC,
|
|
g_type_name (node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE),
|
|
node->name);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return;
|
|
}
|
|
else if (!node->accumulator && !G_VALUE_HOLDS (return_value, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE))
|
|
{
|
|
g_critical ("%s: return value `%s' for signal \"%s\" is of type `%s'",
|
|
G_STRLOC,
|
|
g_type_name (node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE),
|
|
node->name,
|
|
G_VALUE_TYPE_NAME (return_value));
|
|
G_UNLOCK (g_signal_mutex);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
return_value = NULL;
|
|
#endif /* G_ENABLE_DEBUG */
|
|
|
|
signal_emit_R (node, detail, instance, return_value, instance_and_params);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
void
|
|
g_signal_emit_valist (gpointer instance,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
va_list var_args)
|
|
{
|
|
GValue *instance_and_params, stack_values[MAX_STACK_VALUES], *free_me = NULL;
|
|
GValue *param_values;
|
|
SignalNode *node;
|
|
guint i;
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
|
|
g_return_if_fail (signal_id > 0);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
node = LOOKUP_SIGNAL_NODE (signal_id);
|
|
if (!node || !g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype))
|
|
{
|
|
g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return;
|
|
}
|
|
#ifndef G_DISABLE_CHECKS
|
|
if (detail && !(node->flags & G_SIGNAL_DETAILED))
|
|
{
|
|
g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
|
|
G_UNLOCK (g_signal_mutex);
|
|
return;
|
|
}
|
|
#endif /* !G_DISABLE_CHECKS */
|
|
|
|
if (node->n_params < MAX_STACK_VALUES)
|
|
instance_and_params = stack_values;
|
|
else
|
|
{
|
|
free_me = g_new (GValue, node->n_params + 1);
|
|
instance_and_params = free_me;
|
|
}
|
|
param_values = instance_and_params + 1;
|
|
for (i = 0; i < node->n_params; i++)
|
|
{
|
|
gchar *error;
|
|
|
|
param_values[i].g_type = 0;
|
|
g_value_init (param_values + i, node->param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
G_VALUE_COLLECT (param_values + i,
|
|
var_args,
|
|
node->param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE ? G_VALUE_NOCOPY_CONTENTS : 0,
|
|
&error);
|
|
if (error)
|
|
{
|
|
g_warning ("%s: %s", G_STRLOC, error);
|
|
g_free (error);
|
|
|
|
/* we purposely leak the value here, it might not be
|
|
* in a sane state if an error condition occoured
|
|
*/
|
|
while (i--)
|
|
g_value_unset (param_values + i);
|
|
|
|
G_UNLOCK (g_signal_mutex);
|
|
g_free (free_me);
|
|
return;
|
|
}
|
|
}
|
|
instance_and_params->g_type = 0;
|
|
g_value_init (instance_and_params, node->itype);
|
|
g_value_set_instance (instance_and_params, instance);
|
|
if (node->return_type == G_TYPE_NONE)
|
|
signal_emit_R (node, detail, instance, NULL, instance_and_params);
|
|
else
|
|
{
|
|
GValue return_value = { 0, };
|
|
gchar *error = NULL;
|
|
|
|
g_value_init (&return_value, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
if (signal_emit_R (node, detail, instance, &return_value, instance_and_params))
|
|
G_VALUE_LCOPY (&return_value,
|
|
var_args,
|
|
node->return_type & G_SIGNAL_TYPE_STATIC_SCOPE ? G_VALUE_NOCOPY_CONTENTS : 0,
|
|
&error);
|
|
if (!error)
|
|
g_value_unset (&return_value);
|
|
else
|
|
{
|
|
g_warning ("%s: %s", G_STRLOC, error);
|
|
g_free (error);
|
|
|
|
/* we purposely leak the value here, it might not be
|
|
* in a sane state if an error condition occoured
|
|
*/
|
|
}
|
|
}
|
|
for (i = 0; i < node->n_params; i++)
|
|
g_value_unset (param_values + i);
|
|
g_value_unset (instance_and_params);
|
|
if (free_me)
|
|
g_free (free_me);
|
|
G_UNLOCK (g_signal_mutex);
|
|
}
|
|
|
|
void
|
|
g_signal_emit (gpointer instance,
|
|
guint signal_id,
|
|
GQuark detail,
|
|
...)
|
|
{
|
|
va_list var_args;
|
|
|
|
va_start (var_args, detail);
|
|
g_signal_emit_valist (instance, signal_id, detail, var_args);
|
|
va_end (var_args);
|
|
}
|
|
|
|
void
|
|
g_signal_emit_by_name (gpointer instance,
|
|
const gchar *detailed_signal,
|
|
...)
|
|
{
|
|
GQuark detail = 0;
|
|
guint signal_id;
|
|
|
|
g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
|
|
g_return_if_fail (detailed_signal != NULL);
|
|
|
|
G_LOCK (g_signal_mutex);
|
|
signal_id = signal_parse_name (detailed_signal, G_TYPE_FROM_INSTANCE (instance), &detail, TRUE);
|
|
G_UNLOCK (g_signal_mutex);
|
|
|
|
if (signal_id)
|
|
{
|
|
va_list var_args;
|
|
|
|
va_start (var_args, detailed_signal);
|
|
g_signal_emit_valist (instance, signal_id, detail, var_args);
|
|
va_end (var_args);
|
|
}
|
|
else
|
|
g_warning ("%s: signal name `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance);
|
|
}
|
|
|
|
static gboolean
|
|
signal_emit_R (SignalNode *node,
|
|
GQuark detail,
|
|
gpointer instance,
|
|
GValue *return_value,
|
|
const GValue *instance_and_params)
|
|
{
|
|
EmissionState emission_state = 0;
|
|
GSignalAccumulator accumulator;
|
|
GSignalInvocationHint ihint;
|
|
GClosure *class_closure;
|
|
HandlerList *hlist;
|
|
Handler *handler_list = NULL;
|
|
GValue accu = { 0, };
|
|
gboolean accu_used = FALSE;
|
|
guint signal_id = node->signal_id;
|
|
gboolean return_value_altered = FALSE;
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
IF_DEBUG (SIGNALS, g_trace_instance_signals == instance || g_trap_instance_signals == instance)
|
|
{
|
|
g_message ("%s::%s(%u) emitted (instance=%p signal-node=%p)\n",
|
|
g_type_name (G_TYPE_FROM_INSTANCE (instance)),
|
|
node->name, detail,
|
|
instance, node);
|
|
if (g_trap_instance_signals == instance)
|
|
G_BREAKPOINT ();
|
|
}
|
|
#endif /* G_ENABLE_DEBUG */
|
|
|
|
if (node->flags & G_SIGNAL_NO_RECURSE)
|
|
{
|
|
Emission *emission = emission_find (g_restart_emissions, signal_id, detail, instance);
|
|
|
|
if (emission)
|
|
{
|
|
*emission->state_p = EMISSION_RESTART;
|
|
return return_value_altered;
|
|
}
|
|
}
|
|
ihint.signal_id = node->signal_id;
|
|
ihint.detail = detail;
|
|
accumulator = node->accumulator;
|
|
if (accumulator)
|
|
g_value_init (&accu, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
emission_push ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions,
|
|
signal_id, detail, instance, &emission_state);
|
|
class_closure = node->class_closure;
|
|
|
|
EMIT_RESTART:
|
|
|
|
if (handler_list)
|
|
handler_unref_R (signal_id, instance, handler_list);
|
|
hlist = handler_list_lookup (signal_id, instance);
|
|
handler_list = hlist ? hlist->handlers : NULL;
|
|
if (handler_list)
|
|
handler_ref (handler_list);
|
|
|
|
ihint.run_type = G_SIGNAL_RUN_FIRST;
|
|
|
|
if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure)
|
|
{
|
|
emission_state = EMISSION_RUN;
|
|
|
|
G_UNLOCK (g_signal_mutex);
|
|
if (accumulator)
|
|
{
|
|
if (accu_used)
|
|
g_value_reset (&accu);
|
|
g_closure_invoke (class_closure,
|
|
&accu,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
if (!accumulator (&ihint, return_value, &accu) &&
|
|
emission_state == EMISSION_RUN)
|
|
emission_state = EMISSION_STOP;
|
|
accu_used = TRUE;
|
|
}
|
|
else
|
|
g_closure_invoke (class_closure,
|
|
return_value,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
G_LOCK (g_signal_mutex);
|
|
return_value_altered = TRUE;
|
|
|
|
if (emission_state == EMISSION_STOP)
|
|
goto EMIT_CLEANUP;
|
|
else if (emission_state == EMISSION_RESTART)
|
|
goto EMIT_RESTART;
|
|
}
|
|
|
|
if (node->emission_hooks)
|
|
{
|
|
emission_state = EMISSION_HOOK;
|
|
|
|
G_UNLOCK (g_signal_mutex);
|
|
g_print ("emission_hooks()\n");
|
|
G_LOCK (g_signal_mutex);
|
|
|
|
if (emission_state == EMISSION_RESTART)
|
|
goto EMIT_RESTART;
|
|
}
|
|
|
|
if (handler_list)
|
|
{
|
|
Handler *handler = handler_list;
|
|
|
|
emission_state = EMISSION_RUN;
|
|
handler_ref (handler);
|
|
do
|
|
{
|
|
Handler *tmp;
|
|
|
|
if (handler->after)
|
|
{
|
|
handler_unref_R (signal_id, instance, handler_list);
|
|
handler_list = handler;
|
|
break;
|
|
}
|
|
else if (!handler->block_count && (!handler->detail || handler->detail == detail))
|
|
{
|
|
G_UNLOCK (g_signal_mutex);
|
|
if (accumulator)
|
|
{
|
|
if (accu_used)
|
|
g_value_reset (&accu);
|
|
g_closure_invoke (handler->closure,
|
|
&accu,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
if (!accumulator (&ihint, return_value, &accu) &&
|
|
emission_state == EMISSION_RUN)
|
|
emission_state = EMISSION_STOP;
|
|
accu_used = TRUE;
|
|
}
|
|
else
|
|
g_closure_invoke (handler->closure,
|
|
return_value,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
G_LOCK (g_signal_mutex);
|
|
return_value_altered = TRUE;
|
|
|
|
tmp = emission_state == EMISSION_RUN ? handler->next : NULL;
|
|
}
|
|
else
|
|
tmp = handler->next;
|
|
|
|
if (tmp)
|
|
handler_ref (tmp);
|
|
handler_unref_R (signal_id, instance, handler_list);
|
|
handler_list = handler;
|
|
handler = tmp;
|
|
}
|
|
while (handler);
|
|
|
|
if (emission_state == EMISSION_STOP)
|
|
goto EMIT_CLEANUP;
|
|
else if (emission_state == EMISSION_RESTART)
|
|
goto EMIT_RESTART;
|
|
}
|
|
|
|
ihint.run_type = G_SIGNAL_RUN_LAST;
|
|
|
|
if ((node->flags & G_SIGNAL_RUN_LAST) && class_closure)
|
|
{
|
|
emission_state = EMISSION_RUN;
|
|
|
|
G_UNLOCK (g_signal_mutex);
|
|
if (accumulator)
|
|
{
|
|
if (accu_used)
|
|
g_value_reset (&accu);
|
|
g_closure_invoke (class_closure,
|
|
&accu,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
if (!accumulator (&ihint, return_value, &accu) &&
|
|
emission_state == EMISSION_RUN)
|
|
emission_state = EMISSION_STOP;
|
|
accu_used = TRUE;
|
|
}
|
|
else
|
|
g_closure_invoke (class_closure,
|
|
return_value,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
G_LOCK (g_signal_mutex);
|
|
return_value_altered = TRUE;
|
|
|
|
if (emission_state == EMISSION_STOP)
|
|
goto EMIT_CLEANUP;
|
|
else if (emission_state == EMISSION_RESTART)
|
|
goto EMIT_RESTART;
|
|
}
|
|
|
|
if (handler_list)
|
|
{
|
|
Handler *handler = handler_list;
|
|
|
|
emission_state = EMISSION_RUN;
|
|
handler_ref (handler);
|
|
do
|
|
{
|
|
Handler *tmp;
|
|
|
|
if (handler->after && !handler->block_count && (!handler->detail || handler->detail == detail))
|
|
{
|
|
G_UNLOCK (g_signal_mutex);
|
|
if (accumulator)
|
|
{
|
|
if (accu_used)
|
|
g_value_reset (&accu);
|
|
g_closure_invoke (handler->closure,
|
|
&accu,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
if (!accumulator (&ihint, return_value, &accu) &&
|
|
emission_state == EMISSION_RUN)
|
|
emission_state = EMISSION_STOP;
|
|
accu_used = TRUE;
|
|
}
|
|
else
|
|
g_closure_invoke (handler->closure,
|
|
return_value,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
G_LOCK (g_signal_mutex);
|
|
return_value_altered = TRUE;
|
|
|
|
tmp = emission_state == EMISSION_RUN ? handler->next : NULL;
|
|
}
|
|
else
|
|
tmp = handler->next;
|
|
|
|
if (tmp)
|
|
handler_ref (tmp);
|
|
handler_unref_R (signal_id, instance, handler);
|
|
handler = tmp;
|
|
}
|
|
while (handler);
|
|
|
|
if (emission_state == EMISSION_STOP)
|
|
goto EMIT_CLEANUP;
|
|
else if (emission_state == EMISSION_RESTART)
|
|
goto EMIT_RESTART;
|
|
}
|
|
|
|
EMIT_CLEANUP:
|
|
|
|
ihint.run_type = G_SIGNAL_RUN_CLEANUP;
|
|
|
|
if ((node->flags & G_SIGNAL_RUN_CLEANUP) && class_closure)
|
|
{
|
|
gboolean need_unset = FALSE;
|
|
|
|
emission_state = EMISSION_STOP;
|
|
|
|
G_UNLOCK (g_signal_mutex);
|
|
if (node->return_type != G_TYPE_NONE)
|
|
{
|
|
if (!accumulator)
|
|
{
|
|
g_value_init (&accu, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
need_unset = TRUE;
|
|
}
|
|
else if (accu_used)
|
|
g_value_reset (&accu);
|
|
}
|
|
g_closure_invoke (class_closure,
|
|
node->return_type != G_TYPE_NONE ? &accu : NULL,
|
|
node->n_params + 1,
|
|
instance_and_params,
|
|
&ihint);
|
|
if (need_unset)
|
|
g_value_unset (&accu);
|
|
G_LOCK (g_signal_mutex);
|
|
|
|
if (emission_state == EMISSION_RESTART)
|
|
goto EMIT_RESTART;
|
|
}
|
|
|
|
if (handler_list)
|
|
handler_unref_R (signal_id, instance, handler_list);
|
|
|
|
emission_pop ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions, &emission_state);
|
|
if (accumulator)
|
|
g_value_unset (&accu);
|
|
|
|
return return_value_altered;
|
|
}
|
|
|
|
|
|
/* --- compile standard marshallers --- */
|
|
#include "gvaluetypes.h"
|
|
#include "gmarshal.c"
|