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.
21 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gtksignal.h"
31 #include "gtkargcollector.c"
34 #define SIGNAL_BLOCK_SIZE (100)
35 #define HANDLER_BLOCK_SIZE (200)
36 #define EMISSION_BLOCK_SIZE (100)
37 #define DISCONNECT_INFO_BLOCK_SIZE (64)
38 #define MAX_SIGNAL_PARAMS (31)
47 #define GTK_RUN_TYPE(x) ((x) & GTK_RUN_BOTH)
50 typedef struct _GtkSignal GtkSignal;
51 typedef struct _GtkSignalHash GtkSignalHash;
52 typedef struct _GtkHandler GtkHandler;
53 typedef struct _GtkEmission GtkEmission;
54 typedef struct _GtkEmissionHookData GtkEmissionHookData;
55 typedef struct _GtkDisconnectInfo GtkDisconnectInfo;
57 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
65 guint function_offset;
66 GtkSignalMarshaller marshaller;
68 guint signal_flags : 16;
85 guint object_signal : 1;
92 GtkSignalDestroy destroy_func;
105 struct _GtkEmissionHookData
113 struct _GtkDisconnectInfo
116 guint disconnect_handler1;
117 guint signal_handler;
119 guint disconnect_handler2;
123 static guint gtk_signal_hash (gconstpointer h);
124 static gint gtk_signal_compare (gconstpointer h1,
126 static GtkHandler* gtk_signal_handler_new (void);
127 static void gtk_signal_handler_ref (GtkHandler *handler);
128 static void gtk_signal_handler_unref (GtkHandler *handler,
130 static void gtk_signal_handler_insert (GtkObject *object,
131 GtkHandler *handler);
132 static void gtk_signal_real_emit (GtkObject *object,
135 static GtkHandler* gtk_signal_get_handlers (GtkObject *object,
137 static guint gtk_signal_connect_by_type (GtkObject *object,
141 GtkSignalDestroy destroy_func,
145 static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);
146 static GtkEmission* gtk_emission_new (void);
147 static void gtk_emission_add (GtkEmission **emissions,
150 static void gtk_emission_remove (GtkEmission **emissions,
153 static gint gtk_emission_check (GtkEmission *emissions,
156 static gint gtk_handlers_run (GtkHandler *handlers,
161 static gboolean gtk_emission_hook_marshaller (GHook *hook,
163 static gboolean gtk_signal_collect_params (GtkArg *params,
165 GtkType *param_types,
169 #define LOOKUP_SIGNAL_ID(signal_id) ( \
170 signal_id > 0 && signal_id < gtk_n_signals ? \
171 (GtkSignal*) gtk_signals + signal_id : \
176 static GtkSignalMarshal global_marshaller = NULL;
177 static GtkSignalDestroy global_destroy_notify = NULL;
179 static guint gtk_handler_id = 1;
180 static guint handler_quark = 0;
181 static GHashTable *gtk_signal_hash_table = NULL;
182 static GtkSignal *gtk_signals = NULL;
183 static guint gtk_n_signals = 0;
184 static GMemChunk *gtk_signal_hash_mem_chunk = NULL;
185 static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;
186 static GtkHandler *gtk_handler_free_list = NULL;
187 static GtkEmission *gtk_free_emissions = NULL;
191 static GtkEmission *current_emissions = NULL;
192 static GtkEmission *stop_emissions = NULL;
193 static GtkEmission *restart_emissions = NULL;
196 gtk_signal_next_and_invalidate (void)
198 static guint gtk_n_free_signals = 0;
199 register GtkSignal *signal;
200 register guint new_signal_id;
202 /* don't keep *any* GtkSignal pointers across invokation of this function!!!
205 if (gtk_n_free_signals == 0)
212 size = gtk_n_signals + SIGNAL_BLOCK_SIZE;
213 size *= sizeof (GtkSignal);
219 gtk_signals = g_realloc (gtk_signals, size);
221 gtk_n_free_signals = size / sizeof (GtkSignal) - gtk_n_signals;
223 memset (gtk_signals + gtk_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
226 new_signal_id = gtk_n_signals++;
227 gtk_n_free_signals--;
229 g_assert (gtk_n_signals < 65535);
231 signal = LOOKUP_SIGNAL_ID (new_signal_id);
233 signal->signal_id = new_signal_id;
239 gtk_signal_init (void)
245 zero = gtk_signal_next_and_invalidate ();
246 g_assert (zero == NULL);
248 handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
250 gtk_signal_hash_mem_chunk =
251 g_mem_chunk_new ("GtkSignalHash mem chunk",
252 sizeof (GtkSignalHash),
253 sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
255 gtk_disconnect_info_mem_chunk =
256 g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
257 sizeof (GtkDisconnectInfo),
258 sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
260 gtk_handler_free_list = NULL;
261 gtk_free_emissions = NULL;
263 gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
269 gtk_signal_newv (const gchar *r_name,
270 GtkSignalRunType signal_flags,
272 guint function_offset,
273 GtkSignalMarshaller marshaller,
284 g_return_val_if_fail (r_name != NULL, 0);
285 g_return_val_if_fail (marshaller != NULL, 0);
286 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
288 g_return_val_if_fail (params != NULL, 0);
294 name = g_strdup (r_name);
295 g_strdelimit (name, NULL, '_');
297 quark = gtk_signal_lookup (name, object_type);
300 g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
302 gtk_type_name (object_type));
307 if (return_val != GTK_TYPE_NONE &&
308 (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
310 g_warning ("gtk_signal_newv(): signal \"%s\" - return value `%s' incompatible with GTK_RUN_FIRST",
311 name, gtk_type_name (return_val));
316 signal = gtk_signal_next_and_invalidate ();
318 /* signal->signal_id already set */
320 signal->object_type = object_type;
322 signal->function_offset = function_offset;
323 signal->marshaller = marshaller;
324 signal->return_val = return_val;
325 signal->signal_flags = signal_flags;
326 signal->nparams = nparams;
327 signal->hook_list = NULL;
331 signal->params = g_new (GtkType, nparams);
333 for (i = 0; i < nparams; i++)
334 signal->params[i] = params[i];
337 signal->params = NULL;
339 /* insert "signal_name" into hash table
341 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
342 hash->object_type = object_type;
343 hash->quark = g_quark_from_string (signal->name);
344 hash->signal_id = signal->signal_id;
345 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
347 /* insert "signal-name" into hash table
349 g_strdelimit (signal->name, NULL, '-');
350 quark = g_quark_from_static_string (signal->name);
351 if (quark != hash->quark)
353 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
354 hash->object_type = object_type;
356 hash->signal_id = signal->signal_id;
357 g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
360 return signal->signal_id;
364 gtk_signal_new (const gchar *name,
365 GtkSignalRunType signal_flags,
367 guint function_offset,
368 GtkSignalMarshaller marshaller,
378 g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
382 params = g_new (GtkType, nparams);
384 va_start (args, nparams);
386 for (i = 0; i < nparams; i++)
387 params[i] = va_arg (args, GtkType);
394 signal_id = gtk_signal_newv (name,
409 gtk_signal_lookup (const gchar *name,
414 gpointer class = NULL;
416 g_return_val_if_fail (name != NULL, 0);
417 g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0);
421 lookup_type = object_type;
422 hash.quark = g_quark_try_string (name);
429 hash.object_type = lookup_type;
431 signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
435 lookup_type = gtk_type_parent (lookup_type);
441 class = gtk_type_class (object_type);
449 gtk_signal_query (guint signal_id)
451 GtkSignalQuery *query;
454 g_return_val_if_fail (signal_id >= 1, NULL);
456 signal = LOOKUP_SIGNAL_ID (signal_id);
459 query = g_new (GtkSignalQuery, 1);
461 query->object_type = signal->object_type;
462 query->signal_id = signal_id;
463 query->signal_name = signal->name;
464 query->is_user_signal = signal->function_offset == 0;
465 query->signal_flags = signal->signal_flags;
466 query->return_val = signal->return_val;
467 query->nparams = signal->nparams;
468 query->params = signal->params;
477 gtk_signal_name (guint signal_id)
481 g_return_val_if_fail (signal_id >= 1, NULL);
483 signal = LOOKUP_SIGNAL_ID (signal_id);
491 gtk_signal_emitv (GtkObject *object,
497 g_return_if_fail (object != NULL);
498 g_return_if_fail (signal_id >= 1);
500 signal = LOOKUP_SIGNAL_ID (signal_id);
501 g_return_if_fail (signal != NULL);
502 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
504 if (signal->nparams > 0)
505 g_return_if_fail (params != NULL);
507 gtk_signal_real_emit (object, signal_id, params);
511 gtk_signal_emit (GtkObject *object,
517 GtkArg params[MAX_SIGNAL_PARAMS + 1];
520 g_return_if_fail (object != NULL);
521 g_return_if_fail (signal_id >= 1);
523 signal = LOOKUP_SIGNAL_ID (signal_id);
524 g_return_if_fail (signal != NULL);
525 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
527 va_start (args, signal_id);
528 abort = gtk_signal_collect_params (params,
536 gtk_signal_real_emit (object, signal_id, params);
540 gtk_signal_emitv_by_name (GtkObject *object,
546 g_return_if_fail (object != NULL);
547 g_return_if_fail (name != NULL);
548 g_return_if_fail (params != NULL);
550 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
556 signal = LOOKUP_SIGNAL_ID (signal_id);
557 g_return_if_fail (signal != NULL);
558 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
560 gtk_signal_real_emit (object, signal_id, params);
564 g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
566 gtk_type_name (GTK_OBJECT_TYPE (object)));
571 gtk_signal_emit_by_name (GtkObject *object,
577 g_return_if_fail (object != NULL);
578 g_return_if_fail (name != NULL);
580 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
585 GtkArg params[MAX_SIGNAL_PARAMS + 1];
589 signal = LOOKUP_SIGNAL_ID (signal_id);
590 g_return_if_fail (signal != NULL);
591 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
593 va_start (args, name);
594 abort = gtk_signal_collect_params (params,
602 gtk_signal_real_emit (object, signal_id, params);
606 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
608 gtk_type_name (GTK_OBJECT_TYPE (object)));
613 gtk_signal_emit_stop (GtkObject *object,
618 g_return_if_fail (object != NULL);
619 g_return_if_fail (signal_id >= 1);
621 state = gtk_emission_check (current_emissions, object, signal_id);
623 g_warning ("gtk_signal_emit_stop(): emission (%u) for object `%s' cannot be stopped from emission hook",
625 gtk_type_name (GTK_OBJECT_TYPE (object)));
628 if (!gtk_emission_check (stop_emissions, object, signal_id))
629 gtk_emission_add (&stop_emissions, object, signal_id);
632 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
634 gtk_type_name (GTK_OBJECT_TYPE (object)));
638 gtk_signal_emit_stop_by_name (GtkObject *object,
643 g_return_if_fail (object != NULL);
644 g_return_if_fail (name != NULL);
646 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
648 gtk_signal_emit_stop (object, signal_id);
650 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
652 gtk_type_name (GTK_OBJECT_TYPE (object)));
656 gtk_signal_n_emissions (GtkObject *object,
659 GtkEmission *emission;
662 g_return_val_if_fail (object != NULL, 0);
663 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
666 for (emission = current_emissions; emission; emission = emission->next)
668 if (emission->object == object && emission->signal_id == signal_id)
676 gtk_signal_n_emissions_by_name (GtkObject *object,
682 g_return_val_if_fail (object != NULL, 0);
683 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
684 g_return_val_if_fail (name != NULL, 0);
686 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
688 n = gtk_signal_n_emissions (object, signal_id);
691 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
693 gtk_type_name (GTK_OBJECT_TYPE (object)));
701 gtk_signal_connect (GtkObject *object,
708 g_return_val_if_fail (object != NULL, 0);
709 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
711 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
714 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
716 gtk_type_name (GTK_OBJECT_TYPE (object)));
720 return gtk_signal_connect_by_type (object, signal_id,
721 func, func_data, NULL,
722 FALSE, FALSE, FALSE);
726 gtk_signal_connect_after (GtkObject *object,
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_after(): could not find signal \"%s\" in the `%s' class ancestry",
740 gtk_type_name (GTK_OBJECT_TYPE (object)));
744 return gtk_signal_connect_by_type (object, signal_id,
745 func, func_data, NULL,
750 gtk_signal_connect_full (GtkObject *object,
753 GtkCallbackMarshal marshal,
755 GtkDestroyNotify destroy_func,
761 g_return_val_if_fail (object != NULL, 0);
763 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
766 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
768 gtk_type_name (GTK_OBJECT_TYPE (object)));
773 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
774 func_data, destroy_func,
775 object_signal, after, TRUE);
777 return gtk_signal_connect_by_type (object, signal_id, func,
778 func_data, destroy_func,
779 object_signal, after, FALSE);
783 gtk_signal_connect_object (GtkObject *object,
786 GtkObject *slot_object)
790 g_return_val_if_fail (object != NULL, 0);
791 /* slot_object needs to be treated as ordinary pointer
794 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
797 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
799 gtk_type_name (GTK_OBJECT_TYPE (object)));
803 return gtk_signal_connect_by_type (object, signal_id,
804 func, slot_object, NULL,
809 gtk_signal_connect_object_after (GtkObject *object,
812 GtkObject *slot_object)
816 g_return_val_if_fail (object != NULL, 0);
818 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
821 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
823 gtk_type_name (GTK_OBJECT_TYPE (object)));
827 return gtk_signal_connect_by_type (object, signal_id,
828 func, slot_object, NULL,
833 gtk_signal_connect_while_alive (GtkObject *object,
837 GtkObject *alive_object)
839 GtkDisconnectInfo *info;
841 g_return_if_fail (object != NULL);
842 g_return_if_fail (GTK_IS_OBJECT (object));
843 g_return_if_fail (signal != NULL);
844 g_return_if_fail (func != NULL);
845 g_return_if_fail (alive_object != NULL);
846 g_return_if_fail (GTK_IS_OBJECT (alive_object));
848 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
849 info->object1 = object;
850 info->object2 = alive_object;
852 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
853 info->disconnect_handler1 =
854 gtk_signal_connect_object (info->object1,
856 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
858 info->disconnect_handler2 =
859 gtk_signal_connect_object (info->object2,
861 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
866 gtk_signal_connect_object_while_alive (GtkObject *object,
869 GtkObject *alive_object)
871 GtkDisconnectInfo *info;
873 g_return_if_fail (object != NULL);
874 g_return_if_fail (GTK_IS_OBJECT (object));
875 g_return_if_fail (signal != NULL);
876 g_return_if_fail (func != NULL);
877 g_return_if_fail (alive_object != NULL);
878 g_return_if_fail (GTK_IS_OBJECT (alive_object));
880 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
881 info->object1 = object;
882 info->object2 = alive_object;
884 info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
885 info->disconnect_handler1 =
886 gtk_signal_connect_object (info->object1,
888 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
890 info->disconnect_handler2 =
891 gtk_signal_connect_object (info->object2,
893 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
898 gtk_signal_disconnect (GtkObject *object,
903 g_return_if_fail (object != NULL);
904 g_return_if_fail (handler_id > 0);
906 handler = gtk_object_get_data_by_id (object, handler_quark);
910 if (handler->id == handler_id)
913 handler->blocked += 1;
914 gtk_signal_handler_unref (handler, object);
917 handler = handler->next;
920 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
924 gtk_signal_disconnect_by_func (GtkObject *object,
931 g_return_if_fail (object != NULL);
932 g_return_if_fail (func != NULL);
935 handler = gtk_object_get_data_by_id (object, handler_quark);
939 GtkHandler *handler_next;
941 handler_next = handler->next;
942 if ((handler->id > 0) &&
943 (handler->func == func) &&
944 (handler->func_data == data))
948 handler->blocked += 1;
949 gtk_signal_handler_unref (handler, object);
951 handler = handler_next;
955 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
959 gtk_signal_disconnect_by_data (GtkObject *object,
965 g_return_if_fail (object != NULL);
968 handler = gtk_object_get_data_by_id (object, handler_quark);
972 GtkHandler *handler_next;
974 handler_next = handler->next;
975 if ((handler->id > 0) &&
976 (handler->func_data == data))
980 handler->blocked += 1;
981 gtk_signal_handler_unref (handler, object);
983 handler = handler_next;
987 g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
991 gtk_signal_handler_block (GtkObject *object,
996 g_return_if_fail (object != NULL);
997 g_return_if_fail (handler_id > 0);
999 handler = gtk_object_get_data_by_id (object, handler_quark);
1003 if (handler->id == handler_id)
1005 handler->blocked += 1;
1008 handler = handler->next;
1011 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
1015 gtk_signal_handler_block_by_func (GtkObject *object,
1019 GtkHandler *handler;
1022 g_return_if_fail (object != NULL);
1023 g_return_if_fail (func != NULL);
1026 handler = gtk_object_get_data_by_id (object, handler_quark);
1030 if ((handler->id > 0) &&
1031 (handler->func == func) &&
1032 (handler->func_data == data))
1035 handler->blocked += 1;
1037 handler = handler->next;
1041 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1045 gtk_signal_handler_block_by_data (GtkObject *object,
1048 GtkHandler *handler;
1051 g_return_if_fail (object != NULL);
1054 handler = gtk_object_get_data_by_id (object, handler_quark);
1058 if ((handler->id > 0) &&
1059 (handler->func_data == data))
1062 handler->blocked += 1;
1064 handler = handler->next;
1068 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1072 gtk_signal_handler_unblock (GtkObject *object,
1075 GtkHandler *handler;
1077 g_return_if_fail (object != NULL);
1078 g_return_if_fail (handler_id > 0);
1080 handler = gtk_object_get_data_by_id (object, handler_quark);
1084 if (handler->id == handler_id)
1086 if (handler->blocked > 0)
1087 handler->blocked -= 1;
1089 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1092 handler = handler->next;
1095 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1099 gtk_signal_handler_unblock_by_func (GtkObject *object,
1103 GtkHandler *handler;
1106 g_return_if_fail (object != NULL);
1107 g_return_if_fail (func != NULL);
1110 handler = gtk_object_get_data_by_id (object, handler_quark);
1114 if ((handler->id > 0) &&
1115 (handler->func == func) &&
1116 (handler->func_data == data) &&
1117 (handler->blocked > 0))
1119 handler->blocked -= 1;
1122 handler = handler->next;
1126 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1130 gtk_signal_handler_unblock_by_data (GtkObject *object,
1133 GtkHandler *handler;
1136 g_return_if_fail (object != NULL);
1139 handler = gtk_object_get_data_by_id (object, handler_quark);
1143 if ((handler->id > 0) &&
1144 (handler->func_data == data) &&
1145 (handler->blocked > 0))
1147 handler->blocked -= 1;
1150 handler = handler->next;
1154 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1158 gtk_signal_handlers_destroy (GtkObject *object)
1160 GtkHandler *handler;
1162 /* we make the "optimization" of destroying the first handler in the last
1163 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1164 * handler_key data on each removal
1167 handler = gtk_object_get_data_by_id (object, handler_quark);
1170 handler = handler->next;
1175 next = handler->next;
1176 if (handler->id > 0)
1177 gtk_signal_handler_unref (handler, object);
1180 handler = gtk_object_get_data_by_id (object, handler_quark);
1181 if (handler->id > 0)
1182 gtk_signal_handler_unref (handler, object);
1187 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1188 GtkSignalDestroy destroy_func)
1190 global_marshaller = marshal_func;
1191 global_destroy_notify = destroy_func;
1195 gtk_signal_hash (gconstpointer h)
1197 register const GtkSignalHash *hash = h;
1199 return hash->object_type ^ hash->quark;
1203 gtk_signal_compare (gconstpointer h1,
1206 register const GtkSignalHash *hash1 = h1;
1207 register const GtkSignalHash *hash2 = h2;
1209 return (hash1->quark == hash2->quark &&
1210 hash1->object_type == hash2->object_type);
1214 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1216 g_return_val_if_fail (info != NULL, 0);
1218 gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1219 gtk_signal_disconnect (info->object1, info->signal_handler);
1220 gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1222 g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1228 gtk_signal_handler_new (void)
1230 GtkHandler *handler;
1232 if (!gtk_handler_free_list)
1234 GtkHandler *handler_block;
1237 handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1238 for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1240 (handler_block + i)->next = gtk_handler_free_list;
1241 gtk_handler_free_list = (handler_block + i);
1244 handler = handler_block;
1248 handler = gtk_handler_free_list;
1249 gtk_handler_free_list = handler->next;
1253 handler->blocked = 0;
1254 handler->signal_id = 0;
1255 handler->object_signal = FALSE;
1256 handler->after = FALSE;
1257 handler->no_marshal = FALSE;
1258 handler->ref_count = 1;
1259 handler->func = NULL;
1260 handler->func_data = NULL;
1261 handler->destroy_func = NULL;
1262 handler->prev = NULL;
1263 handler->next = NULL;
1269 gtk_signal_handler_ref (GtkHandler *handler)
1271 handler->ref_count += 1;
1275 gtk_signal_handler_unref (GtkHandler *handler,
1278 if (!handler->ref_count)
1280 /* FIXME: i wanna get removed somewhen */
1281 g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1285 handler->ref_count -= 1;
1287 if (handler->ref_count == 0)
1289 if (handler->destroy_func)
1290 (* handler->destroy_func) (handler->func_data);
1291 else if (!handler->func && global_destroy_notify)
1292 (* global_destroy_notify) (handler->func_data);
1295 handler->prev->next = handler->next;
1296 else if (handler->next)
1297 gtk_object_set_data_by_id (object, handler_quark, handler->next);
1300 GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1301 gtk_object_set_data_by_id (object, handler_quark, NULL);
1304 handler->next->prev = handler->prev;
1306 handler->next = gtk_handler_free_list;
1307 gtk_handler_free_list = handler;
1312 gtk_signal_handler_insert (GtkObject *object,
1313 GtkHandler *handler)
1317 /* FIXME: remove */ g_assert (handler->next == NULL);
1318 /* FIXME: remove */ g_assert (handler->prev == NULL);
1320 tmp = gtk_object_get_data_by_id (object, handler_quark);
1323 GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1324 gtk_object_set_data_by_id (object, handler_quark, handler);
1329 if (tmp->signal_id < handler->signal_id)
1333 tmp->prev->next = handler;
1334 handler->prev = tmp->prev;
1337 gtk_object_set_data_by_id (object, handler_quark, handler);
1338 tmp->prev = handler;
1339 handler->next = tmp;
1345 tmp->next = handler;
1346 handler->prev = tmp;
1354 #ifdef G_ENABLE_DEBUG
1355 /* value typically set via gdb */
1356 static GtkObject *gtk_trace_signal_object = NULL;
1357 #endif /* G_ENABLE_DEBUG */
1361 gtk_signal_real_emit (GtkObject *object,
1366 GtkHandler *handlers;
1367 GtkSignalFunc signal_func;
1368 GtkEmission *emission;
1370 /* gtk_handlers_run() expects a reentrant GtkSignal*, so we allocate
1371 * it locally on the stack. we save some lookups ourselves with this as well.
1373 signal = *LOOKUP_SIGNAL_ID (signal_id);
1374 if (signal.function_offset)
1375 signal_func = G_STRUCT_MEMBER (GtkSignalFunc, object->klass, signal.function_offset);
1379 #ifdef G_ENABLE_DEBUG
1380 if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1381 object == gtk_trace_signal_object)
1382 g_message ("%s::%s emitted (object=%p class-method=%p)\n",
1383 gtk_type_name (GTK_OBJECT_TYPE (object)),
1387 #endif /* G_ENABLE_DEBUG */
1389 if (signal.signal_flags & GTK_RUN_NO_RECURSE)
1393 state = gtk_emission_check (current_emissions, object, signal_id);
1397 g_warning ("gtk_signal_real_emit(): emission (%u) for object `%s' cannot be restarted from emission hook",
1399 gtk_type_name (GTK_OBJECT_TYPE (object)));
1400 else if (!gtk_emission_check (restart_emissions, object, signal_id))
1401 gtk_emission_add (&restart_emissions, object, signal_id);
1407 gtk_object_ref (object);
1409 gtk_emission_add (¤t_emissions, object, signal_id);
1410 emission = current_emissions;
1414 if (signal.signal_flags & GTK_RUN_FIRST && signal_func)
1416 signal.marshaller (object, signal_func, NULL, params);
1418 if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1420 gtk_emission_remove (&stop_emissions, object, signal_id);
1423 else if (restart_emissions &&
1424 signal.signal_flags & GTK_RUN_NO_RECURSE &&
1425 gtk_emission_check (restart_emissions, object, signal_id))
1427 gtk_emission_remove (&restart_emissions, object, signal_id);
1429 goto emission_restart;
1433 if (signal.hook_list && !GTK_OBJECT_DESTROYED (object))
1435 GtkEmissionHookData data;
1437 data.object = object;
1438 data.n_params = signal.nparams;
1439 data.params = params;
1440 data.signal_id = signal_id;
1441 emission->in_hook = 1;
1442 g_hook_list_marshal_check (signal.hook_list, TRUE, gtk_emission_hook_marshaller, &data);
1443 emission->in_hook = 0;
1446 if (GTK_OBJECT_CONNECTED (object))
1448 handlers = gtk_signal_get_handlers (object, signal_id);
1453 return_val = gtk_handlers_run (handlers, &signal, object, params, FALSE);
1456 case EMISSION_CONTINUE:
1458 case EMISSION_RESTART:
1459 goto emission_restart;
1466 if (signal.signal_flags & GTK_RUN_LAST && signal_func)
1468 signal.marshaller (object, signal_func, NULL, params);
1470 if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1472 gtk_emission_remove (&stop_emissions, object, signal_id);
1475 else if (restart_emissions &&
1476 signal.signal_flags & GTK_RUN_NO_RECURSE &&
1477 gtk_emission_check (restart_emissions, object, signal_id))
1479 gtk_emission_remove (&restart_emissions, object, signal_id);
1481 goto emission_restart;
1485 if (GTK_OBJECT_CONNECTED (object))
1487 handlers = gtk_signal_get_handlers (object, signal_id);
1492 return_val = gtk_handlers_run (handlers, &signal, object, params, TRUE);
1495 case EMISSION_CONTINUE:
1497 case EMISSION_RESTART:
1498 goto emission_restart;
1506 if (restart_emissions && signal.signal_flags & GTK_RUN_NO_RECURSE)
1507 gtk_emission_remove (&restart_emissions, object, signal_id);
1509 gtk_emission_remove (¤t_emissions, object, signal_id);
1511 gtk_object_unref (object);
1515 gtk_signal_get_handlers (GtkObject *object,
1518 GtkHandler *handlers;
1520 handlers = gtk_object_get_data_by_id (object, handler_quark);
1524 if (handlers->signal_id == signal_id)
1526 handlers = handlers->next;
1533 gtk_signal_handler_pending (GtkObject *object,
1535 gboolean may_be_blocked)
1537 GtkHandler *handlers;
1540 g_return_val_if_fail (object != NULL, 0);
1541 g_return_val_if_fail (signal_id >= 1, 0);
1543 if (GTK_OBJECT_CONNECTED (object))
1544 handlers = gtk_signal_get_handlers (object, signal_id);
1549 while (handlers && handlers->signal_id == signal_id)
1551 if (handlers->id > 0 &&
1552 (may_be_blocked || handlers->blocked == FALSE))
1554 handler_id = handlers->id;
1558 handlers = handlers->next;
1565 gtk_signal_handler_pending_by_func (GtkObject *object,
1567 gboolean may_be_blocked,
1571 GtkHandler *handlers;
1574 g_return_val_if_fail (object != NULL, 0);
1575 g_return_val_if_fail (func != NULL, 0);
1576 g_return_val_if_fail (signal_id >= 1, 0);
1578 if (GTK_OBJECT_CONNECTED (object))
1579 handlers = gtk_signal_get_handlers (object, signal_id);
1584 while (handlers && handlers->signal_id == signal_id)
1586 if (handlers->id > 0 &&
1587 handlers->func == func &&
1588 handlers->func_data == data &&
1589 (may_be_blocked || handlers->blocked == FALSE))
1591 handler_id = handlers->id;
1595 handlers = handlers->next;
1602 gtk_signal_add_emission_hook (guint signal_id,
1603 GtkEmissionHook hook_func,
1606 return gtk_signal_add_emission_hook_full (signal_id, hook_func, data, NULL);
1610 gtk_signal_add_emission_hook_full (guint signal_id,
1611 GtkEmissionHook hook_func,
1613 GDestroyNotify destroy)
1615 static guint seq_hook_id = 1;
1619 g_return_val_if_fail (signal_id > 0, 0);
1620 g_return_val_if_fail (hook_func != NULL, 0);
1622 signal = LOOKUP_SIGNAL_ID (signal_id);
1623 g_return_val_if_fail (signal != NULL, 0);
1624 if (signal->signal_flags & GTK_RUN_NO_HOOKS)
1626 g_warning ("gtk_signal_add_emission_hook_full(): signal \"%s\" does not support emission hooks",
1631 if (!signal->hook_list)
1633 signal->hook_list = g_new (GHookList, 1);
1634 g_hook_list_init (signal->hook_list, sizeof (GHook));
1637 hook = g_hook_alloc (signal->hook_list);
1639 hook->func = hook_func;
1640 hook->destroy = destroy;
1642 signal->hook_list->seq_id = seq_hook_id;
1643 g_hook_prepend (signal->hook_list, hook);
1644 seq_hook_id = signal->hook_list->seq_id;
1646 return hook->hook_id;
1650 gtk_signal_remove_emission_hook (guint signal_id,
1655 g_return_if_fail (signal_id > 0);
1656 g_return_if_fail (hook_id > 0);
1658 signal = LOOKUP_SIGNAL_ID (signal_id);
1659 g_return_if_fail (signal != NULL);
1661 if (!signal->hook_list || !g_hook_destroy (signal->hook_list, hook_id))
1662 g_warning ("gtk_signal_remove_emission_hook(): could not find hook (%u)", hook_id);
1666 gtk_emission_hook_marshaller (GHook *hook,
1669 GtkEmissionHookData *data = data_p;
1670 GtkEmissionHook func;
1674 if (!GTK_OBJECT_DESTROYED (data->object))
1675 return func (data->object, data->signal_id,
1676 data->n_params, data->params,
1683 gtk_signal_connect_by_type (GtkObject *object,
1687 GtkSignalDestroy destroy_func,
1692 GtkObjectClass *class;
1693 GtkHandler *handler;
1697 g_return_val_if_fail (object != NULL, 0);
1698 g_return_val_if_fail (object->klass != NULL, 0);
1700 signal = LOOKUP_SIGNAL_ID (signal_id);
1702 /* Search through the signals for this object and make
1703 * sure the one we are adding is valid. We need to perform
1704 * the lookup on the objects parents as well. If it isn't
1705 * valid then issue a warning and return.
1706 * As of now (1998-05-27) this lookup shouldn't be neccessarry
1707 * anymore since gtk_signal_lookup() has been reworked to only
1708 * return correct signal ids per class-branch.
1711 class = object->klass;
1715 guint *object_signals;
1719 object_signals = class->signals;
1720 nsignals = class->nsignals;
1722 for (i = 0; i < nsignals; i++)
1723 if (object_signals[i] == signal_id)
1729 parent = gtk_type_parent (class->type);
1731 class = gtk_type_class (parent);
1738 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1740 gtk_type_name (object->klass->type));
1744 handler = gtk_signal_handler_new ();
1745 handler->id = gtk_handler_id++;
1746 handler->signal_id = signal_id;
1747 handler->object_signal = object_signal;
1748 handler->func = func;
1749 handler->func_data = func_data;
1750 handler->destroy_func = destroy_func;
1751 handler->after = after != FALSE;
1752 handler->no_marshal = no_marshal;
1754 gtk_signal_handler_insert (object, handler);
1759 gtk_emission_new (void)
1761 GtkEmission *emission;
1763 if (!gtk_free_emissions)
1765 GtkEmission *emission_block;
1768 emission_block = g_new0 (GtkEmission, EMISSION_BLOCK_SIZE);
1769 for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1771 (emission_block + i)->next = gtk_free_emissions;
1772 gtk_free_emissions = (emission_block + i);
1775 emission = emission_block;
1779 emission = gtk_free_emissions;
1780 gtk_free_emissions = emission->next;
1783 emission->object = NULL;
1784 emission->signal_id = 0;
1785 emission->in_hook = 0;
1786 emission->next = NULL;
1792 gtk_emission_add (GtkEmission **emissions,
1796 GtkEmission *emission;
1798 g_return_if_fail (emissions != NULL);
1799 g_return_if_fail (object != NULL);
1801 emission = gtk_emission_new ();
1802 emission->object = object;
1803 emission->signal_id = signal_id;
1805 emission->next = *emissions;
1806 *emissions = emission;
1810 gtk_emission_remove (GtkEmission **emissions,
1814 GtkEmission *emission, *last;
1816 g_return_if_fail (emissions != NULL);
1819 emission = *emissions;
1822 if (emission->object == object && emission->signal_id == signal_id)
1825 last->next = emission->next;
1827 *emissions = emission->next;
1829 emission->next = gtk_free_emissions;
1830 gtk_free_emissions = emission;
1835 emission = last->next;
1840 gtk_emission_check (GtkEmission *emission,
1846 if (emission->object == object && emission->signal_id == signal_id)
1847 return 1 + emission->in_hook;
1848 emission = emission->next;
1854 gtk_handlers_run (GtkHandler *handlers,
1860 /* *signal is a local copy on the stack of gtk_signal_real_emit(),
1861 * so we don't need to look it up every time we invoked a function.
1863 while (handlers && handlers->signal_id == signal->signal_id)
1865 GtkHandler *handlers_next;
1867 gtk_signal_handler_ref (handlers);
1869 if (!handlers->blocked && handlers->after == after)
1873 if (handlers->no_marshal)
1874 (* (GtkCallbackMarshal) handlers->func) (object,
1875 handlers->func_data,
1878 else if (handlers->object_signal)
1879 /* don't cast with GTK_OBJECT () */
1880 (* signal->marshaller) ((GtkObject*) handlers->func_data,
1885 (* signal->marshaller) (object,
1887 handlers->func_data,
1890 else if (global_marshaller)
1891 (* global_marshaller) (object,
1892 handlers->func_data,
1896 signal->return_val);
1898 if (stop_emissions && gtk_emission_check (stop_emissions,
1902 gtk_emission_remove (&stop_emissions, object, signal->signal_id);
1904 gtk_signal_handler_unref (handlers, object);
1906 return EMISSION_DONE;
1908 else if (restart_emissions &&
1909 signal->signal_flags & GTK_RUN_NO_RECURSE &&
1910 gtk_emission_check (restart_emissions, object, signal->signal_id))
1912 gtk_emission_remove (&restart_emissions, object, signal->signal_id);
1914 gtk_signal_handler_unref (handlers, object);
1916 return EMISSION_RESTART;
1920 handlers_next = handlers->next;
1921 gtk_signal_handler_unref (handlers, object);
1922 handlers = handlers_next;
1925 return EMISSION_CONTINUE;
1929 gtk_signal_collect_params (GtkArg *params,
1931 GtkType *param_types,
1932 GtkType return_type,
1935 register GtkArg *last_param;
1936 register gboolean failed = FALSE;
1938 for (last_param = params + n_params; params < last_param; params++)
1940 register gchar *error;
1942 params->name = NULL;
1943 params->type = *(param_types++);
1944 GTK_ARG_COLLECT_VALUE (params,
1950 g_warning ("gtk_signal_collect_params(): %s", error);
1955 params->type = return_type;
1956 params->name = NULL;
1958 return_type = GTK_FUNDAMENTAL_TYPE (return_type);
1959 if (return_type != GTK_TYPE_NONE)
1961 if ((return_type >= GTK_TYPE_FLAT_FIRST &&
1962 return_type <= GTK_TYPE_FLAT_LAST) ||
1963 (return_type == GTK_TYPE_OBJECT))
1965 GTK_VALUE_POINTER (*params) = va_arg (var_args, gpointer);
1967 if (GTK_VALUE_POINTER (*params) == NULL)
1970 g_warning ("gtk_signal_collect_params(): invalid NULL pointer for return argument type `%s'",
1971 gtk_type_name (params->type));
1977 g_warning ("gtk_signal_collect_params(): unsupported return argument type `%s'",
1978 gtk_type_name (params->type));
1982 GTK_VALUE_POINTER (*params) = NULL;