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"
25 #define SIGNAL_BLOCK_SIZE (100)
26 #define HANDLER_BLOCK_SIZE (200)
27 #define EMISSION_BLOCK_SIZE (100)
28 #define DISCONNECT_INFO_BLOCK_SIZE (64)
29 #define MAX_SIGNAL_PARAMS (32)
38 #define GTK_RUN_TYPE(x) ((x) & GTK_RUN_MASK)
41 typedef struct _GtkSignal GtkSignal;
42 typedef struct _GtkSignalHash GtkSignalHash;
43 typedef struct _GtkHandler GtkHandler;
44 typedef struct _GtkHandlerInfo GtkHandlerInfo;
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;
88 struct _GtkHandlerInfo
91 GtkSignalMarshaller marshaller;
95 GtkSignalRunType signal_flags;
106 union _GtkEmissionAllocator
108 GtkEmissionAllocator *next;
109 GtkEmission emission;
112 struct _GtkDisconnectInfo
115 guint disconnect_handler1;
116 guint signal_handler;
118 guint disconnect_handler2;
122 static guint gtk_signal_hash (gconstpointer h);
123 static gint gtk_signal_compare (gconstpointer h1,
125 static GtkHandler* gtk_signal_handler_new (void);
126 static void gtk_signal_handler_ref (GtkHandler *handler);
127 static void gtk_signal_handler_unref (GtkHandler *handler,
129 static void gtk_signal_handler_insert (GtkObject *object,
130 GtkHandler *handler);
131 static void gtk_signal_real_emit (GtkObject *object,
134 static GtkHandler* gtk_signal_get_handlers (GtkObject *object,
136 static guint gtk_signal_connect_by_type (GtkObject *object,
140 GtkSignalDestroy destroy_func,
144 static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);
145 static GtkEmission* gtk_emission_new (void);
146 static void gtk_emission_add (GList **emissions,
149 static void gtk_emission_remove (GList **emissions,
152 static gint gtk_emission_check (GList *emissions,
155 static gint gtk_handlers_run (GtkHandler *handlers,
156 GtkHandlerInfo *info,
158 static void gtk_params_get (GtkArg *params,
160 GtkType *param_types,
164 #define LOOKUP_SIGNAL_ID(signal_id) ( \
165 signal_id > 0 && signal_id < gtk_n_signals ? \
166 (GtkSignal*) gtk_signals + signal_id : \
171 static GtkSignalMarshal global_marshaller = NULL;
172 static GtkSignalDestroy global_destroy_notify = NULL;
174 static guint gtk_handler_id = 1;
175 static guint handler_quark = 0;
176 static GHashTable *gtk_signal_hash_table = NULL;
177 static GtkSignal *gtk_signals = NULL;
178 static guint gtk_n_signals = 0;
179 static GMemChunk *gtk_signal_hash_mem_chunk = NULL;
180 static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;
181 static GtkHandler *gtk_handler_free_list = NULL;
182 static GtkEmissionAllocator *gtk_emission_free_list = NULL;
186 static GList *current_emissions = NULL;
187 static GList *stop_emissions = NULL;
188 static GList *restart_emissions = NULL;
191 gtk_signal_next_and_invalidate (void)
193 static guint gtk_n_free_signals = 0;
194 register GtkSignal *signal;
195 register guint new_signal_id;
197 /* don't keep *any* GtkSignal pointers across invokation of this function!!!
200 if (gtk_n_free_signals == 0)
207 size = gtk_n_signals + SIGNAL_BLOCK_SIZE;
208 size *= sizeof (GtkSignal);
214 gtk_signals = g_realloc (gtk_signals, size);
216 gtk_n_free_signals = size / sizeof (GtkSignal) - gtk_n_signals;
218 memset (gtk_signals + gtk_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
221 new_signal_id = gtk_n_signals++;
222 gtk_n_free_signals--;
224 signal = LOOKUP_SIGNAL_ID (new_signal_id);
226 signal->signal_id = new_signal_id;
232 gtk_signal_init (void)
238 zero = gtk_signal_next_and_invalidate ();
239 g_assert (zero == NULL);
241 handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
243 gtk_signal_hash_mem_chunk =
244 g_mem_chunk_new ("GtkSignalHash mem chunk",
245 sizeof (GtkSignalHash),
246 sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
248 gtk_disconnect_info_mem_chunk =
249 g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
250 sizeof (GtkDisconnectInfo),
251 sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
253 gtk_handler_free_list = NULL;
254 gtk_emission_free_list = NULL;
256 gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
262 gtk_signal_newv (const gchar *r_name,
263 GtkSignalRunType signal_flags,
265 guint function_offset,
266 GtkSignalMarshaller marshaller,
277 g_return_val_if_fail (r_name != NULL, 0);
278 g_return_val_if_fail (marshaller != NULL, 0);
279 g_return_val_if_fail (nparams <= MAX_SIGNAL_PARAMS, 0);
281 g_return_val_if_fail (params != NULL, 0);
287 name = g_strdup (r_name);
288 g_strdelimit (name, NULL, '_');
290 quark = gtk_signal_lookup (name, object_type);
293 g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
295 gtk_type_name (object_type));
300 if (return_val != GTK_TYPE_NONE &&
301 (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
303 g_warning ("gtk_signal_newv(): signal \"%s\" with return value `%s' excludes GTK_RUN_LAST",
304 name, gtk_type_name (return_val));
309 signal = gtk_signal_next_and_invalidate ();
311 /* signal->signal_id already set */
313 signal->object_type = object_type;
315 signal->function_offset = function_offset;
316 signal->signal_flags = signal_flags;
317 signal->marshaller = marshaller;
318 signal->return_val = return_val;
319 signal->nparams = nparams;
323 signal->params = g_new (GtkType, nparams);
325 for (i = 0; i < nparams; i++)
326 signal->params[i] = params[i];
329 signal->params = NULL;
331 /* insert "signal_name" into hash table
333 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
334 hash->object_type = object_type;
335 hash->quark = g_quark_from_string (signal->name);
336 hash->signal_id = signal->signal_id;
337 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
339 /* insert "signal-name" into hash table
341 g_strdelimit (signal->name, NULL, '-');
342 quark = g_quark_from_static_string (signal->name);
343 if (quark != hash->quark)
345 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
346 hash->object_type = object_type;
348 hash->signal_id = signal->signal_id;
349 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
352 return signal->signal_id;
356 gtk_signal_new (const gchar *name,
357 GtkSignalRunType signal_flags,
359 guint function_offset,
360 GtkSignalMarshaller marshaller,
370 g_return_val_if_fail (nparams <= MAX_SIGNAL_PARAMS, 0);
374 params = g_new (GtkType, nparams);
376 va_start (args, nparams);
378 for (i = 0; i < nparams; i++)
379 params[i] = va_arg (args, GtkType);
386 signal_id = gtk_signal_newv (name,
401 gtk_signal_lookup (const gchar *name,
406 g_return_val_if_fail (name != NULL, 0);
407 g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0);
409 hash.quark = g_quark_try_string (name);
416 hash.object_type = object_type;
418 signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
422 object_type = gtk_type_parent (object_type);
430 gtk_signal_query (guint signal_id)
432 GtkSignalQuery *query;
435 g_return_val_if_fail (signal_id >= 1, NULL);
437 signal = LOOKUP_SIGNAL_ID (signal_id);
440 query = g_new (GtkSignalQuery, 1);
442 query->object_type = signal->object_type;
443 query->signal_id = signal_id;
444 query->signal_name = signal->name;
445 query->is_user_signal = signal->function_offset == 0;
446 query->signal_flags = signal->signal_flags;
447 query->return_val = signal->return_val;
448 query->nparams = signal->nparams;
449 query->params = signal->params;
458 gtk_signal_name (guint signal_id)
462 g_return_val_if_fail (signal_id >= 1, NULL);
464 signal = LOOKUP_SIGNAL_ID (signal_id);
472 gtk_signal_emitv (GtkObject *object,
478 g_return_if_fail (object != NULL);
479 g_return_if_fail (signal_id >= 1);
481 signal = LOOKUP_SIGNAL_ID (signal_id);
482 g_return_if_fail (signal != NULL);
483 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
485 if (signal->nparams > 0)
486 g_return_if_fail (params != NULL);
488 gtk_signal_real_emit (object, signal, params);
492 gtk_signal_emit (GtkObject *object,
498 GtkArg params[MAX_SIGNAL_PARAMS];
500 g_return_if_fail (object != NULL);
501 g_return_if_fail (signal_id >= 1);
503 signal = LOOKUP_SIGNAL_ID (signal_id);
504 g_return_if_fail (signal != NULL);
505 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
507 va_start (args, signal_id);
508 gtk_params_get (params,
515 gtk_signal_real_emit (object, signal, params);
519 gtk_signal_emitv_by_name (GtkObject *object,
525 g_return_if_fail (object != NULL);
526 g_return_if_fail (name != NULL);
527 g_return_if_fail (params != NULL);
529 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
535 signal = LOOKUP_SIGNAL_ID (signal_id);
536 g_return_if_fail (signal != NULL);
537 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
539 gtk_signal_real_emit (object, signal, params);
543 g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
545 gtk_type_name (GTK_OBJECT_TYPE (object)));
550 gtk_signal_emit_by_name (GtkObject *object,
556 g_return_if_fail (object != NULL);
557 g_return_if_fail (name != NULL);
559 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
564 GtkArg params[MAX_SIGNAL_PARAMS];
567 signal = LOOKUP_SIGNAL_ID (signal_id);
568 g_return_if_fail (signal != NULL);
569 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
571 va_start (args, name);
572 gtk_params_get (params,
579 gtk_signal_real_emit (object, signal, params);
583 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
585 gtk_type_name (GTK_OBJECT_TYPE (object)));
590 gtk_signal_emit_stop (GtkObject *object,
593 g_return_if_fail (object != NULL);
594 g_return_if_fail (signal_id >= 1);
596 if (gtk_emission_check (current_emissions, object, signal_id))
597 gtk_emission_add (&stop_emissions, object, signal_id);
599 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
601 gtk_type_name (GTK_OBJECT_TYPE (object)));
605 gtk_signal_emit_stop_by_name (GtkObject *object,
610 g_return_if_fail (object != NULL);
611 g_return_if_fail (name != NULL);
613 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
615 gtk_signal_emit_stop (object, signal_id);
617 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
619 gtk_type_name (GTK_OBJECT_TYPE (object)));
623 gtk_signal_n_emissions (GtkObject *object,
629 g_return_val_if_fail (object != NULL, 0);
630 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
633 for (list = current_emissions; list; list = list->next)
635 GtkEmission *emission;
637 emission = list->data;
639 if ((emission->object == object) &&
640 (emission->signal_id == signal_id))
648 gtk_signal_n_emissions_by_name (GtkObject *object,
654 g_return_val_if_fail (object != NULL, 0);
655 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
656 g_return_val_if_fail (name != NULL, 0);
658 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
660 n = gtk_signal_n_emissions (object, signal_id);
663 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
665 gtk_type_name (GTK_OBJECT_TYPE (object)));
673 gtk_signal_connect (GtkObject *object,
680 g_return_val_if_fail (object != NULL, 0);
681 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
683 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
686 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
688 gtk_type_name (GTK_OBJECT_TYPE (object)));
692 return gtk_signal_connect_by_type (object, signal_id,
693 func, func_data, NULL,
694 FALSE, FALSE, FALSE);
698 gtk_signal_connect_after (GtkObject *object,
705 g_return_val_if_fail (object != NULL, 0);
707 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
710 g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
712 gtk_type_name (GTK_OBJECT_TYPE (object)));
716 return gtk_signal_connect_by_type (object, signal_id,
717 func, func_data, NULL,
722 gtk_signal_connect_full (GtkObject *object,
725 GtkCallbackMarshal marshal,
727 GtkDestroyNotify destroy_func,
733 g_return_val_if_fail (object != NULL, 0);
735 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
738 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
740 gtk_type_name (GTK_OBJECT_TYPE (object)));
745 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
746 func_data, destroy_func,
747 object_signal, after, TRUE);
749 return gtk_signal_connect_by_type (object, signal_id, func,
750 func_data, destroy_func,
751 object_signal, after, FALSE);
755 gtk_signal_connect_interp (GtkObject *object,
757 GtkCallbackMarshal func,
759 GtkDestroyNotify destroy_func,
762 return gtk_signal_connect_full (object, name, NULL, func,
763 func_data, destroy_func, FALSE, after);
767 gtk_signal_connect_object (GtkObject *object,
770 GtkObject *slot_object)
774 g_return_val_if_fail (object != NULL, 0);
775 /* slot_object needs to be treated as ordinary pointer
778 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
781 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
783 gtk_type_name (GTK_OBJECT_TYPE (object)));
787 return gtk_signal_connect_by_type (object, signal_id,
788 func, slot_object, NULL,
793 gtk_signal_connect_object_after (GtkObject *object,
796 GtkObject *slot_object)
800 g_return_val_if_fail (object != NULL, 0);
802 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
805 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
807 gtk_type_name (GTK_OBJECT_TYPE (object)));
811 return gtk_signal_connect_by_type (object, signal_id,
812 func, slot_object, NULL,
817 gtk_signal_connect_while_alive (GtkObject *object,
821 GtkObject *alive_object)
823 GtkDisconnectInfo *info;
825 g_return_if_fail (object != NULL);
826 g_return_if_fail (GTK_IS_OBJECT (object));
827 g_return_if_fail (signal != NULL);
828 g_return_if_fail (func != NULL);
829 g_return_if_fail (alive_object != NULL);
830 g_return_if_fail (GTK_IS_OBJECT (alive_object));
832 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
833 info->object1 = object;
834 info->object2 = alive_object;
836 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
837 info->disconnect_handler1 =
838 gtk_signal_connect_object (info->object1,
840 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
842 info->disconnect_handler2 =
843 gtk_signal_connect_object (info->object2,
845 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
850 gtk_signal_connect_object_while_alive (GtkObject *object,
853 GtkObject *alive_object)
855 GtkDisconnectInfo *info;
857 g_return_if_fail (object != NULL);
858 g_return_if_fail (GTK_IS_OBJECT (object));
859 g_return_if_fail (signal != NULL);
860 g_return_if_fail (func != NULL);
861 g_return_if_fail (alive_object != NULL);
862 g_return_if_fail (GTK_IS_OBJECT (alive_object));
864 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
865 info->object1 = object;
866 info->object2 = alive_object;
868 info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
869 info->disconnect_handler1 =
870 gtk_signal_connect_object (info->object1,
872 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
874 info->disconnect_handler2 =
875 gtk_signal_connect_object (info->object2,
877 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
882 gtk_signal_disconnect (GtkObject *object,
887 g_return_if_fail (object != NULL);
888 g_return_if_fail (handler_id > 0);
890 handler = gtk_object_get_data_by_id (object, handler_quark);
894 if (handler->id == handler_id)
897 handler->blocked += 1;
898 gtk_signal_handler_unref (handler, object);
901 handler = handler->next;
904 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
908 gtk_signal_disconnect_by_func (GtkObject *object,
915 g_return_if_fail (object != NULL);
916 g_return_if_fail (func != NULL);
919 handler = gtk_object_get_data_by_id (object, handler_quark);
923 GtkHandler *handler_next;
925 handler_next = handler->next;
926 if ((handler->id > 0) &&
927 (handler->func == func) &&
928 (handler->func_data == data))
932 handler->blocked += 1;
933 gtk_signal_handler_unref (handler, object);
935 handler = handler_next;
939 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
943 gtk_signal_disconnect_by_data (GtkObject *object,
949 g_return_if_fail (object != NULL);
952 handler = gtk_object_get_data_by_id (object, handler_quark);
956 GtkHandler *handler_next;
958 handler_next = handler->next;
959 if ((handler->id > 0) &&
960 (handler->func_data == data))
964 handler->blocked += 1;
965 gtk_signal_handler_unref (handler, object);
967 handler = handler_next;
971 g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
975 gtk_signal_handler_block (GtkObject *object,
980 g_return_if_fail (object != NULL);
981 g_return_if_fail (handler_id > 0);
983 handler = gtk_object_get_data_by_id (object, handler_quark);
987 if (handler->id == handler_id)
989 handler->blocked += 1;
992 handler = handler->next;
995 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
999 gtk_signal_handler_block_by_func (GtkObject *object,
1003 GtkHandler *handler;
1006 g_return_if_fail (object != NULL);
1007 g_return_if_fail (func != NULL);
1010 handler = gtk_object_get_data_by_id (object, handler_quark);
1014 if ((handler->id > 0) &&
1015 (handler->func == func) &&
1016 (handler->func_data == data))
1019 handler->blocked += 1;
1021 handler = handler->next;
1025 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1029 gtk_signal_handler_block_by_data (GtkObject *object,
1032 GtkHandler *handler;
1035 g_return_if_fail (object != NULL);
1038 handler = gtk_object_get_data_by_id (object, handler_quark);
1042 if ((handler->id > 0) &&
1043 (handler->func_data == data))
1046 handler->blocked += 1;
1048 handler = handler->next;
1052 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1056 gtk_signal_handler_unblock (GtkObject *object,
1059 GtkHandler *handler;
1061 g_return_if_fail (object != NULL);
1062 g_return_if_fail (handler_id > 0);
1064 handler = gtk_object_get_data_by_id (object, handler_quark);
1068 if (handler->id == handler_id)
1070 if (handler->blocked > 0)
1071 handler->blocked -= 1;
1073 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1076 handler = handler->next;
1079 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1083 gtk_signal_handler_unblock_by_func (GtkObject *object,
1087 GtkHandler *handler;
1090 g_return_if_fail (object != NULL);
1091 g_return_if_fail (func != NULL);
1094 handler = gtk_object_get_data_by_id (object, handler_quark);
1098 if ((handler->id > 0) &&
1099 (handler->func == func) &&
1100 (handler->func_data == data) &&
1101 (handler->blocked > 0))
1103 handler->blocked -= 1;
1106 handler = handler->next;
1110 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1114 gtk_signal_handler_unblock_by_data (GtkObject *object,
1117 GtkHandler *handler;
1120 g_return_if_fail (object != NULL);
1123 handler = gtk_object_get_data_by_id (object, handler_quark);
1127 if ((handler->id > 0) &&
1128 (handler->func_data == data) &&
1129 (handler->blocked > 0))
1131 handler->blocked -= 1;
1134 handler = handler->next;
1138 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1142 gtk_signal_handlers_destroy (GtkObject *object)
1144 GtkHandler *handler;
1146 /* we make the "optimization" of destroying the first handler in the last
1147 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1148 * handler_key data on each removal
1151 handler = gtk_object_get_data_by_id (object, handler_quark);
1154 handler = handler->next;
1159 next = handler->next;
1160 gtk_signal_handler_unref (handler, object);
1163 handler = gtk_object_get_data_by_id (object, handler_quark);
1164 gtk_signal_handler_unref (handler, object);
1169 gtk_signal_default_marshaller (GtkObject *object,
1174 GtkSignalMarshaller0 rfunc;
1176 rfunc = (GtkSignalMarshaller0) func;
1178 (* rfunc) (object, func_data);
1182 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1183 GtkSignalDestroy destroy_func)
1185 global_marshaller = marshal_func;
1186 global_destroy_notify = destroy_func;
1190 gtk_signal_hash (gconstpointer h)
1192 register const GtkSignalHash *hash = h;
1194 return hash->object_type ^ hash->quark;
1198 gtk_signal_compare (gconstpointer h1,
1201 register const GtkSignalHash *hash1 = h1;
1202 register const GtkSignalHash *hash2 = h2;
1204 return (hash1->quark == hash2->quark &&
1205 hash1->object_type == hash2->object_type);
1209 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1211 g_return_val_if_fail (info != NULL, 0);
1213 gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1214 gtk_signal_disconnect (info->object1, info->signal_handler);
1215 gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1217 g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1223 gtk_signal_handler_new (void)
1225 GtkHandler *handler;
1227 if (!gtk_handler_free_list)
1229 GtkHandler *handler_block;
1232 handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1233 for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1235 (handler_block + i)->next = gtk_handler_free_list;
1236 gtk_handler_free_list = (handler_block + i);
1239 handler = handler_block;
1243 handler = gtk_handler_free_list;
1244 gtk_handler_free_list = handler->next;
1248 handler->blocked = 0;
1249 handler->signal_id = 0;
1250 handler->object_signal = FALSE;
1251 handler->after = FALSE;
1252 handler->no_marshal = FALSE;
1253 handler->ref_count = 1;
1254 handler->func = NULL;
1255 handler->func_data = NULL;
1256 handler->destroy_func = NULL;
1257 handler->prev = NULL;
1258 handler->next = NULL;
1264 gtk_signal_handler_ref (GtkHandler *handler)
1266 handler->ref_count += 1;
1270 gtk_signal_handler_unref (GtkHandler *handler,
1273 if (!handler->ref_count)
1275 /* FIXME: i wanna get removed somewhen */
1276 g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1280 handler->ref_count -= 1;
1282 if (handler->ref_count == 0)
1284 if (handler->destroy_func)
1285 (* handler->destroy_func) (handler->func_data);
1286 else if (!handler->func && global_destroy_notify)
1287 (* global_destroy_notify) (handler->func_data);
1290 handler->prev->next = handler->next;
1291 else if (handler->next)
1292 gtk_object_set_data_by_id (object, handler_quark, handler->next);
1295 GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1296 gtk_object_set_data_by_id (object, handler_quark, NULL);
1299 handler->next->prev = handler->prev;
1301 handler->next = gtk_handler_free_list;
1302 gtk_handler_free_list = handler;
1307 gtk_signal_handler_insert (GtkObject *object,
1308 GtkHandler *handler)
1312 /* FIXME: remove */ g_assert (handler->next == NULL);
1313 /* FIXME: remove */ g_assert (handler->prev == NULL);
1315 tmp = gtk_object_get_data_by_id (object, handler_quark);
1318 GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1319 gtk_object_set_data_by_id (object, handler_quark, handler);
1324 if (tmp->signal_id < handler->signal_id)
1328 tmp->prev->next = handler;
1329 handler->prev = tmp->prev;
1332 gtk_object_set_data_by_id (object, handler_quark, handler);
1333 tmp->prev = handler;
1334 handler->next = tmp;
1340 tmp->next = handler;
1341 handler->prev = tmp;
1348 static GtkObject *gtk_trace_signal_object = NULL;
1351 gtk_signal_real_emit (GtkObject *object,
1355 GtkHandler *handlers;
1356 GtkHandlerInfo info;
1357 guchar **signal_func_offset;
1358 register guint signal_id = signal->signal_id;
1360 #ifdef G_ENABLE_DEBUG
1361 if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1362 object == gtk_trace_signal_object)
1363 fprintf (stdout, "trace: signal_emit(\"%s\") for %s:%p\n",
1365 gtk_type_name (GTK_OBJECT_TYPE (object)),
1367 #endif /* G_ENABLE_DEBUG */
1369 if ((signal->signal_flags & GTK_RUN_NO_RECURSE) &&
1370 gtk_emission_check (current_emissions, object, signal_id))
1372 gtk_emission_add (&restart_emissions, object, signal_id);
1376 gtk_object_ref (object);
1378 gtk_emission_add (¤t_emissions, object, signal_id);
1381 if (GTK_RUN_TYPE (signal->signal_flags) != GTK_RUN_LAST && signal->function_offset != 0)
1383 signal_func_offset = (guchar**) ((guchar*) object->klass +
1384 signal->function_offset);
1385 if (*signal_func_offset)
1386 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1390 if (GTK_OBJECT_CONNECTED (object))
1392 handlers = gtk_signal_get_handlers (object, signal_id);
1395 info.object = object;
1396 info.marshaller = signal->marshaller;
1397 info.params = params;
1398 info.param_types = signal->params;
1399 info.return_val = signal->return_val;
1400 info.nparams = signal->nparams;
1401 info.signal_flags = signal->signal_flags;
1402 info.signal_id = signal_id;
1404 switch (gtk_handlers_run (handlers, &info, FALSE))
1406 case EMISSION_CONTINUE:
1408 case EMISSION_RESTART:
1409 goto emission_restart;
1420 if (GTK_RUN_TYPE (signal->signal_flags) != GTK_RUN_FIRST && signal->function_offset != 0)
1422 signal_func_offset = (guchar**) ((guchar*) object->klass +
1423 signal->function_offset);
1424 if (*signal_func_offset)
1425 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1429 if (GTK_OBJECT_CONNECTED (object))
1431 handlers = gtk_signal_get_handlers (object, signal_id);
1436 info.object = object;
1437 info.marshaller = signal->marshaller;
1438 info.params = params;
1439 info.param_types = signal->params;
1440 info.return_val = signal->return_val;
1441 info.nparams = signal->nparams;
1442 info.signal_flags = signal->signal_flags;
1443 info.signal_id = signal_id;
1445 switch (gtk_handlers_run (handlers, &info, TRUE))
1447 case EMISSION_CONTINUE:
1449 case EMISSION_RESTART:
1450 goto emission_restart;
1459 gtk_emission_remove (¤t_emissions, object, signal_id);
1461 if (signal->signal_flags & GTK_RUN_NO_RECURSE)
1462 gtk_emission_remove (&restart_emissions, object, signal_id);
1464 gtk_object_unref (object);
1468 gtk_signal_get_handlers (GtkObject *object,
1471 GtkHandler *handlers;
1473 handlers = gtk_object_get_data_by_id (object, handler_quark);
1477 if (handlers->signal_id == signal_id)
1479 handlers = handlers->next;
1486 gtk_signal_handler_pending (GtkObject *object,
1488 gboolean may_be_blocked)
1490 GtkHandler *handlers;
1493 g_return_val_if_fail (object != NULL, 0);
1494 g_return_val_if_fail (signal_id >= 1, 0);
1496 if (GTK_OBJECT_CONNECTED (object))
1497 handlers = gtk_signal_get_handlers (object, signal_id);
1502 while (handlers && handlers->signal_id == signal_id)
1504 if (handlers->id > 0 &&
1505 (may_be_blocked || handlers->blocked == FALSE))
1507 handler_id = handlers->id;
1511 handlers = handlers->next;
1518 gtk_signal_handler_pending_by_func (GtkObject *object,
1520 gboolean may_be_blocked,
1524 GtkHandler *handlers;
1527 g_return_val_if_fail (object != NULL, 0);
1528 g_return_val_if_fail (func != NULL, 0);
1529 g_return_val_if_fail (signal_id >= 1, 0);
1531 if (GTK_OBJECT_CONNECTED (object))
1532 handlers = gtk_signal_get_handlers (object, signal_id);
1537 while (handlers && handlers->signal_id == signal_id)
1539 if (handlers->id > 0 &&
1540 handlers->func == func &&
1541 handlers->func_data == data &&
1542 (may_be_blocked || handlers->blocked == FALSE))
1544 handler_id = handlers->id;
1548 handlers = handlers->next;
1555 gtk_signal_connect_by_type (GtkObject *object,
1559 GtkSignalDestroy destroy_func,
1564 GtkObjectClass *class;
1565 GtkHandler *handler;
1568 g_return_val_if_fail (object != NULL, 0);
1569 g_return_val_if_fail (object->klass != NULL, 0);
1571 /* Search through the signals for this object and make
1572 * sure the one we are adding is valid. We need to perform
1573 * the lookup on the objects parents as well. If it isn't
1574 * valid then issue a warning and return.
1575 * As of now (1998-05-27) this lookup shouldn't be neccessarry
1576 * anymore since gtk_signal_lookup() has been reworked to only
1577 * return correct signal ids per class-branch.
1580 class = object->klass;
1584 guint *object_signals;
1588 object_signals = class->signals;
1589 nsignals = class->nsignals;
1591 for (i = 0; i < nsignals; i++)
1592 if (object_signals[i] == signal_id)
1598 parent = gtk_type_parent (class->type);
1600 class = gtk_type_class (parent);
1607 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1609 gtk_type_name (object->klass->type));
1613 handler = gtk_signal_handler_new ();
1614 handler->id = gtk_handler_id++;
1615 handler->signal_id = signal_id;
1616 handler->object_signal = object_signal;
1617 handler->func = func;
1618 handler->func_data = func_data;
1619 handler->destroy_func = destroy_func;
1620 handler->after = after != FALSE;
1621 handler->no_marshal = no_marshal;
1623 gtk_signal_handler_insert (object, handler);
1628 gtk_emission_new (void)
1630 GtkEmission *emission;
1632 if (!gtk_emission_free_list)
1634 GtkEmissionAllocator *emission_block;
1637 emission_block = g_new0 (GtkEmissionAllocator, EMISSION_BLOCK_SIZE);
1638 for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1640 (emission_block + i)->next = gtk_emission_free_list;
1641 gtk_emission_free_list = (emission_block + i);
1644 emission = &emission_block->emission;
1648 emission = >k_emission_free_list->emission;
1649 gtk_emission_free_list = gtk_emission_free_list->next;
1652 emission->object = NULL;
1653 emission->signal_id = 0;
1659 gtk_emission_add (GList **emissions,
1663 GtkEmission *emission;
1665 g_return_if_fail (emissions != NULL);
1666 g_return_if_fail (object != NULL);
1668 emission = gtk_emission_new ();
1669 emission->object = object;
1670 emission->signal_id = signal_id;
1672 *emissions = g_list_prepend (*emissions, emission);
1676 gtk_emission_remove (GList **emissions,
1682 g_return_if_fail (emissions != NULL);
1687 GtkEmissionAllocator *ea;
1691 if ((ea->emission.object == object) &&
1692 (ea->emission.signal_id == signal_id))
1694 *emissions = g_list_remove_link (*emissions, tmp);
1697 ea->next = gtk_emission_free_list;
1698 gtk_emission_free_list = ea;
1707 gtk_emission_check (GList *emissions,
1711 GtkEmission *emission;
1717 emission = tmp->data;
1720 if ((emission->object == object) &&
1721 (emission->signal_id == signal_id))
1728 gtk_handlers_run (GtkHandler *handlers,
1729 GtkHandlerInfo *info,
1732 while (handlers && handlers->signal_id == info->signal_id)
1734 GtkHandler *handlers_next;
1736 gtk_signal_handler_ref (handlers);
1738 if (handlers->blocked == 0 && (handlers->after == after))
1742 if (handlers->no_marshal)
1743 (* (GtkCallbackMarshal) handlers->func) (info->object,
1744 handlers->func_data,
1747 else if (handlers->object_signal)
1748 (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
1750 handlers->func_data,
1753 (* info->marshaller) (info->object,
1755 handlers->func_data,
1758 else if (global_marshaller)
1759 (* global_marshaller) (info->object,
1760 handlers->func_data,
1766 if (gtk_emission_check (stop_emissions, info->object,
1769 gtk_emission_remove (&stop_emissions, info->object,
1772 if (info->signal_flags & GTK_RUN_NO_RECURSE)
1773 gtk_emission_remove (&restart_emissions, info->object,
1775 gtk_signal_handler_unref (handlers, info->object);
1776 return EMISSION_DONE;
1778 else if ((info->signal_flags & GTK_RUN_NO_RECURSE) &&
1779 gtk_emission_check (restart_emissions, info->object,
1782 gtk_emission_remove (&restart_emissions, info->object,
1784 gtk_signal_handler_unref (handlers, info->object);
1785 return EMISSION_RESTART;
1789 handlers_next = handlers->next;
1790 gtk_signal_handler_unref (handlers, info->object);
1791 handlers = handlers_next;
1794 return EMISSION_CONTINUE;
1798 gtk_params_get (GtkArg *params,
1800 GtkType *param_types,
1806 for (i = 0; i < nparams; i++)
1808 params[i].type = param_types[i];
1809 params[i].name = NULL;
1811 switch (GTK_FUNDAMENTAL_TYPE (param_types[i]))
1813 case GTK_TYPE_INVALID:
1818 GTK_VALUE_CHAR(params[i]) = va_arg (args, gint);
1821 GTK_VALUE_BOOL(params[i]) = va_arg (args, gint);
1824 GTK_VALUE_INT(params[i]) = va_arg (args, gint);
1827 GTK_VALUE_UINT(params[i]) = va_arg (args, guint);
1830 GTK_VALUE_ENUM(params[i]) = va_arg (args, gint);
1832 case GTK_TYPE_FLAGS:
1833 GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint);
1836 GTK_VALUE_LONG(params[i]) = va_arg (args, glong);
1838 case GTK_TYPE_ULONG:
1839 GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong);
1841 case GTK_TYPE_FLOAT:
1842 GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat);
1844 case GTK_TYPE_DOUBLE:
1845 GTK_VALUE_DOUBLE(params[i]) = va_arg (args, gdouble);
1847 case GTK_TYPE_STRING:
1848 GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*);
1850 case GTK_TYPE_POINTER:
1851 GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer);
1853 case GTK_TYPE_BOXED:
1854 GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer);
1856 case GTK_TYPE_SIGNAL:
1857 GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction);
1858 GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer);
1860 case GTK_TYPE_FOREIGN:
1861 GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer);
1862 GTK_VALUE_FOREIGN(params[i]).notify =
1863 va_arg (args, GtkDestroyNotify);
1865 case GTK_TYPE_CALLBACK:
1866 GTK_VALUE_CALLBACK(params[i]).marshal =
1867 va_arg (args, GtkCallbackMarshal);
1868 GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer);
1869 GTK_VALUE_CALLBACK(params[i]).notify =
1870 va_arg (args, GtkDestroyNotify);
1872 case GTK_TYPE_C_CALLBACK:
1873 GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction);
1874 GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer);
1877 GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, gint);
1878 GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*);
1880 case GTK_TYPE_OBJECT:
1881 GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*);
1882 if (GTK_VALUE_OBJECT(params[i]) != NULL &&
1883 !GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]), params[i].type))
1884 g_warning ("signal arg `%s' is not of type `%s'",
1885 gtk_type_name (GTK_OBJECT_TYPE (GTK_VALUE_OBJECT(params[i]))),
1886 gtk_type_name (params[i].type));
1889 g_error ("unsupported type `%s' in signal arg",
1890 gtk_type_name (params[i].type));
1895 params[i].type = return_val;
1896 params[i].name = NULL;
1898 switch (GTK_FUNDAMENTAL_TYPE (return_val))
1900 case GTK_TYPE_INVALID:
1905 params[i].d.pointer_data = va_arg (args, gchar*);
1908 params[i].d.pointer_data = va_arg (args, gint*);
1911 params[i].d.pointer_data = va_arg (args, gint*);
1914 params[i].d.pointer_data = va_arg (args, guint*);
1917 params[i].d.pointer_data = va_arg (args, gint*);
1919 case GTK_TYPE_FLAGS:
1920 params[i].d.pointer_data = va_arg (args, gint*);
1923 params[i].d.pointer_data = va_arg (args, glong*);
1925 case GTK_TYPE_ULONG:
1926 params[i].d.pointer_data = va_arg (args, gulong*);
1928 case GTK_TYPE_FLOAT:
1929 params[i].d.pointer_data = va_arg (args, gfloat*);
1931 case GTK_TYPE_DOUBLE:
1932 params[i].d.pointer_data = va_arg (args, gdouble*);
1934 case GTK_TYPE_STRING:
1935 params[i].d.pointer_data = va_arg (args, gchar**);
1937 case GTK_TYPE_POINTER:
1938 params[i].d.pointer_data = va_arg (args, gpointer*);
1940 case GTK_TYPE_BOXED:
1941 params[i].d.pointer_data = va_arg (args, gpointer*);
1943 case GTK_TYPE_OBJECT:
1944 params[i].d.pointer_data = va_arg (args, GtkObject**);
1946 case GTK_TYPE_SIGNAL:
1947 case GTK_TYPE_FOREIGN:
1948 case GTK_TYPE_CALLBACK:
1949 case GTK_TYPE_C_CALLBACK:
1952 g_error ("Gtk: unsupported type `%s' in signal return",
1953 gtk_type_name (return_val));