📄 gsignal.c
字号:
/* GObject - GLib Type, Object, Parameter and Signal Library * Copyright (C) 2000-2001 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 "glibconfig.h"#include "gsignal.h"#include "gbsearcharray.h"#include "gvaluecollector.h"#include "gvaluetypes.h"#include "gboxed.h"#include <string.h> #include <signal.h>/* pre allocation configurations */#define MAX_STACK_VALUES (16)#define HANDLER_PRE_ALLOC (48)#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_POOLSstatic inline gpointerg_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, gulong 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 gint handler_lists_cmp (gconstpointer node1, gconstpointer node2);static inline void emission_push (Emission **emission_list_p, Emission *emission);static inline void emission_pop (Emission **emission_list_p, Emission *emission);static inline Emission* emission_find (Emission *emission_list, guint signal_id, GQuark detail, gpointer instance);static gint class_closures_cmp (gconstpointer node1, gconstpointer node2);static gint signal_key_cmp (gconstpointer node1, gconstpointer node2);static gboolean signal_emit_unlocked_R (SignalNode *node, GQuark detail, gpointer instance, GValue *return_value, const GValue *instance_and_params);static const gchar * type_debug_name (GType type);/* --- structures --- */typedef struct{ GSignalAccumulator func; gpointer data;} SignalAccumulator;typedef struct{ GHook hook; GQuark detail;} SignalHook;#define SIGNAL_HOOK(hook) ((SignalHook*) (hook))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 */ GBSearchArray *class_closure_bsa; SignalAccumulator *accumulator; GSignalCMarshaller c_marshaller; GHookList *emission_hooks;};struct _SignalKey{ GType itype; GQuark quark; guint signal_id;};struct _Emission{ Emission *next; gpointer instance; GSignalInvocationHint ihint; EmissionState state; GType chain_type;};struct _HandlerList{ guint signal_id; Handler *handlers;};struct _Handler{ gulong sequential_number; 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;};typedef struct{ GType instance_type; /* 0 for default closure */ GClosure *closure;} ClassClosure;/* --- variables --- */static GBSearchArray *g_signal_key_bsa = NULL;static GBSearchConfig g_signal_key_bconfig = G_STATIC_BCONFIG (sizeof (SignalKey), signal_key_cmp, G_BSEARCH_ARRAY_ALIGN_POWER2);static GBSearchConfig g_signal_hlbsa_bconfig = G_STATIC_BCONFIG (sizeof (HandlerList), handler_lists_cmp, G_BSEARCH_ARRAY_DEFER_SHRINK);static GBSearchConfig g_class_closure_bconfig = G_STATIC_BCONFIG (sizeof (ClassClosure), class_closures_cmp, 0);static GHashTable *g_handler_list_bsa_ht = NULL;static Emission *g_recursive_emissions = NULL;static Emission *g_restart_emissions = NULL;#ifndef DISABLE_MEM_POOLSstatic GTrashStack *g_handler_ts = NULL;#endifstatic gulong g_handler_sequential_number = 1;G_LOCK_DEFINE_STATIC (g_signal_mutex);#define SIGNAL_LOCK() G_LOCK (g_signal_mutex)#define SIGNAL_UNLOCK() G_UNLOCK (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 guintsignal_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, &g_signal_key_bconfig, &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, &g_signal_key_bconfig, &key); if (signal_key) { g_free (ifaces); return signal_key->signal_id; } } g_free (ifaces); return 0;}static gintclass_closures_cmp (gconstpointer node1, gconstpointer node2){ const ClassClosure *c1 = node1, *c2 = node2; return G_BSEARCH_ARRAY_CMP (c1->instance_type, c2->instance_type);}static ginthandler_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; key.signal_id = signal_id; key.handlers = NULL; if (!hlbsa) { hlbsa = g_bsearch_array_new (&g_signal_hlbsa_bconfig); hlbsa = g_bsearch_array_insert (hlbsa, &g_signal_hlbsa_bconfig, &key, FALSE); g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa); } else { GBSearchArray *o = hlbsa; hlbsa = g_bsearch_array_insert (o, &g_signal_hlbsa_bconfig, &key, FALSE); if (hlbsa != o) g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa); } return g_bsearch_array_lookup (hlbsa, &g_signal_hlbsa_bconfig, &key);}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, &g_signal_hlbsa_bconfig, &key) : NULL;}static Handler*handler_lookup (gpointer instance, gulong 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, &g_signal_hlbsa_bconfig, i); Handler *handler; for (handler = hlist->handlers; handler; handler = handler->next) if (handler->sequential_number == 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -