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.
20 #include "gtksignal.h"
23 #define SIGNAL_BLOCK_SIZE (100)
24 #define HANDLER_BLOCK_SIZE (200)
25 #define EMISSION_BLOCK_SIZE (100)
26 #define DISCONNECT_INFO_BLOCK_SIZE (64)
27 #define MAX_SIGNAL_PARAMS (32)
36 #define GTK_RUN_TYPE(x) ((x) & GTK_RUN_MASK)
39 typedef struct _GtkSignal GtkSignal;
40 typedef struct _GtkSignalHash GtkSignalHash;
41 typedef struct _GtkHandler GtkHandler;
42 typedef struct _GtkHandlerInfo GtkHandlerInfo;
43 typedef struct _GtkEmission GtkEmission;
44 typedef union _GtkEmissionAllocator GtkEmissionAllocator;
45 typedef struct _GtkDisconnectInfo GtkDisconnectInfo;
47 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
55 guint function_offset;
56 GtkSignalRunType run_type;
57 GtkSignalMarshaller marshaller;
74 guint object_signal : 1;
81 GtkSignalDestroy destroy_func;
86 struct _GtkHandlerInfo
89 GtkSignalMarshaller marshaller;
93 GtkSignalRunType run_type;
104 union _GtkEmissionAllocator
106 GtkEmissionAllocator *next;
107 GtkEmission emission;
110 struct _GtkDisconnectInfo
113 guint disconnect_handler1;
114 guint signal_handler;
116 guint disconnect_handler2;
120 static guint gtk_signal_hash (const gpointer h);
121 static gint gtk_signal_compare (const gpointer h1,
123 static GtkHandler* gtk_signal_handler_new (void);
124 static void gtk_signal_handler_ref (GtkHandler *handler);
125 static void gtk_signal_handler_unref (GtkHandler *handler,
127 static void gtk_signal_handler_insert (GtkObject *object,
128 GtkHandler *handler);
129 static void gtk_signal_real_emit (GtkObject *object,
132 static GtkHandler* gtk_signal_get_handlers (GtkObject *object,
134 static guint gtk_signal_connect_by_type (GtkObject *object,
138 GtkSignalDestroy destroy_func,
142 static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);
143 static GtkEmission* gtk_emission_new (void);
144 static void gtk_emission_add (GList **emissions,
147 static void gtk_emission_remove (GList **emissions,
150 static gint gtk_emission_check (GList *emissions,
153 static gint gtk_handlers_run (GtkHandler *handlers,
154 GtkHandlerInfo *info,
156 static void gtk_params_get (GtkArg *params,
158 GtkType *param_types,
162 #define LOOKUP_SIGNAL_ID(signal_id) ( \
163 signal_id > 0 && signal_id < gtk_n_signals ? \
164 (GtkSignal*) gtk_signals + signal_id : \
169 static GtkSignalMarshal global_marshaller = NULL;
170 static GtkSignalDestroy global_destroy_notify = NULL;
172 static guint gtk_handler_id = 1;
173 static guint handler_key_id = 0;
174 static GHashTable *gtk_signal_hash_table = NULL;
175 static GtkSignal *gtk_signals = NULL;
176 static guint gtk_n_signals = 0;
177 static GMemChunk *gtk_signal_hash_mem_chunk = NULL;
178 static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;
179 static GtkHandler *gtk_handler_free_list = NULL;
180 static GtkEmissionAllocator *gtk_emission_free_list = NULL;
184 static GList *current_emissions = NULL;
185 static GList *stop_emissions = NULL;
186 static GList *restart_emissions = NULL;
189 gtk_signal_next_and_invalidate (void)
191 static guint gtk_n_free_signals = 0;
192 register GtkSignal *signal;
193 register guint new_signal_id;
195 /* don't keep *any* GtkSignal pointers across invokation of this function!!!
198 if (gtk_n_free_signals == 0)
205 size = gtk_n_signals + SIGNAL_BLOCK_SIZE;
206 size *= sizeof (GtkSignal);
212 gtk_signals = g_realloc (gtk_signals, size);
214 gtk_n_free_signals = size / sizeof (GtkSignal) - gtk_n_signals;
216 memset (gtk_signals + gtk_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
219 new_signal_id = gtk_n_signals++;
220 gtk_n_free_signals--;
222 signal = LOOKUP_SIGNAL_ID (new_signal_id);
224 signal->signal_id = new_signal_id;
230 gtk_signal_init (void)
236 zero = gtk_signal_next_and_invalidate ();
237 g_assert (zero == NULL);
239 handler_key_id = gtk_object_data_force_id ("gtk-signal-handlers");
241 gtk_signal_hash_mem_chunk =
242 g_mem_chunk_new ("GtkSignalHash mem chunk",
243 sizeof (GtkSignalHash),
244 sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
246 gtk_disconnect_info_mem_chunk =
247 g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
248 sizeof (GtkDisconnectInfo),
249 sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
251 gtk_handler_free_list = NULL;
252 gtk_emission_free_list = NULL;
254 gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
260 gtk_signal_newv (const gchar *r_name,
261 GtkSignalRunType run_type,
263 guint function_offset,
264 GtkSignalMarshaller marshaller,
275 g_return_val_if_fail (r_name != NULL, 0);
276 g_return_val_if_fail (marshaller != NULL, 0);
277 g_return_val_if_fail (nparams <= MAX_SIGNAL_PARAMS, 0);
279 g_return_val_if_fail (params != NULL, 0);
284 name = g_strdup (r_name);
285 g_strdelimit (name, NULL, '_');
287 id = gtk_signal_lookup (name, object_type);
290 g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
292 gtk_type_name (object_type));
297 signal = gtk_signal_next_and_invalidate ();
299 /* signal->signal_id already set */
301 signal->object_type = object_type;
303 signal->function_offset = function_offset;
304 signal->run_type = run_type;
305 signal->marshaller = marshaller;
306 signal->return_val = return_val;
307 signal->nparams = nparams;
311 signal->params = g_new (GtkType, nparams);
313 for (i = 0; i < nparams; i++)
314 signal->params[i] = params[i];
317 signal->params = NULL;
319 /* insert "signal_name" into hash table
321 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
322 hash->object_type = object_type;
323 hash->name_key_id = gtk_object_data_force_id (signal->name);
324 hash->signal_id = signal->signal_id;
325 g_hash_table_insert (gtk_signal_hash_table, hash, (gpointer) hash->signal_id);
327 /* insert "signal-name" into hash table
329 g_strdelimit (signal->name, NULL, '-');
330 id = gtk_object_data_force_id (signal->name);
331 if (id != hash->name_key_id)
333 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
334 hash->object_type = object_type;
335 hash->name_key_id = id;
336 hash->signal_id = signal->signal_id;
337 g_hash_table_insert (gtk_signal_hash_table, hash, (gpointer) hash->signal_id);
340 return signal->signal_id;
344 gtk_signal_new (const gchar *name,
345 GtkSignalRunType run_type,
347 guint function_offset,
348 GtkSignalMarshaller marshaller,
358 g_return_val_if_fail (nparams <= MAX_SIGNAL_PARAMS, 0);
362 params = g_new (GtkType, nparams);
364 va_start (args, nparams);
366 for (i = 0; i < nparams; i++)
367 params[i] = va_arg (args, GtkType);
374 signal_id = gtk_signal_newv (name,
389 gtk_signal_lookup (const gchar *name,
394 g_return_val_if_fail (name != NULL, 0);
395 g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0);
397 hash.name_key_id = gtk_object_data_try_key (name);
398 if (hash.name_key_id)
404 hash.object_type = object_type;
406 signal_id = (guint) g_hash_table_lookup (gtk_signal_hash_table, &hash);
410 object_type = gtk_type_parent (object_type);
418 gtk_signal_query (guint signal_id)
420 GtkSignalQuery *query;
423 g_return_val_if_fail (signal_id >= 1, NULL);
425 signal = LOOKUP_SIGNAL_ID (signal_id);
428 query = g_new (GtkSignalQuery, 1);
430 query->object_type = signal->object_type;
431 query->signal_id = signal_id;
432 query->signal_name = signal->name;
433 query->is_user_signal = signal->function_offset == 0;
434 query->run_type = signal->run_type;
435 query->return_val = signal->return_val;
436 query->nparams = signal->nparams;
437 query->params = signal->params;
446 gtk_signal_name (guint signal_id)
450 g_return_val_if_fail (signal_id >= 1, NULL);
452 signal = LOOKUP_SIGNAL_ID (signal_id);
460 gtk_signal_emitv (GtkObject *object,
466 g_return_if_fail (object != NULL);
467 g_return_if_fail (signal_id >= 1);
468 g_return_if_fail (params != NULL);
470 signal = LOOKUP_SIGNAL_ID (signal_id);
471 g_return_if_fail (signal != NULL);
472 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
474 gtk_signal_real_emit (object, signal, params);
478 gtk_signal_emit (GtkObject *object,
484 GtkArg params[MAX_SIGNAL_PARAMS];
486 g_return_if_fail (object != NULL);
487 g_return_if_fail (signal_id >= 1);
489 signal = LOOKUP_SIGNAL_ID (signal_id);
490 g_return_if_fail (signal != NULL);
491 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
493 va_start (args, signal_id);
494 gtk_params_get (params,
501 gtk_signal_real_emit (object, signal, params);
505 gtk_signal_emitv_by_name (GtkObject *object,
511 g_return_if_fail (object != NULL);
512 g_return_if_fail (name != NULL);
513 g_return_if_fail (params != NULL);
515 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
521 signal = LOOKUP_SIGNAL_ID (signal_id);
522 g_return_if_fail (signal != NULL);
523 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
525 gtk_signal_real_emit (object, signal, params);
529 g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
531 gtk_type_name (GTK_OBJECT_TYPE (object)));
536 gtk_signal_emit_by_name (GtkObject *object,
542 g_return_if_fail (object != NULL);
543 g_return_if_fail (name != NULL);
545 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
550 GtkArg params[MAX_SIGNAL_PARAMS];
553 signal = LOOKUP_SIGNAL_ID (signal_id);
554 g_return_if_fail (signal != NULL);
555 g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
557 va_start (args, name);
558 gtk_params_get (params,
565 gtk_signal_real_emit (object, signal, params);
569 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
571 gtk_type_name (GTK_OBJECT_TYPE (object)));
576 gtk_signal_emit_stop (GtkObject *object,
579 g_return_if_fail (object != NULL);
580 g_return_if_fail (signal_id >= 1);
582 if (gtk_emission_check (current_emissions, object, signal_id))
583 gtk_emission_add (&stop_emissions, object, signal_id);
585 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
587 gtk_type_name (GTK_OBJECT_TYPE (object)));
591 gtk_signal_emit_stop_by_name (GtkObject *object,
596 g_return_if_fail (object != NULL);
597 g_return_if_fail (name != NULL);
599 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
601 gtk_signal_emit_stop (object, signal_id);
603 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
605 gtk_type_name (GTK_OBJECT_TYPE (object)));
609 gtk_signal_n_emissions (GtkObject *object,
615 g_return_val_if_fail (object != NULL, 0);
616 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
619 for (list = current_emissions; list; list = list->next)
621 GtkEmission *emission;
623 emission = list->data;
625 if ((emission->object == object) &&
626 (emission->signal_id == signal_id))
634 gtk_signal_n_emissions_by_name (GtkObject *object,
640 g_return_val_if_fail (object != NULL, 0);
641 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
642 g_return_val_if_fail (name != NULL, 0);
644 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
646 n = gtk_signal_n_emissions (object, signal_id);
649 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
651 gtk_type_name (GTK_OBJECT_TYPE (object)));
659 gtk_signal_connect (GtkObject *object,
666 g_return_val_if_fail (object != NULL, 0);
667 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
669 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
672 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
674 gtk_type_name (GTK_OBJECT_TYPE (object)));
678 return gtk_signal_connect_by_type (object, signal_id,
679 func, func_data, NULL,
680 FALSE, FALSE, FALSE);
684 gtk_signal_connect_after (GtkObject *object,
691 g_return_val_if_fail (object != NULL, 0);
693 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
696 g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
698 gtk_type_name (GTK_OBJECT_TYPE (object)));
702 return gtk_signal_connect_by_type (object, signal_id,
703 func, func_data, NULL,
708 gtk_signal_connect_full (GtkObject *object,
711 GtkCallbackMarshal marshal,
713 GtkDestroyNotify destroy_func,
719 g_return_val_if_fail (object != NULL, 0);
721 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
724 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
726 gtk_type_name (GTK_OBJECT_TYPE (object)));
731 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
732 func_data, destroy_func,
733 object_signal, after, TRUE);
735 return gtk_signal_connect_by_type (object, signal_id, func,
736 func_data, destroy_func,
737 object_signal, after, FALSE);
741 gtk_signal_connect_interp (GtkObject *object,
743 GtkCallbackMarshal func,
745 GtkDestroyNotify destroy_func,
748 return gtk_signal_connect_full (object, name, NULL, func,
749 func_data, destroy_func, FALSE, after);
753 gtk_signal_connect_object (GtkObject *object,
756 GtkObject *slot_object)
760 g_return_val_if_fail (object != NULL, 0);
761 /* slot_object needs to be treated as ordinary pointer
764 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
767 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
769 gtk_type_name (GTK_OBJECT_TYPE (object)));
773 return gtk_signal_connect_by_type (object, signal_id,
774 func, slot_object, NULL,
779 gtk_signal_connect_object_after (GtkObject *object,
782 GtkObject *slot_object)
786 g_return_val_if_fail (object != NULL, 0);
788 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
791 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
793 gtk_type_name (GTK_OBJECT_TYPE (object)));
797 return gtk_signal_connect_by_type (object, signal_id,
798 func, slot_object, NULL,
803 gtk_signal_connect_while_alive (GtkObject *object,
807 GtkObject *alive_object)
809 GtkDisconnectInfo *info;
811 g_return_if_fail (object != NULL);
812 g_return_if_fail (GTK_IS_OBJECT (object));
813 g_return_if_fail (signal != NULL);
814 g_return_if_fail (func != NULL);
815 g_return_if_fail (alive_object != NULL);
816 g_return_if_fail (GTK_IS_OBJECT (alive_object));
818 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
819 info->object1 = object;
820 info->object2 = alive_object;
822 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
823 info->disconnect_handler1 =
824 gtk_signal_connect_object (info->object1,
826 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
828 info->disconnect_handler2 =
829 gtk_signal_connect_object (info->object2,
831 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
836 gtk_signal_connect_object_while_alive (GtkObject *object,
839 GtkObject *alive_object)
841 GtkDisconnectInfo *info;
843 g_return_if_fail (object != NULL);
844 g_return_if_fail (GTK_IS_OBJECT (object));
845 g_return_if_fail (signal != NULL);
846 g_return_if_fail (func != NULL);
847 g_return_if_fail (alive_object != NULL);
848 g_return_if_fail (GTK_IS_OBJECT (alive_object));
850 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
851 info->object1 = object;
852 info->object2 = alive_object;
854 info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
855 info->disconnect_handler1 =
856 gtk_signal_connect_object (info->object1,
858 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
860 info->disconnect_handler2 =
861 gtk_signal_connect_object (info->object2,
863 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
868 gtk_signal_disconnect (GtkObject *object,
873 g_return_if_fail (object != NULL);
874 g_return_if_fail (handler_id > 0);
876 handler = gtk_object_get_data_by_id (object, handler_key_id);
880 if (handler->id == handler_id)
883 handler->blocked += 1;
884 gtk_signal_handler_unref (handler, object);
887 handler = handler->next;
890 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
894 gtk_signal_disconnect_by_func (GtkObject *object,
901 g_return_if_fail (object != NULL);
902 g_return_if_fail (func != NULL);
905 handler = gtk_object_get_data_by_id (object, handler_key_id);
909 GtkHandler *handler_next;
911 handler_next = handler->next;
912 if ((handler->id > 0) &&
913 (handler->func == func) &&
914 (handler->func_data == data))
918 handler->blocked += 1;
919 gtk_signal_handler_unref (handler, object);
921 handler = handler_next;
925 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
929 gtk_signal_disconnect_by_data (GtkObject *object,
935 g_return_if_fail (object != NULL);
938 handler = gtk_object_get_data_by_id (object, handler_key_id);
942 GtkHandler *handler_next;
944 handler_next = handler->next;
945 if ((handler->id > 0) &&
946 (handler->func_data == data))
950 handler->blocked += 1;
951 gtk_signal_handler_unref (handler, object);
953 handler = handler_next;
957 g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
961 gtk_signal_handler_block (GtkObject *object,
966 g_return_if_fail (object != NULL);
967 g_return_if_fail (handler_id > 0);
969 handler = gtk_object_get_data_by_id (object, handler_key_id);
973 if (handler->id == handler_id)
975 handler->blocked += 1;
978 handler = handler->next;
981 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
985 gtk_signal_handler_block_by_func (GtkObject *object,
992 g_return_if_fail (object != NULL);
993 g_return_if_fail (func != NULL);
996 handler = gtk_object_get_data_by_id (object, handler_key_id);
1000 if ((handler->id > 0) &&
1001 (handler->func == func) &&
1002 (handler->func_data == data))
1005 handler->blocked += 1;
1007 handler = handler->next;
1011 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1015 gtk_signal_handler_block_by_data (GtkObject *object,
1018 GtkHandler *handler;
1021 g_return_if_fail (object != NULL);
1024 handler = gtk_object_get_data_by_id (object, handler_key_id);
1028 if ((handler->id > 0) &&
1029 (handler->func_data == data))
1032 handler->blocked += 1;
1034 handler = handler->next;
1038 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1042 gtk_signal_handler_unblock (GtkObject *object,
1045 GtkHandler *handler;
1047 g_return_if_fail (object != NULL);
1048 g_return_if_fail (handler_id > 0);
1050 handler = gtk_object_get_data_by_id (object, handler_key_id);
1054 if (handler->id == handler_id)
1056 if (handler->blocked > 0)
1057 handler->blocked -= 1;
1059 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1062 handler = handler->next;
1065 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1069 gtk_signal_handler_unblock_by_func (GtkObject *object,
1073 GtkHandler *handler;
1076 g_return_if_fail (object != NULL);
1077 g_return_if_fail (func != NULL);
1080 handler = gtk_object_get_data_by_id (object, handler_key_id);
1084 if ((handler->id > 0) &&
1085 (handler->func == func) &&
1086 (handler->func_data == data) &&
1087 (handler->blocked > 0))
1089 handler->blocked -= 1;
1092 handler = handler->next;
1096 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1100 gtk_signal_handler_unblock_by_data (GtkObject *object,
1103 GtkHandler *handler;
1106 g_return_if_fail (object != NULL);
1109 handler = gtk_object_get_data_by_id (object, handler_key_id);
1113 if ((handler->id > 0) &&
1114 (handler->func_data == data) &&
1115 (handler->blocked > 0))
1117 handler->blocked -= 1;
1120 handler = handler->next;
1124 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1128 gtk_signal_handlers_destroy (GtkObject *object)
1130 GtkHandler *handler;
1132 /* we make the "optimization" of destroying the first handler in the last
1133 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1134 * handler_key data on each removal
1137 handler = gtk_object_get_data_by_id (object, handler_key_id);
1140 handler = handler->next;
1145 next = handler->next;
1146 gtk_signal_handler_unref (handler, object);
1149 handler = gtk_object_get_data_by_id (object, handler_key_id);
1150 gtk_signal_handler_unref (handler, object);
1155 gtk_signal_default_marshaller (GtkObject *object,
1160 GtkSignalMarshaller0 rfunc;
1162 rfunc = (GtkSignalMarshaller0) func;
1164 (* rfunc) (object, func_data);
1168 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1169 GtkSignalDestroy destroy_func)
1171 global_marshaller = marshal_func;
1172 global_destroy_notify = destroy_func;
1176 gtk_signal_hash (const gpointer h)
1178 register GtkSignalHash *hash = h;
1180 return hash->object_type ^ hash->name_key_id;
1184 gtk_signal_compare (const gpointer h1,
1187 register GtkSignalHash *hash1 = h1;
1188 register GtkSignalHash *hash2 = h2;
1190 return (hash1->name_key_id == hash2->name_key_id &&
1191 hash1->object_type == hash2->object_type);
1195 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1197 g_return_val_if_fail (info != NULL, 0);
1199 gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1200 gtk_signal_disconnect (info->object1, info->signal_handler);
1201 gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1203 g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1209 gtk_signal_handler_new (void)
1211 GtkHandler *handler;
1213 if (!gtk_handler_free_list)
1215 GtkHandler *handler_block;
1218 handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1219 for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1221 (handler_block + i)->next = gtk_handler_free_list;
1222 gtk_handler_free_list = (handler_block + i);
1225 handler = handler_block;
1229 handler = gtk_handler_free_list;
1230 gtk_handler_free_list = handler->next;
1234 handler->blocked = 0;
1235 handler->signal_id = 0;
1236 handler->object_signal = FALSE;
1237 handler->after = FALSE;
1238 handler->no_marshal = FALSE;
1239 handler->ref_count = 1;
1240 handler->func = NULL;
1241 handler->func_data = NULL;
1242 handler->destroy_func = NULL;
1243 handler->prev = NULL;
1244 handler->next = NULL;
1250 gtk_signal_handler_ref (GtkHandler *handler)
1252 handler->ref_count += 1;
1256 gtk_signal_handler_unref (GtkHandler *handler,
1259 if (!handler->ref_count)
1261 /* FIXME: i wanna get removed somewhen */
1262 g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1266 handler->ref_count -= 1;
1268 if (handler->ref_count == 0)
1270 if (handler->destroy_func)
1271 (* handler->destroy_func) (handler->func_data);
1272 else if (!handler->func && global_destroy_notify)
1273 (* global_destroy_notify) (handler->func_data);
1276 handler->prev->next = handler->next;
1277 else if (handler->next)
1278 gtk_object_set_data_by_id (object, handler_key_id, handler->next);
1281 GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1282 gtk_object_set_data_by_id (object, handler_key_id, NULL);
1285 handler->next->prev = handler->prev;
1287 handler->next = gtk_handler_free_list;
1288 gtk_handler_free_list = handler;
1293 gtk_signal_handler_insert (GtkObject *object,
1294 GtkHandler *handler)
1298 /* FIXME: remove */ g_assert (handler->next == NULL);
1299 /* FIXME: remove */ g_assert (handler->prev == NULL);
1301 tmp = gtk_object_get_data_by_id (object, handler_key_id);
1304 GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1305 gtk_object_set_data_by_id (object, handler_key_id, handler);
1310 if (tmp->signal_id < handler->signal_id)
1314 tmp->prev->next = handler;
1315 handler->prev = tmp->prev;
1318 gtk_object_set_data_by_id (object, handler_key_id, handler);
1319 tmp->prev = handler;
1320 handler->next = tmp;
1326 tmp->next = handler;
1327 handler->prev = tmp;
1335 gtk_signal_real_emit (GtkObject *object,
1339 GtkHandler *handlers;
1340 GtkHandlerInfo info;
1341 guchar **signal_func_offset;
1342 register guint signal_id = signal->signal_id;
1344 if ((signal->run_type & GTK_RUN_NO_RECURSE) &&
1345 gtk_emission_check (current_emissions, object, signal_id))
1347 gtk_emission_add (&restart_emissions, object, signal_id);
1351 gtk_object_ref (object);
1353 gtk_emission_add (¤t_emissions, object, signal_id);
1356 if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST && signal->function_offset != 0)
1358 signal_func_offset = (guchar**) ((guchar*) object->klass +
1359 signal->function_offset);
1360 if (*signal_func_offset)
1361 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1365 if (GTK_OBJECT_CONNECTED (object))
1367 handlers = gtk_signal_get_handlers (object, signal_id);
1370 info.object = object;
1371 info.marshaller = signal->marshaller;
1372 info.params = params;
1373 info.param_types = signal->params;
1374 info.return_val = signal->return_val;
1375 info.nparams = signal->nparams;
1376 info.run_type = signal->run_type;
1377 info.signal_id = signal_id;
1379 switch (gtk_handlers_run (handlers, &info, FALSE))
1381 case EMISSION_CONTINUE:
1383 case EMISSION_RESTART:
1384 goto emission_restart;
1395 if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST && signal->function_offset != 0)
1397 signal_func_offset = (guchar**) ((guchar*) object->klass +
1398 signal->function_offset);
1399 if (*signal_func_offset)
1400 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1404 if (GTK_OBJECT_CONNECTED (object))
1406 handlers = gtk_signal_get_handlers (object, signal_id);
1411 info.object = object;
1412 info.marshaller = signal->marshaller;
1413 info.params = params;
1414 info.param_types = signal->params;
1415 info.return_val = signal->return_val;
1416 info.nparams = signal->nparams;
1417 info.run_type = signal->run_type;
1418 info.signal_id = signal_id;
1420 switch (gtk_handlers_run (handlers, &info, TRUE))
1422 case EMISSION_CONTINUE:
1424 case EMISSION_RESTART:
1425 goto emission_restart;
1434 gtk_emission_remove (¤t_emissions, object, signal_id);
1436 if (signal->run_type & GTK_RUN_NO_RECURSE)
1437 gtk_emission_remove (&restart_emissions, object, signal_id);
1439 gtk_object_unref (object);
1443 gtk_signal_get_handlers (GtkObject *object,
1446 GtkHandler *handlers;
1448 handlers = gtk_object_get_data_by_id (object, handler_key_id);
1452 if (handlers->signal_id == signal_id)
1454 handlers = handlers->next;
1461 gtk_signal_handler_pending (GtkObject *object,
1463 gboolean may_be_blocked)
1465 GtkHandler *handlers;
1468 g_return_val_if_fail (object != NULL, 0);
1469 g_return_val_if_fail (signal_id >= 1, 0);
1471 if (GTK_OBJECT_CONNECTED (object))
1472 handlers = gtk_signal_get_handlers (object, signal_id);
1477 while (handlers && handlers->signal_id == signal_id)
1479 if (handlers->id > 0 &&
1480 (may_be_blocked || handlers->blocked == 0))
1482 handler_id = handlers->id;
1486 handlers = handlers->next;
1493 gtk_signal_connect_by_type (GtkObject *object,
1497 GtkSignalDestroy destroy_func,
1502 GtkObjectClass *class;
1503 GtkHandler *handler;
1506 g_return_val_if_fail (object != NULL, 0);
1507 g_return_val_if_fail (object->klass != NULL, 0);
1509 /* Search through the signals for this object and make
1510 * sure the one we are adding is valid. We need to perform
1511 * the lookup on the objects parents as well. If it isn't
1512 * valid then issue a warning and return.
1515 class = object->klass;
1519 guint *object_signals;
1523 object_signals = class->signals;
1524 nsignals = class->nsignals;
1526 for (i = 0; i < nsignals; i++)
1527 if (object_signals[i] == signal_id)
1533 parent = gtk_type_parent (class->type);
1535 class = gtk_type_class (parent);
1542 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1544 gtk_type_name (object->klass->type));
1548 handler = gtk_signal_handler_new ();
1549 handler->id = gtk_handler_id++;
1550 handler->signal_id = signal_id;
1551 handler->object_signal = object_signal;
1552 handler->func = func;
1553 handler->func_data = func_data;
1554 handler->destroy_func = destroy_func;
1555 handler->after = after != FALSE;
1556 handler->no_marshal = no_marshal;
1558 gtk_signal_handler_insert (object, handler);
1563 gtk_emission_new (void)
1565 GtkEmission *emission;
1567 if (!gtk_emission_free_list)
1569 GtkEmissionAllocator *emission_block;
1572 emission_block = g_new0 (GtkEmissionAllocator, EMISSION_BLOCK_SIZE);
1573 for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1575 (emission_block + i)->next = gtk_emission_free_list;
1576 gtk_emission_free_list = (emission_block + i);
1579 emission = &emission_block->emission;
1583 emission = >k_emission_free_list->emission;
1584 gtk_emission_free_list = gtk_emission_free_list->next;
1587 emission->object = NULL;
1588 emission->signal_id = 0;
1594 gtk_emission_add (GList **emissions,
1598 GtkEmission *emission;
1600 g_return_if_fail (emissions != NULL);
1601 g_return_if_fail (object != NULL);
1603 emission = gtk_emission_new ();
1604 emission->object = object;
1605 emission->signal_id = signal_id;
1607 *emissions = g_list_prepend (*emissions, emission);
1611 gtk_emission_remove (GList **emissions,
1617 g_return_if_fail (emissions != NULL);
1622 GtkEmissionAllocator *ea;
1626 if ((ea->emission.object == object) &&
1627 (ea->emission.signal_id == signal_id))
1629 *emissions = g_list_remove_link (*emissions, tmp);
1632 ea->next = gtk_emission_free_list;
1633 gtk_emission_free_list = ea;
1642 gtk_emission_check (GList *emissions,
1646 GtkEmission *emission;
1652 emission = tmp->data;
1655 if ((emission->object == object) &&
1656 (emission->signal_id == signal_id))
1663 gtk_handlers_run (GtkHandler *handlers,
1664 GtkHandlerInfo *info,
1667 while (handlers && handlers->signal_id == info->signal_id)
1669 GtkHandler *handlers_next;
1671 gtk_signal_handler_ref (handlers);
1673 if (handlers->blocked == 0 && (handlers->after == after))
1677 if (handlers->no_marshal)
1678 (* (GtkCallbackMarshal) handlers->func) (info->object,
1679 handlers->func_data,
1682 else if (handlers->object_signal)
1683 (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
1685 handlers->func_data,
1688 (* info->marshaller) (info->object,
1690 handlers->func_data,
1693 else if (global_marshaller)
1694 (* global_marshaller) (info->object,
1695 handlers->func_data,
1701 if (gtk_emission_check (stop_emissions, info->object,
1704 gtk_emission_remove (&stop_emissions, info->object,
1707 if (info->run_type & GTK_RUN_NO_RECURSE)
1708 gtk_emission_remove (&restart_emissions, info->object,
1710 gtk_signal_handler_unref (handlers, info->object);
1711 return EMISSION_DONE;
1713 else if ((info->run_type & GTK_RUN_NO_RECURSE) &&
1714 gtk_emission_check (restart_emissions, info->object,
1717 gtk_emission_remove (&restart_emissions, info->object,
1719 gtk_signal_handler_unref (handlers, info->object);
1720 return EMISSION_RESTART;
1724 handlers_next = handlers->next;
1725 gtk_signal_handler_unref (handlers, info->object);
1726 handlers = handlers_next;
1729 return EMISSION_CONTINUE;
1733 gtk_params_get (GtkArg *params,
1735 GtkType *param_types,
1741 for (i = 0; i < nparams; i++)
1743 params[i].type = param_types[i];
1744 params[i].name = NULL;
1746 switch (GTK_FUNDAMENTAL_TYPE (param_types[i]))
1748 case GTK_TYPE_INVALID:
1753 GTK_VALUE_CHAR(params[i]) = va_arg (args, gint);
1756 GTK_VALUE_BOOL(params[i]) = va_arg (args, gint);
1759 GTK_VALUE_INT(params[i]) = va_arg (args, gint);
1762 GTK_VALUE_UINT(params[i]) = va_arg (args, guint);
1765 GTK_VALUE_ENUM(params[i]) = va_arg (args, gint);
1767 case GTK_TYPE_FLAGS:
1768 GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint);
1771 GTK_VALUE_LONG(params[i]) = va_arg (args, glong);
1773 case GTK_TYPE_ULONG:
1774 GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong);
1776 case GTK_TYPE_FLOAT:
1777 GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat);
1779 case GTK_TYPE_DOUBLE:
1780 GTK_VALUE_DOUBLE(params[i]) = va_arg (args, gdouble);
1782 case GTK_TYPE_STRING:
1783 GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*);
1785 case GTK_TYPE_POINTER:
1786 GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer);
1788 case GTK_TYPE_BOXED:
1789 GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer);
1791 case GTK_TYPE_SIGNAL:
1792 GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction);
1793 GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer);
1795 case GTK_TYPE_FOREIGN:
1796 GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer);
1797 GTK_VALUE_FOREIGN(params[i]).notify =
1798 va_arg (args, GtkDestroyNotify);
1800 case GTK_TYPE_CALLBACK:
1801 GTK_VALUE_CALLBACK(params[i]).marshal =
1802 va_arg (args, GtkCallbackMarshal);
1803 GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer);
1804 GTK_VALUE_CALLBACK(params[i]).notify =
1805 va_arg (args, GtkDestroyNotify);
1807 case GTK_TYPE_C_CALLBACK:
1808 GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction);
1809 GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer);
1812 GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, gint);
1813 GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*);
1815 case GTK_TYPE_OBJECT:
1816 GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*);
1817 if (GTK_VALUE_OBJECT(params[i]) != NULL &&
1818 !GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]), params[i].type))
1819 g_warning ("signal arg `%s' is not of type `%s'",
1820 gtk_type_name (GTK_OBJECT_TYPE (GTK_VALUE_OBJECT(params[i]))),
1821 gtk_type_name (params[i].type));
1824 g_error ("unsupported type `%s' in signal arg",
1825 gtk_type_name (params[i].type));
1830 params[i].type = return_val;
1831 params[i].name = NULL;
1833 switch (GTK_FUNDAMENTAL_TYPE (return_val))
1835 case GTK_TYPE_INVALID:
1840 params[i].d.pointer_data = va_arg (args, gchar*);
1843 params[i].d.pointer_data = va_arg (args, gint*);
1846 params[i].d.pointer_data = va_arg (args, gint*);
1849 params[i].d.pointer_data = va_arg (args, guint*);
1852 params[i].d.pointer_data = va_arg (args, gint*);
1854 case GTK_TYPE_FLAGS:
1855 params[i].d.pointer_data = va_arg (args, gint*);
1858 params[i].d.pointer_data = va_arg (args, glong*);
1860 case GTK_TYPE_ULONG:
1861 params[i].d.pointer_data = va_arg (args, gulong*);
1863 case GTK_TYPE_FLOAT:
1864 params[i].d.pointer_data = va_arg (args, gfloat*);
1866 case GTK_TYPE_DOUBLE:
1867 params[i].d.pointer_data = va_arg (args, gdouble*);
1869 case GTK_TYPE_STRING:
1870 params[i].d.pointer_data = va_arg (args, gchar**);
1872 case GTK_TYPE_POINTER:
1873 params[i].d.pointer_data = va_arg (args, gpointer*);
1875 case GTK_TYPE_BOXED:
1876 params[i].d.pointer_data = va_arg (args, gpointer*);
1878 case GTK_TYPE_OBJECT:
1879 params[i].d.pointer_data = va_arg (args, GtkObject**);
1881 case GTK_TYPE_SIGNAL:
1882 case GTK_TYPE_FOREIGN:
1883 case GTK_TYPE_CALLBACK:
1884 case GTK_TYPE_C_CALLBACK:
1887 g_error ("unsupported type `%s' in signal return",
1888 gtk_type_name (return_val));