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 _GtkEmission GtkEmission;
46 typedef union _GtkEmissionAllocator GtkEmissionAllocator;
47 typedef struct _GtkDisconnectInfo GtkDisconnectInfo;
49 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
57 guint function_offset;
58 GtkSignalRunType signal_flags;
59 GtkSignalMarshaller marshaller;
76 guint object_signal : 1;
83 GtkSignalDestroy destroy_func;
94 union _GtkEmissionAllocator
96 GtkEmissionAllocator *next;
100 struct _GtkDisconnectInfo
103 guint disconnect_handler1;
104 guint signal_handler;
106 guint disconnect_handler2;
110 static guint gtk_signal_hash (gconstpointer h);
111 static gint gtk_signal_compare (gconstpointer h1,
113 static GtkHandler* gtk_signal_handler_new (void);
114 static void gtk_signal_handler_ref (GtkHandler *handler);
115 static void gtk_signal_handler_unref (GtkHandler *handler,
117 static void gtk_signal_handler_insert (GtkObject *object,
118 GtkHandler *handler);
119 static void gtk_signal_real_emit (GtkObject *object,
122 static GtkHandler* gtk_signal_get_handlers (GtkObject *object,
124 static guint gtk_signal_connect_by_type (GtkObject *object,
128 GtkSignalDestroy destroy_func,
132 static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);
133 static GtkEmission* gtk_emission_new (void);
134 static void gtk_emission_add (GList **emissions,
137 static void gtk_emission_remove (GList **emissions,
140 static gint gtk_emission_check (GList *emissions,
143 static gint gtk_handlers_run (GtkHandler *handlers,
148 static gboolean gtk_signal_collect_params (GtkArg *params,
150 GtkType *param_types,
154 #define LOOKUP_SIGNAL_ID(signal_id) ( \
155 signal_id > 0 && signal_id < gtk_n_signals ? \
156 (GtkSignal*) gtk_signals + signal_id : \
161 static GtkSignalMarshal global_marshaller = NULL;
162 static GtkSignalDestroy global_destroy_notify = NULL;
164 static guint gtk_handler_id = 1;
165 static guint handler_quark = 0;
166 static GHashTable *gtk_signal_hash_table = NULL;
167 static GtkSignal *gtk_signals = NULL;
168 static guint gtk_n_signals = 0;
169 static GMemChunk *gtk_signal_hash_mem_chunk = NULL;
170 static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;
171 static GtkHandler *gtk_handler_free_list = NULL;
172 static GtkEmissionAllocator *gtk_emission_free_list = NULL;
176 static GList *current_emissions = NULL;
177 static GList *stop_emissions = NULL;
178 static GList *restart_emissions = NULL;
181 gtk_signal_next_and_invalidate (void)
183 static guint gtk_n_free_signals = 0;
184 register GtkSignal *signal;
185 register guint new_signal_id;
187 /* don't keep *any* GtkSignal pointers across invokation of this function!!!
190 if (gtk_n_free_signals == 0)
197 size = gtk_n_signals + SIGNAL_BLOCK_SIZE;
198 size *= sizeof (GtkSignal);
204 gtk_signals = g_realloc (gtk_signals, size);
206 gtk_n_free_signals = size / sizeof (GtkSignal) - gtk_n_signals;
208 memset (gtk_signals + gtk_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
211 new_signal_id = gtk_n_signals++;
212 gtk_n_free_signals--;
214 signal = LOOKUP_SIGNAL_ID (new_signal_id);
216 signal->signal_id = new_signal_id;
222 gtk_signal_init (void)
228 zero = gtk_signal_next_and_invalidate ();
229 g_assert (zero == NULL);
231 handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
233 gtk_signal_hash_mem_chunk =
234 g_mem_chunk_new ("GtkSignalHash mem chunk",
235 sizeof (GtkSignalHash),
236 sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
238 gtk_disconnect_info_mem_chunk =
239 g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
240 sizeof (GtkDisconnectInfo),
241 sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
243 gtk_handler_free_list = NULL;
244 gtk_emission_free_list = NULL;
246 gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
252 gtk_signal_newv (const gchar *r_name,
253 GtkSignalRunType signal_flags,
255 guint function_offset,
256 GtkSignalMarshaller marshaller,
267 g_return_val_if_fail (r_name != NULL, 0);
268 g_return_val_if_fail (marshaller != NULL, 0);
269 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
271 g_return_val_if_fail (params != NULL, 0);
277 name = g_strdup (r_name);
278 g_strdelimit (name, NULL, '_');
280 quark = gtk_signal_lookup (name, object_type);
283 g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
285 gtk_type_name (object_type));
290 if (return_val != GTK_TYPE_NONE &&
291 (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
293 g_warning ("gtk_signal_newv(): signal \"%s\" with return value `%s' excludes GTK_RUN_LAST",
294 name, gtk_type_name (return_val));
299 signal = gtk_signal_next_and_invalidate ();
301 /* signal->signal_id already set */
303 signal->object_type = object_type;
305 signal->function_offset = function_offset;
306 signal->signal_flags = signal_flags;
307 signal->marshaller = marshaller;
308 signal->return_val = return_val;
309 signal->nparams = nparams;
313 signal->params = g_new (GtkType, nparams);
315 for (i = 0; i < nparams; i++)
316 signal->params[i] = params[i];
319 signal->params = NULL;
321 /* insert "signal_name" into hash table
323 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
324 hash->object_type = object_type;
325 hash->quark = g_quark_from_string (signal->name);
326 hash->signal_id = signal->signal_id;
327 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
329 /* insert "signal-name" into hash table
331 g_strdelimit (signal->name, NULL, '-');
332 quark = g_quark_from_static_string (signal->name);
333 if (quark != hash->quark)
335 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
336 hash->object_type = object_type;
338 hash->signal_id = signal->signal_id;
339 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
342 return signal->signal_id;
346 gtk_signal_new (const gchar *name,
347 GtkSignalRunType signal_flags,
349 guint function_offset,
350 GtkSignalMarshaller marshaller,
360 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
364 params = g_new (GtkType, nparams);
366 va_start (args, nparams);
368 for (i = 0; i < nparams; i++)
369 params[i] = va_arg (args, GtkType);
376 signal_id = gtk_signal_newv (name,
391 gtk_signal_lookup (const gchar *name,
396 g_return_val_if_fail (name != NULL, 0);
397 g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0);
399 hash.quark = g_quark_try_string (name);
406 hash.object_type = object_type;
408 signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
412 object_type = gtk_type_parent (object_type);
420 gtk_signal_query (guint signal_id)
422 GtkSignalQuery *query;
425 g_return_val_if_fail (signal_id >= 1, NULL);
427 signal = LOOKUP_SIGNAL_ID (signal_id);
430 query = g_new (GtkSignalQuery, 1);
432 query->object_type = signal->object_type;
433 query->signal_id = signal_id;
434 query->signal_name = signal->name;
435 query->is_user_signal = signal->function_offset == 0;
436 query->signal_flags = signal->signal_flags;
437 query->return_val = signal->return_val;
438 query->nparams = signal->nparams;
439 query->params = signal->params;
448 gtk_signal_name (guint signal_id)
452 g_return_val_if_fail (signal_id >= 1, NULL);
454 signal = LOOKUP_SIGNAL_ID (signal_id);
462 gtk_signal_emitv (GtkObject *object,
468 g_return_if_fail (object != NULL);
469 g_return_if_fail (signal_id >= 1);
471 signal = LOOKUP_SIGNAL_ID (signal_id);
472 g_return_if_fail (signal != NULL);
473 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
475 if (signal->nparams > 0)
476 g_return_if_fail (params != NULL);
478 gtk_signal_real_emit (object, signal_id, params);
482 gtk_signal_emit (GtkObject *object,
488 GtkArg params[MAX_SIGNAL_PARAMS + 1];
491 g_return_if_fail (object != NULL);
492 g_return_if_fail (signal_id >= 1);
494 signal = LOOKUP_SIGNAL_ID (signal_id);
495 g_return_if_fail (signal != NULL);
496 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
498 va_start (args, signal_id);
499 abort = gtk_signal_collect_params (params,
507 gtk_signal_real_emit (object, signal_id, params);
511 gtk_signal_emitv_by_name (GtkObject *object,
517 g_return_if_fail (object != NULL);
518 g_return_if_fail (name != NULL);
519 g_return_if_fail (params != NULL);
521 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
527 signal = LOOKUP_SIGNAL_ID (signal_id);
528 g_return_if_fail (signal != NULL);
529 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
531 gtk_signal_real_emit (object, signal_id, params);
535 g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
537 gtk_type_name (GTK_OBJECT_TYPE (object)));
542 gtk_signal_emit_by_name (GtkObject *object,
548 g_return_if_fail (object != NULL);
549 g_return_if_fail (name != NULL);
551 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
556 GtkArg params[MAX_SIGNAL_PARAMS + 1];
560 signal = LOOKUP_SIGNAL_ID (signal_id);
561 g_return_if_fail (signal != NULL);
562 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
564 va_start (args, name);
565 abort = gtk_signal_collect_params (params,
573 gtk_signal_real_emit (object, signal_id, params);
577 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
579 gtk_type_name (GTK_OBJECT_TYPE (object)));
584 gtk_signal_emit_stop (GtkObject *object,
587 g_return_if_fail (object != NULL);
588 g_return_if_fail (signal_id >= 1);
590 if (gtk_emission_check (current_emissions, object, signal_id))
591 gtk_emission_add (&stop_emissions, object, signal_id);
593 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
595 gtk_type_name (GTK_OBJECT_TYPE (object)));
599 gtk_signal_emit_stop_by_name (GtkObject *object,
604 g_return_if_fail (object != NULL);
605 g_return_if_fail (name != NULL);
607 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
609 gtk_signal_emit_stop (object, signal_id);
611 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
613 gtk_type_name (GTK_OBJECT_TYPE (object)));
617 gtk_signal_n_emissions (GtkObject *object,
623 g_return_val_if_fail (object != NULL, 0);
624 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
627 for (list = current_emissions; list; list = list->next)
629 GtkEmission *emission;
631 emission = list->data;
633 if ((emission->object == object) &&
634 (emission->signal_id == signal_id))
642 gtk_signal_n_emissions_by_name (GtkObject *object,
648 g_return_val_if_fail (object != NULL, 0);
649 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
650 g_return_val_if_fail (name != NULL, 0);
652 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
654 n = gtk_signal_n_emissions (object, signal_id);
657 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
659 gtk_type_name (GTK_OBJECT_TYPE (object)));
667 gtk_signal_connect (GtkObject *object,
674 g_return_val_if_fail (object != NULL, 0);
675 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
677 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
680 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
682 gtk_type_name (GTK_OBJECT_TYPE (object)));
686 return gtk_signal_connect_by_type (object, signal_id,
687 func, func_data, NULL,
688 FALSE, FALSE, FALSE);
692 gtk_signal_connect_after (GtkObject *object,
699 g_return_val_if_fail (object != NULL, 0);
701 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
704 g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
706 gtk_type_name (GTK_OBJECT_TYPE (object)));
710 return gtk_signal_connect_by_type (object, signal_id,
711 func, func_data, NULL,
716 gtk_signal_connect_full (GtkObject *object,
719 GtkCallbackMarshal marshal,
721 GtkDestroyNotify destroy_func,
727 g_return_val_if_fail (object != NULL, 0);
729 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
732 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
734 gtk_type_name (GTK_OBJECT_TYPE (object)));
739 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
740 func_data, destroy_func,
741 object_signal, after, TRUE);
743 return gtk_signal_connect_by_type (object, signal_id, func,
744 func_data, destroy_func,
745 object_signal, after, FALSE);
749 gtk_signal_connect_interp (GtkObject *object,
751 GtkCallbackMarshal func,
753 GtkDestroyNotify destroy_func,
756 return gtk_signal_connect_full (object, name, NULL, func,
757 func_data, destroy_func, FALSE, after);
761 gtk_signal_connect_object (GtkObject *object,
764 GtkObject *slot_object)
768 g_return_val_if_fail (object != NULL, 0);
769 /* slot_object needs to be treated as ordinary pointer
772 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
775 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
777 gtk_type_name (GTK_OBJECT_TYPE (object)));
781 return gtk_signal_connect_by_type (object, signal_id,
782 func, slot_object, NULL,
787 gtk_signal_connect_object_after (GtkObject *object,
790 GtkObject *slot_object)
794 g_return_val_if_fail (object != NULL, 0);
796 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
799 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
801 gtk_type_name (GTK_OBJECT_TYPE (object)));
805 return gtk_signal_connect_by_type (object, signal_id,
806 func, slot_object, NULL,
811 gtk_signal_connect_while_alive (GtkObject *object,
815 GtkObject *alive_object)
817 GtkDisconnectInfo *info;
819 g_return_if_fail (object != NULL);
820 g_return_if_fail (GTK_IS_OBJECT (object));
821 g_return_if_fail (signal != NULL);
822 g_return_if_fail (func != NULL);
823 g_return_if_fail (alive_object != NULL);
824 g_return_if_fail (GTK_IS_OBJECT (alive_object));
826 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
827 info->object1 = object;
828 info->object2 = alive_object;
830 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
831 info->disconnect_handler1 =
832 gtk_signal_connect_object (info->object1,
834 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
836 info->disconnect_handler2 =
837 gtk_signal_connect_object (info->object2,
839 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
844 gtk_signal_connect_object_while_alive (GtkObject *object,
847 GtkObject *alive_object)
849 GtkDisconnectInfo *info;
851 g_return_if_fail (object != NULL);
852 g_return_if_fail (GTK_IS_OBJECT (object));
853 g_return_if_fail (signal != NULL);
854 g_return_if_fail (func != NULL);
855 g_return_if_fail (alive_object != NULL);
856 g_return_if_fail (GTK_IS_OBJECT (alive_object));
858 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
859 info->object1 = object;
860 info->object2 = alive_object;
862 info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
863 info->disconnect_handler1 =
864 gtk_signal_connect_object (info->object1,
866 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
868 info->disconnect_handler2 =
869 gtk_signal_connect_object (info->object2,
871 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
876 gtk_signal_disconnect (GtkObject *object,
881 g_return_if_fail (object != NULL);
882 g_return_if_fail (handler_id > 0);
884 handler = gtk_object_get_data_by_id (object, handler_quark);
888 if (handler->id == handler_id)
891 handler->blocked += 1;
892 gtk_signal_handler_unref (handler, object);
895 handler = handler->next;
898 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
902 gtk_signal_disconnect_by_func (GtkObject *object,
909 g_return_if_fail (object != NULL);
910 g_return_if_fail (func != NULL);
913 handler = gtk_object_get_data_by_id (object, handler_quark);
917 GtkHandler *handler_next;
919 handler_next = handler->next;
920 if ((handler->id > 0) &&
921 (handler->func == func) &&
922 (handler->func_data == data))
926 handler->blocked += 1;
927 gtk_signal_handler_unref (handler, object);
929 handler = handler_next;
933 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
937 gtk_signal_disconnect_by_data (GtkObject *object,
943 g_return_if_fail (object != NULL);
946 handler = gtk_object_get_data_by_id (object, handler_quark);
950 GtkHandler *handler_next;
952 handler_next = handler->next;
953 if ((handler->id > 0) &&
954 (handler->func_data == data))
958 handler->blocked += 1;
959 gtk_signal_handler_unref (handler, object);
961 handler = handler_next;
965 g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
969 gtk_signal_handler_block (GtkObject *object,
974 g_return_if_fail (object != NULL);
975 g_return_if_fail (handler_id > 0);
977 handler = gtk_object_get_data_by_id (object, handler_quark);
981 if (handler->id == handler_id)
983 handler->blocked += 1;
986 handler = handler->next;
989 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
993 gtk_signal_handler_block_by_func (GtkObject *object,
1000 g_return_if_fail (object != NULL);
1001 g_return_if_fail (func != NULL);
1004 handler = gtk_object_get_data_by_id (object, handler_quark);
1008 if ((handler->id > 0) &&
1009 (handler->func == func) &&
1010 (handler->func_data == data))
1013 handler->blocked += 1;
1015 handler = handler->next;
1019 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1023 gtk_signal_handler_block_by_data (GtkObject *object,
1026 GtkHandler *handler;
1029 g_return_if_fail (object != NULL);
1032 handler = gtk_object_get_data_by_id (object, handler_quark);
1036 if ((handler->id > 0) &&
1037 (handler->func_data == data))
1040 handler->blocked += 1;
1042 handler = handler->next;
1046 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1050 gtk_signal_handler_unblock (GtkObject *object,
1053 GtkHandler *handler;
1055 g_return_if_fail (object != NULL);
1056 g_return_if_fail (handler_id > 0);
1058 handler = gtk_object_get_data_by_id (object, handler_quark);
1062 if (handler->id == handler_id)
1064 if (handler->blocked > 0)
1065 handler->blocked -= 1;
1067 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1070 handler = handler->next;
1073 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1077 gtk_signal_handler_unblock_by_func (GtkObject *object,
1081 GtkHandler *handler;
1084 g_return_if_fail (object != NULL);
1085 g_return_if_fail (func != NULL);
1088 handler = gtk_object_get_data_by_id (object, handler_quark);
1092 if ((handler->id > 0) &&
1093 (handler->func == func) &&
1094 (handler->func_data == data) &&
1095 (handler->blocked > 0))
1097 handler->blocked -= 1;
1100 handler = handler->next;
1104 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1108 gtk_signal_handler_unblock_by_data (GtkObject *object,
1111 GtkHandler *handler;
1114 g_return_if_fail (object != NULL);
1117 handler = gtk_object_get_data_by_id (object, handler_quark);
1121 if ((handler->id > 0) &&
1122 (handler->func_data == data) &&
1123 (handler->blocked > 0))
1125 handler->blocked -= 1;
1128 handler = handler->next;
1132 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1136 gtk_signal_handlers_destroy (GtkObject *object)
1138 GtkHandler *handler;
1140 /* we make the "optimization" of destroying the first handler in the last
1141 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1142 * handler_key data on each removal
1145 handler = gtk_object_get_data_by_id (object, handler_quark);
1148 handler = handler->next;
1153 next = handler->next;
1154 if (handler->id > 0)
1155 gtk_signal_handler_unref (handler, object);
1158 handler = gtk_object_get_data_by_id (object, handler_quark);
1159 if (handler->id > 0)
1160 gtk_signal_handler_unref (handler, object);
1165 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1166 GtkSignalDestroy destroy_func)
1168 global_marshaller = marshal_func;
1169 global_destroy_notify = destroy_func;
1173 gtk_signal_hash (gconstpointer h)
1175 register const GtkSignalHash *hash = h;
1177 return hash->object_type ^ hash->quark;
1181 gtk_signal_compare (gconstpointer h1,
1184 register const GtkSignalHash *hash1 = h1;
1185 register const GtkSignalHash *hash2 = h2;
1187 return (hash1->quark == hash2->quark &&
1188 hash1->object_type == hash2->object_type);
1192 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1194 g_return_val_if_fail (info != NULL, 0);
1196 gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1197 gtk_signal_disconnect (info->object1, info->signal_handler);
1198 gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1200 g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1206 gtk_signal_handler_new (void)
1208 GtkHandler *handler;
1210 if (!gtk_handler_free_list)
1212 GtkHandler *handler_block;
1215 handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1216 for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1218 (handler_block + i)->next = gtk_handler_free_list;
1219 gtk_handler_free_list = (handler_block + i);
1222 handler = handler_block;
1226 handler = gtk_handler_free_list;
1227 gtk_handler_free_list = handler->next;
1231 handler->blocked = 0;
1232 handler->signal_id = 0;
1233 handler->object_signal = FALSE;
1234 handler->after = FALSE;
1235 handler->no_marshal = FALSE;
1236 handler->ref_count = 1;
1237 handler->func = NULL;
1238 handler->func_data = NULL;
1239 handler->destroy_func = NULL;
1240 handler->prev = NULL;
1241 handler->next = NULL;
1247 gtk_signal_handler_ref (GtkHandler *handler)
1249 handler->ref_count += 1;
1253 gtk_signal_handler_unref (GtkHandler *handler,
1256 if (!handler->ref_count)
1258 /* FIXME: i wanna get removed somewhen */
1259 g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1263 handler->ref_count -= 1;
1265 if (handler->ref_count == 0)
1267 if (handler->destroy_func)
1268 (* handler->destroy_func) (handler->func_data);
1269 else if (!handler->func && global_destroy_notify)
1270 (* global_destroy_notify) (handler->func_data);
1273 handler->prev->next = handler->next;
1274 else if (handler->next)
1275 gtk_object_set_data_by_id (object, handler_quark, handler->next);
1278 GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1279 gtk_object_set_data_by_id (object, handler_quark, NULL);
1282 handler->next->prev = handler->prev;
1284 handler->next = gtk_handler_free_list;
1285 gtk_handler_free_list = handler;
1290 gtk_signal_handler_insert (GtkObject *object,
1291 GtkHandler *handler)
1295 /* FIXME: remove */ g_assert (handler->next == NULL);
1296 /* FIXME: remove */ g_assert (handler->prev == NULL);
1298 tmp = gtk_object_get_data_by_id (object, handler_quark);
1301 GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1302 gtk_object_set_data_by_id (object, handler_quark, handler);
1307 if (tmp->signal_id < handler->signal_id)
1311 tmp->prev->next = handler;
1312 handler->prev = tmp->prev;
1315 gtk_object_set_data_by_id (object, handler_quark, handler);
1316 tmp->prev = handler;
1317 handler->next = tmp;
1323 tmp->next = handler;
1324 handler->prev = tmp;
1331 static GtkObject *gtk_trace_signal_object = NULL;
1334 gtk_signal_real_emit (GtkObject *object,
1339 GtkHandler *handlers;
1340 GtkSignalFunc *signal_func_offset;
1342 /* gtk_handlers_run() expects a reentrant GtkSignal*, so we allocate
1343 * it locally on the stack. we save some lookups ourselves with this as well.
1345 signal = *LOOKUP_SIGNAL_ID (signal_id);
1346 if (signal.function_offset)
1348 signal_func_offset = (GtkSignalFunc*) ((guchar*) object->klass + signal.function_offset);
1349 if (!*signal_func_offset)
1350 signal_func_offset = (GtkSignalFunc*) 0;
1353 signal_func_offset = NULL;
1355 #ifdef G_ENABLE_DEBUG
1356 if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1357 object == gtk_trace_signal_object)
1358 fprintf (stdout, "GTK-DEBUG: signal_emit (\"%s\") for %s:%p (class-pointer %p)\n",
1360 gtk_type_name (GTK_OBJECT_TYPE (object)),
1362 signal_func_offset);
1363 #endif /* G_ENABLE_DEBUG */
1365 if ((signal.signal_flags & GTK_RUN_NO_RECURSE) &&
1366 gtk_emission_check (current_emissions, object, signal_id))
1368 gtk_emission_add (&restart_emissions, object, signal_id);
1372 gtk_object_ref (object);
1374 gtk_emission_add (¤t_emissions, object, signal_id);
1377 if (GTK_RUN_TYPE (signal.signal_flags) != GTK_RUN_LAST && signal_func_offset)
1378 signal.marshaller (object, *signal_func_offset, NULL, params);
1380 if (GTK_OBJECT_CONNECTED (object))
1382 handlers = gtk_signal_get_handlers (object, signal_id);
1387 return_val = gtk_handlers_run (handlers, &signal, object, params, FALSE);
1390 case EMISSION_CONTINUE:
1392 case EMISSION_RESTART:
1393 goto emission_restart;
1400 if (GTK_RUN_TYPE (signal.signal_flags) != GTK_RUN_FIRST && signal_func_offset)
1401 signal.marshaller (object, *signal_func_offset, NULL, params);
1403 if (GTK_OBJECT_CONNECTED (object))
1405 handlers = gtk_signal_get_handlers (object, signal_id);
1410 return_val = gtk_handlers_run (handlers, &signal, object, params, TRUE);
1413 case EMISSION_CONTINUE:
1415 case EMISSION_RESTART:
1416 goto emission_restart;
1425 gtk_emission_remove (¤t_emissions, object, signal_id);
1427 if (signal.signal_flags & GTK_RUN_NO_RECURSE)
1428 gtk_emission_remove (&restart_emissions, object, signal_id);
1430 gtk_object_unref (object);
1434 gtk_signal_get_handlers (GtkObject *object,
1437 GtkHandler *handlers;
1439 handlers = gtk_object_get_data_by_id (object, handler_quark);
1443 if (handlers->signal_id == signal_id)
1445 handlers = handlers->next;
1452 gtk_signal_handler_pending (GtkObject *object,
1454 gboolean may_be_blocked)
1456 GtkHandler *handlers;
1459 g_return_val_if_fail (object != NULL, 0);
1460 g_return_val_if_fail (signal_id >= 1, 0);
1462 if (GTK_OBJECT_CONNECTED (object))
1463 handlers = gtk_signal_get_handlers (object, signal_id);
1468 while (handlers && handlers->signal_id == signal_id)
1470 if (handlers->id > 0 &&
1471 (may_be_blocked || handlers->blocked == FALSE))
1473 handler_id = handlers->id;
1477 handlers = handlers->next;
1484 gtk_signal_handler_pending_by_func (GtkObject *object,
1486 gboolean may_be_blocked,
1490 GtkHandler *handlers;
1493 g_return_val_if_fail (object != NULL, 0);
1494 g_return_val_if_fail (func != NULL, 0);
1495 g_return_val_if_fail (signal_id >= 1, 0);
1497 if (GTK_OBJECT_CONNECTED (object))
1498 handlers = gtk_signal_get_handlers (object, signal_id);
1503 while (handlers && handlers->signal_id == signal_id)
1505 if (handlers->id > 0 &&
1506 handlers->func == func &&
1507 handlers->func_data == data &&
1508 (may_be_blocked || handlers->blocked == FALSE))
1510 handler_id = handlers->id;
1514 handlers = handlers->next;
1521 gtk_signal_connect_by_type (GtkObject *object,
1525 GtkSignalDestroy destroy_func,
1530 GtkObjectClass *class;
1531 GtkHandler *handler;
1534 g_return_val_if_fail (object != NULL, 0);
1535 g_return_val_if_fail (object->klass != NULL, 0);
1537 /* Search through the signals for this object and make
1538 * sure the one we are adding is valid. We need to perform
1539 * the lookup on the objects parents as well. If it isn't
1540 * valid then issue a warning and return.
1541 * As of now (1998-05-27) this lookup shouldn't be neccessarry
1542 * anymore since gtk_signal_lookup() has been reworked to only
1543 * return correct signal ids per class-branch.
1546 class = object->klass;
1550 guint *object_signals;
1554 object_signals = class->signals;
1555 nsignals = class->nsignals;
1557 for (i = 0; i < nsignals; i++)
1558 if (object_signals[i] == signal_id)
1564 parent = gtk_type_parent (class->type);
1566 class = gtk_type_class (parent);
1573 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1575 gtk_type_name (object->klass->type));
1579 handler = gtk_signal_handler_new ();
1580 handler->id = gtk_handler_id++;
1581 handler->signal_id = signal_id;
1582 handler->object_signal = object_signal;
1583 handler->func = func;
1584 handler->func_data = func_data;
1585 handler->destroy_func = destroy_func;
1586 handler->after = after != FALSE;
1587 handler->no_marshal = no_marshal;
1589 gtk_signal_handler_insert (object, handler);
1594 gtk_emission_new (void)
1596 GtkEmission *emission;
1598 if (!gtk_emission_free_list)
1600 GtkEmissionAllocator *emission_block;
1603 emission_block = g_new0 (GtkEmissionAllocator, EMISSION_BLOCK_SIZE);
1604 for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1606 (emission_block + i)->next = gtk_emission_free_list;
1607 gtk_emission_free_list = (emission_block + i);
1610 emission = &emission_block->emission;
1614 emission = >k_emission_free_list->emission;
1615 gtk_emission_free_list = gtk_emission_free_list->next;
1618 emission->object = NULL;
1619 emission->signal_id = 0;
1625 gtk_emission_add (GList **emissions,
1629 GtkEmission *emission;
1631 g_return_if_fail (emissions != NULL);
1632 g_return_if_fail (object != NULL);
1634 emission = gtk_emission_new ();
1635 emission->object = object;
1636 emission->signal_id = signal_id;
1638 *emissions = g_list_prepend (*emissions, emission);
1642 gtk_emission_remove (GList **emissions,
1648 g_return_if_fail (emissions != NULL);
1653 GtkEmissionAllocator *ea;
1657 if ((ea->emission.object == object) &&
1658 (ea->emission.signal_id == signal_id))
1660 *emissions = g_list_remove_link (*emissions, tmp);
1663 ea->next = gtk_emission_free_list;
1664 gtk_emission_free_list = ea;
1673 gtk_emission_check (GList *emissions,
1677 GtkEmission *emission;
1683 emission = tmp->data;
1686 if ((emission->object == object) &&
1687 (emission->signal_id == signal_id))
1694 gtk_handlers_run (GtkHandler *handlers,
1700 /* *signal is a local copy on the stack of gtk_signal_real_emit(),
1701 * so we don't need to look it up every time we invoked a function.
1703 while (handlers && handlers->signal_id == signal->signal_id)
1705 GtkHandler *handlers_next;
1707 gtk_signal_handler_ref (handlers);
1709 if (handlers->blocked == 0 && (handlers->after == after))
1713 if (handlers->no_marshal)
1714 (* (GtkCallbackMarshal) handlers->func) (object,
1715 handlers->func_data,
1718 else if (handlers->object_signal)
1719 /* don't GTK_OBJECT(handlers->func_data) cast */
1720 (* signal->marshaller) ((GtkObject*) handlers->func_data,
1722 handlers->func_data,
1725 (* signal->marshaller) (object,
1727 handlers->func_data,
1730 else if (global_marshaller)
1731 (* global_marshaller) (object,
1732 handlers->func_data,
1736 signal->return_val);
1738 if (gtk_emission_check (stop_emissions, object,
1741 gtk_emission_remove (&stop_emissions, object,
1744 if (signal->signal_flags & GTK_RUN_NO_RECURSE)
1745 gtk_emission_remove (&restart_emissions, object,
1747 gtk_signal_handler_unref (handlers, object);
1748 return EMISSION_DONE;
1750 else if ((signal->signal_flags & GTK_RUN_NO_RECURSE) &&
1751 gtk_emission_check (restart_emissions, object,
1754 gtk_emission_remove (&restart_emissions, object,
1756 gtk_signal_handler_unref (handlers, object);
1757 return EMISSION_RESTART;
1761 handlers_next = handlers->next;
1762 gtk_signal_handler_unref (handlers, object);
1763 handlers = handlers_next;
1766 return EMISSION_CONTINUE;
1770 gtk_signal_collect_params (GtkArg *params,
1772 GtkType *param_types,
1773 GtkType return_type,
1776 register GtkArg *last_param;
1777 register gboolean failed = FALSE;
1779 for (last_param = params + n_params; params < last_param; params++)
1781 register gchar *error;
1783 params->name = NULL;
1784 params->type = *(param_types++);
1785 GTK_ARG_COLLECT_VALUE (params,
1791 g_warning ("gtk_signal_collect_params(): %s", error);
1796 params->type = return_type;
1797 params->name = NULL;
1799 return_type = GTK_FUNDAMENTAL_TYPE (return_type);
1800 if (return_type != GTK_TYPE_NONE)
1802 if ((return_type >= GTK_TYPE_FLAT_FIRST &&
1803 return_type <= GTK_TYPE_FLAT_LAST) ||
1804 (return_type == GTK_TYPE_OBJECT))
1806 GTK_VALUE_POINTER (*params) = va_arg (var_args, gpointer);
1808 if (GTK_VALUE_POINTER (*params) == NULL)
1811 g_warning ("gtk_signal_collect_params(): invalid NULL pointer for return argument type `%s'",
1812 gtk_type_name (params->type));
1818 g_warning ("gtk_signal_collect_params(): unsupported return argument type `%s'",
1819 gtk_type_name (params->type));
1823 GTK_VALUE_POINTER (*params) = NULL;