📄 gtksignal.c
字号:
/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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. *//* * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */#include <stdarg.h>#include <string.h>#include <stdio.h>#include "gtksignal.h"#include "gtkargcollector.c"#define SIGNAL_BLOCK_SIZE (100)#define HANDLER_BLOCK_SIZE (200)#define EMISSION_BLOCK_SIZE (100)#define DISCONNECT_INFO_BLOCK_SIZE (64)#define MAX_SIGNAL_PARAMS (31)enum{ EMISSION_CONTINUE, EMISSION_RESTART, EMISSION_DONE};#define GTK_RUN_TYPE(x) ((x) & GTK_RUN_BOTH)typedef struct _GtkSignal GtkSignal;typedef struct _GtkSignalHash GtkSignalHash;typedef struct _GtkHandler GtkHandler;typedef struct _GtkEmission GtkEmission;typedef struct _GtkEmissionHookData GtkEmissionHookData;typedef struct _GtkDisconnectInfo GtkDisconnectInfo;typedef void (*GtkSignalMarshaller0) (GtkObject *object, gpointer data);struct _GtkSignal{ guint signal_id; GtkType object_type; gchar *name; guint function_offset; GtkSignalMarshaller marshaller; GtkType return_val; guint signal_flags : 16; guint nparams : 16; GtkType *params; GHookList *hook_list;};struct _GtkSignalHash{ GtkType object_type; GQuark quark; guint signal_id;};struct _GtkHandler{ guint id; GtkHandler *next; GtkHandler *prev; guint blocked : 20; guint object_signal : 1; guint after : 1; guint no_marshal : 1; guint16 ref_count; guint16 signal_id; GtkSignalFunc func; gpointer func_data; GtkSignalDestroy destroy_func;};struct _GtkEmission{ GtkObject *object; guint16 signal_id; guint in_hook : 1; GtkEmission *next;};struct _GtkEmissionHookData{ GtkObject *object; guint signal_id; guint n_params; GtkArg *params;};struct _GtkDisconnectInfo{ GtkObject *object1; guint disconnect_handler1; guint signal_handler; GtkObject *object2; guint disconnect_handler2;};static guint gtk_signal_hash (gconstpointer h);static gint gtk_signal_compare (gconstpointer h1, gconstpointer h2);static GtkHandler* gtk_signal_handler_new (void);static void gtk_signal_handler_ref (GtkHandler *handler);static void gtk_signal_handler_unref (GtkHandler *handler, GtkObject *object);static void gtk_signal_handler_insert (GtkObject *object, GtkHandler *handler);static void gtk_signal_real_emit (GtkObject *object, guint signal_id, GtkArg *params);static guint gtk_signal_connect_by_type (GtkObject *object, guint signal_id, GtkSignalFunc func, gpointer func_data, GtkSignalDestroy destroy_func, gint object_signal, gint after, gint no_marshal);static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);static GtkEmission* gtk_emission_new (void);static void gtk_emission_add (GtkEmission **emissions, GtkObject *object, guint signal_type);static void gtk_emission_remove (GtkEmission **emissions, GtkObject *object, guint signal_type);static gint gtk_emission_check (GtkEmission *emissions, GtkObject *object, guint signal_type);static gint gtk_handlers_run (GtkHandler *handlers, GtkSignal *signal, GtkObject *object, GtkArg *params, gint after);static gboolean gtk_emission_hook_marshaller (GHook *hook, gpointer data);static gboolean gtk_signal_collect_params (GtkArg *params, guint nparams, GtkType *param_types, GtkType return_type, va_list var_args);#define LOOKUP_SIGNAL_ID(signal_id) ( \ signal_id > 0 && signal_id < _gtk_private_n_signals ? \ (GtkSignal*) _gtk_private_signals + signal_id : \ (GtkSignal*) 0 \)static GtkSignalMarshal global_marshaller = NULL;static GtkSignalDestroy global_destroy_notify = NULL;static guint gtk_handler_id = 1;static guint gtk_handler_quark = 0;static GHashTable *gtk_signal_hash_table = NULL; GtkSignal *_gtk_private_signals = NULL; guint _gtk_private_n_signals = 0;static GMemChunk *gtk_signal_hash_mem_chunk = NULL;static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;static GtkHandler *gtk_handler_free_list = NULL;static GtkEmission *gtk_free_emissions = NULL;static GtkEmission *current_emissions = NULL;static GtkEmission *stop_emissions = NULL;static GtkEmission *restart_emissions = NULL;static GtkSignal*gtk_signal_next_and_invalidate (void){ static guint gtk_n_free_signals = 0; register GtkSignal *signal; register guint new_signal_id; /* don't keep *any* GtkSignal pointers across invokation of this function!!! */ if (gtk_n_free_signals == 0) { register guint i; register guint size; /* nearest pow */ size = _gtk_private_n_signals + SIGNAL_BLOCK_SIZE; size *= sizeof (GtkSignal); i = 1; while (i < size) i <<= 1; size = i; _gtk_private_signals = g_realloc (_gtk_private_signals, size); gtk_n_free_signals = size / sizeof (GtkSignal) - _gtk_private_n_signals; memset (_gtk_private_signals + _gtk_private_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal)); } new_signal_id = _gtk_private_n_signals++; gtk_n_free_signals--; g_assert (_gtk_private_n_signals < 65535); signal = LOOKUP_SIGNAL_ID (new_signal_id); if (signal) signal->signal_id = new_signal_id; return signal;}static inline GtkHandler*gtk_signal_get_handlers (GtkObject *object, guint signal_id){ GtkHandler *handlers; handlers = gtk_object_get_data_by_id (object, gtk_handler_quark); while (handlers) { if (handlers->signal_id == signal_id) return handlers; handlers = handlers->next; } return NULL;}voidgtk_signal_init (void){ if (!gtk_handler_quark) { GtkSignal *zero; zero = gtk_signal_next_and_invalidate (); g_assert (zero == NULL); gtk_handler_quark = g_quark_from_static_string ("gtk-signal-handlers"); gtk_signal_hash_mem_chunk = g_mem_chunk_new ("GtkSignalHash mem chunk", sizeof (GtkSignalHash), sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE, G_ALLOC_ONLY); gtk_disconnect_info_mem_chunk = g_mem_chunk_new ("GtkDisconnectInfo mem chunk", sizeof (GtkDisconnectInfo), sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE, G_ALLOC_AND_FREE); gtk_handler_free_list = NULL; gtk_free_emissions = NULL; gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash, gtk_signal_compare); }}guintgtk_signal_newv (const gchar *r_name, GtkSignalRunType signal_flags, GtkType object_type, guint function_offset, GtkSignalMarshaller marshaller, GtkType return_val, guint nparams, GtkType *params){ GtkSignal *signal; GtkSignalHash *hash; GQuark quark; guint i; gchar *name; g_return_val_if_fail (r_name != NULL, 0); g_return_val_if_fail (marshaller != NULL, 0); g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0); if (nparams) g_return_val_if_fail (params != NULL, 0); if (!gtk_handler_quark) gtk_signal_init (); name = g_strdup (r_name); g_strdelimit (name, NULL, '_'); quark = gtk_signal_lookup (name, object_type); if (quark) { g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n", r_name, gtk_type_name (object_type)); g_free (name); return 0; } if (return_val != GTK_TYPE_NONE && (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST) { g_warning ("gtk_signal_newv(): signal \"%s\" - return value `%s' incompatible with GTK_RUN_FIRST", name, gtk_type_name (return_val)); g_free (name); return 0; } signal = gtk_signal_next_and_invalidate (); /* signal->signal_id already set */ signal->object_type = object_type; signal->name = name; signal->function_offset = function_offset; signal->marshaller = marshaller; signal->return_val = return_val; signal->signal_flags = signal_flags; signal->nparams = nparams; signal->hook_list = NULL; if (nparams > 0) { signal->params = g_new (GtkType, nparams); for (i = 0; i < nparams; i++) signal->params[i] = params[i]; } else signal->params = NULL; /* insert "signal_name" into hash table */ hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk); hash->object_type = object_type; hash->quark = g_quark_from_string (signal->name); hash->signal_id = signal->signal_id; g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id)); /* insert "signal-name" into hash table */ g_strdelimit (signal->name, NULL, '-'); quark = g_quark_from_static_string (signal->name); if (quark != hash->quark) { hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk); hash->object_type = object_type; hash->quark = quark; hash->signal_id = signal->signal_id; g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id)); } return signal->signal_id;}guintgtk_signal_new (const gchar *name, GtkSignalRunType signal_flags, GtkType object_type, guint function_offset, GtkSignalMarshaller marshaller, GtkType return_val, guint nparams, ...){ GtkType *params; guint i; va_list args; guint signal_id; g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0); if (nparams > 0) { params = g_new (GtkType, nparams); va_start (args, nparams); for (i = 0; i < nparams; i++) params[i] = va_arg (args, GtkType); va_end (args); } else params = NULL; signal_id = gtk_signal_newv (name, signal_flags, object_type, function_offset, marshaller, return_val, nparams, params); g_free (params); return signal_id;}guintgtk_signal_lookup (const gchar *name, GtkType object_type){ GtkSignalHash hash; GtkType lookup_type; gpointer class = NULL; g_return_val_if_fail (name != NULL, 0); g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0); relookup: lookup_type = object_type; hash.quark = g_quark_try_string (name); if (hash.quark) { while (lookup_type) { guint signal_id; hash.object_type = lookup_type; signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash)); if (signal_id) return signal_id; lookup_type = gtk_type_parent (lookup_type); } } if (!class) { class = gtk_type_class (object_type); goto relookup; } return 0;}GtkSignalQuery*gtk_signal_query (guint signal_id){ GtkSignalQuery *query; GtkSignal *signal; g_return_val_if_fail (signal_id >= 1, NULL); signal = LOOKUP_SIGNAL_ID (signal_id); if (signal) { query = g_new (GtkSignalQuery, 1); query->object_type = signal->object_type; query->signal_id = signal_id; query->signal_name = signal->name; query->is_user_signal = signal->function_offset == 0; query->signal_flags = signal->signal_flags; query->return_val = signal->return_val; query->nparams = signal->nparams; query->params = signal->params; } else query = NULL; return query;}gchar*gtk_signal_name (guint signal_id){ GtkSignal *signal; g_return_val_if_fail (signal_id >= 1, NULL); signal = LOOKUP_SIGNAL_ID (signal_id); if (signal) return signal->name; return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -