1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtksignal.h"
31 #include "gtkargcollector.c"
34 #define SIGNAL_BLOCK_SIZE (100)
35 #define HANDLER_BLOCK_SIZE (200)
36 #define EMISSION_BLOCK_SIZE (100)
37 #define DISCONNECT_INFO_BLOCK_SIZE (64)
38 #define MAX_SIGNAL_PARAMS (31)
47 #define GTK_RUN_TYPE(x) ((x) & GTK_RUN_BOTH)
50 typedef struct _GtkSignal GtkSignal;
51 typedef struct _GtkSignalHash GtkSignalHash;
52 typedef struct _GtkHandler GtkHandler;
53 typedef struct _GtkEmission GtkEmission;
54 typedef struct _GtkEmissionHookData GtkEmissionHookData;
55 typedef struct _GtkDisconnectInfo GtkDisconnectInfo;
57 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
65 guint function_offset;
66 GtkSignalMarshaller marshaller;
68 guint signal_flags : 16;
87 guint object_signal : 1;
94 GtkSignalDestroy destroy_func;
105 struct _GtkEmissionHookData
113 struct _GtkDisconnectInfo
116 guint disconnect_handler1;
117 guint signal_handler;
119 guint disconnect_handler2;
123 static guint gtk_signal_hash (gconstpointer h);
124 static gint gtk_signal_compare (gconstpointer h1,
126 static GtkHandler* gtk_signal_handler_new (void);
127 static void gtk_signal_handler_ref (GtkHandler *handler);
128 static void gtk_signal_handler_unref (GtkHandler *handler,
130 static void gtk_signal_handler_insert (GtkObject *object,
131 GtkHandler *handler);
132 static void gtk_signal_real_emit (GtkObject *object,
135 static guint gtk_signal_connect_by_type (GtkObject *object,
139 GtkSignalDestroy destroy_func,
143 static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);
144 static GtkEmission* gtk_emission_new (void);
145 static void gtk_emission_add (GtkEmission **emissions,
148 static void gtk_emission_remove (GtkEmission **emissions,
151 static gint gtk_emission_check (GtkEmission *emissions,
154 static gint gtk_handlers_run (GtkHandler *handlers,
159 static gboolean gtk_emission_hook_marshaller (GHook *hook,
161 static gboolean gtk_signal_collect_params (GtkArg *params,
163 GtkType *param_types,
167 #define LOOKUP_SIGNAL_ID(signal_id) ( \
168 signal_id > 0 && signal_id < _gtk_private_n_signals ? \
169 (GtkSignal*) _gtk_private_signals + signal_id : \
174 static GtkSignalMarshal global_marshaller = NULL;
175 static GtkSignalDestroy global_destroy_notify = NULL;
177 static guint gtk_handler_id = 1;
178 static guint gtk_handler_quark = 0;
179 static GHashTable *gtk_signal_hash_table = NULL;
181 #define EXPORT __declspec(dllexport)
185 EXPORT GtkSignal *_gtk_private_signals = NULL;
186 EXPORT guint _gtk_private_n_signals = 0;
187 static GMemChunk *gtk_signal_hash_mem_chunk = NULL;
188 static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;
189 static GtkHandler *gtk_handler_free_list = NULL;
190 static GtkEmission *gtk_free_emissions = NULL;
194 static GtkEmission *current_emissions = NULL;
195 static GtkEmission *stop_emissions = NULL;
196 static GtkEmission *restart_emissions = NULL;
199 gtk_signal_next_and_invalidate (void)
201 static guint gtk_n_free_signals = 0;
202 register GtkSignal *signal;
203 register guint new_signal_id;
205 /* don't keep *any* GtkSignal pointers across invokation of this function!!!
208 if (gtk_n_free_signals == 0)
215 size = _gtk_private_n_signals + SIGNAL_BLOCK_SIZE;
216 size *= sizeof (GtkSignal);
222 _gtk_private_signals = g_realloc (_gtk_private_signals, size);
224 gtk_n_free_signals = size / sizeof (GtkSignal) - _gtk_private_n_signals;
226 memset (_gtk_private_signals + _gtk_private_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
229 new_signal_id = _gtk_private_n_signals++;
230 gtk_n_free_signals--;
232 g_assert (_gtk_private_n_signals < 65535);
234 signal = LOOKUP_SIGNAL_ID (new_signal_id);
236 signal->signal_id = new_signal_id;
241 static inline GtkHandler*
242 gtk_signal_get_handlers (GtkObject *object,
245 GtkHandler *handlers;
247 handlers = gtk_object_get_data_by_id (object, gtk_handler_quark);
251 if (handlers->signal_id == signal_id)
253 handlers = handlers->next;
260 gtk_signal_init (void)
262 if (!gtk_handler_quark)
266 zero = gtk_signal_next_and_invalidate ();
267 g_assert (zero == NULL);
269 gtk_handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
271 gtk_signal_hash_mem_chunk =
272 g_mem_chunk_new ("GtkSignalHash mem chunk",
273 sizeof (GtkSignalHash),
274 sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
276 gtk_disconnect_info_mem_chunk =
277 g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
278 sizeof (GtkDisconnectInfo),
279 sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
281 gtk_handler_free_list = NULL;
282 gtk_free_emissions = NULL;
284 gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
290 gtk_signal_newv (const gchar *r_name,
291 GtkSignalRunType signal_flags,
293 guint function_offset,
294 GtkSignalMarshaller marshaller,
305 g_return_val_if_fail (r_name != NULL, 0);
306 g_return_val_if_fail (marshaller != NULL, 0);
307 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
309 g_return_val_if_fail (params != NULL, 0);
311 if (!gtk_handler_quark)
315 name = g_strdup (r_name);
316 g_strdelimit (name, NULL, '_');
318 quark = gtk_signal_lookup (name, object_type);
321 g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
323 gtk_type_name (object_type));
328 if (return_val != GTK_TYPE_NONE &&
329 (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
331 g_warning ("gtk_signal_newv(): signal \"%s\" - return value `%s' incompatible with GTK_RUN_FIRST",
332 name, gtk_type_name (return_val));
337 signal = gtk_signal_next_and_invalidate ();
339 /* signal->signal_id already set */
341 signal->object_type = object_type;
343 signal->function_offset = function_offset;
344 signal->marshaller = marshaller;
345 signal->return_val = return_val;
346 signal->signal_flags = signal_flags;
347 signal->nparams = nparams;
348 signal->hook_list = NULL;
352 signal->params = g_new (GtkType, nparams);
354 for (i = 0; i < nparams; i++)
355 signal->params[i] = params[i];
358 signal->params = NULL;
360 /* insert "signal_name" into hash table
362 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
363 hash->object_type = object_type;
364 hash->quark = g_quark_from_string (signal->name);
365 hash->signal_id = signal->signal_id;
366 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
368 /* insert "signal-name" into hash table
370 g_strdelimit (signal->name, NULL, '-');
371 quark = g_quark_from_static_string (signal->name);
372 if (quark != hash->quark)
374 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
375 hash->object_type = object_type;
377 hash->signal_id = signal->signal_id;
378 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
381 return signal->signal_id;
385 gtk_signal_new (const gchar *name,
386 GtkSignalRunType signal_flags,
388 guint function_offset,
389 GtkSignalMarshaller marshaller,
399 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
403 params = g_new (GtkType, nparams);
405 va_start (args, nparams);
407 for (i = 0; i < nparams; i++)
408 params[i] = va_arg (args, GtkType);
415 signal_id = gtk_signal_newv (name,
430 gtk_signal_lookup (const gchar *name,
435 gpointer class = NULL;
437 g_return_val_if_fail (name != NULL, 0);
438 g_return_val_if_fail (GTK_TYPE_IS_OBJECT (object_type), 0);
442 lookup_type = object_type;
443 hash.quark = g_quark_try_string (name);
450 hash.object_type = lookup_type;
452 signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
456 lookup_type = gtk_type_parent (lookup_type);
462 class = gtk_type_class (object_type);
470 gtk_signal_query (guint signal_id)
472 GtkSignalQuery *query;
475 g_return_val_if_fail (signal_id >= 1, NULL);
477 signal = LOOKUP_SIGNAL_ID (signal_id);
480 query = g_new (GtkSignalQuery, 1);
482 query->object_type = signal->object_type;
483 query->signal_id = signal_id;
484 query->signal_name = signal->name;
485 query->is_user_signal = signal->function_offset == 0;
486 query->signal_flags = signal->signal_flags;
487 query->return_val = signal->return_val;
488 query->nparams = signal->nparams;
489 query->params = signal->params;
498 gtk_signal_name (guint signal_id)
502 g_return_val_if_fail (signal_id >= 1, NULL);
504 signal = LOOKUP_SIGNAL_ID (signal_id);
512 gtk_signal_emitv (GtkObject *object,
518 g_return_if_fail (object != NULL);
519 g_return_if_fail (signal_id >= 1);
521 signal = LOOKUP_SIGNAL_ID (signal_id);
522 g_return_if_fail (signal != NULL);
523 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
525 if (signal->nparams > 0)
526 g_return_if_fail (params != NULL);
528 gtk_signal_real_emit (object, signal_id, params);
532 gtk_signal_emit (GtkObject *object,
538 GtkArg params[MAX_SIGNAL_PARAMS + 1];
541 g_return_if_fail (object != NULL);
542 g_return_if_fail (signal_id >= 1);
544 signal = LOOKUP_SIGNAL_ID (signal_id);
545 g_return_if_fail (signal != NULL);
546 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
548 va_start (args, signal_id);
549 abort = gtk_signal_collect_params (params,
557 gtk_signal_real_emit (object, signal_id, params);
561 gtk_signal_emitv_by_name (GtkObject *object,
567 g_return_if_fail (object != NULL);
568 g_return_if_fail (name != NULL);
569 g_return_if_fail (params != NULL);
571 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
577 signal = LOOKUP_SIGNAL_ID (signal_id);
578 g_return_if_fail (signal != NULL);
579 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
581 gtk_signal_real_emit (object, signal_id, params);
585 g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
587 gtk_type_name (GTK_OBJECT_TYPE (object)));
592 gtk_signal_emit_by_name (GtkObject *object,
598 g_return_if_fail (object != NULL);
599 g_return_if_fail (name != NULL);
601 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
606 GtkArg params[MAX_SIGNAL_PARAMS + 1];
610 signal = LOOKUP_SIGNAL_ID (signal_id);
611 g_return_if_fail (signal != NULL);
612 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
614 va_start (args, name);
615 abort = gtk_signal_collect_params (params,
623 gtk_signal_real_emit (object, signal_id, params);
627 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
629 gtk_type_name (GTK_OBJECT_TYPE (object)));
634 gtk_signal_emit_stop (GtkObject *object,
639 g_return_if_fail (object != NULL);
640 g_return_if_fail (signal_id >= 1);
642 state = gtk_emission_check (current_emissions, object, signal_id);
644 g_warning ("gtk_signal_emit_stop(): emission (%u) for object `%s' cannot be stopped from emission hook",
646 gtk_type_name (GTK_OBJECT_TYPE (object)));
649 if (!gtk_emission_check (stop_emissions, object, signal_id))
650 gtk_emission_add (&stop_emissions, object, signal_id);
653 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
655 gtk_type_name (GTK_OBJECT_TYPE (object)));
659 gtk_signal_emit_stop_by_name (GtkObject *object,
664 g_return_if_fail (object != NULL);
665 g_return_if_fail (name != NULL);
667 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
669 gtk_signal_emit_stop (object, signal_id);
671 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
673 gtk_type_name (GTK_OBJECT_TYPE (object)));
677 gtk_signal_n_emissions (GtkObject *object,
680 GtkEmission *emission;
683 g_return_val_if_fail (object != NULL, 0);
684 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
687 for (emission = current_emissions; emission; emission = emission->next)
689 if (emission->object == object && emission->signal_id == signal_id)
697 gtk_signal_n_emissions_by_name (GtkObject *object,
703 g_return_val_if_fail (object != NULL, 0);
704 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
705 g_return_val_if_fail (name != NULL, 0);
707 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
709 n = gtk_signal_n_emissions (object, signal_id);
712 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
714 gtk_type_name (GTK_OBJECT_TYPE (object)));
722 gtk_signal_connect (GtkObject *object,
729 g_return_val_if_fail (object != NULL, 0);
730 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
732 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
735 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
737 gtk_type_name (GTK_OBJECT_TYPE (object)));
741 return gtk_signal_connect_by_type (object, signal_id,
742 func, func_data, NULL,
743 FALSE, FALSE, FALSE);
747 gtk_signal_connect_after (GtkObject *object,
754 g_return_val_if_fail (object != NULL, 0);
756 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
759 g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
761 gtk_type_name (GTK_OBJECT_TYPE (object)));
765 return gtk_signal_connect_by_type (object, signal_id,
766 func, func_data, NULL,
771 gtk_signal_connect_full (GtkObject *object,
774 GtkCallbackMarshal marshal,
776 GtkDestroyNotify destroy_func,
782 g_return_val_if_fail (object != NULL, 0);
784 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
787 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
789 gtk_type_name (GTK_OBJECT_TYPE (object)));
794 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
795 func_data, destroy_func,
796 object_signal, after, TRUE);
798 return gtk_signal_connect_by_type (object, signal_id, func,
799 func_data, destroy_func,
800 object_signal, after, FALSE);
804 gtk_signal_connect_object (GtkObject *object,
807 GtkObject *slot_object)
811 g_return_val_if_fail (object != NULL, 0);
812 /* slot_object needs to be treated as ordinary pointer
815 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
818 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
820 gtk_type_name (GTK_OBJECT_TYPE (object)));
824 return gtk_signal_connect_by_type (object, signal_id,
825 func, slot_object, NULL,
830 gtk_signal_connect_object_after (GtkObject *object,
833 GtkObject *slot_object)
837 g_return_val_if_fail (object != NULL, 0);
839 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
842 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
844 gtk_type_name (GTK_OBJECT_TYPE (object)));
848 return gtk_signal_connect_by_type (object, signal_id,
849 func, slot_object, NULL,
854 gtk_signal_connect_while_alive (GtkObject *object,
858 GtkObject *alive_object)
860 GtkDisconnectInfo *info;
862 g_return_if_fail (object != NULL);
863 g_return_if_fail (GTK_IS_OBJECT (object));
864 g_return_if_fail (signal != NULL);
865 g_return_if_fail (func != NULL);
866 g_return_if_fail (alive_object != NULL);
867 g_return_if_fail (GTK_IS_OBJECT (alive_object));
869 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
870 info->object1 = object;
871 info->object2 = alive_object;
873 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
874 info->disconnect_handler1 =
875 gtk_signal_connect_object (info->object1,
877 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
879 info->disconnect_handler2 =
880 gtk_signal_connect_object (info->object2,
882 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
887 gtk_signal_connect_object_while_alive (GtkObject *object,
890 GtkObject *alive_object)
892 GtkDisconnectInfo *info;
894 g_return_if_fail (object != NULL);
895 g_return_if_fail (GTK_IS_OBJECT (object));
896 g_return_if_fail (signal != NULL);
897 g_return_if_fail (func != NULL);
898 g_return_if_fail (alive_object != NULL);
899 g_return_if_fail (GTK_IS_OBJECT (alive_object));
901 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
902 info->object1 = object;
903 info->object2 = alive_object;
905 info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
906 info->disconnect_handler1 =
907 gtk_signal_connect_object (info->object1,
909 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
911 info->disconnect_handler2 =
912 gtk_signal_connect_object (info->object2,
914 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
919 gtk_signal_disconnect (GtkObject *object,
924 g_return_if_fail (object != NULL);
925 g_return_if_fail (handler_id > 0);
927 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
931 if (handler->id == handler_id)
934 handler->blocked += 1;
935 gtk_signal_handler_unref (handler, object);
938 handler = handler->next;
941 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
945 gtk_signal_disconnect_by_func (GtkObject *object,
952 g_return_if_fail (object != NULL);
953 g_return_if_fail (func != NULL);
956 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
960 GtkHandler *handler_next;
962 handler_next = handler->next;
963 if ((handler->id > 0) &&
964 (handler->func == func) &&
965 (handler->func_data == data))
969 handler->blocked += 1;
970 gtk_signal_handler_unref (handler, object);
972 handler = handler_next;
976 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
980 gtk_signal_disconnect_by_data (GtkObject *object,
986 g_return_if_fail (object != NULL);
989 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
993 GtkHandler *handler_next;
995 handler_next = handler->next;
996 if ((handler->id > 0) &&
997 (handler->func_data == data))
1001 handler->blocked += 1;
1002 gtk_signal_handler_unref (handler, object);
1004 handler = handler_next;
1008 g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1012 gtk_signal_handler_block (GtkObject *object,
1015 GtkHandler *handler;
1017 g_return_if_fail (object != NULL);
1018 g_return_if_fail (handler_id > 0);
1020 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1024 if (handler->id == handler_id)
1026 handler->blocked += 1;
1029 handler = handler->next;
1032 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
1036 gtk_signal_handler_block_by_func (GtkObject *object,
1040 GtkHandler *handler;
1043 g_return_if_fail (object != NULL);
1044 g_return_if_fail (func != NULL);
1047 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1051 if ((handler->id > 0) &&
1052 (handler->func == func) &&
1053 (handler->func_data == data))
1056 handler->blocked += 1;
1058 handler = handler->next;
1062 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1066 gtk_signal_handler_block_by_data (GtkObject *object,
1069 GtkHandler *handler;
1072 g_return_if_fail (object != NULL);
1075 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1079 if ((handler->id > 0) &&
1080 (handler->func_data == data))
1083 handler->blocked += 1;
1085 handler = handler->next;
1089 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1093 gtk_signal_handler_unblock (GtkObject *object,
1096 GtkHandler *handler;
1098 g_return_if_fail (object != NULL);
1099 g_return_if_fail (handler_id > 0);
1101 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1105 if (handler->id == handler_id)
1107 if (handler->blocked > 0)
1108 handler->blocked -= 1;
1110 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1113 handler = handler->next;
1116 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1120 gtk_signal_handler_unblock_by_func (GtkObject *object,
1124 GtkHandler *handler;
1127 g_return_if_fail (object != NULL);
1128 g_return_if_fail (func != NULL);
1131 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1135 if ((handler->id > 0) &&
1136 (handler->func == func) &&
1137 (handler->func_data == data) &&
1138 (handler->blocked > 0))
1140 handler->blocked -= 1;
1143 handler = handler->next;
1147 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1151 gtk_signal_handler_unblock_by_data (GtkObject *object,
1154 GtkHandler *handler;
1157 g_return_if_fail (object != NULL);
1160 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1164 if ((handler->id > 0) &&
1165 (handler->func_data == data) &&
1166 (handler->blocked > 0))
1168 handler->blocked -= 1;
1171 handler = handler->next;
1175 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1179 gtk_signal_handlers_destroy (GtkObject *object)
1181 GtkHandler *handler;
1183 /* we make the "optimization" of destroying the first handler in the last
1184 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1185 * handler_key data on each removal
1188 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1191 handler = handler->next;
1196 next = handler->next;
1197 if (handler->id > 0)
1200 handler->blocked += 1;
1201 gtk_signal_handler_unref (handler, object);
1205 handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1206 if (handler->id > 0)
1209 handler->blocked += 1;
1210 gtk_signal_handler_unref (handler, object);
1216 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1217 GtkSignalDestroy destroy_func)
1219 global_marshaller = marshal_func;
1220 global_destroy_notify = destroy_func;
1224 gtk_signal_hash (gconstpointer h)
1226 register const GtkSignalHash *hash = h;
1228 return hash->object_type ^ hash->quark;
1232 gtk_signal_compare (gconstpointer h1,
1235 register const GtkSignalHash *hash1 = h1;
1236 register const GtkSignalHash *hash2 = h2;
1238 return (hash1->quark == hash2->quark &&
1239 hash1->object_type == hash2->object_type);
1243 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1245 g_return_val_if_fail (info != NULL, 0);
1247 gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1248 gtk_signal_disconnect (info->object1, info->signal_handler);
1249 gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1251 g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1257 gtk_signal_handler_new (void)
1259 GtkHandler *handler;
1261 if (!gtk_handler_free_list)
1263 GtkHandler *handler_block;
1266 handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1267 for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1269 (handler_block + i)->next = gtk_handler_free_list;
1270 gtk_handler_free_list = (handler_block + i);
1273 handler = handler_block;
1277 handler = gtk_handler_free_list;
1278 gtk_handler_free_list = handler->next;
1282 handler->blocked = 0;
1283 handler->signal_id = 0;
1284 handler->object_signal = FALSE;
1285 handler->after = FALSE;
1286 handler->no_marshal = FALSE;
1287 handler->ref_count = 1;
1288 handler->func = NULL;
1289 handler->func_data = NULL;
1290 handler->destroy_func = NULL;
1291 handler->prev = NULL;
1292 handler->next = NULL;
1298 gtk_signal_handler_ref (GtkHandler *handler)
1300 handler->ref_count += 1;
1304 gtk_signal_handler_unref (GtkHandler *handler,
1307 if (!handler->ref_count)
1309 /* FIXME: i wanna get removed somewhen */
1310 g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1314 handler->ref_count -= 1;
1316 if (handler->ref_count == 0)
1318 if (handler->destroy_func)
1319 (* handler->destroy_func) (handler->func_data);
1320 else if (!handler->func && global_destroy_notify)
1321 (* global_destroy_notify) (handler->func_data);
1324 handler->prev->next = handler->next;
1325 else if (handler->next)
1326 gtk_object_set_data_by_id (object, gtk_handler_quark, handler->next);
1329 GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1330 gtk_object_set_data_by_id (object, gtk_handler_quark, NULL);
1333 handler->next->prev = handler->prev;
1335 handler->next = gtk_handler_free_list;
1336 gtk_handler_free_list = handler;
1341 gtk_signal_handler_insert (GtkObject *object,
1342 GtkHandler *handler)
1346 /* FIXME: remove */ g_assert (handler->next == NULL);
1347 /* FIXME: remove */ g_assert (handler->prev == NULL);
1349 tmp = gtk_object_get_data_by_id (object, gtk_handler_quark);
1352 GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1353 gtk_object_set_data_by_id (object, gtk_handler_quark, handler);
1358 if (tmp->signal_id < handler->signal_id)
1362 tmp->prev->next = handler;
1363 handler->prev = tmp->prev;
1366 gtk_object_set_data_by_id (object, gtk_handler_quark, handler);
1367 tmp->prev = handler;
1368 handler->next = tmp;
1374 tmp->next = handler;
1375 handler->prev = tmp;
1383 #ifdef G_ENABLE_DEBUG
1384 /* value typically set via gdb */
1385 static GtkObject *gtk_trace_signal_object = NULL;
1386 #endif /* G_ENABLE_DEBUG */
1390 gtk_signal_real_emit (GtkObject *object,
1395 GtkHandler *handlers;
1396 GtkSignalFunc signal_func;
1397 GtkEmission *emission;
1399 /* gtk_handlers_run() expects a reentrant GtkSignal*, so we allocate
1400 * it locally on the stack. we save some lookups ourselves with this as well.
1402 signal = *LOOKUP_SIGNAL_ID (signal_id);
1403 if (signal.function_offset)
1404 signal_func = G_STRUCT_MEMBER (GtkSignalFunc, ((GTypeInstance*) object)->g_class, signal.function_offset);
1408 #ifdef G_ENABLE_DEBUG
1409 if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1410 object == gtk_trace_signal_object)
1411 g_message ("%s::%s emitted (object=%p class-method=%p)\n",
1412 gtk_type_name (GTK_OBJECT_TYPE (object)),
1416 #endif /* G_ENABLE_DEBUG */
1418 if (signal.signal_flags & GTK_RUN_NO_RECURSE)
1422 state = gtk_emission_check (current_emissions, object, signal_id);
1426 g_warning ("gtk_signal_real_emit(): emission (%u) for object `%s' cannot be restarted from emission hook",
1428 gtk_type_name (GTK_OBJECT_TYPE (object)));
1429 else if (!gtk_emission_check (restart_emissions, object, signal_id))
1430 gtk_emission_add (&restart_emissions, object, signal_id);
1436 gtk_object_ref (object);
1438 gtk_emission_add (¤t_emissions, object, signal_id);
1439 emission = current_emissions;
1443 if (signal.signal_flags & GTK_RUN_FIRST && signal_func)
1445 signal.marshaller (object, signal_func, NULL, params);
1447 if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1449 gtk_emission_remove (&stop_emissions, object, signal_id);
1452 else if (restart_emissions &&
1453 signal.signal_flags & GTK_RUN_NO_RECURSE &&
1454 gtk_emission_check (restart_emissions, object, signal_id))
1456 gtk_emission_remove (&restart_emissions, object, signal_id);
1458 goto emission_restart;
1462 if (signal.hook_list && !GTK_OBJECT_DESTROYED (object))
1464 GtkEmissionHookData data;
1466 data.object = object;
1467 data.n_params = signal.nparams;
1468 data.params = params;
1469 data.signal_id = signal_id;
1470 emission->in_hook = 1;
1471 g_hook_list_marshal_check (signal.hook_list, TRUE, gtk_emission_hook_marshaller, &data);
1472 emission->in_hook = 0;
1475 if (GTK_OBJECT_CONNECTED (object))
1477 handlers = gtk_signal_get_handlers (object, signal_id);
1482 return_val = gtk_handlers_run (handlers, &signal, object, params, FALSE);
1485 case EMISSION_CONTINUE:
1487 case EMISSION_RESTART:
1488 goto emission_restart;
1495 if (signal.signal_flags & GTK_RUN_LAST && signal_func)
1497 signal.marshaller (object, signal_func, NULL, params);
1499 if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1501 gtk_emission_remove (&stop_emissions, object, signal_id);
1504 else if (restart_emissions &&
1505 signal.signal_flags & GTK_RUN_NO_RECURSE &&
1506 gtk_emission_check (restart_emissions, object, signal_id))
1508 gtk_emission_remove (&restart_emissions, object, signal_id);
1510 goto emission_restart;
1514 if (GTK_OBJECT_CONNECTED (object))
1516 handlers = gtk_signal_get_handlers (object, signal_id);
1521 return_val = gtk_handlers_run (handlers, &signal, object, params, TRUE);
1524 case EMISSION_CONTINUE:
1526 case EMISSION_RESTART:
1527 goto emission_restart;
1535 if (restart_emissions && signal.signal_flags & GTK_RUN_NO_RECURSE)
1536 gtk_emission_remove (&restart_emissions, object, signal_id);
1538 gtk_emission_remove (¤t_emissions, object, signal_id);
1540 gtk_object_unref (object);
1544 gtk_signal_handler_pending (GtkObject *object,
1546 gboolean may_be_blocked)
1548 GtkHandler *handlers;
1551 g_return_val_if_fail (object != NULL, 0);
1552 g_return_val_if_fail (signal_id >= 1, 0);
1554 if (GTK_OBJECT_CONNECTED (object))
1555 handlers = gtk_signal_get_handlers (object, signal_id);
1560 while (handlers && handlers->signal_id == signal_id)
1562 if (handlers->id > 0 &&
1563 (may_be_blocked || handlers->blocked == FALSE))
1565 handler_id = handlers->id;
1569 handlers = handlers->next;
1576 gtk_signal_handler_pending_by_func (GtkObject *object,
1578 gboolean may_be_blocked,
1582 GtkHandler *handlers;
1585 g_return_val_if_fail (object != NULL, 0);
1586 g_return_val_if_fail (func != NULL, 0);
1587 g_return_val_if_fail (signal_id >= 1, 0);
1589 if (GTK_OBJECT_CONNECTED (object))
1590 handlers = gtk_signal_get_handlers (object, signal_id);
1595 while (handlers && handlers->signal_id == signal_id)
1597 if (handlers->id > 0 &&
1598 handlers->func == func &&
1599 handlers->func_data == data &&
1600 (may_be_blocked || handlers->blocked == 0))
1602 handler_id = handlers->id;
1606 handlers = handlers->next;
1613 gtk_signal_handler_pending_by_id (GtkObject *object,
1615 gboolean may_be_blocked)
1617 GtkHandler *handlers;
1619 g_return_val_if_fail (object != NULL, FALSE);
1620 g_return_val_if_fail (handler_id >= 1, FALSE);
1622 if (GTK_OBJECT_CONNECTED (object))
1623 handlers = gtk_object_get_data_by_id (object, gtk_handler_quark);
1629 if (handlers->id == handler_id)
1630 return may_be_blocked || handlers->blocked == 0;
1632 handlers = handlers->next;
1639 gtk_signal_add_emission_hook (guint signal_id,
1640 GtkEmissionHook hook_func,
1643 return gtk_signal_add_emission_hook_full (signal_id, hook_func, data, NULL);
1647 gtk_signal_add_emission_hook_full (guint signal_id,
1648 GtkEmissionHook hook_func,
1650 GDestroyNotify destroy)
1652 static guint seq_hook_id = 1;
1656 g_return_val_if_fail (signal_id > 0, 0);
1657 g_return_val_if_fail (hook_func != NULL, 0);
1659 signal = LOOKUP_SIGNAL_ID (signal_id);
1660 g_return_val_if_fail (signal != NULL, 0);
1661 if (signal->signal_flags & GTK_RUN_NO_HOOKS)
1663 g_warning ("gtk_signal_add_emission_hook_full(): signal \"%s\" does not support emission hooks",
1668 if (!signal->hook_list)
1670 signal->hook_list = g_new (GHookList, 1);
1671 g_hook_list_init (signal->hook_list, sizeof (GHook));
1674 hook = g_hook_alloc (signal->hook_list);
1676 hook->func = hook_func;
1677 hook->destroy = destroy;
1679 signal->hook_list->seq_id = seq_hook_id;
1680 g_hook_prepend (signal->hook_list, hook);
1681 seq_hook_id = signal->hook_list->seq_id;
1683 return hook->hook_id;
1687 gtk_signal_remove_emission_hook (guint signal_id,
1692 g_return_if_fail (signal_id > 0);
1693 g_return_if_fail (hook_id > 0);
1695 signal = LOOKUP_SIGNAL_ID (signal_id);
1696 g_return_if_fail (signal != NULL);
1698 if (!signal->hook_list || !g_hook_destroy (signal->hook_list, hook_id))
1699 g_warning ("gtk_signal_remove_emission_hook(): could not find hook (%u)", hook_id);
1703 gtk_emission_hook_marshaller (GHook *hook,
1706 GtkEmissionHookData *data = data_p;
1707 GtkEmissionHook func;
1711 if (!GTK_OBJECT_DESTROYED (data->object))
1712 return func (data->object, data->signal_id,
1713 data->n_params, data->params,
1720 gtk_signal_connect_by_type (GtkObject *object,
1724 GtkSignalDestroy destroy_func,
1729 GtkObjectClass *class;
1730 GtkHandler *handler;
1734 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
1736 signal = LOOKUP_SIGNAL_ID (signal_id);
1738 /* Search through the signals for this object and make
1739 * sure the one we are adding is valid. We need to perform
1740 * the lookup on the objects parents as well. If it isn't
1741 * valid then issue a warning and return.
1742 * As of now (1998-05-27) this lookup shouldn't be neccessarry
1743 * anymore since gtk_signal_lookup() has been reworked to only
1744 * return correct signal ids per class-branch.
1747 class = GTK_OBJECT_GET_CLASS (object);
1751 guint *object_signals;
1755 object_signals = class->signals;
1756 nsignals = class->nsignals;
1758 for (i = 0; i < nsignals; i++)
1759 if (object_signals[i] == signal_id)
1765 parent = g_type_parent (GTK_CLASS_TYPE (class));
1766 if (GTK_TYPE_IS_OBJECT (parent))
1767 class = g_type_class_peek (parent);
1774 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1776 GTK_OBJECT_TYPE_NAME (object));
1780 handler = gtk_signal_handler_new ();
1781 handler->id = gtk_handler_id++;
1782 handler->signal_id = signal_id;
1783 handler->object_signal = object_signal != FALSE;
1784 handler->func = func;
1785 handler->func_data = func_data;
1786 handler->destroy_func = destroy_func;
1787 handler->after = after != FALSE;
1788 handler->no_marshal = no_marshal;
1790 gtk_signal_handler_insert (object, handler);
1795 gtk_emission_new (void)
1797 GtkEmission *emission;
1799 if (!gtk_free_emissions)
1801 GtkEmission *emission_block;
1804 emission_block = g_new0 (GtkEmission, EMISSION_BLOCK_SIZE);
1805 for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1807 (emission_block + i)->next = gtk_free_emissions;
1808 gtk_free_emissions = (emission_block + i);
1811 emission = emission_block;
1815 emission = gtk_free_emissions;
1816 gtk_free_emissions = emission->next;
1819 emission->object = NULL;
1820 emission->signal_id = 0;
1821 emission->in_hook = 0;
1822 emission->next = NULL;
1828 gtk_emission_add (GtkEmission **emissions,
1832 GtkEmission *emission;
1834 g_return_if_fail (emissions != NULL);
1835 g_return_if_fail (object != NULL);
1837 emission = gtk_emission_new ();
1838 emission->object = object;
1839 emission->signal_id = signal_id;
1841 emission->next = *emissions;
1842 *emissions = emission;
1846 gtk_emission_remove (GtkEmission **emissions,
1850 GtkEmission *emission, *last;
1852 g_return_if_fail (emissions != NULL);
1855 emission = *emissions;
1858 if (emission->object == object && emission->signal_id == signal_id)
1861 last->next = emission->next;
1863 *emissions = emission->next;
1865 emission->next = gtk_free_emissions;
1866 gtk_free_emissions = emission;
1871 emission = last->next;
1876 gtk_emission_check (GtkEmission *emission,
1882 if (emission->object == object && emission->signal_id == signal_id)
1883 return 1 + emission->in_hook;
1884 emission = emission->next;
1890 gtk_handlers_run (GtkHandler *handlers,
1896 /* *signal is a local copy on the stack of gtk_signal_real_emit(),
1897 * so we don't need to look it up every time we invoked a function.
1899 while (handlers && handlers->signal_id == signal->signal_id)
1901 GtkHandler *handlers_next;
1903 gtk_signal_handler_ref (handlers);
1905 if (!handlers->blocked && handlers->after == after)
1909 if (handlers->no_marshal)
1910 (* (GtkCallbackMarshal) handlers->func) (object,
1911 handlers->func_data,
1914 else if (handlers->object_signal)
1915 /* don't cast with GTK_OBJECT () */
1916 (* signal->marshaller) ((GtkObject*) handlers->func_data,
1921 (* signal->marshaller) (object,
1923 handlers->func_data,
1926 else if (global_marshaller)
1927 (* global_marshaller) (object,
1928 handlers->func_data,
1932 signal->return_val);
1934 if (stop_emissions && gtk_emission_check (stop_emissions,
1938 gtk_emission_remove (&stop_emissions, object, signal->signal_id);
1940 gtk_signal_handler_unref (handlers, object);
1942 return EMISSION_DONE;
1944 else if (restart_emissions &&
1945 signal->signal_flags & GTK_RUN_NO_RECURSE &&
1946 gtk_emission_check (restart_emissions, object, signal->signal_id))
1948 gtk_emission_remove (&restart_emissions, object, signal->signal_id);
1950 gtk_signal_handler_unref (handlers, object);
1952 return EMISSION_RESTART;
1956 handlers_next = handlers->next;
1957 gtk_signal_handler_unref (handlers, object);
1958 handlers = handlers_next;
1961 return EMISSION_CONTINUE;
1965 gtk_signal_collect_params (GtkArg *params,
1967 GtkType *param_types,
1968 GtkType return_type,
1971 register GtkArg *last_param;
1972 register gboolean failed = FALSE;
1974 for (last_param = params + n_params; params < last_param; params++)
1976 register gchar *error;
1978 params->name = NULL;
1979 params->type = *(param_types++);
1980 GTK_ARG_COLLECT_VALUE (params,
1986 g_warning ("gtk_signal_collect_params(): %s", error);
1991 params->type = return_type;
1992 params->name = NULL;
1994 return_type = GTK_FUNDAMENTAL_TYPE (return_type);
1995 if (return_type != GTK_TYPE_NONE)
1997 if (return_type != 0) /* FIXME: check for IS_PARAM */
1999 GTK_VALUE_POINTER (*params) = va_arg (var_args, gpointer);
2001 if (GTK_VALUE_POINTER (*params) == NULL)
2004 g_warning ("gtk_signal_collect_params(): invalid NULL pointer for return argument type `%s'",
2005 gtk_type_name (params->type));
2011 g_warning ("gtk_signal_collect_params(): unsupported return argument type `%s'",
2012 gtk_type_name (params->type));
2016 GTK_VALUE_POINTER (*params) = NULL;