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 GTK_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 struct _GtkDisconnectInfo GtkDisconnectInfo;
46 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
54 guint function_offset;
55 GtkSignalRunType run_type;
56 GtkSignalMarshaller marshaller;
73 guint object_signal : 1;
80 GtkSignalDestroy destroy_func;
85 struct _GtkHandlerInfo
88 GtkSignalMarshaller marshaller;
92 GtkSignalRunType run_type;
103 struct _GtkDisconnectInfo
106 guint disconnect_handler1;
107 guint signal_handler;
109 guint disconnect_handler2;
113 static guint gtk_signal_hash (const gpointer h);
114 static gint gtk_signal_compare (const gpointer h1,
116 static GtkHandler* gtk_signal_handler_new (void);
117 static void gtk_signal_handler_ref (GtkHandler *handler);
118 static void gtk_signal_handler_unref (GtkHandler *handler,
120 static void gtk_signal_handler_insert (GtkObject *object,
121 GtkHandler *handler);
122 static void gtk_signal_real_emit (GtkObject *object,
125 static GtkHandler* gtk_signal_get_handlers (GtkObject *object,
127 static guint gtk_signal_connect_by_type (GtkObject *object,
131 GtkSignalDestroy destroy_func,
135 static guint gtk_alive_disconnecter (GtkDisconnectInfo *info);
136 static GtkEmission* gtk_emission_new (void);
137 static void gtk_emission_destroy (GtkEmission *emission);
138 static void gtk_emission_add (GList **emissions,
141 static void gtk_emission_remove (GList **emissions,
144 static gint gtk_emission_check (GList *emissions,
147 static gint gtk_handlers_run (GtkHandler *handlers,
148 GtkHandlerInfo *info,
150 static void gtk_params_get (GtkArg *params,
152 GtkType *param_types,
156 #define LOOKUP_SIGNAL_ID(signal_id) ( \
157 signal_id > 0 && signal_id < gtk_n_signals ? \
158 (GtkSignal*) gtk_signals + signal_id : \
163 static GtkSignalMarshal global_marshaller = NULL;
164 static GtkSignalDestroy global_destroy_notify = NULL;
166 static guint gtk_handler_id = 1;
167 static guint handler_key_id = 0;
168 static GHashTable *gtk_signal_hash_table = NULL;
169 static GtkSignal *gtk_signals = NULL;
170 static guint gtk_n_signals = 0;
171 static GMemChunk *gtk_signal_hash_mem_chunk = NULL;
172 static GMemChunk *gtk_handler_mem_chunk = NULL;
173 static GMemChunk *gtk_emission_mem_chunk = NULL;
174 static GMemChunk *gtk_disconnect_info_mem_chunk = NULL;
176 static GList *current_emissions = NULL;
177 static GList *stop_emissions = NULL;
178 static GList *restart_emissions = NULL;
181 gtk_signal_next_and_invalidate (void)
183 static guint gtk_n_free_signals = 0;
184 register GtkSignal *signal;
185 register guint new_signal_id;
187 /* don't keep *any* GtkSignal pointers across invokation of this function!!!
190 if (gtk_n_free_signals == 0)
197 size = gtk_n_signals + SIGNAL_BLOCK_SIZE;
198 size *= sizeof (GtkSignal);
204 gtk_signals = g_realloc (gtk_signals, size);
206 gtk_n_free_signals = size / sizeof (GtkSignal) - gtk_n_signals;
208 memset (gtk_signals + gtk_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
211 new_signal_id = gtk_n_signals++;
212 gtk_n_free_signals--;
214 signal = LOOKUP_SIGNAL_ID (new_signal_id);
216 signal->signal_id = new_signal_id;
222 gtk_signal_init (void)
228 zero = gtk_signal_next_and_invalidate ();
229 g_assert (zero == NULL);
231 handler_key_id = gtk_object_data_force_id ("gtk-signal-handlers");
233 gtk_signal_hash_mem_chunk =
234 g_mem_chunk_new ("GtkSignalHash mem chunk",
235 sizeof (GtkSignalHash),
236 sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
238 gtk_handler_mem_chunk =
239 g_mem_chunk_new ("GtkHandler mem chunk",
241 sizeof (GtkHandler) * HANDLER_BLOCK_SIZE,
243 gtk_emission_mem_chunk =
244 g_mem_chunk_new ("GtkEmission mem chunk",
245 sizeof (GtkEmission),
246 sizeof (GtkEmission) * EMISSION_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,
254 gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
260 gtk_signal_newv (const gchar *name,
261 GtkSignalRunType run_type,
263 guint function_offset,
264 GtkSignalMarshaller marshaller,
274 g_return_val_if_fail (name != NULL, 0);
275 g_return_val_if_fail (marshaller != NULL, 0);
276 g_return_val_if_fail (nparams <= GTK_MAX_SIGNAL_PARAMS, 0);
278 g_return_val_if_fail (params != NULL, 0);
283 type = gtk_signal_lookup (name, object_type);
286 g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
288 gtk_type_name (object_type));
292 signal = gtk_signal_next_and_invalidate ();
294 /* signal->signal_id already set */
296 signal->object_type = object_type;
297 signal->name = g_strdup (name);
298 signal->function_offset = function_offset;
299 signal->run_type = run_type;
300 signal->marshaller = marshaller;
301 signal->return_val = return_val;
302 signal->nparams = nparams;
306 signal->params = g_new (GtkType, nparams);
308 for (i = 0; i < nparams; i++)
309 signal->params[i] = params[i];
312 signal->params = NULL;
314 hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
315 hash->object_type = object_type;
316 hash->name_key_id = gtk_object_data_force_id (signal->name);
317 hash->signal_id = signal->signal_id;
318 g_hash_table_insert (gtk_signal_hash_table, hash, (gpointer) hash->signal_id);
320 return signal->signal_id;
324 gtk_signal_new (const gchar *name,
325 GtkSignalRunType run_type,
327 guint function_offset,
328 GtkSignalMarshaller marshaller,
338 g_return_val_if_fail (nparams <= GTK_MAX_SIGNAL_PARAMS, 0);
342 params = g_new (GtkType, nparams);
344 va_start (args, nparams);
346 for (i = 0; i < nparams; i++)
347 params[i] = va_arg (args, GtkType);
354 signal_id = gtk_signal_newv (name,
369 gtk_signal_lookup (const gchar *name,
374 g_return_val_if_fail (name != NULL, 0);
375 g_return_val_if_fail (GTK_TYPE_IS_A (object_type, GTK_TYPE_OBJECT), 0);
377 hash.name_key_id = gtk_object_data_try_key (name);
378 if (hash.name_key_id)
384 hash.object_type = object_type;
386 signal_id = (guint) g_hash_table_lookup (gtk_signal_hash_table, &hash);
390 object_type = gtk_type_parent (object_type);
398 gtk_signal_query (guint signal_id)
400 GtkSignalQuery *query;
403 g_return_val_if_fail (signal_id >= 1, NULL);
405 signal = LOOKUP_SIGNAL_ID (signal_id);
408 query = g_new (GtkSignalQuery, 1);
410 query->object_type = signal->object_type;
411 query->signal_id = signal_id;
412 query->signal_name = signal->name;
413 query->is_user_signal = signal->function_offset == 0;
414 query->run_type = signal->run_type;
415 query->return_val = signal->return_val;
416 query->nparams = signal->nparams;
417 query->params = signal->params;
426 gtk_signal_name (guint signal_id)
430 g_return_val_if_fail (signal_id >= 1, NULL);
432 signal = LOOKUP_SIGNAL_ID (signal_id);
440 gtk_signal_emit (GtkObject *object,
446 g_return_if_fail (object != NULL);
447 g_return_if_fail (signal_id >= 1);
449 va_start (args, signal_id);
451 gtk_signal_real_emit (object, signal_id, args);
457 gtk_signal_emit_by_name (GtkObject *object,
464 g_return_if_fail (object != NULL);
465 g_return_if_fail (name != NULL);
467 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
471 va_start (args, name);
473 gtk_signal_real_emit (object, signal_id, args);
479 g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
481 gtk_type_name (GTK_OBJECT_TYPE (object)));
486 gtk_signal_emit_stop (GtkObject *object,
489 g_return_if_fail (object != NULL);
490 g_return_if_fail (signal_id >= 1);
492 if (gtk_emission_check (current_emissions, object, signal_id))
493 gtk_emission_add (&stop_emissions, object, signal_id);
495 g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
497 gtk_type_name (GTK_OBJECT_TYPE (object)));
501 gtk_signal_emit_stop_by_name (GtkObject *object,
506 g_return_if_fail (object != NULL);
507 g_return_if_fail (name != NULL);
509 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
511 gtk_signal_emit_stop (object, signal_id);
513 g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
515 gtk_type_name (GTK_OBJECT_TYPE (object)));
519 gtk_signal_n_emissions (GtkObject *object,
525 g_return_val_if_fail (object != NULL, 0);
526 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
529 for (list = current_emissions; list; list = list->next)
531 GtkEmission *emission;
533 emission = list->data;
535 if ((emission->object == object) &&
536 (emission->signal_id == signal_id))
544 gtk_signal_n_emissions_by_name (GtkObject *object,
550 g_return_val_if_fail (object != NULL, 0);
551 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
552 g_return_val_if_fail (name != NULL, 0);
554 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
556 n = gtk_signal_n_emissions (object, signal_id);
559 g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
561 gtk_type_name (GTK_OBJECT_TYPE (object)));
569 gtk_signal_connect (GtkObject *object,
576 g_return_val_if_fail (object != NULL, 0);
577 g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
579 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
582 g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
584 gtk_type_name (GTK_OBJECT_TYPE (object)));
588 return gtk_signal_connect_by_type (object, signal_id,
589 func, func_data, NULL,
590 FALSE, FALSE, FALSE);
594 gtk_signal_connect_after (GtkObject *object,
601 g_return_val_if_fail (object != NULL, 0);
603 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
606 g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
608 gtk_type_name (GTK_OBJECT_TYPE (object)));
612 return gtk_signal_connect_by_type (object, signal_id,
613 func, func_data, NULL,
618 gtk_signal_connect_full (GtkObject *object,
621 GtkCallbackMarshal marshal,
623 GtkDestroyNotify destroy_func,
629 g_return_val_if_fail (object != NULL, 0);
631 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
634 g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
636 gtk_type_name (GTK_OBJECT_TYPE (object)));
641 return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
642 func_data, destroy_func,
643 object_signal, after, TRUE);
645 return gtk_signal_connect_by_type (object, signal_id, func,
646 func_data, destroy_func,
647 object_signal, after, FALSE);
651 gtk_signal_connect_interp (GtkObject *object,
653 GtkCallbackMarshal func,
655 GtkDestroyNotify destroy_func,
658 return gtk_signal_connect_full (object, name, NULL, func,
659 func_data, destroy_func, FALSE, after);
663 gtk_signal_connect_object (GtkObject *object,
666 GtkObject *slot_object)
670 g_return_val_if_fail (object != NULL, 0);
671 /* slot_object needs to be treated as ordinary pointer
674 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
677 g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
679 gtk_type_name (GTK_OBJECT_TYPE (object)));
683 return gtk_signal_connect_by_type (object, signal_id,
684 func, slot_object, NULL,
689 gtk_signal_connect_object_after (GtkObject *object,
692 GtkObject *slot_object)
696 g_return_val_if_fail (object != NULL, 0);
698 signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
701 g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
703 gtk_type_name (GTK_OBJECT_TYPE (object)));
707 return gtk_signal_connect_by_type (object, signal_id,
708 func, slot_object, NULL,
713 gtk_signal_connect_while_alive (GtkObject *object,
717 GtkObject *alive_object)
719 GtkDisconnectInfo *info;
721 g_return_if_fail (object != NULL);
722 g_return_if_fail (GTK_IS_OBJECT (object));
723 g_return_if_fail (signal != NULL);
724 g_return_if_fail (func != NULL);
725 g_return_if_fail (alive_object != NULL);
726 g_return_if_fail (GTK_IS_OBJECT (alive_object));
728 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
729 info->object1 = object;
730 info->object2 = alive_object;
732 info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
733 info->disconnect_handler1 =
734 gtk_signal_connect_object (info->object1,
736 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
738 info->disconnect_handler2 =
739 gtk_signal_connect_object (info->object2,
741 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
746 gtk_signal_connect_object_while_alive (GtkObject *object,
749 GtkObject *alive_object)
751 GtkDisconnectInfo *info;
753 g_return_if_fail (object != NULL);
754 g_return_if_fail (GTK_IS_OBJECT (object));
755 g_return_if_fail (signal != NULL);
756 g_return_if_fail (func != NULL);
757 g_return_if_fail (alive_object != NULL);
758 g_return_if_fail (GTK_IS_OBJECT (alive_object));
760 info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
761 info->object1 = object;
762 info->object2 = alive_object;
764 info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
765 info->disconnect_handler1 =
766 gtk_signal_connect_object (info->object1,
768 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
770 info->disconnect_handler2 =
771 gtk_signal_connect_object (info->object2,
773 GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
778 gtk_signal_disconnect (GtkObject *object,
783 g_return_if_fail (object != NULL);
784 g_return_if_fail (handler_id > 0);
786 handler = gtk_object_get_data_by_id (object, handler_key_id);
790 if (handler->id == handler_id)
793 handler->blocked += 1;
794 gtk_signal_handler_unref (handler, object);
797 handler = handler->next;
800 g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
804 gtk_signal_disconnect_by_func (GtkObject *object,
811 g_return_if_fail (object != NULL);
812 g_return_if_fail (func != NULL);
815 handler = gtk_object_get_data_by_id (object, handler_key_id);
819 GtkHandler *handler_next;
821 handler_next = handler->next;
822 if ((handler->id > 0) &&
823 (handler->func == func) &&
824 (handler->func_data == data))
828 handler->blocked += 1;
829 gtk_signal_handler_unref (handler, object);
831 handler = handler_next;
835 g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
839 gtk_signal_disconnect_by_data (GtkObject *object,
845 g_return_if_fail (object != NULL);
848 handler = gtk_object_get_data_by_id (object, handler_key_id);
852 GtkHandler *handler_next;
854 handler_next = handler->next;
855 if ((handler->id > 0) &&
856 (handler->func_data == data))
860 handler->blocked += 1;
861 gtk_signal_handler_unref (handler, object);
863 handler = handler_next;
867 g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
871 gtk_signal_handler_block (GtkObject *object,
876 g_return_if_fail (object != NULL);
877 g_return_if_fail (handler_id > 0);
879 handler = gtk_object_get_data_by_id (object, handler_key_id);
883 if (handler->id == handler_id)
885 handler->blocked += 1;
888 handler = handler->next;
891 g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
895 gtk_signal_handler_block_by_func (GtkObject *object,
902 g_return_if_fail (object != NULL);
903 g_return_if_fail (func != NULL);
906 handler = gtk_object_get_data_by_id (object, handler_key_id);
910 if ((handler->id > 0) &&
911 (handler->func == func) &&
912 (handler->func_data == data))
915 handler->blocked += 1;
917 handler = handler->next;
921 g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
925 gtk_signal_handler_block_by_data (GtkObject *object,
931 g_return_if_fail (object != NULL);
934 handler = gtk_object_get_data_by_id (object, handler_key_id);
938 if ((handler->id > 0) &&
939 (handler->func_data == data))
942 handler->blocked += 1;
944 handler = handler->next;
948 g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
952 gtk_signal_handler_unblock (GtkObject *object,
957 g_return_if_fail (object != NULL);
958 g_return_if_fail (handler_id > 0);
960 handler = gtk_object_get_data_by_id (object, handler_key_id);
964 if (handler->id == handler_id)
966 if (handler->blocked > 0)
967 handler->blocked -= 1;
969 g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
972 handler = handler->next;
975 g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
979 gtk_signal_handler_unblock_by_func (GtkObject *object,
986 g_return_if_fail (object != NULL);
987 g_return_if_fail (func != NULL);
990 handler = gtk_object_get_data_by_id (object, handler_key_id);
994 if ((handler->id > 0) &&
995 (handler->func == func) &&
996 (handler->func_data == data) &&
997 (handler->blocked > 0))
999 handler->blocked -= 1;
1002 handler = handler->next;
1006 g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1010 gtk_signal_handler_unblock_by_data (GtkObject *object,
1013 GtkHandler *handler;
1016 g_return_if_fail (object != NULL);
1019 handler = gtk_object_get_data_by_id (object, handler_key_id);
1023 if ((handler->id > 0) &&
1024 (handler->func_data == data) &&
1025 (handler->blocked > 0))
1027 handler->blocked -= 1;
1030 handler = handler->next;
1034 g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1038 gtk_signal_handlers_destroy (GtkObject *object)
1040 GtkHandler *handler;
1042 /* we make the "optimization" of destroying the first handler in the last
1043 * place, since we don't want gtk_signal_handler_unref() to reset the objects
1044 * handler_key data on each removal
1047 handler = gtk_object_get_data_by_id (object, handler_key_id);
1050 handler = handler->next;
1055 next = handler->next;
1056 gtk_signal_handler_unref (handler, object);
1059 handler = gtk_object_get_data_by_id (object, handler_key_id);
1060 gtk_signal_handler_unref (handler, object);
1065 gtk_signal_default_marshaller (GtkObject *object,
1070 GtkSignalMarshaller0 rfunc;
1072 rfunc = (GtkSignalMarshaller0) func;
1074 (* rfunc) (object, func_data);
1078 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1079 GtkSignalDestroy destroy_func)
1081 global_marshaller = marshal_func;
1082 global_destroy_notify = destroy_func;
1086 gtk_signal_hash (const gpointer h)
1088 register GtkSignalHash *hash = h;
1090 return hash->object_type ^ hash->name_key_id;
1094 gtk_signal_compare (const gpointer h1,
1097 register GtkSignalHash *hash1 = h1;
1098 register GtkSignalHash *hash2 = h2;
1100 return (hash1->name_key_id == hash2->name_key_id &&
1101 hash1->object_type == hash2->object_type);
1105 gtk_alive_disconnecter (GtkDisconnectInfo *info)
1107 g_return_val_if_fail (info != NULL, 0);
1109 gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1110 gtk_signal_disconnect (info->object1, info->signal_handler);
1111 gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1113 g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1119 gtk_signal_handler_new (void)
1121 GtkHandler *handler;
1123 handler = g_chunk_new (GtkHandler, gtk_handler_mem_chunk);
1126 handler->blocked = 0;
1127 handler->signal_id = 0;
1128 handler->object_signal = FALSE;
1129 handler->after = FALSE;
1130 handler->no_marshal = FALSE;
1131 handler->ref_count = 1;
1132 handler->func = NULL;
1133 handler->func_data = NULL;
1134 handler->destroy_func = NULL;
1135 handler->prev = NULL;
1136 handler->next = NULL;
1142 gtk_signal_handler_ref (GtkHandler *handler)
1144 handler->ref_count += 1;
1148 gtk_signal_handler_unref (GtkHandler *handler,
1151 if (!handler->ref_count)
1153 /* FIXME: i wanna get removed somewhen */
1154 g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1158 handler->ref_count -= 1;
1160 if (handler->ref_count == 0)
1162 if (handler->destroy_func)
1163 (* handler->destroy_func) (handler->func_data);
1164 else if (!handler->func && global_destroy_notify)
1165 (* global_destroy_notify) (handler->func_data);
1168 handler->prev->next = handler->next;
1170 gtk_object_set_data_by_id (object, handler_key_id, handler->next);
1172 handler->next->prev = handler->prev;
1174 g_mem_chunk_free (gtk_handler_mem_chunk, handler);
1179 gtk_signal_handler_insert (GtkObject *object,
1180 GtkHandler *handler)
1184 /* FIXME: remove */ g_assert (handler->next == NULL);
1185 /* FIXME: remove */ g_assert (handler->prev == NULL);
1187 tmp = gtk_object_get_data_by_id (object, handler_key_id);
1189 gtk_object_set_data_by_id (object, handler_key_id, handler);
1193 if (tmp->signal_id < handler->signal_id)
1197 tmp->prev->next = handler;
1198 handler->prev = tmp->prev;
1201 gtk_object_set_data_by_id (object, handler_key_id, handler);
1202 tmp->prev = handler;
1203 handler->next = tmp;
1209 tmp->next = handler;
1210 handler->prev = tmp;
1218 gtk_signal_real_emit (GtkObject *object,
1223 GtkHandler *handlers;
1224 GtkHandlerInfo info;
1225 guchar **signal_func_offset;
1226 GtkArg params[GTK_MAX_SIGNAL_PARAMS];
1228 signal = LOOKUP_SIGNAL_ID (signal_id);
1229 g_return_if_fail (signal != NULL);
1230 g_return_if_fail (GTK_TYPE_IS_A (GTK_OBJECT_TYPE (object), signal->object_type));
1232 if ((signal->run_type & GTK_RUN_NO_RECURSE) &&
1233 gtk_emission_check (current_emissions, object, signal_id))
1235 gtk_emission_add (&restart_emissions, object, signal_id);
1239 gtk_params_get (params, signal->nparams, signal->params,
1240 signal->return_val, args);
1242 gtk_emission_add (¤t_emissions, object, signal_id);
1244 gtk_object_ref (object);
1247 if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST && signal->function_offset != 0)
1249 signal_func_offset = (guchar**) ((guchar*) object->klass +
1250 signal->function_offset);
1251 if (*signal_func_offset)
1252 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1256 info.object = object;
1257 info.marshaller = signal->marshaller;
1258 info.params = params;
1259 info.param_types = signal->params;
1260 info.return_val = signal->return_val;
1261 info.nparams = signal->nparams;
1262 info.run_type = signal->run_type;
1263 info.signal_id = signal_id;
1265 handlers = gtk_signal_get_handlers (object, signal_id);
1266 switch (gtk_handlers_run (handlers, &info, FALSE))
1268 case EMISSION_CONTINUE:
1270 case EMISSION_RESTART:
1271 goto emission_restart;
1276 if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST && signal->function_offset != 0)
1278 signal_func_offset = (guchar**) ((guchar*) object->klass +
1279 signal->function_offset);
1280 if (*signal_func_offset)
1281 (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1285 handlers = gtk_signal_get_handlers (object, signal_id);
1286 switch (gtk_handlers_run (handlers, &info, TRUE))
1288 case EMISSION_CONTINUE:
1290 case EMISSION_RESTART:
1291 goto emission_restart;
1298 gtk_emission_remove (¤t_emissions, object, signal_id);
1300 if (signal->run_type & GTK_RUN_NO_RECURSE)
1301 gtk_emission_remove (&restart_emissions, object, signal_id);
1303 gtk_object_unref (object);
1307 gtk_signal_get_handlers (GtkObject *object,
1310 GtkHandler *handlers;
1312 handlers = gtk_object_get_data_by_id (object, handler_key_id);
1316 if (handlers->signal_id == signal_id)
1318 handlers = handlers->next;
1325 gtk_signal_handler_pending (GtkObject *object,
1327 gboolean may_be_blocked)
1329 GtkHandler *handlers;
1332 g_return_val_if_fail (object != NULL, 0);
1333 g_return_val_if_fail (signal_id >= 1, 0);
1335 handlers = gtk_signal_get_handlers (object, signal_id);
1338 while (handlers && handlers->signal_id == signal_id)
1340 if (handlers->id > 0 &&
1341 (may_be_blocked || handlers->blocked == 0))
1343 handler_id = handlers->id;
1347 handlers = handlers->next;
1354 gtk_signal_connect_by_type (GtkObject *object,
1358 GtkSignalDestroy destroy_func,
1363 GtkObjectClass *class;
1364 GtkHandler *handler;
1367 g_return_val_if_fail (object != NULL, 0);
1368 g_return_val_if_fail (object->klass != NULL, 0);
1370 /* Search through the signals for this object and make
1371 * sure the one we are adding is valid. We need to perform
1372 * the lookup on the objects parents as well. If it isn't
1373 * valid then issue a warning and return.
1376 class = object->klass;
1380 guint *object_signals;
1384 object_signals = class->signals;
1385 nsignals = class->nsignals;
1387 for (i = 0; i < nsignals; i++)
1388 if (object_signals[i] == signal_id)
1394 parent = gtk_type_parent (class->type);
1396 class = gtk_type_class (parent);
1403 g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1405 gtk_type_name (object->klass->type));
1409 handler = gtk_signal_handler_new ();
1410 handler->id = gtk_handler_id++;
1411 handler->signal_id = signal_id;
1412 handler->object_signal = object_signal;
1413 handler->func = func;
1414 handler->func_data = func_data;
1415 handler->destroy_func = destroy_func;
1416 handler->after = after != FALSE;
1417 handler->no_marshal = no_marshal;
1419 gtk_signal_handler_insert (object, handler);
1424 gtk_emission_new (void)
1426 GtkEmission *emission;
1428 emission = g_chunk_new (GtkEmission, gtk_emission_mem_chunk);
1430 emission->object = NULL;
1431 emission->signal_id = 0;
1437 gtk_emission_destroy (GtkEmission *emission)
1439 g_mem_chunk_free (gtk_emission_mem_chunk, emission);
1443 gtk_emission_add (GList **emissions,
1447 GtkEmission *emission;
1449 g_return_if_fail (emissions != NULL);
1450 g_return_if_fail (object != NULL);
1452 emission = gtk_emission_new ();
1453 emission->object = object;
1454 emission->signal_id = signal_id;
1456 *emissions = g_list_prepend (*emissions, emission);
1460 gtk_emission_remove (GList **emissions,
1464 GtkEmission *emission;
1467 g_return_if_fail (emissions != NULL);
1472 emission = tmp->data;
1474 if ((emission->object == object) &&
1475 (emission->signal_id == signal_id))
1477 gtk_emission_destroy (emission);
1478 *emissions = g_list_remove_link (*emissions, tmp);
1488 gtk_emission_check (GList *emissions,
1492 GtkEmission *emission;
1498 emission = tmp->data;
1501 if ((emission->object == object) &&
1502 (emission->signal_id == signal_id))
1509 gtk_handlers_run (GtkHandler *handlers,
1510 GtkHandlerInfo *info,
1513 while (handlers && handlers->signal_id == info->signal_id)
1515 GtkHandler *handlers_next;
1517 gtk_signal_handler_ref (handlers);
1519 if (handlers->blocked == 0 && (handlers->after == after))
1523 if (handlers->no_marshal)
1524 (* (GtkCallbackMarshal) handlers->func) (info->object,
1525 handlers->func_data,
1528 else if (handlers->object_signal)
1529 (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
1531 handlers->func_data,
1534 (* info->marshaller) (info->object,
1536 handlers->func_data,
1539 else if (global_marshaller)
1540 (* global_marshaller) (info->object,
1541 handlers->func_data,
1547 if (gtk_emission_check (stop_emissions, info->object,
1550 gtk_emission_remove (&stop_emissions, info->object,
1553 if (info->run_type & GTK_RUN_NO_RECURSE)
1554 gtk_emission_remove (&restart_emissions, info->object,
1556 gtk_signal_handler_unref (handlers, info->object);
1557 return EMISSION_DONE;
1559 else if ((info->run_type & GTK_RUN_NO_RECURSE) &&
1560 gtk_emission_check (restart_emissions, info->object,
1563 gtk_emission_remove (&restart_emissions, info->object,
1565 gtk_signal_handler_unref (handlers, info->object);
1566 return EMISSION_RESTART;
1570 handlers_next = handlers->next;
1571 gtk_signal_handler_unref (handlers, info->object);
1572 handlers = handlers_next;
1575 return EMISSION_CONTINUE;
1579 gtk_params_get (GtkArg *params,
1581 GtkType *param_types,
1587 for (i = 0; i < nparams; i++)
1589 params[i].type = param_types[i];
1590 params[i].name = NULL;
1592 switch (GTK_FUNDAMENTAL_TYPE (param_types[i]))
1594 case GTK_TYPE_INVALID:
1599 GTK_VALUE_CHAR(params[i]) = va_arg (args, gint);
1602 GTK_VALUE_BOOL(params[i]) = va_arg (args, gint);
1605 GTK_VALUE_INT(params[i]) = va_arg (args, gint);
1608 GTK_VALUE_UINT(params[i]) = va_arg (args, guint);
1611 GTK_VALUE_ENUM(params[i]) = va_arg (args, gint);
1613 case GTK_TYPE_FLAGS:
1614 GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint);
1617 GTK_VALUE_LONG(params[i]) = va_arg (args, glong);
1619 case GTK_TYPE_ULONG:
1620 GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong);
1622 case GTK_TYPE_FLOAT:
1623 GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat);
1625 case GTK_TYPE_DOUBLE:
1626 GTK_VALUE_DOUBLE(params[i]) = va_arg (args, gdouble);
1628 case GTK_TYPE_STRING:
1629 GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*);
1631 case GTK_TYPE_POINTER:
1632 GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer);
1634 case GTK_TYPE_BOXED:
1635 GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer);
1637 case GTK_TYPE_SIGNAL:
1638 GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction);
1639 GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer);
1641 case GTK_TYPE_FOREIGN:
1642 GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer);
1643 GTK_VALUE_FOREIGN(params[i]).notify =
1644 va_arg (args, GtkDestroyNotify);
1646 case GTK_TYPE_CALLBACK:
1647 GTK_VALUE_CALLBACK(params[i]).marshal =
1648 va_arg (args, GtkCallbackMarshal);
1649 GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer);
1650 GTK_VALUE_CALLBACK(params[i]).notify =
1651 va_arg (args, GtkDestroyNotify);
1653 case GTK_TYPE_C_CALLBACK:
1654 GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction);
1655 GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer);
1658 GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, gint);
1659 GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*);
1661 case GTK_TYPE_OBJECT:
1662 GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*);
1663 if (GTK_VALUE_OBJECT(params[i]) != NULL &&
1664 !GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]), params[i].type))
1665 g_warning ("signal arg `%s' is not of type `%s'",
1666 gtk_type_name (GTK_OBJECT_TYPE (GTK_VALUE_OBJECT(params[i]))),
1667 gtk_type_name (params[i].type));
1670 g_error ("unsupported type `%s' in signal arg",
1671 gtk_type_name (params[i].type));
1676 params[i].type = return_val;
1677 params[i].name = NULL;
1679 switch (GTK_FUNDAMENTAL_TYPE (return_val))
1681 case GTK_TYPE_INVALID:
1686 params[i].d.pointer_data = va_arg (args, gchar*);
1689 params[i].d.pointer_data = va_arg (args, gint*);
1692 params[i].d.pointer_data = va_arg (args, gint*);
1695 params[i].d.pointer_data = va_arg (args, guint*);
1698 params[i].d.pointer_data = va_arg (args, gint*);
1700 case GTK_TYPE_FLAGS:
1701 params[i].d.pointer_data = va_arg (args, gint*);
1704 params[i].d.pointer_data = va_arg (args, glong*);
1706 case GTK_TYPE_ULONG:
1707 params[i].d.pointer_data = va_arg (args, gulong*);
1709 case GTK_TYPE_FLOAT:
1710 params[i].d.pointer_data = va_arg (args, gfloat*);
1712 case GTK_TYPE_DOUBLE:
1713 params[i].d.pointer_data = va_arg (args, gdouble*);
1715 case GTK_TYPE_STRING:
1716 params[i].d.pointer_data = va_arg (args, gchar**);
1718 case GTK_TYPE_POINTER:
1719 params[i].d.pointer_data = va_arg (args, gpointer*);
1721 case GTK_TYPE_BOXED:
1722 params[i].d.pointer_data = va_arg (args, gpointer*);
1724 case GTK_TYPE_OBJECT:
1725 params[i].d.pointer_data = va_arg (args, GtkObject**);
1727 case GTK_TYPE_SIGNAL:
1728 case GTK_TYPE_FOREIGN:
1729 case GTK_TYPE_CALLBACK:
1730 case GTK_TYPE_C_CALLBACK:
1733 g_error ("unsupported type `%s' in signal return",
1734 gtk_type_name (return_val));