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_BOTH)
42 typedef struct _GtkSignal GtkSignal;
43 typedef struct _GtkSignalHash GtkSignalHash;
44 typedef struct _GtkHandler GtkHandler;
45 typedef struct _GtkEmission GtkEmission;
46 typedef struct _GtkEmissionHookData GtkEmissionHookData;
47 typedef struct _GtkDisconnectInfo GtkDisconnectInfo;
49 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
57 guint function_offset;
58 GtkSignalMarshaller marshaller;
60 GtkSignalRunType signal_flags : 16;
77 guint object_signal : 1;
84 GtkSignalDestroy destroy_func;
97 struct _GtkEmissionHookData
105 struct _GtkDisconnectInfo
108 guint disconnect_handler1;
109 guint signal_handler;
111 guint disconnect_handler2;
115 static guint gtk_signal_hash (gconstpointer h);
116 static gint gtk_signal_compare (gconstpointer h1,
118 static GtkHandler* gtk_signal_handler_new (void);
119 static void gtk_signal_handler_ref (GtkHandler *handler);
120 static void gtk_signal_handler_unref (GtkHandler *handler,
122 static void gtk_signal_handler_insert (GtkObject *object,
123 GtkHandler *handler);
124 static void gtk_signal_real_emit (GtkObject *object,
127 static GtkHandler* gtk_signal_get_handlers (GtkObject *object,
129 static guint gtk_signal_connect_by_type (GtkObject *object,
133 GtkSignalDestroy destroy_func,
137 static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);
138 static GtkEmission* gtk_emission_new (void);
139 static void gtk_emission_add (GtkEmission **emissions,
142 static void gtk_emission_remove (GtkEmission **emissions,
145 static gint gtk_emission_check (GtkEmission *emissions,
148 static gint gtk_handlers_run (GtkHandler *handlers,
153 static gboolean gtk_emission_hook_marshaller (GHook *hook,
155 static gboolean gtk_signal_collect_params (GtkArg *params,
157 GtkType *param_types,
161 #define LOOKUP_SIGNAL_ID(signal_id) ( \
162 signal_id > 0 && signal_id < gtk_n_signals ? \
163 (GtkSignal*) gtk_signals + signal_id : \
168 static GtkSignalMarshal global_marshaller = NULL;
169 static GtkSignalDestroy global_destroy_notify = NULL;
171 static guint gtk_handler_id = 1;
172 static guint handler_quark = 0;
173 static GHashTable *gtk_signal_hash_table = NULL;
174 static GtkSignal *gtk_signals = NULL;
175 static guint gtk_n_signals = 0;
176 static GMemChunk *gtk_signal_hash_mem_chunk = NULL;
177 static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;
178 static GtkHandler *gtk_handler_free_list = NULL;
179 static GtkEmission *gtk_free_emissions = NULL;
183 static GtkEmission *current_emissions = NULL;
184 static GtkEmission *stop_emissions = NULL;
185 static GtkEmission *restart_emissions = NULL;
188 gtk_signal_next_and_invalidate (void)
190 static guint gtk_n_free_signals = 0;
191 register GtkSignal *signal;
192 register guint new_signal_id;
194 /* don't keep *any* GtkSignal pointers across invokation of this function!!!
197 if (gtk_n_free_signals == 0)
204 size = gtk_n_signals + SIGNAL_BLOCK_SIZE;
205 size *= sizeof (GtkSignal);
211 gtk_signals = g_realloc (gtk_signals, size);
213 gtk_n_free_signals = size / sizeof (GtkSignal) - gtk_n_signals;
215 memset (gtk_signals + gtk_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
218 new_signal_id = gtk_n_signals++;
219 gtk_n_free_signals--;
221 g_assert (gtk_n_signals < 65535);
223 signal = LOOKUP_SIGNAL_ID (new_signal_id);
225 signal->signal_id = new_signal_id;
231 gtk_signal_init (void)
237 zero = gtk_signal_next_and_invalidate ();
238 g_assert (zero == NULL);
240 handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
242 gtk_signal_hash_mem_chunk =
243 g_mem_chunk_new ("GtkSignalHash mem chunk",
244 sizeof (GtkSignalHash),
245 sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
247 gtk_disconnect_info_mem_chunk =
248 g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
249 sizeof (GtkDisconnectInfo),
250 sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
252 gtk_handler_free_list = NULL;
253 gtk_free_emissions = NULL;
255 gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
261 gtk_signal_newv (const gchar *r_name,
262 GtkSignalRunType signal_flags,
264 guint function_offset,
265 GtkSignalMarshaller marshaller,
276 g_return_val_if_fail (r_name != NULL, 0);
277 g_return_val_if_fail (marshaller != NULL, 0);
278 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
280 g_return_val_if_fail (params != NULL, 0);
286 name = g_strdup (r_name);
287 g_strdelimit (name, NULL, '_');
289 quark = gtk_signal_lookup (name, object_type);
292 g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
294 gtk_type_name (object_type));
299 if (return_val != GTK_TYPE_NONE &&
300 (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
302 g_warning ("gtk_signal_newv(): signal \"%s\" - return value `%s' incompatible with GTK_RUN_FIRST",
303 name, gtk_type_name (return_val));
308 signal = gtk_signal_next_and_invalidate ();
310 /* signal->signal_id already set */
312 signal->object_type = object_type;
314 signal->function_offset = function_offset;
315 signal->marshaller = marshaller;
316 signal->return_val = return_val;
317 signal->signal_flags = signal_flags;
318 signal->nparams = nparams;
319 signal->hook_list = NULL;
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_id, params);
492 gtk_signal_emit (GtkObject *object,
498 GtkArg params[MAX_SIGNAL_PARAMS + 1];
501 g_return_if_fail (object != NULL);
502 g_return_if_fail (signal_id >= 1);
504 signal = LOOKUP_SIGNAL_ID (signal_id);
505 g_return_if_fail (signal != NULL);
506 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
508 va_start (args, signal_id);
509 abort = gtk_signal_collect_params (params,
517 gtk_signal_real_emit (object, signal_id, params);
521 gtk_signal_emitv_by_name (GtkObject *object,
527 g_return_if_fail (object != NULL);
528 g_return_if_fail (name != NULL);
529 g_return_if_fail (params != NULL);
531 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
537 signal = LOOKUP_SIGNAL_ID (signal_id);
538 g_return_if_fail (signal != NULL);
539 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
541 gtk_signal_real_emit (object, signal_id, params);
545 g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
547 gtk_type_name (GTK_OBJECT_TYPE (object)));
552 gtk_signal_emit_by_name (GtkObject *object,
558 g_return_if_fail (object != NULL);
559 g_return_if_fail (name != NULL);
561 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
566 GtkArg params[MAX_SIGNAL_PARAMS + 1];
570 signal = LOOKUP_SIGNAL_ID (signal_id);
571 g_return_if_fail (signal != NULL);
572 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
574 va_start (args, name);
575 abort = gtk_signal_collect_params (params,
583 gtk_signal_real_emit (object, signal_id, params);
587 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
589 gtk_type_name (GTK_OBJECT_TYPE (object)));
594 gtk_signal_emit_stop (GtkObject *object,
599 g_return_if_fail (object != NULL);
600 g_return_if_fail (signal_id >= 1);
602 state = gtk_emission_check (current_emissions, object, signal_id);
604 g_warning ("gtk_signal_emit_stop(): emission (%u) for object `%s' cannot be stopped from emission hook",
606 gtk_type_name (GTK_OBJECT_TYPE (object)));
609 if (!gtk_emission_check (stop_emissions, object, signal_id))
610 gtk_emission_add (&stop_emissions, object, signal_id);
613 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
615 gtk_type_name (GTK_OBJECT_TYPE (object)));
619 gtk_signal_emit_stop_by_name (GtkObject *object,
624 g_return_if_fail (object != NULL);
625 g_return_if_fail (name != NULL);
627 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
629 gtk_signal_emit_stop (object, signal_id);
631 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
633 gtk_type_name (GTK_OBJECT_TYPE (object)));
637 gtk_signal_n_emissions (GtkObject *object,
640 GtkEmission *emission;
643 g_return_val_if_fail (object != NULL, 0);
644 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
647 for (emission = current_emissions; emission; emission = emission->next)
649 if (emission->object == object && emission->signal_id == signal_id)
657 gtk_signal_n_emissions_by_name (GtkObject *object,
663 g_return_val_if_fail (object != NULL, 0);
664 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
665 g_return_val_if_fail (name != NULL, 0);
667 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
669 n = gtk_signal_n_emissions (object, signal_id);
672 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
674 gtk_type_name (GTK_OBJECT_TYPE (object)));
682 gtk_signal_connect (GtkObject *object,
689 g_return_val_if_fail (object != NULL, 0);
690 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
692 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
695 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
697 gtk_type_name (GTK_OBJECT_TYPE (object)));
701 return gtk_signal_connect_by_type (object, signal_id,
702 func, func_data, NULL,
703 FALSE, FALSE, FALSE);
707 gtk_signal_connect_after (GtkObject *object,
714 g_return_val_if_fail (object != NULL, 0);
716 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
719 g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
721 gtk_type_name (GTK_OBJECT_TYPE (object)));
725 return gtk_signal_connect_by_type (object, signal_id,
726 func, func_data, NULL,
731 gtk_signal_connect_full (GtkObject *object,
734 GtkCallbackMarshal marshal,
736 GtkDestroyNotify destroy_func,
742 g_return_val_if_fail (object != NULL, 0);
744 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
747 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
749 gtk_type_name (GTK_OBJECT_TYPE (object)));
754 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
755 func_data, destroy_func,
756 object_signal, after, TRUE);
758 return gtk_signal_connect_by_type (object, signal_id, func,
759 func_data, destroy_func,
760 object_signal, after, FALSE);
764 gtk_signal_connect_interp (GtkObject *object,
766 GtkCallbackMarshal func,
768 GtkDestroyNotify destroy_func,
771 g_message ("gtk_signal_connect_interp() is deprecated");
773 return gtk_signal_connect_full (object, name, NULL, func,
774 func_data, destroy_func, FALSE, after);
778 gtk_signal_connect_object (GtkObject *object,
781 GtkObject *slot_object)
785 g_return_val_if_fail (object != NULL, 0);
786 /* slot_object needs to be treated as ordinary pointer
789 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
792 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
794 gtk_type_name (GTK_OBJECT_TYPE (object)));
798 return gtk_signal_connect_by_type (object, signal_id,
799 func, slot_object, NULL,
804 gtk_signal_connect_object_after (GtkObject *object,
807 GtkObject *slot_object)
811 g_return_val_if_fail (object != NULL, 0);
813 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
816 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
818 gtk_type_name (GTK_OBJECT_TYPE (object)));
822 return gtk_signal_connect_by_type (object, signal_id,
823 func, slot_object, NULL,
828 gtk_signal_connect_while_alive (GtkObject *object,
832 GtkObject *alive_object)
834 GtkDisconnectInfo *info;
836 g_return_if_fail (object != NULL);
837 g_return_if_fail (GTK_IS_OBJECT (object));
838 g_return_if_fail (signal != NULL);
839 g_return_if_fail (func != NULL);
840 g_return_if_fail (alive_object != NULL);
841 g_return_if_fail (GTK_IS_OBJECT (alive_object));
843 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
844 info->object1 = object;
845 info->object2 = alive_object;
847 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
848 info->disconnect_handler1 =
849 gtk_signal_connect_object (info->object1,
851 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
853 info->disconnect_handler2 =
854 gtk_signal_connect_object (info->object2,
856 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
861 gtk_signal_connect_object_while_alive (GtkObject *object,
864 GtkObject *alive_object)
866 GtkDisconnectInfo *info;
868 g_return_if_fail (object != NULL);
869 g_return_if_fail (GTK_IS_OBJECT (object));
870 g_return_if_fail (signal != NULL);
871 g_return_if_fail (func != NULL);
872 g_return_if_fail (alive_object != NULL);
873 g_return_if_fail (GTK_IS_OBJECT (alive_object));
875 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
876 info->object1 = object;
877 info->object2 = alive_object;
879 info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
880 info->disconnect_handler1 =
881 gtk_signal_connect_object (info->object1,
883 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
885 info->disconnect_handler2 =
886 gtk_signal_connect_object (info->object2,
888 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
893 gtk_signal_disconnect (GtkObject *object,
898 g_return_if_fail (object != NULL);
899 g_return_if_fail (handler_id > 0);
901 handler = gtk_object_get_data_by_id (object, handler_quark);
905 if (handler->id == handler_id)
908 handler->blocked += 1;
909 gtk_signal_handler_unref (handler, object);
912 handler = handler->next;
915 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
919 gtk_signal_disconnect_by_func (GtkObject *object,
926 g_return_if_fail (object != NULL);
927 g_return_if_fail (func != NULL);
930 handler = gtk_object_get_data_by_id (object, handler_quark);
934 GtkHandler *handler_next;
936 handler_next = handler->next;
937 if ((handler->id > 0) &&
938 (handler->func == func) &&
939 (handler->func_data == data))
943 handler->blocked += 1;
944 gtk_signal_handler_unref (handler, object);
946 handler = handler_next;
950 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
954 gtk_signal_disconnect_by_data (GtkObject *object,
960 g_return_if_fail (object != NULL);
963 handler = gtk_object_get_data_by_id (object, handler_quark);
967 GtkHandler *handler_next;
969 handler_next = handler->next;
970 if ((handler->id > 0) &&
971 (handler->func_data == data))
975 handler->blocked += 1;
976 gtk_signal_handler_unref (handler, object);
978 handler = handler_next;
982 g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
986 gtk_signal_handler_block (GtkObject *object,
991 g_return_if_fail (object != NULL);
992 g_return_if_fail (handler_id > 0);
994 handler = gtk_object_get_data_by_id (object, handler_quark);
998 if (handler->id == handler_id)
1000 handler->blocked += 1;
1003 handler = handler->next;
1006 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
1010 gtk_signal_handler_block_by_func (GtkObject *object,
1014 GtkHandler *handler;
1017 g_return_if_fail (object != NULL);
1018 g_return_if_fail (func != NULL);
1021 handler = gtk_object_get_data_by_id (object, handler_quark);
1025 if ((handler->id > 0) &&
1026 (handler->func == func) &&
1027 (handler->func_data == data))
1030 handler->blocked += 1;
1032 handler = handler->next;
1036 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1040 gtk_signal_handler_block_by_data (GtkObject *object,
1043 GtkHandler *handler;
1046 g_return_if_fail (object != NULL);
1049 handler = gtk_object_get_data_by_id (object, handler_quark);
1053 if ((handler->id > 0) &&
1054 (handler->func_data == data))
1057 handler->blocked += 1;
1059 handler = handler->next;
1063 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1067 gtk_signal_handler_unblock (GtkObject *object,
1070 GtkHandler *handler;
1072 g_return_if_fail (object != NULL);
1073 g_return_if_fail (handler_id > 0);
1075 handler = gtk_object_get_data_by_id (object, handler_quark);
1079 if (handler->id == handler_id)
1081 if (handler->blocked > 0)
1082 handler->blocked -= 1;
1084 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1087 handler = handler->next;
1090 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1094 gtk_signal_handler_unblock_by_func (GtkObject *object,
1098 GtkHandler *handler;
1101 g_return_if_fail (object != NULL);
1102 g_return_if_fail (func != NULL);
1105 handler = gtk_object_get_data_by_id (object, handler_quark);
1109 if ((handler->id > 0) &&
1110 (handler->func == func) &&
1111 (handler->func_data == data) &&
1112 (handler->blocked > 0))
1114 handler->blocked -= 1;
1117 handler = handler->next;
1121 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1125 gtk_signal_handler_unblock_by_data (GtkObject *object,
1128 GtkHandler *handler;
1131 g_return_if_fail (object != NULL);
1134 handler = gtk_object_get_data_by_id (object, handler_quark);
1138 if ((handler->id > 0) &&
1139 (handler->func_data == data) &&
1140 (handler->blocked > 0))
1142 handler->blocked -= 1;
1145 handler = handler->next;
1149 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1153 gtk_signal_handlers_destroy (GtkObject *object)
1155 GtkHandler *handler;
1157 /* we make the "optimization" of destroying the first handler in the last
1158 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1159 * handler_key data on each removal
1162 handler = gtk_object_get_data_by_id (object, handler_quark);
1165 handler = handler->next;
1170 next = handler->next;
1171 if (handler->id > 0)
1172 gtk_signal_handler_unref (handler, object);
1175 handler = gtk_object_get_data_by_id (object, handler_quark);
1176 if (handler->id > 0)
1177 gtk_signal_handler_unref (handler, object);
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;
1349 #ifdef G_ENABLE_DEBUG
1350 /* value typically set via gdb */
1351 static GtkObject *gtk_trace_signal_object = NULL;
1352 #endif /* G_ENABLE_DEBUG */
1356 gtk_signal_real_emit (GtkObject *object,
1361 GtkHandler *handlers;
1362 GtkSignalFunc signal_func;
1363 GtkEmission *emission;
1365 /* gtk_handlers_run() expects a reentrant GtkSignal*, so we allocate
1366 * it locally on the stack. we save some lookups ourselves with this as well.
1368 signal = *LOOKUP_SIGNAL_ID (signal_id);
1369 if (signal.function_offset)
1370 signal_func = G_STRUCT_MEMBER (GtkSignalFunc, object->klass, signal.function_offset);
1374 #ifdef G_ENABLE_DEBUG
1375 if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1376 object == gtk_trace_signal_object)
1377 g_message ("%s::%s emitted (object=%p class-method=%p)\n",
1378 gtk_type_name (GTK_OBJECT_TYPE (object)),
1382 #endif /* G_ENABLE_DEBUG */
1384 if (signal.signal_flags & GTK_RUN_NO_RECURSE)
1388 state = gtk_emission_check (current_emissions, object, signal_id);
1392 g_warning ("gtk_signal_real_emit(): emission (%u) for object `%s' cannot be restarted from emission hook",
1394 gtk_type_name (GTK_OBJECT_TYPE (object)));
1395 else if (!gtk_emission_check (restart_emissions, object, signal_id))
1396 gtk_emission_add (&restart_emissions, object, signal_id);
1402 gtk_object_ref (object);
1404 gtk_emission_add (¤t_emissions, object, signal_id);
1405 emission = current_emissions;
1409 if (signal.signal_flags & GTK_RUN_FIRST && signal_func)
1411 signal.marshaller (object, signal_func, NULL, params);
1413 if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1415 gtk_emission_remove (&stop_emissions, object, signal_id);
1418 else if (restart_emissions &&
1419 signal.signal_flags & GTK_RUN_NO_RECURSE &&
1420 gtk_emission_check (restart_emissions, object, signal_id))
1422 gtk_emission_remove (&restart_emissions, object, signal_id);
1424 goto emission_restart;
1428 if (signal.hook_list && !GTK_OBJECT_DESTROYED (object))
1430 GtkEmissionHookData data;
1432 data.object = object;
1433 data.n_params = signal.nparams;
1434 data.params = params;
1435 data.signal_id = signal_id;
1436 emission->in_hook = 1;
1437 g_hook_list_marshal_check (signal.hook_list, TRUE, gtk_emission_hook_marshaller, &data);
1438 emission->in_hook = 0;
1441 if (GTK_OBJECT_CONNECTED (object))
1443 handlers = gtk_signal_get_handlers (object, signal_id);
1448 return_val = gtk_handlers_run (handlers, &signal, object, params, FALSE);
1451 case EMISSION_CONTINUE:
1453 case EMISSION_RESTART:
1454 goto emission_restart;
1461 if (signal.signal_flags & GTK_RUN_LAST && signal_func)
1463 signal.marshaller (object, signal_func, NULL, params);
1465 if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1467 gtk_emission_remove (&stop_emissions, object, signal_id);
1470 else if (restart_emissions &&
1471 signal.signal_flags & GTK_RUN_NO_RECURSE &&
1472 gtk_emission_check (restart_emissions, object, signal_id))
1474 gtk_emission_remove (&restart_emissions, object, signal_id);
1476 goto emission_restart;
1480 if (GTK_OBJECT_CONNECTED (object))
1482 handlers = gtk_signal_get_handlers (object, signal_id);
1487 return_val = gtk_handlers_run (handlers, &signal, object, params, TRUE);
1490 case EMISSION_CONTINUE:
1492 case EMISSION_RESTART:
1493 goto emission_restart;
1501 if (restart_emissions && signal.signal_flags & GTK_RUN_NO_RECURSE)
1502 gtk_emission_remove (&restart_emissions, object, signal_id);
1504 gtk_emission_remove (¤t_emissions, object, signal_id);
1506 gtk_object_unref (object);
1510 gtk_signal_get_handlers (GtkObject *object,
1513 GtkHandler *handlers;
1515 handlers = gtk_object_get_data_by_id (object, handler_quark);
1519 if (handlers->signal_id == signal_id)
1521 handlers = handlers->next;
1528 gtk_signal_handler_pending (GtkObject *object,
1530 gboolean may_be_blocked)
1532 GtkHandler *handlers;
1535 g_return_val_if_fail (object != NULL, 0);
1536 g_return_val_if_fail (signal_id >= 1, 0);
1538 if (GTK_OBJECT_CONNECTED (object))
1539 handlers = gtk_signal_get_handlers (object, signal_id);
1544 while (handlers && handlers->signal_id == signal_id)
1546 if (handlers->id > 0 &&
1547 (may_be_blocked || handlers->blocked == FALSE))
1549 handler_id = handlers->id;
1553 handlers = handlers->next;
1560 gtk_signal_handler_pending_by_func (GtkObject *object,
1562 gboolean may_be_blocked,
1566 GtkHandler *handlers;
1569 g_return_val_if_fail (object != NULL, 0);
1570 g_return_val_if_fail (func != NULL, 0);
1571 g_return_val_if_fail (signal_id >= 1, 0);
1573 if (GTK_OBJECT_CONNECTED (object))
1574 handlers = gtk_signal_get_handlers (object, signal_id);
1579 while (handlers && handlers->signal_id == signal_id)
1581 if (handlers->id > 0 &&
1582 handlers->func == func &&
1583 handlers->func_data == data &&
1584 (may_be_blocked || handlers->blocked == FALSE))
1586 handler_id = handlers->id;
1590 handlers = handlers->next;
1597 gtk_signal_add_emission_hook (guint signal_id,
1598 GtkEmissionHook hook_func,
1601 return gtk_signal_add_emission_hook_full (signal_id, hook_func, data, NULL);
1605 gtk_signal_add_emission_hook_full (guint signal_id,
1606 GtkEmissionHook hook_func,
1608 GDestroyNotify destroy)
1610 static guint seq_hook_id = 1;
1614 g_return_val_if_fail (signal_id > 0, 0);
1615 g_return_val_if_fail (hook_func != NULL, 0);
1617 signal = LOOKUP_SIGNAL_ID (signal_id);
1618 g_return_val_if_fail (signal != NULL, 0);
1619 if (signal->signal_flags & GTK_RUN_NO_HOOKS)
1621 g_warning ("gtk_signal_add_emission_hook_full(): signal \"%s\" does not support emission hooks",
1626 if (!signal->hook_list)
1628 signal->hook_list = g_new (GHookList, 1);
1629 g_hook_list_init (signal->hook_list, sizeof (GHook));
1632 hook = g_hook_alloc (signal->hook_list);
1634 hook->func = hook_func;
1635 hook->destroy = destroy;
1637 signal->hook_list->seq_id = seq_hook_id;
1638 g_hook_prepend (signal->hook_list, hook);
1639 seq_hook_id = signal->hook_list->seq_id;
1641 return hook->hook_id;
1645 gtk_signal_remove_emission_hook (guint signal_id,
1650 g_return_if_fail (signal_id > 0);
1651 g_return_if_fail (hook_id > 0);
1653 signal = LOOKUP_SIGNAL_ID (signal_id);
1654 g_return_if_fail (signal != NULL);
1656 if (!signal->hook_list || !g_hook_destroy (signal->hook_list, hook_id))
1657 g_warning ("gtk_signal_remove_emission_hook(): could not find hook (%u)", hook_id);
1661 gtk_emission_hook_marshaller (GHook *hook,
1664 GtkEmissionHookData *data = data_p;
1665 GtkEmissionHook func;
1669 if (!GTK_OBJECT_DESTROYED (data->object))
1670 return func (data->object, data->signal_id,
1671 data->n_params, data->params,
1678 gtk_signal_connect_by_type (GtkObject *object,
1682 GtkSignalDestroy destroy_func,
1687 GtkObjectClass *class;
1688 GtkHandler *handler;
1692 g_return_val_if_fail (object != NULL, 0);
1693 g_return_val_if_fail (object->klass != NULL, 0);
1695 signal = LOOKUP_SIGNAL_ID (signal_id);
1697 /* Search through the signals for this object and make
1698 * sure the one we are adding is valid. We need to perform
1699 * the lookup on the objects parents as well. If it isn't
1700 * valid then issue a warning and return.
1701 * As of now (1998-05-27) this lookup shouldn't be neccessarry
1702 * anymore since gtk_signal_lookup() has been reworked to only
1703 * return correct signal ids per class-branch.
1706 class = object->klass;
1710 guint *object_signals;
1714 object_signals = class->signals;
1715 nsignals = class->nsignals;
1717 for (i = 0; i < nsignals; i++)
1718 if (object_signals[i] == signal_id)
1724 parent = gtk_type_parent (class->type);
1726 class = gtk_type_class (parent);
1733 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1735 gtk_type_name (object->klass->type));
1739 handler = gtk_signal_handler_new ();
1740 handler->id = gtk_handler_id++;
1741 handler->signal_id = signal_id;
1742 handler->object_signal = object_signal;
1743 handler->func = func;
1744 handler->func_data = func_data;
1745 handler->destroy_func = destroy_func;
1746 handler->after = after != FALSE;
1747 handler->no_marshal = no_marshal;
1749 gtk_signal_handler_insert (object, handler);
1754 gtk_emission_new (void)
1756 GtkEmission *emission;
1758 if (!gtk_free_emissions)
1760 GtkEmission *emission_block;
1763 emission_block = g_new0 (GtkEmission, EMISSION_BLOCK_SIZE);
1764 for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1766 (emission_block + i)->next = gtk_free_emissions;
1767 gtk_free_emissions = (emission_block + i);
1770 emission = emission_block;
1774 emission = gtk_free_emissions;
1775 gtk_free_emissions = emission->next;
1778 emission->object = NULL;
1779 emission->signal_id = 0;
1780 emission->in_hook = 0;
1781 emission->next = NULL;
1787 gtk_emission_add (GtkEmission **emissions,
1791 GtkEmission *emission;
1793 g_return_if_fail (emissions != NULL);
1794 g_return_if_fail (object != NULL);
1796 emission = gtk_emission_new ();
1797 emission->object = object;
1798 emission->signal_id = signal_id;
1800 emission->next = *emissions;
1801 *emissions = emission;
1805 gtk_emission_remove (GtkEmission **emissions,
1809 GtkEmission *emission, *last;
1811 g_return_if_fail (emissions != NULL);
1814 emission = *emissions;
1817 if (emission->object == object && emission->signal_id == signal_id)
1820 last->next = emission->next;
1822 *emissions = emission->next;
1824 emission->next = gtk_free_emissions;
1825 gtk_free_emissions = emission;
1830 emission = last->next;
1835 gtk_emission_check (GtkEmission *emission,
1841 if (emission->object == object && emission->signal_id == signal_id)
1842 return 1 + emission->in_hook;
1843 emission = emission->next;
1849 gtk_handlers_run (GtkHandler *handlers,
1855 /* *signal is a local copy on the stack of gtk_signal_real_emit(),
1856 * so we don't need to look it up every time we invoked a function.
1858 while (handlers && handlers->signal_id == signal->signal_id)
1860 GtkHandler *handlers_next;
1862 gtk_signal_handler_ref (handlers);
1864 if (!handlers->blocked && handlers->after == after)
1868 if (handlers->no_marshal)
1869 (* (GtkCallbackMarshal) handlers->func) (object,
1870 handlers->func_data,
1873 else if (handlers->object_signal)
1874 /* don't cast with GTK_OBJECT () */
1875 (* signal->marshaller) ((GtkObject*) handlers->func_data,
1877 handlers->func_data,
1880 (* signal->marshaller) (object,
1882 handlers->func_data,
1885 else if (global_marshaller)
1886 (* global_marshaller) (object,
1887 handlers->func_data,
1891 signal->return_val);
1893 if (stop_emissions && gtk_emission_check (stop_emissions,
1897 gtk_emission_remove (&stop_emissions, object, signal->signal_id);
1899 gtk_signal_handler_unref (handlers, object);
1901 return EMISSION_DONE;
1903 else if (restart_emissions &&
1904 signal->signal_flags & GTK_RUN_NO_RECURSE &&
1905 gtk_emission_check (restart_emissions, object, signal->signal_id))
1907 gtk_emission_remove (&restart_emissions, object, signal->signal_id);
1909 gtk_signal_handler_unref (handlers, object);
1911 return EMISSION_RESTART;
1915 handlers_next = handlers->next;
1916 gtk_signal_handler_unref (handlers, object);
1917 handlers = handlers_next;
1920 return EMISSION_CONTINUE;
1924 gtk_signal_collect_params (GtkArg *params,
1926 GtkType *param_types,
1927 GtkType return_type,
1930 register GtkArg *last_param;
1931 register gboolean failed = FALSE;
1933 for (last_param = params + n_params; params < last_param; params++)
1935 register gchar *error;
1937 params->name = NULL;
1938 params->type = *(param_types++);
1939 GTK_ARG_COLLECT_VALUE (params,
1945 g_warning ("gtk_signal_collect_params(): %s", error);
1950 params->type = return_type;
1951 params->name = NULL;
1953 return_type = GTK_FUNDAMENTAL_TYPE (return_type);
1954 if (return_type != GTK_TYPE_NONE)
1956 if ((return_type >= GTK_TYPE_FLAT_FIRST &&
1957 return_type <= GTK_TYPE_FLAT_LAST) ||
1958 (return_type == GTK_TYPE_OBJECT))
1960 GTK_VALUE_POINTER (*params) = va_arg (var_args, gpointer);
1962 if (GTK_VALUE_POINTER (*params) == NULL)
1965 g_warning ("gtk_signal_collect_params(): invalid NULL pointer for return argument type `%s'",
1966 gtk_type_name (params->type));
1972 g_warning ("gtk_signal_collect_params(): unsupported return argument type `%s'",
1973 gtk_type_name (params->type));
1977 GTK_VALUE_POINTER (*params) = NULL;