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 (g_const_pointer h);
123 static gint gtk_signal_compare (g_const_pointer 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_key_id = 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_key_id = gtk_object_data_force_id ("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 id = 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));
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->signal_flags = signal_flags;
316 signal->marshaller = marshaller;
317 signal->return_val = return_val;
318 signal->nparams = nparams;
322 signal->params = g_new (GtkType, nparams);
324 for (i = 0; i < nparams; i++)
325 signal->params[i] = params[i];
328 signal->params = NULL;
330 /* insert "signal_name" into hash table
332 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
333 hash->object_type = object_type;
334 hash->name_key_id = gtk_object_data_force_id (signal->name);
335 hash->signal_id = signal->signal_id;
336 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
338 /* insert "signal-name" into hash table
340 g_strdelimit (signal->name, NULL, '-');
341 id = gtk_object_data_force_id (signal->name);
342 if (id != hash->name_key_id)
344 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
345 hash->object_type = object_type;
346 hash->name_key_id = id;
347 hash->signal_id = signal->signal_id;
348 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
351 return signal->signal_id;
355 gtk_signal_new (const gchar *name,
356 GtkSignalRunType signal_flags,
358 guint function_offset,
359 GtkSignalMarshaller marshaller,
369 g_return_val_if_fail (nparams <= MAX_SIGNAL_PARAMS, 0);
373 params = g_new (GtkType, nparams);
375 va_start (args, nparams);
377 for (i = 0; i < nparams; i++)
378 params[i] = va_arg (args, GtkType);
385 signal_id = gtk_signal_newv (name,
400 gtk_signal_lookup (const gchar *name,
405 g_return_val_if_fail (name != NULL, 0);
406 g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0);
408 hash.name_key_id = gtk_object_data_try_key (name);
409 if (hash.name_key_id)
415 hash.object_type = object_type;
417 signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
421 object_type = gtk_type_parent (object_type);
429 gtk_signal_query (guint signal_id)
431 GtkSignalQuery *query;
434 g_return_val_if_fail (signal_id >= 1, NULL);
436 signal = LOOKUP_SIGNAL_ID (signal_id);
439 query = g_new (GtkSignalQuery, 1);
441 query->object_type = signal->object_type;
442 query->signal_id = signal_id;
443 query->signal_name = signal->name;
444 query->is_user_signal = signal->function_offset == 0;
445 query->signal_flags = signal->signal_flags;
446 query->return_val = signal->return_val;
447 query->nparams = signal->nparams;
448 query->params = signal->params;
457 gtk_signal_name (guint signal_id)
461 g_return_val_if_fail (signal_id >= 1, NULL);
463 signal = LOOKUP_SIGNAL_ID (signal_id);
471 gtk_signal_emitv (GtkObject *object,
477 g_return_if_fail (object != NULL);
478 g_return_if_fail (signal_id >= 1);
480 signal = LOOKUP_SIGNAL_ID (signal_id);
481 g_return_if_fail (signal != NULL);
482 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
484 if (signal->nparams > 0)
485 g_return_if_fail (params != NULL);
487 gtk_signal_real_emit (object, signal, params);
491 gtk_signal_emit (GtkObject *object,
497 GtkArg params[MAX_SIGNAL_PARAMS];
499 g_return_if_fail (object != NULL);
500 g_return_if_fail (signal_id >= 1);
502 signal = LOOKUP_SIGNAL_ID (signal_id);
503 g_return_if_fail (signal != NULL);
504 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
506 va_start (args, signal_id);
507 gtk_params_get (params,
514 gtk_signal_real_emit (object, signal, params);
518 gtk_signal_emitv_by_name (GtkObject *object,
524 g_return_if_fail (object != NULL);
525 g_return_if_fail (name != NULL);
526 g_return_if_fail (params != NULL);
528 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
534 signal = LOOKUP_SIGNAL_ID (signal_id);
535 g_return_if_fail (signal != NULL);
536 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
538 gtk_signal_real_emit (object, signal, params);
542 g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
544 gtk_type_name (GTK_OBJECT_TYPE (object)));
549 gtk_signal_emit_by_name (GtkObject *object,
555 g_return_if_fail (object != NULL);
556 g_return_if_fail (name != NULL);
558 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
563 GtkArg params[MAX_SIGNAL_PARAMS];
566 signal = LOOKUP_SIGNAL_ID (signal_id);
567 g_return_if_fail (signal != NULL);
568 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
570 va_start (args, name);
571 gtk_params_get (params,
578 gtk_signal_real_emit (object, signal, params);
582 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
584 gtk_type_name (GTK_OBJECT_TYPE (object)));
589 gtk_signal_emit_stop (GtkObject *object,
592 g_return_if_fail (object != NULL);
593 g_return_if_fail (signal_id >= 1);
595 if (gtk_emission_check (current_emissions, object, signal_id))
596 gtk_emission_add (&stop_emissions, object, signal_id);
598 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
600 gtk_type_name (GTK_OBJECT_TYPE (object)));
604 gtk_signal_emit_stop_by_name (GtkObject *object,
609 g_return_if_fail (object != NULL);
610 g_return_if_fail (name != NULL);
612 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
614 gtk_signal_emit_stop (object, signal_id);
616 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
618 gtk_type_name (GTK_OBJECT_TYPE (object)));
622 gtk_signal_n_emissions (GtkObject *object,
628 g_return_val_if_fail (object != NULL, 0);
629 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
632 for (list = current_emissions; list; list = list->next)
634 GtkEmission *emission;
636 emission = list->data;
638 if ((emission->object == object) &&
639 (emission->signal_id == signal_id))
647 gtk_signal_n_emissions_by_name (GtkObject *object,
653 g_return_val_if_fail (object != NULL, 0);
654 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
655 g_return_val_if_fail (name != NULL, 0);
657 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
659 n = gtk_signal_n_emissions (object, signal_id);
662 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
664 gtk_type_name (GTK_OBJECT_TYPE (object)));
672 gtk_signal_connect (GtkObject *object,
679 g_return_val_if_fail (object != NULL, 0);
680 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
682 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
685 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
687 gtk_type_name (GTK_OBJECT_TYPE (object)));
691 return gtk_signal_connect_by_type (object, signal_id,
692 func, func_data, NULL,
693 FALSE, FALSE, FALSE);
697 gtk_signal_connect_after (GtkObject *object,
704 g_return_val_if_fail (object != NULL, 0);
706 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
709 g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
711 gtk_type_name (GTK_OBJECT_TYPE (object)));
715 return gtk_signal_connect_by_type (object, signal_id,
716 func, func_data, NULL,
721 gtk_signal_connect_full (GtkObject *object,
724 GtkCallbackMarshal marshal,
726 GtkDestroyNotify destroy_func,
732 g_return_val_if_fail (object != NULL, 0);
734 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
737 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
739 gtk_type_name (GTK_OBJECT_TYPE (object)));
744 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
745 func_data, destroy_func,
746 object_signal, after, TRUE);
748 return gtk_signal_connect_by_type (object, signal_id, func,
749 func_data, destroy_func,
750 object_signal, after, FALSE);
754 gtk_signal_connect_interp (GtkObject *object,
756 GtkCallbackMarshal func,
758 GtkDestroyNotify destroy_func,
761 return gtk_signal_connect_full (object, name, NULL, func,
762 func_data, destroy_func, FALSE, after);
766 gtk_signal_connect_object (GtkObject *object,
769 GtkObject *slot_object)
773 g_return_val_if_fail (object != NULL, 0);
774 /* slot_object needs to be treated as ordinary pointer
777 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
780 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
782 gtk_type_name (GTK_OBJECT_TYPE (object)));
786 return gtk_signal_connect_by_type (object, signal_id,
787 func, slot_object, NULL,
792 gtk_signal_connect_object_after (GtkObject *object,
795 GtkObject *slot_object)
799 g_return_val_if_fail (object != NULL, 0);
801 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
804 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
806 gtk_type_name (GTK_OBJECT_TYPE (object)));
810 return gtk_signal_connect_by_type (object, signal_id,
811 func, slot_object, NULL,
816 gtk_signal_connect_while_alive (GtkObject *object,
820 GtkObject *alive_object)
822 GtkDisconnectInfo *info;
824 g_return_if_fail (object != NULL);
825 g_return_if_fail (GTK_IS_OBJECT (object));
826 g_return_if_fail (signal != NULL);
827 g_return_if_fail (func != NULL);
828 g_return_if_fail (alive_object != NULL);
829 g_return_if_fail (GTK_IS_OBJECT (alive_object));
831 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
832 info->object1 = object;
833 info->object2 = alive_object;
835 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
836 info->disconnect_handler1 =
837 gtk_signal_connect_object (info->object1,
839 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
841 info->disconnect_handler2 =
842 gtk_signal_connect_object (info->object2,
844 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
849 gtk_signal_connect_object_while_alive (GtkObject *object,
852 GtkObject *alive_object)
854 GtkDisconnectInfo *info;
856 g_return_if_fail (object != NULL);
857 g_return_if_fail (GTK_IS_OBJECT (object));
858 g_return_if_fail (signal != NULL);
859 g_return_if_fail (func != NULL);
860 g_return_if_fail (alive_object != NULL);
861 g_return_if_fail (GTK_IS_OBJECT (alive_object));
863 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
864 info->object1 = object;
865 info->object2 = alive_object;
867 info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
868 info->disconnect_handler1 =
869 gtk_signal_connect_object (info->object1,
871 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
873 info->disconnect_handler2 =
874 gtk_signal_connect_object (info->object2,
876 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
881 gtk_signal_disconnect (GtkObject *object,
886 g_return_if_fail (object != NULL);
887 g_return_if_fail (handler_id > 0);
889 handler = gtk_object_get_data_by_id (object, handler_key_id);
893 if (handler->id == handler_id)
896 handler->blocked += 1;
897 gtk_signal_handler_unref (handler, object);
900 handler = handler->next;
903 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
907 gtk_signal_disconnect_by_func (GtkObject *object,
914 g_return_if_fail (object != NULL);
915 g_return_if_fail (func != NULL);
918 handler = gtk_object_get_data_by_id (object, handler_key_id);
922 GtkHandler *handler_next;
924 handler_next = handler->next;
925 if ((handler->id > 0) &&
926 (handler->func == func) &&
927 (handler->func_data == data))
931 handler->blocked += 1;
932 gtk_signal_handler_unref (handler, object);
934 handler = handler_next;
938 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
942 gtk_signal_disconnect_by_data (GtkObject *object,
948 g_return_if_fail (object != NULL);
951 handler = gtk_object_get_data_by_id (object, handler_key_id);
955 GtkHandler *handler_next;
957 handler_next = handler->next;
958 if ((handler->id > 0) &&
959 (handler->func_data == data))
963 handler->blocked += 1;
964 gtk_signal_handler_unref (handler, object);
966 handler = handler_next;
970 g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
974 gtk_signal_handler_block (GtkObject *object,
979 g_return_if_fail (object != NULL);
980 g_return_if_fail (handler_id > 0);
982 handler = gtk_object_get_data_by_id (object, handler_key_id);
986 if (handler->id == handler_id)
988 handler->blocked += 1;
991 handler = handler->next;
994 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
998 gtk_signal_handler_block_by_func (GtkObject *object,
1002 GtkHandler *handler;
1005 g_return_if_fail (object != NULL);
1006 g_return_if_fail (func != NULL);
1009 handler = gtk_object_get_data_by_id (object, handler_key_id);
1013 if ((handler->id > 0) &&
1014 (handler->func == func) &&
1015 (handler->func_data == data))
1018 handler->blocked += 1;
1020 handler = handler->next;
1024 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1028 gtk_signal_handler_block_by_data (GtkObject *object,
1031 GtkHandler *handler;
1034 g_return_if_fail (object != NULL);
1037 handler = gtk_object_get_data_by_id (object, handler_key_id);
1041 if ((handler->id > 0) &&
1042 (handler->func_data == data))
1045 handler->blocked += 1;
1047 handler = handler->next;
1051 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1055 gtk_signal_handler_unblock (GtkObject *object,
1058 GtkHandler *handler;
1060 g_return_if_fail (object != NULL);
1061 g_return_if_fail (handler_id > 0);
1063 handler = gtk_object_get_data_by_id (object, handler_key_id);
1067 if (handler->id == handler_id)
1069 if (handler->blocked > 0)
1070 handler->blocked -= 1;
1072 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1075 handler = handler->next;
1078 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1082 gtk_signal_handler_unblock_by_func (GtkObject *object,
1086 GtkHandler *handler;
1089 g_return_if_fail (object != NULL);
1090 g_return_if_fail (func != NULL);
1093 handler = gtk_object_get_data_by_id (object, handler_key_id);
1097 if ((handler->id > 0) &&
1098 (handler->func == func) &&
1099 (handler->func_data == data) &&
1100 (handler->blocked > 0))
1102 handler->blocked -= 1;
1105 handler = handler->next;
1109 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1113 gtk_signal_handler_unblock_by_data (GtkObject *object,
1116 GtkHandler *handler;
1119 g_return_if_fail (object != NULL);
1122 handler = gtk_object_get_data_by_id (object, handler_key_id);
1126 if ((handler->id > 0) &&
1127 (handler->func_data == data) &&
1128 (handler->blocked > 0))
1130 handler->blocked -= 1;
1133 handler = handler->next;
1137 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1141 gtk_signal_handlers_destroy (GtkObject *object)
1143 GtkHandler *handler;
1145 /* we make the "optimization" of destroying the first handler in the last
1146 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1147 * handler_key data on each removal
1150 handler = gtk_object_get_data_by_id (object, handler_key_id);
1153 handler = handler->next;
1158 next = handler->next;
1159 gtk_signal_handler_unref (handler, object);
1162 handler = gtk_object_get_data_by_id (object, handler_key_id);
1163 gtk_signal_handler_unref (handler, object);
1168 gtk_signal_default_marshaller (GtkObject *object,
1173 GtkSignalMarshaller0 rfunc;
1175 rfunc = (GtkSignalMarshaller0) func;
1177 (* rfunc) (object, func_data);
1181 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1182 GtkSignalDestroy destroy_func)
1184 global_marshaller = marshal_func;
1185 global_destroy_notify = destroy_func;
1189 gtk_signal_hash (g_const_pointer h)
1191 register const GtkSignalHash *hash = h;
1193 return hash->object_type ^ hash->name_key_id;
1197 gtk_signal_compare (g_const_pointer h1,
1200 register const GtkSignalHash *hash1 = h1;
1201 register const GtkSignalHash *hash2 = h2;
1203 return (hash1->name_key_id == hash2->name_key_id &&
1204 hash1->object_type == hash2->object_type);
1208 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1210 g_return_val_if_fail (info != NULL, 0);
1212 gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1213 gtk_signal_disconnect (info->object1, info->signal_handler);
1214 gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1216 g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1222 gtk_signal_handler_new (void)
1224 GtkHandler *handler;
1226 if (!gtk_handler_free_list)
1228 GtkHandler *handler_block;
1231 handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1232 for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1234 (handler_block + i)->next = gtk_handler_free_list;
1235 gtk_handler_free_list = (handler_block + i);
1238 handler = handler_block;
1242 handler = gtk_handler_free_list;
1243 gtk_handler_free_list = handler->next;
1247 handler->blocked = 0;
1248 handler->signal_id = 0;
1249 handler->object_signal = FALSE;
1250 handler->after = FALSE;
1251 handler->no_marshal = FALSE;
1252 handler->ref_count = 1;
1253 handler->func = NULL;
1254 handler->func_data = NULL;
1255 handler->destroy_func = NULL;
1256 handler->prev = NULL;
1257 handler->next = NULL;
1263 gtk_signal_handler_ref (GtkHandler *handler)
1265 handler->ref_count += 1;
1269 gtk_signal_handler_unref (GtkHandler *handler,
1272 if (!handler->ref_count)
1274 /* FIXME: i wanna get removed somewhen */
1275 g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1279 handler->ref_count -= 1;
1281 if (handler->ref_count == 0)
1283 if (handler->destroy_func)
1284 (* handler->destroy_func) (handler->func_data);
1285 else if (!handler->func && global_destroy_notify)
1286 (* global_destroy_notify) (handler->func_data);
1289 handler->prev->next = handler->next;
1290 else if (handler->next)
1291 gtk_object_set_data_by_id (object, handler_key_id, handler->next);
1294 GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1295 gtk_object_set_data_by_id (object, handler_key_id, NULL);
1298 handler->next->prev = handler->prev;
1300 handler->next = gtk_handler_free_list;
1301 gtk_handler_free_list = handler;
1306 gtk_signal_handler_insert (GtkObject *object,
1307 GtkHandler *handler)
1311 /* FIXME: remove */ g_assert (handler->next == NULL);
1312 /* FIXME: remove */ g_assert (handler->prev == NULL);
1314 tmp = gtk_object_get_data_by_id (object, handler_key_id);
1317 GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1318 gtk_object_set_data_by_id (object, handler_key_id, handler);
1323 if (tmp->signal_id < handler->signal_id)
1327 tmp->prev->next = handler;
1328 handler->prev = tmp->prev;
1331 gtk_object_set_data_by_id (object, handler_key_id, handler);
1332 tmp->prev = handler;
1333 handler->next = tmp;
1339 tmp->next = handler;
1340 handler->prev = tmp;
1347 static GtkObject *gtk_trace_signal_object = NULL;
1350 gtk_signal_real_emit (GtkObject *object,
1354 GtkHandler *handlers;
1355 GtkHandlerInfo info;
1356 guchar **signal_func_offset;
1357 register guint signal_id = signal->signal_id;
1359 #ifdef G_ENABLE_DEBUG
1360 if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1361 object == gtk_trace_signal_object)
1362 fprintf (stdout, "trace: signal_emit(\"%s\") for %s:%p\n",
1364 gtk_type_name (GTK_OBJECT_TYPE (object)),
1366 #endif /* G_ENABLE_DEBUG */
1368 if ((signal->signal_flags & GTK_RUN_NO_RECURSE) &&
1369 gtk_emission_check (current_emissions, object, signal_id))
1371 gtk_emission_add (&restart_emissions, object, signal_id);
1375 gtk_object_ref (object);
1377 gtk_emission_add (¤t_emissions, object, signal_id);
1380 if (GTK_RUN_TYPE (signal->signal_flags) != GTK_RUN_LAST && signal->function_offset != 0)
1382 signal_func_offset = (guchar**) ((guchar*) object->klass +
1383 signal->function_offset);
1384 if (*signal_func_offset)
1385 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1389 if (GTK_OBJECT_CONNECTED (object))
1391 handlers = gtk_signal_get_handlers (object, signal_id);
1394 info.object = object;
1395 info.marshaller = signal->marshaller;
1396 info.params = params;
1397 info.param_types = signal->params;
1398 info.return_val = signal->return_val;
1399 info.nparams = signal->nparams;
1400 info.signal_flags = signal->signal_flags;
1401 info.signal_id = signal_id;
1403 switch (gtk_handlers_run (handlers, &info, FALSE))
1405 case EMISSION_CONTINUE:
1407 case EMISSION_RESTART:
1408 goto emission_restart;
1419 if (GTK_RUN_TYPE (signal->signal_flags) != GTK_RUN_FIRST && signal->function_offset != 0)
1421 signal_func_offset = (guchar**) ((guchar*) object->klass +
1422 signal->function_offset);
1423 if (*signal_func_offset)
1424 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1428 if (GTK_OBJECT_CONNECTED (object))
1430 handlers = gtk_signal_get_handlers (object, signal_id);
1435 info.object = object;
1436 info.marshaller = signal->marshaller;
1437 info.params = params;
1438 info.param_types = signal->params;
1439 info.return_val = signal->return_val;
1440 info.nparams = signal->nparams;
1441 info.signal_flags = signal->signal_flags;
1442 info.signal_id = signal_id;
1444 switch (gtk_handlers_run (handlers, &info, TRUE))
1446 case EMISSION_CONTINUE:
1448 case EMISSION_RESTART:
1449 goto emission_restart;
1458 gtk_emission_remove (¤t_emissions, object, signal_id);
1460 if (signal->signal_flags & GTK_RUN_NO_RECURSE)
1461 gtk_emission_remove (&restart_emissions, object, signal_id);
1463 gtk_object_unref (object);
1467 gtk_signal_get_handlers (GtkObject *object,
1470 GtkHandler *handlers;
1472 handlers = gtk_object_get_data_by_id (object, handler_key_id);
1476 if (handlers->signal_id == signal_id)
1478 handlers = handlers->next;
1485 gtk_signal_handler_pending (GtkObject *object,
1487 gboolean may_be_blocked)
1489 GtkHandler *handlers;
1492 g_return_val_if_fail (object != NULL, 0);
1493 g_return_val_if_fail (signal_id >= 1, 0);
1495 if (GTK_OBJECT_CONNECTED (object))
1496 handlers = gtk_signal_get_handlers (object, signal_id);
1501 while (handlers && handlers->signal_id == signal_id)
1503 if (handlers->id > 0 &&
1504 (may_be_blocked || handlers->blocked == 0))
1506 handler_id = handlers->id;
1510 handlers = handlers->next;
1517 gtk_signal_connect_by_type (GtkObject *object,
1521 GtkSignalDestroy destroy_func,
1526 GtkObjectClass *class;
1527 GtkHandler *handler;
1530 g_return_val_if_fail (object != NULL, 0);
1531 g_return_val_if_fail (object->klass != NULL, 0);
1533 /* Search through the signals for this object and make
1534 * sure the one we are adding is valid. We need to perform
1535 * the lookup on the objects parents as well. If it isn't
1536 * valid then issue a warning and return.
1537 * As of now (1998-05-27) this lookup shouldn't be neccessarry
1538 * anymore since gtk_signal_lookup() has been reworked to only
1539 * return correct signal ids per class-branch.
1542 class = object->klass;
1546 guint *object_signals;
1550 object_signals = class->signals;
1551 nsignals = class->nsignals;
1553 for (i = 0; i < nsignals; i++)
1554 if (object_signals[i] == signal_id)
1560 parent = gtk_type_parent (class->type);
1562 class = gtk_type_class (parent);
1569 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1571 gtk_type_name (object->klass->type));
1575 handler = gtk_signal_handler_new ();
1576 handler->id = gtk_handler_id++;
1577 handler->signal_id = signal_id;
1578 handler->object_signal = object_signal;
1579 handler->func = func;
1580 handler->func_data = func_data;
1581 handler->destroy_func = destroy_func;
1582 handler->after = after != FALSE;
1583 handler->no_marshal = no_marshal;
1585 gtk_signal_handler_insert (object, handler);
1590 gtk_emission_new (void)
1592 GtkEmission *emission;
1594 if (!gtk_emission_free_list)
1596 GtkEmissionAllocator *emission_block;
1599 emission_block = g_new0 (GtkEmissionAllocator, EMISSION_BLOCK_SIZE);
1600 for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1602 (emission_block + i)->next = gtk_emission_free_list;
1603 gtk_emission_free_list = (emission_block + i);
1606 emission = &emission_block->emission;
1610 emission = >k_emission_free_list->emission;
1611 gtk_emission_free_list = gtk_emission_free_list->next;
1614 emission->object = NULL;
1615 emission->signal_id = 0;
1621 gtk_emission_add (GList **emissions,
1625 GtkEmission *emission;
1627 g_return_if_fail (emissions != NULL);
1628 g_return_if_fail (object != NULL);
1630 emission = gtk_emission_new ();
1631 emission->object = object;
1632 emission->signal_id = signal_id;
1634 *emissions = g_list_prepend (*emissions, emission);
1638 gtk_emission_remove (GList **emissions,
1644 g_return_if_fail (emissions != NULL);
1649 GtkEmissionAllocator *ea;
1653 if ((ea->emission.object == object) &&
1654 (ea->emission.signal_id == signal_id))
1656 *emissions = g_list_remove_link (*emissions, tmp);
1659 ea->next = gtk_emission_free_list;
1660 gtk_emission_free_list = ea;
1669 gtk_emission_check (GList *emissions,
1673 GtkEmission *emission;
1679 emission = tmp->data;
1682 if ((emission->object == object) &&
1683 (emission->signal_id == signal_id))
1690 gtk_handlers_run (GtkHandler *handlers,
1691 GtkHandlerInfo *info,
1694 while (handlers && handlers->signal_id == info->signal_id)
1696 GtkHandler *handlers_next;
1698 gtk_signal_handler_ref (handlers);
1700 if (handlers->blocked == 0 && (handlers->after == after))
1704 if (handlers->no_marshal)
1705 (* (GtkCallbackMarshal) handlers->func) (info->object,
1706 handlers->func_data,
1709 else if (handlers->object_signal)
1710 (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
1712 handlers->func_data,
1715 (* info->marshaller) (info->object,
1717 handlers->func_data,
1720 else if (global_marshaller)
1721 (* global_marshaller) (info->object,
1722 handlers->func_data,
1728 if (gtk_emission_check (stop_emissions, info->object,
1731 gtk_emission_remove (&stop_emissions, info->object,
1734 if (info->signal_flags & GTK_RUN_NO_RECURSE)
1735 gtk_emission_remove (&restart_emissions, info->object,
1737 gtk_signal_handler_unref (handlers, info->object);
1738 return EMISSION_DONE;
1740 else if ((info->signal_flags & GTK_RUN_NO_RECURSE) &&
1741 gtk_emission_check (restart_emissions, info->object,
1744 gtk_emission_remove (&restart_emissions, info->object,
1746 gtk_signal_handler_unref (handlers, info->object);
1747 return EMISSION_RESTART;
1751 handlers_next = handlers->next;
1752 gtk_signal_handler_unref (handlers, info->object);
1753 handlers = handlers_next;
1756 return EMISSION_CONTINUE;
1760 gtk_params_get (GtkArg *params,
1762 GtkType *param_types,
1768 for (i = 0; i < nparams; i++)
1770 params[i].type = param_types[i];
1771 params[i].name = NULL;
1773 switch (GTK_FUNDAMENTAL_TYPE (param_types[i]))
1775 case GTK_TYPE_INVALID:
1780 GTK_VALUE_CHAR(params[i]) = va_arg (args, gint);
1783 GTK_VALUE_BOOL(params[i]) = va_arg (args, gint);
1786 GTK_VALUE_INT(params[i]) = va_arg (args, gint);
1789 GTK_VALUE_UINT(params[i]) = va_arg (args, guint);
1792 GTK_VALUE_ENUM(params[i]) = va_arg (args, gint);
1794 case GTK_TYPE_FLAGS:
1795 GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint);
1798 GTK_VALUE_LONG(params[i]) = va_arg (args, glong);
1800 case GTK_TYPE_ULONG:
1801 GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong);
1803 case GTK_TYPE_FLOAT:
1804 GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat);
1806 case GTK_TYPE_DOUBLE:
1807 GTK_VALUE_DOUBLE(params[i]) = va_arg (args, gdouble);
1809 case GTK_TYPE_STRING:
1810 GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*);
1812 case GTK_TYPE_POINTER:
1813 GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer);
1815 case GTK_TYPE_BOXED:
1816 GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer);
1818 case GTK_TYPE_SIGNAL:
1819 GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction);
1820 GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer);
1822 case GTK_TYPE_FOREIGN:
1823 GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer);
1824 GTK_VALUE_FOREIGN(params[i]).notify =
1825 va_arg (args, GtkDestroyNotify);
1827 case GTK_TYPE_CALLBACK:
1828 GTK_VALUE_CALLBACK(params[i]).marshal =
1829 va_arg (args, GtkCallbackMarshal);
1830 GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer);
1831 GTK_VALUE_CALLBACK(params[i]).notify =
1832 va_arg (args, GtkDestroyNotify);
1834 case GTK_TYPE_C_CALLBACK:
1835 GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction);
1836 GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer);
1839 GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, gint);
1840 GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*);
1842 case GTK_TYPE_OBJECT:
1843 GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*);
1844 if (GTK_VALUE_OBJECT(params[i]) != NULL &&
1845 !GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]), params[i].type))
1846 g_warning ("signal arg `%s' is not of type `%s'",
1847 gtk_type_name (GTK_OBJECT_TYPE (GTK_VALUE_OBJECT(params[i]))),
1848 gtk_type_name (params[i].type));
1851 g_error ("unsupported type `%s' in signal arg",
1852 gtk_type_name (params[i].type));
1857 params[i].type = return_val;
1858 params[i].name = NULL;
1860 switch (GTK_FUNDAMENTAL_TYPE (return_val))
1862 case GTK_TYPE_INVALID:
1867 params[i].d.pointer_data = va_arg (args, gchar*);
1870 params[i].d.pointer_data = va_arg (args, gint*);
1873 params[i].d.pointer_data = va_arg (args, gint*);
1876 params[i].d.pointer_data = va_arg (args, guint*);
1879 params[i].d.pointer_data = va_arg (args, gint*);
1881 case GTK_TYPE_FLAGS:
1882 params[i].d.pointer_data = va_arg (args, gint*);
1885 params[i].d.pointer_data = va_arg (args, glong*);
1887 case GTK_TYPE_ULONG:
1888 params[i].d.pointer_data = va_arg (args, gulong*);
1890 case GTK_TYPE_FLOAT:
1891 params[i].d.pointer_data = va_arg (args, gfloat*);
1893 case GTK_TYPE_DOUBLE:
1894 params[i].d.pointer_data = va_arg (args, gdouble*);
1896 case GTK_TYPE_STRING:
1897 params[i].d.pointer_data = va_arg (args, gchar**);
1899 case GTK_TYPE_POINTER:
1900 params[i].d.pointer_data = va_arg (args, gpointer*);
1902 case GTK_TYPE_BOXED:
1903 params[i].d.pointer_data = va_arg (args, gpointer*);
1905 case GTK_TYPE_OBJECT:
1906 params[i].d.pointer_data = va_arg (args, GtkObject**);
1908 case GTK_TYPE_SIGNAL:
1909 case GTK_TYPE_FOREIGN:
1910 case GTK_TYPE_CALLBACK:
1911 case GTK_TYPE_C_CALLBACK:
1914 g_error ("Gtk: unsupported type `%s' in signal return",
1915 gtk_type_name (return_val));