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 Library 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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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.
22 #include "gtksignal.h"
23 #include "gtkargcollector.c"
26 #define SIGNAL_BLOCK_SIZE (100)
27 #define HANDLER_BLOCK_SIZE (200)
28 #define EMISSION_BLOCK_SIZE (100)
29 #define DISCONNECT_INFO_BLOCK_SIZE (64)
30 #define MAX_SIGNAL_PARAMS (31)
39 #define GTK_RUN_TYPE(x) ((x) & GTK_RUN_MASK)
42 typedef struct _GtkSignal GtkSignal;
43 typedef struct _GtkSignalHash GtkSignalHash;
44 typedef struct _GtkHandler GtkHandler;
45 typedef struct _GtkHandlerInfo GtkHandlerInfo;
46 typedef struct _GtkEmission GtkEmission;
47 typedef union _GtkEmissionAllocator GtkEmissionAllocator;
48 typedef struct _GtkDisconnectInfo GtkDisconnectInfo;
50 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
58 guint function_offset;
59 GtkSignalRunType signal_flags;
60 GtkSignalMarshaller marshaller;
77 guint object_signal : 1;
84 GtkSignalDestroy destroy_func;
89 struct _GtkHandlerInfo
92 GtkSignalMarshaller marshaller;
96 GtkSignalRunType signal_flags;
107 union _GtkEmissionAllocator
109 GtkEmissionAllocator *next;
110 GtkEmission emission;
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 GtkHandler* gtk_signal_get_handlers (GtkObject *object,
137 static guint gtk_signal_connect_by_type (GtkObject *object,
141 GtkSignalDestroy destroy_func,
145 static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);
146 static GtkEmission* gtk_emission_new (void);
147 static void gtk_emission_add (GList **emissions,
150 static void gtk_emission_remove (GList **emissions,
153 static gint gtk_emission_check (GList *emissions,
156 static gint gtk_handlers_run (GtkHandler *handlers,
157 GtkHandlerInfo *info,
159 static gboolean gtk_signal_collect_params (GtkArg *params,
161 GtkType *param_types,
165 #define LOOKUP_SIGNAL_ID(signal_id) ( \
166 signal_id > 0 && signal_id < gtk_n_signals ? \
167 (GtkSignal*) gtk_signals + signal_id : \
172 static GtkSignalMarshal global_marshaller = NULL;
173 static GtkSignalDestroy global_destroy_notify = NULL;
175 static guint gtk_handler_id = 1;
176 static guint handler_quark = 0;
177 static GHashTable *gtk_signal_hash_table = NULL;
178 static GtkSignal *gtk_signals = NULL;
179 static guint gtk_n_signals = 0;
180 static GMemChunk *gtk_signal_hash_mem_chunk = NULL;
181 static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;
182 static GtkHandler *gtk_handler_free_list = NULL;
183 static GtkEmissionAllocator *gtk_emission_free_list = NULL;
187 static GList *current_emissions = NULL;
188 static GList *stop_emissions = NULL;
189 static GList *restart_emissions = NULL;
192 gtk_signal_next_and_invalidate (void)
194 static guint gtk_n_free_signals = 0;
195 register GtkSignal *signal;
196 register guint new_signal_id;
198 /* don't keep *any* GtkSignal pointers across invokation of this function!!!
201 if (gtk_n_free_signals == 0)
208 size = gtk_n_signals + SIGNAL_BLOCK_SIZE;
209 size *= sizeof (GtkSignal);
215 gtk_signals = g_realloc (gtk_signals, size);
217 gtk_n_free_signals = size / sizeof (GtkSignal) - gtk_n_signals;
219 memset (gtk_signals + gtk_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
222 new_signal_id = gtk_n_signals++;
223 gtk_n_free_signals--;
225 signal = LOOKUP_SIGNAL_ID (new_signal_id);
227 signal->signal_id = new_signal_id;
233 gtk_signal_init (void)
239 zero = gtk_signal_next_and_invalidate ();
240 g_assert (zero == NULL);
242 handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
244 gtk_signal_hash_mem_chunk =
245 g_mem_chunk_new ("GtkSignalHash mem chunk",
246 sizeof (GtkSignalHash),
247 sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
249 gtk_disconnect_info_mem_chunk =
250 g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
251 sizeof (GtkDisconnectInfo),
252 sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
254 gtk_handler_free_list = NULL;
255 gtk_emission_free_list = NULL;
257 gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
263 gtk_signal_newv (const gchar *r_name,
264 GtkSignalRunType signal_flags,
266 guint function_offset,
267 GtkSignalMarshaller marshaller,
278 g_return_val_if_fail (r_name != NULL, 0);
279 g_return_val_if_fail (marshaller != NULL, 0);
280 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
282 g_return_val_if_fail (params != NULL, 0);
288 name = g_strdup (r_name);
289 g_strdelimit (name, NULL, '_');
291 quark = gtk_signal_lookup (name, object_type);
294 g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
296 gtk_type_name (object_type));
301 if (return_val != GTK_TYPE_NONE &&
302 (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
304 g_warning ("gtk_signal_newv(): signal \"%s\" with return value `%s' excludes GTK_RUN_LAST",
305 name, gtk_type_name (return_val));
310 signal = gtk_signal_next_and_invalidate ();
312 /* signal->signal_id already set */
314 signal->object_type = object_type;
316 signal->function_offset = function_offset;
317 signal->signal_flags = signal_flags;
318 signal->marshaller = marshaller;
319 signal->return_val = return_val;
320 signal->nparams = nparams;
324 signal->params = g_new (GtkType, nparams);
326 for (i = 0; i < nparams; i++)
327 signal->params[i] = params[i];
330 signal->params = NULL;
332 /* insert "signal_name" into hash table
334 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
335 hash->object_type = object_type;
336 hash->quark = g_quark_from_string (signal->name);
337 hash->signal_id = signal->signal_id;
338 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
340 /* insert "signal-name" into hash table
342 g_strdelimit (signal->name, NULL, '-');
343 quark = g_quark_from_static_string (signal->name);
344 if (quark != hash->quark)
346 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
347 hash->object_type = object_type;
349 hash->signal_id = signal->signal_id;
350 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
353 return signal->signal_id;
357 gtk_signal_new (const gchar *name,
358 GtkSignalRunType signal_flags,
360 guint function_offset,
361 GtkSignalMarshaller marshaller,
371 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
375 params = g_new (GtkType, nparams);
377 va_start (args, nparams);
379 for (i = 0; i < nparams; i++)
380 params[i] = va_arg (args, GtkType);
387 signal_id = gtk_signal_newv (name,
402 gtk_signal_lookup (const gchar *name,
407 g_return_val_if_fail (name != NULL, 0);
408 g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0);
410 hash.quark = g_quark_try_string (name);
417 hash.object_type = object_type;
419 signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
423 object_type = gtk_type_parent (object_type);
431 gtk_signal_query (guint signal_id)
433 GtkSignalQuery *query;
436 g_return_val_if_fail (signal_id >= 1, NULL);
438 signal = LOOKUP_SIGNAL_ID (signal_id);
441 query = g_new (GtkSignalQuery, 1);
443 query->object_type = signal->object_type;
444 query->signal_id = signal_id;
445 query->signal_name = signal->name;
446 query->is_user_signal = signal->function_offset == 0;
447 query->signal_flags = signal->signal_flags;
448 query->return_val = signal->return_val;
449 query->nparams = signal->nparams;
450 query->params = signal->params;
459 gtk_signal_name (guint signal_id)
463 g_return_val_if_fail (signal_id >= 1, NULL);
465 signal = LOOKUP_SIGNAL_ID (signal_id);
473 gtk_signal_emitv (GtkObject *object,
479 g_return_if_fail (object != NULL);
480 g_return_if_fail (signal_id >= 1);
482 signal = LOOKUP_SIGNAL_ID (signal_id);
483 g_return_if_fail (signal != NULL);
484 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
486 if (signal->nparams > 0)
487 g_return_if_fail (params != NULL);
489 gtk_signal_real_emit (object, signal_id, params);
493 gtk_signal_emit (GtkObject *object,
499 GtkArg params[MAX_SIGNAL_PARAMS + 1];
502 g_return_if_fail (object != NULL);
503 g_return_if_fail (signal_id >= 1);
505 signal = LOOKUP_SIGNAL_ID (signal_id);
506 g_return_if_fail (signal != NULL);
507 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
509 va_start (args, signal_id);
510 abort = gtk_signal_collect_params (params,
518 gtk_signal_real_emit (object, signal_id, params);
522 gtk_signal_emitv_by_name (GtkObject *object,
528 g_return_if_fail (object != NULL);
529 g_return_if_fail (name != NULL);
530 g_return_if_fail (params != NULL);
532 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
538 signal = LOOKUP_SIGNAL_ID (signal_id);
539 g_return_if_fail (signal != NULL);
540 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
542 gtk_signal_real_emit (object, signal_id, params);
546 g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
548 gtk_type_name (GTK_OBJECT_TYPE (object)));
553 gtk_signal_emit_by_name (GtkObject *object,
559 g_return_if_fail (object != NULL);
560 g_return_if_fail (name != NULL);
562 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
567 GtkArg params[MAX_SIGNAL_PARAMS + 1];
571 signal = LOOKUP_SIGNAL_ID (signal_id);
572 g_return_if_fail (signal != NULL);
573 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
575 va_start (args, name);
576 abort = gtk_signal_collect_params (params,
584 gtk_signal_real_emit (object, signal_id, params);
588 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
590 gtk_type_name (GTK_OBJECT_TYPE (object)));
595 gtk_signal_emit_stop (GtkObject *object,
598 g_return_if_fail (object != NULL);
599 g_return_if_fail (signal_id >= 1);
601 if (gtk_emission_check (current_emissions, object, signal_id))
602 gtk_emission_add (&stop_emissions, object, signal_id);
604 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
606 gtk_type_name (GTK_OBJECT_TYPE (object)));
610 gtk_signal_emit_stop_by_name (GtkObject *object,
615 g_return_if_fail (object != NULL);
616 g_return_if_fail (name != NULL);
618 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
620 gtk_signal_emit_stop (object, signal_id);
622 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
624 gtk_type_name (GTK_OBJECT_TYPE (object)));
628 gtk_signal_n_emissions (GtkObject *object,
634 g_return_val_if_fail (object != NULL, 0);
635 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
638 for (list = current_emissions; list; list = list->next)
640 GtkEmission *emission;
642 emission = list->data;
644 if ((emission->object == object) &&
645 (emission->signal_id == signal_id))
653 gtk_signal_n_emissions_by_name (GtkObject *object,
659 g_return_val_if_fail (object != NULL, 0);
660 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
661 g_return_val_if_fail (name != NULL, 0);
663 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
665 n = gtk_signal_n_emissions (object, signal_id);
668 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
670 gtk_type_name (GTK_OBJECT_TYPE (object)));
678 gtk_signal_connect (GtkObject *object,
685 g_return_val_if_fail (object != NULL, 0);
686 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
688 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
691 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
693 gtk_type_name (GTK_OBJECT_TYPE (object)));
697 return gtk_signal_connect_by_type (object, signal_id,
698 func, func_data, NULL,
699 FALSE, FALSE, FALSE);
703 gtk_signal_connect_after (GtkObject *object,
710 g_return_val_if_fail (object != NULL, 0);
712 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
715 g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
717 gtk_type_name (GTK_OBJECT_TYPE (object)));
721 return gtk_signal_connect_by_type (object, signal_id,
722 func, func_data, NULL,
727 gtk_signal_connect_full (GtkObject *object,
730 GtkCallbackMarshal marshal,
732 GtkDestroyNotify destroy_func,
738 g_return_val_if_fail (object != NULL, 0);
740 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
743 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
745 gtk_type_name (GTK_OBJECT_TYPE (object)));
750 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
751 func_data, destroy_func,
752 object_signal, after, TRUE);
754 return gtk_signal_connect_by_type (object, signal_id, func,
755 func_data, destroy_func,
756 object_signal, after, FALSE);
760 gtk_signal_connect_interp (GtkObject *object,
762 GtkCallbackMarshal func,
764 GtkDestroyNotify destroy_func,
767 return gtk_signal_connect_full (object, name, NULL, func,
768 func_data, destroy_func, FALSE, after);
772 gtk_signal_connect_object (GtkObject *object,
775 GtkObject *slot_object)
779 g_return_val_if_fail (object != NULL, 0);
780 /* slot_object needs to be treated as ordinary pointer
783 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
786 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
788 gtk_type_name (GTK_OBJECT_TYPE (object)));
792 return gtk_signal_connect_by_type (object, signal_id,
793 func, slot_object, NULL,
798 gtk_signal_connect_object_after (GtkObject *object,
801 GtkObject *slot_object)
805 g_return_val_if_fail (object != NULL, 0);
807 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
810 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
812 gtk_type_name (GTK_OBJECT_TYPE (object)));
816 return gtk_signal_connect_by_type (object, signal_id,
817 func, slot_object, NULL,
822 gtk_signal_connect_while_alive (GtkObject *object,
826 GtkObject *alive_object)
828 GtkDisconnectInfo *info;
830 g_return_if_fail (object != NULL);
831 g_return_if_fail (GTK_IS_OBJECT (object));
832 g_return_if_fail (signal != NULL);
833 g_return_if_fail (func != NULL);
834 g_return_if_fail (alive_object != NULL);
835 g_return_if_fail (GTK_IS_OBJECT (alive_object));
837 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
838 info->object1 = object;
839 info->object2 = alive_object;
841 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
842 info->disconnect_handler1 =
843 gtk_signal_connect_object (info->object1,
845 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
847 info->disconnect_handler2 =
848 gtk_signal_connect_object (info->object2,
850 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
855 gtk_signal_connect_object_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 (object, signal, func, alive_object);
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_disconnect (GtkObject *object,
892 g_return_if_fail (object != NULL);
893 g_return_if_fail (handler_id > 0);
895 handler = gtk_object_get_data_by_id (object, handler_quark);
899 if (handler->id == handler_id)
902 handler->blocked += 1;
903 gtk_signal_handler_unref (handler, object);
906 handler = handler->next;
909 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
913 gtk_signal_disconnect_by_func (GtkObject *object,
920 g_return_if_fail (object != NULL);
921 g_return_if_fail (func != NULL);
924 handler = gtk_object_get_data_by_id (object, handler_quark);
928 GtkHandler *handler_next;
930 handler_next = handler->next;
931 if ((handler->id > 0) &&
932 (handler->func == func) &&
933 (handler->func_data == data))
937 handler->blocked += 1;
938 gtk_signal_handler_unref (handler, object);
940 handler = handler_next;
944 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
948 gtk_signal_disconnect_by_data (GtkObject *object,
954 g_return_if_fail (object != NULL);
957 handler = gtk_object_get_data_by_id (object, handler_quark);
961 GtkHandler *handler_next;
963 handler_next = handler->next;
964 if ((handler->id > 0) &&
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_data(): could not find handler containing data (0x%0lX)", (long) data);
980 gtk_signal_handler_block (GtkObject *object,
985 g_return_if_fail (object != NULL);
986 g_return_if_fail (handler_id > 0);
988 handler = gtk_object_get_data_by_id (object, handler_quark);
992 if (handler->id == handler_id)
994 handler->blocked += 1;
997 handler = handler->next;
1000 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
1004 gtk_signal_handler_block_by_func (GtkObject *object,
1008 GtkHandler *handler;
1011 g_return_if_fail (object != NULL);
1012 g_return_if_fail (func != NULL);
1015 handler = gtk_object_get_data_by_id (object, handler_quark);
1019 if ((handler->id > 0) &&
1020 (handler->func == func) &&
1021 (handler->func_data == data))
1024 handler->blocked += 1;
1026 handler = handler->next;
1030 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1034 gtk_signal_handler_block_by_data (GtkObject *object,
1037 GtkHandler *handler;
1040 g_return_if_fail (object != NULL);
1043 handler = gtk_object_get_data_by_id (object, handler_quark);
1047 if ((handler->id > 0) &&
1048 (handler->func_data == data))
1051 handler->blocked += 1;
1053 handler = handler->next;
1057 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1061 gtk_signal_handler_unblock (GtkObject *object,
1064 GtkHandler *handler;
1066 g_return_if_fail (object != NULL);
1067 g_return_if_fail (handler_id > 0);
1069 handler = gtk_object_get_data_by_id (object, handler_quark);
1073 if (handler->id == handler_id)
1075 if (handler->blocked > 0)
1076 handler->blocked -= 1;
1078 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1081 handler = handler->next;
1084 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1088 gtk_signal_handler_unblock_by_func (GtkObject *object,
1092 GtkHandler *handler;
1095 g_return_if_fail (object != NULL);
1096 g_return_if_fail (func != NULL);
1099 handler = gtk_object_get_data_by_id (object, handler_quark);
1103 if ((handler->id > 0) &&
1104 (handler->func == func) &&
1105 (handler->func_data == data) &&
1106 (handler->blocked > 0))
1108 handler->blocked -= 1;
1111 handler = handler->next;
1115 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1119 gtk_signal_handler_unblock_by_data (GtkObject *object,
1122 GtkHandler *handler;
1125 g_return_if_fail (object != NULL);
1128 handler = gtk_object_get_data_by_id (object, handler_quark);
1132 if ((handler->id > 0) &&
1133 (handler->func_data == data) &&
1134 (handler->blocked > 0))
1136 handler->blocked -= 1;
1139 handler = handler->next;
1143 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1147 gtk_signal_handlers_destroy (GtkObject *object)
1149 GtkHandler *handler;
1151 /* we make the "optimization" of destroying the first handler in the last
1152 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1153 * handler_key data on each removal
1156 handler = gtk_object_get_data_by_id (object, handler_quark);
1159 handler = handler->next;
1164 next = handler->next;
1165 gtk_signal_handler_unref (handler, object);
1168 handler = gtk_object_get_data_by_id (object, handler_quark);
1169 gtk_signal_handler_unref (handler, object);
1174 gtk_signal_default_marshaller (GtkObject *object,
1179 GtkSignalMarshaller0 rfunc;
1181 rfunc = (GtkSignalMarshaller0) func;
1183 (* rfunc) (object, func_data);
1187 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1188 GtkSignalDestroy destroy_func)
1190 global_marshaller = marshal_func;
1191 global_destroy_notify = destroy_func;
1195 gtk_signal_hash (gconstpointer h)
1197 register const GtkSignalHash *hash = h;
1199 return hash->object_type ^ hash->quark;
1203 gtk_signal_compare (gconstpointer h1,
1206 register const GtkSignalHash *hash1 = h1;
1207 register const GtkSignalHash *hash2 = h2;
1209 return (hash1->quark == hash2->quark &&
1210 hash1->object_type == hash2->object_type);
1214 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1216 g_return_val_if_fail (info != NULL, 0);
1218 gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1219 gtk_signal_disconnect (info->object1, info->signal_handler);
1220 gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1222 g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1228 gtk_signal_handler_new (void)
1230 GtkHandler *handler;
1232 if (!gtk_handler_free_list)
1234 GtkHandler *handler_block;
1237 handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1238 for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1240 (handler_block + i)->next = gtk_handler_free_list;
1241 gtk_handler_free_list = (handler_block + i);
1244 handler = handler_block;
1248 handler = gtk_handler_free_list;
1249 gtk_handler_free_list = handler->next;
1253 handler->blocked = 0;
1254 handler->signal_id = 0;
1255 handler->object_signal = FALSE;
1256 handler->after = FALSE;
1257 handler->no_marshal = FALSE;
1258 handler->ref_count = 1;
1259 handler->func = NULL;
1260 handler->func_data = NULL;
1261 handler->destroy_func = NULL;
1262 handler->prev = NULL;
1263 handler->next = NULL;
1269 gtk_signal_handler_ref (GtkHandler *handler)
1271 handler->ref_count += 1;
1275 gtk_signal_handler_unref (GtkHandler *handler,
1278 if (!handler->ref_count)
1280 /* FIXME: i wanna get removed somewhen */
1281 g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1285 handler->ref_count -= 1;
1287 if (handler->ref_count == 0)
1289 if (handler->destroy_func)
1290 (* handler->destroy_func) (handler->func_data);
1291 else if (!handler->func && global_destroy_notify)
1292 (* global_destroy_notify) (handler->func_data);
1295 handler->prev->next = handler->next;
1296 else if (handler->next)
1297 gtk_object_set_data_by_id (object, handler_quark, handler->next);
1300 GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1301 gtk_object_set_data_by_id (object, handler_quark, NULL);
1304 handler->next->prev = handler->prev;
1306 handler->next = gtk_handler_free_list;
1307 gtk_handler_free_list = handler;
1312 gtk_signal_handler_insert (GtkObject *object,
1313 GtkHandler *handler)
1317 /* FIXME: remove */ g_assert (handler->next == NULL);
1318 /* FIXME: remove */ g_assert (handler->prev == NULL);
1320 tmp = gtk_object_get_data_by_id (object, handler_quark);
1323 GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1324 gtk_object_set_data_by_id (object, handler_quark, handler);
1329 if (tmp->signal_id < handler->signal_id)
1333 tmp->prev->next = handler;
1334 handler->prev = tmp->prev;
1337 gtk_object_set_data_by_id (object, handler_quark, handler);
1338 tmp->prev = handler;
1339 handler->next = tmp;
1345 tmp->next = handler;
1346 handler->prev = tmp;
1353 static GtkObject *gtk_trace_signal_object = NULL;
1356 gtk_signal_real_emit (GtkObject *object,
1361 GtkHandler *handlers;
1362 GtkHandlerInfo info;
1363 guchar **signal_func_offset;
1365 signal = LOOKUP_SIGNAL_ID (signal_id);
1367 #ifdef G_ENABLE_DEBUG
1368 if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1369 object == gtk_trace_signal_object)
1370 fprintf (stdout, "trace: signal_emit(\"%s\") for %s:%p\n",
1372 gtk_type_name (GTK_OBJECT_TYPE (object)),
1374 #endif /* G_ENABLE_DEBUG */
1376 if ((signal->signal_flags & GTK_RUN_NO_RECURSE) &&
1377 gtk_emission_check (current_emissions, object, signal_id))
1379 gtk_emission_add (&restart_emissions, object, signal_id);
1383 gtk_object_ref (object);
1385 gtk_emission_add (¤t_emissions, object, signal_id);
1388 if (GTK_RUN_TYPE (signal->signal_flags) != GTK_RUN_LAST && signal->function_offset != 0)
1390 signal_func_offset = (guchar**) ((guchar*) object->klass +
1391 signal->function_offset);
1392 if (*signal_func_offset)
1394 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1396 signal = LOOKUP_SIGNAL_ID (signal_id);
1400 if (GTK_OBJECT_CONNECTED (object))
1402 handlers = gtk_signal_get_handlers (object, signal_id);
1407 info.object = object;
1408 info.marshaller = signal->marshaller;
1409 info.params = params;
1410 info.param_types = signal->params;
1411 info.return_val = signal->return_val;
1412 info.nparams = signal->nparams;
1413 info.signal_flags = signal->signal_flags;
1414 info.signal_id = signal_id;
1416 return_val = gtk_handlers_run (handlers, &info, FALSE);
1417 signal = LOOKUP_SIGNAL_ID (signal_id);
1420 case EMISSION_CONTINUE:
1422 case EMISSION_RESTART:
1423 goto emission_restart;
1434 if (GTK_RUN_TYPE (signal->signal_flags) != GTK_RUN_FIRST && signal->function_offset != 0)
1436 signal_func_offset = (guchar**) ((guchar*) object->klass +
1437 signal->function_offset);
1438 if (*signal_func_offset)
1440 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1442 signal = LOOKUP_SIGNAL_ID (signal_id);
1446 if (GTK_OBJECT_CONNECTED (object))
1448 handlers = gtk_signal_get_handlers (object, signal_id);
1455 info.object = object;
1456 info.marshaller = signal->marshaller;
1457 info.params = params;
1458 info.param_types = signal->params;
1459 info.return_val = signal->return_val;
1460 info.nparams = signal->nparams;
1461 info.signal_flags = signal->signal_flags;
1462 info.signal_id = signal_id;
1464 return_val = gtk_handlers_run (handlers, &info, TRUE);
1465 signal = LOOKUP_SIGNAL_ID (signal_id);
1468 case EMISSION_CONTINUE:
1470 case EMISSION_RESTART:
1471 goto emission_restart;
1480 gtk_emission_remove (¤t_emissions, object, signal_id);
1482 if (signal->signal_flags & GTK_RUN_NO_RECURSE)
1483 gtk_emission_remove (&restart_emissions, object, signal_id);
1485 gtk_object_unref (object);
1489 gtk_signal_get_handlers (GtkObject *object,
1492 GtkHandler *handlers;
1494 handlers = gtk_object_get_data_by_id (object, handler_quark);
1498 if (handlers->signal_id == signal_id)
1500 handlers = handlers->next;
1507 gtk_signal_handler_pending (GtkObject *object,
1509 gboolean may_be_blocked)
1511 GtkHandler *handlers;
1514 g_return_val_if_fail (object != NULL, 0);
1515 g_return_val_if_fail (signal_id >= 1, 0);
1517 if (GTK_OBJECT_CONNECTED (object))
1518 handlers = gtk_signal_get_handlers (object, signal_id);
1523 while (handlers && handlers->signal_id == signal_id)
1525 if (handlers->id > 0 &&
1526 (may_be_blocked || handlers->blocked == FALSE))
1528 handler_id = handlers->id;
1532 handlers = handlers->next;
1539 gtk_signal_handler_pending_by_func (GtkObject *object,
1541 gboolean may_be_blocked,
1545 GtkHandler *handlers;
1548 g_return_val_if_fail (object != NULL, 0);
1549 g_return_val_if_fail (func != NULL, 0);
1550 g_return_val_if_fail (signal_id >= 1, 0);
1552 if (GTK_OBJECT_CONNECTED (object))
1553 handlers = gtk_signal_get_handlers (object, signal_id);
1558 while (handlers && handlers->signal_id == signal_id)
1560 if (handlers->id > 0 &&
1561 handlers->func == func &&
1562 handlers->func_data == data &&
1563 (may_be_blocked || handlers->blocked == FALSE))
1565 handler_id = handlers->id;
1569 handlers = handlers->next;
1576 gtk_signal_connect_by_type (GtkObject *object,
1580 GtkSignalDestroy destroy_func,
1585 GtkObjectClass *class;
1586 GtkHandler *handler;
1589 g_return_val_if_fail (object != NULL, 0);
1590 g_return_val_if_fail (object->klass != NULL, 0);
1592 /* Search through the signals for this object and make
1593 * sure the one we are adding is valid. We need to perform
1594 * the lookup on the objects parents as well. If it isn't
1595 * valid then issue a warning and return.
1596 * As of now (1998-05-27) this lookup shouldn't be neccessarry
1597 * anymore since gtk_signal_lookup() has been reworked to only
1598 * return correct signal ids per class-branch.
1601 class = object->klass;
1605 guint *object_signals;
1609 object_signals = class->signals;
1610 nsignals = class->nsignals;
1612 for (i = 0; i < nsignals; i++)
1613 if (object_signals[i] == signal_id)
1619 parent = gtk_type_parent (class->type);
1621 class = gtk_type_class (parent);
1628 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1630 gtk_type_name (object->klass->type));
1634 handler = gtk_signal_handler_new ();
1635 handler->id = gtk_handler_id++;
1636 handler->signal_id = signal_id;
1637 handler->object_signal = object_signal;
1638 handler->func = func;
1639 handler->func_data = func_data;
1640 handler->destroy_func = destroy_func;
1641 handler->after = after != FALSE;
1642 handler->no_marshal = no_marshal;
1644 gtk_signal_handler_insert (object, handler);
1649 gtk_emission_new (void)
1651 GtkEmission *emission;
1653 if (!gtk_emission_free_list)
1655 GtkEmissionAllocator *emission_block;
1658 emission_block = g_new0 (GtkEmissionAllocator, EMISSION_BLOCK_SIZE);
1659 for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1661 (emission_block + i)->next = gtk_emission_free_list;
1662 gtk_emission_free_list = (emission_block + i);
1665 emission = &emission_block->emission;
1669 emission = >k_emission_free_list->emission;
1670 gtk_emission_free_list = gtk_emission_free_list->next;
1673 emission->object = NULL;
1674 emission->signal_id = 0;
1680 gtk_emission_add (GList **emissions,
1684 GtkEmission *emission;
1686 g_return_if_fail (emissions != NULL);
1687 g_return_if_fail (object != NULL);
1689 emission = gtk_emission_new ();
1690 emission->object = object;
1691 emission->signal_id = signal_id;
1693 *emissions = g_list_prepend (*emissions, emission);
1697 gtk_emission_remove (GList **emissions,
1703 g_return_if_fail (emissions != NULL);
1708 GtkEmissionAllocator *ea;
1712 if ((ea->emission.object == object) &&
1713 (ea->emission.signal_id == signal_id))
1715 *emissions = g_list_remove_link (*emissions, tmp);
1718 ea->next = gtk_emission_free_list;
1719 gtk_emission_free_list = ea;
1728 gtk_emission_check (GList *emissions,
1732 GtkEmission *emission;
1738 emission = tmp->data;
1741 if ((emission->object == object) &&
1742 (emission->signal_id == signal_id))
1749 gtk_handlers_run (GtkHandler *handlers,
1750 GtkHandlerInfo *info,
1753 while (handlers && handlers->signal_id == info->signal_id)
1755 GtkHandler *handlers_next;
1757 gtk_signal_handler_ref (handlers);
1759 if (handlers->blocked == 0 && (handlers->after == after))
1763 if (handlers->no_marshal)
1764 (* (GtkCallbackMarshal) handlers->func) (info->object,
1765 handlers->func_data,
1768 else if (handlers->object_signal)
1769 (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
1771 handlers->func_data,
1774 (* info->marshaller) (info->object,
1776 handlers->func_data,
1779 else if (global_marshaller)
1780 (* global_marshaller) (info->object,
1781 handlers->func_data,
1787 if (gtk_emission_check (stop_emissions, info->object,
1790 gtk_emission_remove (&stop_emissions, info->object,
1793 if (info->signal_flags & GTK_RUN_NO_RECURSE)
1794 gtk_emission_remove (&restart_emissions, info->object,
1796 gtk_signal_handler_unref (handlers, info->object);
1797 return EMISSION_DONE;
1799 else if ((info->signal_flags & GTK_RUN_NO_RECURSE) &&
1800 gtk_emission_check (restart_emissions, info->object,
1803 gtk_emission_remove (&restart_emissions, info->object,
1805 gtk_signal_handler_unref (handlers, info->object);
1806 return EMISSION_RESTART;
1810 handlers_next = handlers->next;
1811 gtk_signal_handler_unref (handlers, info->object);
1812 handlers = handlers_next;
1815 return EMISSION_CONTINUE;
1819 gtk_signal_collect_params (GtkArg *params,
1821 GtkType *param_types,
1822 GtkType return_type,
1825 register GtkArg *last_param;
1826 register gboolean failed = FALSE;
1828 for (last_param = params + n_params; params < last_param; params++)
1830 register gchar *error;
1832 params->type = *(param_types++);
1833 params->name = NULL;
1834 error = gtk_arg_collect_value (GTK_FUNDAMENTAL_TYPE (params->type),
1840 g_warning ("gtk_signal_collect_params(): %s", error);
1845 params->type = return_type;
1846 params->name = NULL;
1848 return_type = GTK_FUNDAMENTAL_TYPE (return_type);
1849 if (return_type != GTK_TYPE_NONE)
1851 if ((return_type >= GTK_TYPE_FLAT_FIRST &&
1852 return_type <= GTK_TYPE_FLAT_LAST) ||
1853 (return_type == GTK_TYPE_OBJECT))
1855 GTK_VALUE_POINTER (*params) = va_arg (var_args, gpointer);
1857 if (GTK_VALUE_POINTER (*params) == NULL)
1860 g_warning ("gtk_signal_collect_params(): invalid NULL pointer for return argument type `%s'",
1861 gtk_type_name (params->type));
1867 g_warning ("gtk_signal_collect_params(): unsupported return argument type `%s'",
1868 gtk_type_name (params->type));
1872 GTK_VALUE_POINTER (*params) = NULL;