]> Pileus Git - ~andy/gtk/blob - gtk/gtksignal.c
typos and warning fixes.
[~andy/gtk] / gtk / gtksignal.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <stdarg.h>
19 #include "gtksignal.h"
20
21
22 #define MAX_PARAMS       20
23 #define DONE             1
24 #define RESTART          2
25
26 #define GTK_RUN_TYPE(x)  ((x) & GTK_RUN_MASK)
27
28
29 typedef struct _GtkSignal       GtkSignal;
30 typedef struct _GtkSignalInfo   GtkSignalInfo;
31 typedef struct _GtkHandler      GtkHandler;
32 typedef struct _GtkHandlerInfo  GtkHandlerInfo;
33 typedef struct _GtkEmission     GtkEmission;
34
35 typedef void (*GtkSignalMarshaller0) (GtkObject *object,
36                                       gpointer   data);
37
38 struct _GtkSignalInfo
39 {
40   gchar *name;
41   gint object_type;
42   gint signal_type;
43 };
44
45 struct _GtkSignal
46 {
47   GtkSignalInfo info;
48   gint function_offset;
49   GtkSignalRunType run_type;
50   GtkSignalMarshaller marshaller;
51   GtkType return_val;
52   GtkType *params;
53   gint nparams;
54 };
55
56 struct _GtkHandler
57 {
58   guint id : 28;
59   guint blocked : 1;
60   guint object_signal : 1;
61   guint after : 1;
62   guint no_marshal : 1;
63   guint16 ref_count;
64   guint16 signal_type;
65   GtkSignalFunc func;
66   gpointer func_data;
67   GtkSignalDestroy destroy_func;
68   GtkHandler *prev;
69   GtkHandler *next;
70 };
71
72 struct _GtkHandlerInfo
73 {
74   GtkObject *object;
75   GtkSignalMarshaller marshaller;
76   GtkArg *params;
77   GtkType *param_types;
78   GtkType return_val;
79   GtkSignalRunType run_type;
80   gint nparams;
81   gint signal_type;
82 };
83
84 struct _GtkEmission
85 {
86   GtkObject *object;
87   gint signal_type;
88 };
89
90
91 static void         gtk_signal_init            (void);
92 static guint        gtk_signal_hash            (gint          *key);
93 static gint         gtk_signal_compare         (gint          *a,
94                                                 gint          *b);
95 static guint        gtk_signal_info_hash       (GtkSignalInfo *a);
96 static gint         gtk_signal_info_compare    (GtkSignalInfo *a,
97                                                 GtkSignalInfo *b);
98 static GtkHandler*  gtk_signal_handler_new     (void);
99 static void         gtk_signal_handler_ref     (GtkHandler    *handler);
100 static void         gtk_signal_handler_unref   (GtkHandler    *handler,
101                                                 GtkObject     *object);
102 static void         gtk_signal_handler_insert  (GtkObject     *object,
103                                                 GtkHandler    *handler);
104 static void         gtk_signal_real_emit       (GtkObject     *object,
105                                                 gint           signal_type,
106                                                 va_list        args);
107 static GtkHandler*  gtk_signal_get_handlers    (GtkObject     *object,
108                                                 gint           signal_type);
109 static gint         gtk_signal_connect_by_type (GtkObject     *object,
110                                                 gint           signal_type,
111                                                 GtkSignalFunc  func,
112                                                 gpointer       func_data,
113                                                 GtkSignalDestroy destroy_func,
114                                                 gint           object_signal,
115                                                 gint           after,
116                                                 gint           no_marshal);
117 static GtkEmission* gtk_emission_new           (void);
118 static void         gtk_emission_destroy       (GtkEmission    *emission);
119 static void         gtk_emission_add           (GList         **emissions,
120                                                 GtkObject      *object,
121                                                 gint            signal_type);
122 static void         gtk_emission_remove        (GList         **emissions,
123                                                 GtkObject      *object,
124                                                 gint            signal_type);
125 static gint         gtk_emission_check         (GList          *emissions,
126                                                 GtkObject      *object,
127                                                 gint            signal_type);
128 static gint         gtk_handlers_run           (GtkHandler     *handlers,
129                                                 GtkHandlerInfo *info,
130                                                 gint            after);
131 static void         gtk_params_get             (GtkArg         *params,
132                                                 gint            nparams,
133                                                 GtkType        *param_types,
134                                                 GtkType         return_val,
135                                                 va_list         args);
136
137
138 static gint initialize = TRUE;
139 static GHashTable *signal_hash_table = NULL;
140 static GHashTable *signal_info_hash_table = NULL;
141 static guint next_signal = 1;
142 static guint next_handler_id = 1;
143
144 static const gchar *handler_key = "gtk-signal-handlers";
145
146 static GMemChunk *handler_mem_chunk = NULL;
147 static GMemChunk *emission_mem_chunk = NULL;
148
149 static GList *current_emissions = NULL;
150 static GList *stop_emissions = NULL;
151 static GList *restart_emissions = NULL;
152
153 static GtkSignalMarshal marshal = NULL;
154 static GtkSignalDestroy destroy = NULL;
155
156
157 gint
158 gtk_signal_new (const gchar         *name,
159                 GtkSignalRunType     run_type,
160                 gint                 object_type,
161                 gint                 function_offset,
162                 GtkSignalMarshaller  marshaller,
163                 GtkType              return_val,
164                 gint                 nparams,
165                 ...)
166 {
167   GtkType *params;
168   guint i;
169   va_list args;
170   gint return_id;
171
172   g_return_val_if_fail (nparams < 16, 0);
173
174   if (nparams > 0)
175     {
176       params = g_new (GtkType, nparams);
177
178       va_start (args, nparams);
179
180       for (i = 0; i < nparams; i++)
181         params[i] = va_arg (args, GtkType);
182
183       va_end (args);
184     }
185   else
186     params = NULL;
187
188   return_id = gtk_signal_newv (name,
189                                run_type,
190                                object_type,
191                                function_offset,
192                                marshaller,
193                                return_val,
194                                nparams,
195                                params);
196
197   g_free (params);
198
199   return return_id;
200 }
201
202 gint
203 gtk_signal_newv (const gchar         *name,
204                  GtkSignalRunType     run_type,
205                  gint                 object_type,
206                  gint                 function_offset,
207                  GtkSignalMarshaller  marshaller,
208                  GtkType              return_val,
209                  gint                 nparams,
210                  GtkType             *params)
211 {
212   GtkSignal *signal;
213   GtkSignalInfo info;
214   gint *type;
215   guint i;
216
217   g_return_val_if_fail (name != NULL, 0);
218   g_return_val_if_fail (marshaller != NULL, 0);
219   g_return_val_if_fail (nparams < 16, 0);
220   if (nparams)
221     g_return_val_if_fail (params != NULL, 0);
222
223   if (initialize)
224     gtk_signal_init ();
225
226   info.name = (char*)name;
227   info.object_type = object_type;
228
229   type = g_hash_table_lookup (signal_info_hash_table, &info);
230   if (type)
231     {
232       g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
233                  name, gtk_type_name (object_type));
234       return 0;
235     }
236
237   signal = g_new (GtkSignal, 1);
238   signal->info.name = g_strdup (name);
239   signal->info.object_type = object_type;
240   signal->info.signal_type = next_signal++;
241   signal->function_offset = function_offset;
242   signal->run_type = run_type;
243   signal->marshaller = marshaller;
244   signal->return_val = return_val;
245   signal->nparams = nparams;
246
247   if (nparams > 0)
248     {
249       signal->params = g_new (GtkType, nparams);
250
251       for (i = 0; i < nparams; i++)
252         signal->params[i] = params[i];
253     }
254   else
255     signal->params = NULL;
256
257   g_hash_table_insert (signal_hash_table, &signal->info.signal_type, signal);
258   g_hash_table_insert (signal_info_hash_table, &signal->info, &signal->info.signal_type);
259
260   return signal->info.signal_type;
261 }
262
263 GtkSignalQuery*
264 gtk_signal_query (gint                 signal_num)
265 {
266   GtkSignalQuery *query;
267   GtkSignal *signal;
268
269   signal = g_hash_table_lookup (signal_hash_table, &signal_num);
270   if (signal)
271     {
272       query = g_new (GtkSignalQuery, 1);
273
274       query->object_type = signal->info.object_type;
275       query->signal_name = signal->info.name;
276       query->is_user_signal = signal->function_offset == 0;
277       query->run_type = signal->run_type;
278       query->return_val = signal->return_val;
279       query->nparams = signal->nparams;
280       query->params = signal->params;
281     }
282   else
283     query = NULL;
284
285   return query;
286 }
287
288 gint
289 gtk_signal_lookup (const gchar *name,
290                    gint         object_type)
291 {
292   GtkSignalInfo info;
293   gint *type;
294
295   g_return_val_if_fail (name != NULL, 0);
296
297   if (initialize)
298     gtk_signal_init ();
299
300   info.name = (char*)name;
301
302   while (object_type)
303     {
304       info.object_type = object_type;
305
306       type = g_hash_table_lookup (signal_info_hash_table, &info);
307       if (type)
308         return *type;
309
310       object_type = gtk_type_parent (object_type);
311     }
312
313   return 0;
314 }
315
316 gchar*
317 gtk_signal_name (gint signal_num)
318 {
319   GtkSignal *signal;
320
321   signal = g_hash_table_lookup (signal_hash_table, &signal_num);
322   if (signal)
323     return signal->info.name;
324
325   return NULL;
326 }
327
328 void
329 gtk_signal_emit (GtkObject *object,
330                  gint       signal_type,
331                  ...)
332 {
333   va_list args;
334
335   g_return_if_fail (object != NULL);
336
337   if (initialize)
338     gtk_signal_init ();
339
340   va_start (args, signal_type);
341
342   gtk_signal_real_emit (object, signal_type, args);
343
344   va_end (args);
345 }
346
347 void
348 gtk_signal_emit_by_name (GtkObject       *object,
349                          const gchar     *name,
350                          ...)
351 {
352   gint type;
353   va_list args;
354
355   g_return_if_fail (object != NULL);
356
357   if (initialize)
358     gtk_signal_init ();
359
360   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
361
362   if (type)
363     {
364       va_start (args, name);
365
366       gtk_signal_real_emit (object, type, args);
367
368       va_end (args);
369     }
370   else
371     {
372       g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
373                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
374     }
375 }
376
377 void
378 gtk_signal_emit_stop (GtkObject *object,
379                       gint       signal_type)
380 {
381   g_return_if_fail (object != NULL);
382   g_return_if_fail (signal_type >= 1);
383
384   if (initialize)
385     gtk_signal_init ();
386
387   if (gtk_emission_check (current_emissions, object, signal_type))
388     gtk_emission_add (&stop_emissions, object, signal_type);
389   else
390     g_warning ("gtk_signal_emit_stop(): no current emission (%d) for object `%s'",
391                signal_type, gtk_type_name (GTK_OBJECT_TYPE (object)));
392 }
393
394 void
395 gtk_signal_emit_stop_by_name (GtkObject       *object,
396                               const gchar     *name)
397 {
398   gint type;
399
400   g_return_if_fail (object != NULL);
401   g_return_if_fail (name != NULL);
402
403   if (initialize)
404     gtk_signal_init ();
405
406   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
407   if (type)
408     gtk_signal_emit_stop (object, type);
409   else
410     g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
411                name, gtk_type_name (GTK_OBJECT_TYPE (object)));
412 }
413
414 gint
415 gtk_signal_connect (GtkObject     *object,
416                     const gchar   *name,
417                     GtkSignalFunc  func,
418                     gpointer       func_data)
419 {
420   gint type;
421
422   g_return_val_if_fail (object != NULL, 0);
423
424   if (initialize)
425     gtk_signal_init ();
426
427   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
428   if (!type)
429     {
430       g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
431                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
432       return 0;
433     }
434
435   return gtk_signal_connect_by_type (object, type, 
436                                      func, func_data, NULL,
437                                      FALSE, FALSE, FALSE);
438 }
439
440 gint
441 gtk_signal_connect_after (GtkObject     *object,
442                           const gchar   *name,
443                           GtkSignalFunc  func,
444                           gpointer       func_data)
445 {
446   gint type;
447
448   g_return_val_if_fail (object != NULL, 0);
449
450   if (initialize)
451     gtk_signal_init ();
452
453   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
454   if (!type)
455     {
456       g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
457                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
458       return 0;
459     }
460
461   return gtk_signal_connect_by_type (object, type, 
462                                      func, func_data, NULL,
463                                      FALSE, TRUE, FALSE);
464 }
465
466 gint   
467 gtk_signal_connect_full (GtkObject           *object,
468                          gchar               *name,
469                          GtkSignalFunc        func,
470                          GtkCallbackMarshal   marshal,
471                          gpointer             func_data,
472                          GtkDestroyNotify     destroy_func,
473                          gint                 object_signal,
474                          gint                 after)
475 {
476   gint type;
477
478   g_return_val_if_fail (object != NULL, 0);
479
480   if (initialize)
481     gtk_signal_init ();
482
483   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
484   if (!type)
485     {
486       g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
487                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
488       return 0;
489     }
490
491   if (marshal)
492     return gtk_signal_connect_by_type (object, type, (GtkSignalFunc) marshal, 
493                                        func_data, destroy_func, 
494                                        object_signal, after, TRUE);
495   else
496     return gtk_signal_connect_by_type (object, type, func, 
497                                        func_data, destroy_func, 
498                                        object_signal, after, FALSE);
499 }
500
501 gint
502 gtk_signal_connect_interp (GtkObject         *object,
503                            gchar             *name,
504                            GtkCallbackMarshal func,
505                            gpointer           func_data,
506                            GtkDestroyNotify   destroy_func,
507                            gint               after)
508 {
509   return gtk_signal_connect_full (object, name, NULL, func,
510                                   func_data, destroy_func, FALSE, after);
511 }
512
513 gint
514 gtk_signal_connect_object (GtkObject     *object,
515                            const gchar   *name,
516                            GtkSignalFunc  func,
517                            GtkObject     *slot_object)
518 {
519   gint type;
520
521   g_return_val_if_fail (object != NULL, 0);
522   /* slot_object needs to be treated as ordinary pointer */
523
524   if (initialize)
525     gtk_signal_init ();
526
527   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
528   if (!type)
529     {
530       g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
531                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
532       return 0;
533     }
534
535   return gtk_signal_connect_by_type (object, type, 
536                                      func, slot_object, NULL,
537                                      TRUE, FALSE, FALSE);
538 }
539
540 gint
541 gtk_signal_connect_object_after (GtkObject     *object,
542                                  const gchar   *name,
543                                  GtkSignalFunc  func,
544                                  GtkObject     *slot_object)
545 {
546   gint type;
547
548   g_return_val_if_fail (object != NULL, 0);
549
550   if (initialize)
551     gtk_signal_init ();
552
553   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
554   if (!type)
555     {
556       g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
557                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
558       return 0;
559     }
560
561   return gtk_signal_connect_by_type (object, type, 
562                                      func, slot_object, NULL,
563                                      TRUE, TRUE, FALSE);
564 }
565
566 typedef struct _GtkDisconnectInfo       GtkDisconnectInfo;
567 struct _GtkDisconnectInfo
568 {
569   GtkObject     *object1;
570   gint          disconnect_handler1;
571   gint          signal_handler;
572   GtkObject     *object2;
573   gint          disconnect_handler2;
574 };
575
576 static gint
577 gtk_alive_disconnecter (GtkDisconnectInfo *info)
578 {
579   g_return_val_if_fail (info != NULL, 0);
580
581   gtk_signal_disconnect (info->object1, info->disconnect_handler1);
582   gtk_signal_disconnect (info->object1, info->signal_handler);
583   gtk_signal_disconnect (info->object2, info->disconnect_handler2);
584   g_free (info);
585
586   return 0;
587 }
588
589 void
590 gtk_signal_connect_while_alive (GtkObject        *object,
591                                 const gchar      *signal,
592                                 GtkSignalFunc     func,
593                                 gpointer          func_data,
594                                 GtkObject        *alive_object)
595 {
596   GtkDisconnectInfo *info;
597
598   g_return_if_fail (object != NULL);
599   g_return_if_fail (GTK_IS_OBJECT (object));
600   g_return_if_fail (signal != NULL);
601   g_return_if_fail (func != NULL);
602   g_return_if_fail (alive_object != NULL);
603   g_return_if_fail (GTK_IS_OBJECT (alive_object));
604
605   info = g_new (GtkDisconnectInfo, 1);
606   info->object1 = object;
607   info->object2 = alive_object;
608
609   info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
610   info->disconnect_handler1 = gtk_signal_connect_object (info->object1,
611                                                          "destroy",
612                                                          GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
613                                                          (GtkObject*) info);
614   info->disconnect_handler2 = gtk_signal_connect_object (info->object2,
615                                                          "destroy",
616                                                          GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
617                                                          (GtkObject*) info);
618 }
619
620 void
621 gtk_signal_connect_object_while_alive (GtkObject        *object,
622                                        const gchar      *signal,
623                                        GtkSignalFunc     func,
624                                        GtkObject        *alive_object)
625 {
626   GtkDisconnectInfo *info;
627
628   g_return_if_fail (object != NULL);
629   g_return_if_fail (GTK_IS_OBJECT (object));
630   g_return_if_fail (signal != NULL);
631   g_return_if_fail (func != NULL);
632   g_return_if_fail (alive_object != NULL);
633   g_return_if_fail (GTK_IS_OBJECT (alive_object));
634
635   info = g_new (GtkDisconnectInfo, 1);
636   info->object1 = object;
637   info->object2 = alive_object;
638
639   info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
640   info->disconnect_handler1 = gtk_signal_connect_object (info->object1,
641                                                          "destroy",
642                                                          GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
643                                                          (GtkObject*) info);
644   info->disconnect_handler2 = gtk_signal_connect_object (info->object2,
645                                                          "destroy",
646                                                          GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
647                                                          (GtkObject*) info);
648 }
649
650 void
651 gtk_signal_disconnect (GtkObject *object,
652                        gint       an_id)
653 {
654   GtkHandler *handler;
655
656   g_return_if_fail (object != NULL);
657   g_return_if_fail (an_id > 0);
658
659   handler = gtk_object_get_data (object, handler_key);
660
661   while (handler)
662     {
663       if (handler->id == an_id)
664         {
665           handler->id = 0;
666           handler->blocked = TRUE;
667           gtk_signal_handler_unref (handler, object);
668           return;
669         }
670       handler = handler->next;
671     }
672
673   g_warning ("gtk_signal_disconnect(): could not find handler (%d)", an_id);
674 }
675
676 void
677 gtk_signal_disconnect_by_data (GtkObject *object,
678                                gpointer   data)
679 {
680   GtkHandler *handler;
681   gint found_one;
682
683   g_return_if_fail (object != NULL);
684
685   found_one = FALSE;
686   handler = gtk_object_get_data (object, handler_key);
687
688   while (handler)
689     {
690       GtkHandler *handler_next;
691
692       handler_next = handler->next;
693       if (handler->func_data == data &&
694           handler->id > 0)
695         {
696           found_one = TRUE;
697           handler->id = 0;
698           handler->blocked = TRUE;
699           gtk_signal_handler_unref (handler, object);
700         }
701       handler = handler_next;
702     }
703
704   if (!found_one)
705     g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
706 }
707
708 void
709 gtk_signal_handler_block (GtkObject *object,
710                           gint       an_id)
711 {
712   GtkHandler *tmp;
713
714   g_return_if_fail (object != NULL);
715   g_return_if_fail (an_id > 0);
716
717   tmp = gtk_object_get_data (object, handler_key);
718
719   while (tmp)
720     {
721       if (tmp->id == an_id)
722         {
723           tmp->blocked = TRUE;
724           return;
725         }
726
727       tmp = tmp->next;
728     }
729
730   g_warning ("gtk_signal_handler_block(): could not find handler (%d)", an_id);
731 }
732
733 void
734 gtk_signal_handler_block_by_data (GtkObject *object,
735                                   gpointer   data)
736 {
737   GtkHandler *handler;
738   gint found_one;
739
740   g_return_if_fail (object != NULL);
741
742   if (initialize)
743     gtk_signal_init ();
744
745   found_one = FALSE;
746   handler = gtk_object_get_data (object, handler_key);
747
748   while (handler)
749     {
750       if (handler->func_data == data &&
751           handler->id > 0)
752         {
753           found_one = TRUE;
754           handler->blocked = TRUE;
755         }
756
757       handler = handler->next;
758     }
759
760   if (!found_one)
761     g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
762 }
763
764 void
765 gtk_signal_handler_unblock (GtkObject *object,
766                             gint       an_id)
767 {
768   GtkHandler *handler;
769
770   g_return_if_fail (object != NULL);
771   g_return_if_fail (an_id > 0);
772
773   if (initialize)
774     gtk_signal_init ();
775
776   handler = gtk_object_get_data (object, handler_key);
777
778   while (handler)
779     {
780       if (handler->id == an_id)
781         {
782           handler->blocked = FALSE;
783           return;
784         }
785
786       handler = handler->next;
787     }
788
789   g_warning ("gtk_signal_handler_unblock(): could not find handler (%d)", an_id);
790 }
791
792 void
793 gtk_signal_handler_unblock_by_data (GtkObject *object,
794                                     gpointer   data)
795 {
796   GtkHandler *handler;
797   gint found_one;
798
799   g_return_if_fail (object != NULL);
800
801   if (initialize)
802     gtk_signal_init ();
803
804   found_one = FALSE;
805   handler = gtk_object_get_data (object, handler_key);
806
807   while (handler)
808     {
809       if (handler->func_data == data &&
810           handler->id > 0)
811         {
812           found_one = TRUE;
813           handler->blocked = FALSE;
814         }
815
816       handler = handler->next;
817     }
818
819   if (!found_one)
820     g_warning ("gtk_signal_handler_unblock_by_data(): could not find handler containing data (0x%0lX)", (long) data);
821 }
822
823 void
824 gtk_signal_handlers_destroy (GtkObject *object)
825 {
826   GtkHandler *handler;
827
828   /* we make the "optimization" of destroying the first handler in the last
829    * place, since we don't want gtk_signal_handler_unref() to reset the objects
830    * handler_key data on each removal
831    */
832
833   handler = gtk_object_get_data (object, handler_key);
834   if (handler)
835     {
836       handler = handler->next;
837       while (handler)
838         {
839           GtkHandler *next;
840
841           next = handler->next;
842           gtk_signal_handler_unref (handler, object);
843           handler = next;
844         }
845       handler = gtk_object_get_data (object, handler_key);
846       gtk_signal_handler_unref (handler, object);
847     }
848 }
849
850 void
851 gtk_signal_default_marshaller (GtkObject      *object,
852                                GtkSignalFunc   func,
853                                gpointer        func_data,
854                                GtkArg         *params)
855 {
856   GtkSignalMarshaller0 rfunc;
857
858   rfunc = (GtkSignalMarshaller0) func;
859
860   (* rfunc) (object, func_data);
861 }
862
863 void
864 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
865                       GtkSignalDestroy destroy_func)
866 {
867   marshal = marshal_func;
868   destroy = destroy_func;
869 }
870
871
872 static void
873 gtk_signal_init ()
874 {
875   if (initialize)
876     {
877       initialize = FALSE;
878       signal_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_hash,
879                                             (GCompareFunc) gtk_signal_compare);
880       signal_info_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_info_hash,
881                                                  (GCompareFunc) gtk_signal_info_compare);
882     }
883 }
884
885 static guint
886 gtk_signal_hash (gint *key)
887 {
888   return (guint) *key;
889 }
890
891 static gint
892 gtk_signal_compare (gint *a,
893                     gint *b)
894 {
895   return (*a == *b);
896 }
897
898 static guint
899 gtk_signal_info_hash (GtkSignalInfo *a)
900 {
901   return (g_str_hash (a->name) + a->object_type);
902 }
903
904 static gint
905 gtk_signal_info_compare (GtkSignalInfo *a,
906                          GtkSignalInfo *b)
907 {
908   return ((a->object_type == b->object_type) &&
909           g_str_equal (a->name, b->name));
910 }
911
912 static GtkHandler*
913 gtk_signal_handler_new ()
914 {
915   GtkHandler *handler;
916
917   if (!handler_mem_chunk)
918     handler_mem_chunk = g_mem_chunk_new ("handler mem chunk", sizeof (GtkHandler),
919                                          1024, G_ALLOC_AND_FREE);
920
921   handler = g_chunk_new (GtkHandler, handler_mem_chunk);
922
923   handler->id = 0;
924   handler->ref_count = 1;
925   handler->signal_type = 0;
926   handler->blocked = FALSE;
927   handler->object_signal = FALSE;
928   handler->after = FALSE;
929   handler->no_marshal = FALSE;
930   handler->func = NULL;
931   handler->func_data = NULL;
932   handler->destroy_func = NULL;
933   handler->prev = NULL;
934   handler->next = NULL;
935
936   return handler;
937 }
938
939 static void
940 gtk_signal_handler_ref (GtkHandler *handler)
941 {
942   handler->ref_count += 1;
943 }
944
945 static void
946 gtk_signal_handler_unref (GtkHandler *handler,
947                           GtkObject  *object)
948 {
949   if (!handler->ref_count)
950     {
951       /* FIXME: i wanna get removed some when (maybe at gtk+-1.0?) */
952       g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
953       return;
954     }
955
956   handler->ref_count -= 1;
957   if (handler->ref_count == 0)
958     {
959       if (!handler->func && destroy)
960         (* destroy) (handler->func_data);
961       else if (handler->destroy_func)
962         (* handler->destroy_func) (handler->func_data);
963
964
965       if (handler->prev)
966         handler->prev->next = handler->next;
967       else
968         gtk_object_set_data (object, handler_key, handler->next);
969       if (handler->next)
970         handler->next->prev = handler->prev;
971
972       g_mem_chunk_free (handler_mem_chunk, handler);
973     }
974 }
975
976 static void
977 gtk_signal_handler_insert (GtkObject  *object,
978                            GtkHandler *handler)
979 {
980   GtkHandler *tmp;
981   
982   /* FIXME: remove */ g_assert (handler->next == NULL);
983   /* FIXME: remove */ g_assert (handler->prev == NULL);
984   
985   tmp = gtk_object_get_data (object, handler_key);
986   if (!tmp)
987     gtk_object_set_data (object, handler_key, handler);
988   else
989     while (tmp)
990       {
991         if (tmp->signal_type < handler->signal_type)
992           {
993             if (tmp->prev)
994               {
995                 tmp->prev->next = handler;
996                 handler->prev = tmp->prev;
997               }
998             else
999               gtk_object_set_data (object, handler_key, handler);
1000             tmp->prev = handler;
1001             handler->next = tmp;
1002             break;
1003           }
1004
1005         if (!tmp->next)
1006           {
1007             tmp->next = handler;
1008             handler->prev = tmp;
1009             break;
1010           }
1011         tmp = tmp->next;
1012       }
1013 }
1014
1015 static void
1016 gtk_signal_real_emit (GtkObject *object,
1017                       gint       signal_type,
1018                       va_list    args)
1019 {
1020   GtkSignal *signal;
1021   GtkHandler *handlers;
1022   GtkHandlerInfo info;
1023   guchar **signal_func_offset;
1024   GtkArg         params[MAX_PARAMS];
1025   
1026   g_return_if_fail (object != NULL);
1027   g_return_if_fail (signal_type >= 1);
1028   
1029   signal = g_hash_table_lookup (signal_hash_table, &signal_type);
1030   g_return_if_fail (signal != NULL);
1031   g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object),
1032                                    signal->info.object_type));
1033   
1034   if ((signal->run_type & GTK_RUN_NO_RECURSE) &&
1035       gtk_emission_check (current_emissions, object, signal_type))
1036     {
1037       gtk_emission_add (&restart_emissions, object, signal_type);
1038       return;
1039     }
1040   
1041   gtk_params_get (params, signal->nparams, signal->params,
1042                   signal->return_val, args);
1043   
1044   gtk_emission_add (&current_emissions, object, signal_type);
1045   
1046   gtk_object_ref (object);
1047   
1048 restart:
1049   if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST && signal->function_offset != 0)
1050     {
1051       signal_func_offset = (guchar**) ((guchar*) object->klass +
1052                                        signal->function_offset);
1053       if (*signal_func_offset)
1054         (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1055                                 NULL, params);
1056     }
1057   
1058   info.object = object;
1059   info.marshaller = signal->marshaller;
1060   info.params = params;
1061   info.param_types = signal->params;
1062   info.return_val = signal->return_val;
1063   info.nparams = signal->nparams;
1064   info.run_type = signal->run_type;
1065   info.signal_type = signal_type;
1066   
1067   handlers = gtk_signal_get_handlers (object, signal_type);
1068   switch (gtk_handlers_run (handlers, &info, FALSE))
1069     {
1070     case DONE:
1071       goto done;
1072     case RESTART:
1073       goto restart;
1074     }
1075   
1076   if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST  && signal->function_offset != 0)
1077     {
1078       signal_func_offset = (guchar**) ((guchar*) object->klass +
1079                                        signal->function_offset);
1080       if (*signal_func_offset)
1081         (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1082                                 NULL, params);
1083     }
1084   
1085   handlers = gtk_signal_get_handlers (object, signal_type);
1086   switch (gtk_handlers_run (handlers, &info, TRUE))
1087     {
1088     case DONE:
1089       goto done;
1090     case RESTART:
1091       goto restart;
1092     }
1093   
1094 done:
1095   
1096   gtk_emission_remove (&current_emissions, object, signal_type);
1097   
1098   if (signal->run_type & GTK_RUN_NO_RECURSE)
1099     gtk_emission_remove (&restart_emissions, object, signal_type);
1100   
1101   gtk_object_unref (object);
1102 }
1103
1104 static GtkHandler*
1105 gtk_signal_get_handlers (GtkObject *object,
1106                          gint       signal_type)
1107 {
1108   GtkHandler *handlers;
1109
1110   g_return_val_if_fail (object != NULL, NULL);
1111   g_return_val_if_fail (signal_type >= 1, NULL);
1112
1113   handlers = gtk_object_get_data (object, handler_key);
1114
1115   while (handlers)
1116     {
1117       if (handlers->signal_type == signal_type)
1118         return handlers;
1119       handlers = handlers->next;
1120     }
1121
1122   return NULL;
1123 }
1124
1125 guint
1126 gtk_signal_handler_pending (GtkObject           *object,
1127                             gint                 signal_type,
1128                             gboolean             may_be_blocked)
1129 {
1130   GtkHandler *handlers;
1131   guint handler_id;
1132   
1133   g_return_val_if_fail (object != NULL, 0);
1134   g_return_val_if_fail (signal_type >= 1, 0);
1135   
1136   handlers = gtk_signal_get_handlers (object, signal_type);
1137   
1138   handler_id = 0;
1139   while (handlers && handlers->signal_type == signal_type)
1140     {
1141       if (handlers->id > 0 &&
1142           (may_be_blocked ||
1143            !handlers->blocked))
1144         {
1145           handler_id = handlers->id;
1146           break;
1147         }
1148       
1149       handlers = handlers->next;
1150     }
1151   
1152   return handler_id;
1153 }
1154
1155 static gint
1156 gtk_signal_connect_by_type (GtkObject       *object,
1157                             gint             signal_type,
1158                             GtkSignalFunc    func,
1159                             gpointer         func_data,
1160                             GtkSignalDestroy destroy_func,
1161                             gint             object_signal,
1162                             gint             after,
1163                             gint             no_marshal)
1164 {
1165   GtkObjectClass *class;
1166   GtkHandler *handler;
1167   gint found_it;
1168
1169   g_return_val_if_fail (object != NULL, 0);
1170   g_return_val_if_fail (object->klass != NULL, 0);
1171
1172   /* Search through the signals for this object and make
1173    *  sure the one we are adding is valid. We need to perform
1174    *  the lookup on the objects parents as well. If it isn't
1175    *  valid then issue a warning and return.
1176    */
1177   found_it = FALSE;
1178   class = object->klass;
1179   while (class)
1180     {
1181       GtkType parent;
1182       gint *object_signals;
1183       gint  nsignals;
1184       guint i;
1185       
1186       object_signals = class->signals;
1187       nsignals = class->nsignals;
1188       
1189       for (i = 0; i < nsignals; i++)
1190         if (object_signals[i] == signal_type)
1191           {
1192             found_it = TRUE;
1193             break;
1194           }
1195       
1196       parent = gtk_type_parent (class->type);
1197       if (parent)
1198         class = gtk_type_class (parent);
1199       else
1200         class = NULL;
1201     }
1202   
1203   if (!found_it)
1204     {
1205       g_warning ("gtk_signal_connect_by_type(): could not find signal type (%d) in signal list of `%s'",
1206                  signal_type,
1207                  gtk_type_name (class->type));
1208       return 0;
1209     }
1210
1211   handler = gtk_signal_handler_new ();
1212   handler->id = next_handler_id++;
1213   handler->signal_type = signal_type;
1214   handler->object_signal = object_signal;
1215   handler->func = func;
1216   handler->func_data = func_data;
1217   handler->destroy_func = destroy_func;
1218   handler->after = after != FALSE;
1219   handler->no_marshal = no_marshal;
1220
1221   gtk_signal_handler_insert (object, handler);
1222   return handler->id;
1223 }
1224
1225 static GtkEmission*
1226 gtk_emission_new ()
1227 {
1228   GtkEmission *emission;
1229
1230   if (!emission_mem_chunk)
1231     emission_mem_chunk = g_mem_chunk_new ("emission mem chunk", sizeof (GtkEmission),
1232                                           1024, G_ALLOC_AND_FREE);
1233
1234   emission = g_chunk_new (GtkEmission, emission_mem_chunk);
1235
1236   emission->object = NULL;
1237   emission->signal_type = 0;
1238
1239   return emission;
1240 }
1241
1242 static void
1243 gtk_emission_destroy (GtkEmission *emission)
1244 {
1245   g_mem_chunk_free (emission_mem_chunk, emission);
1246 }
1247
1248 static void
1249 gtk_emission_add (GList     **emissions,
1250                   GtkObject  *object,
1251                   gint        signal_type)
1252 {
1253   GtkEmission *emission;
1254
1255   g_return_if_fail (emissions != NULL);
1256   g_return_if_fail (object != NULL);
1257
1258   emission = gtk_emission_new ();
1259   emission->object = object;
1260   emission->signal_type = signal_type;
1261
1262   *emissions = g_list_prepend (*emissions, emission);
1263 }
1264
1265 static void
1266 gtk_emission_remove (GList     **emissions,
1267                      GtkObject  *object,
1268                      gint        signal_type)
1269 {
1270   GtkEmission *emission;
1271   GList *tmp;
1272
1273   g_return_if_fail (emissions != NULL);
1274   g_return_if_fail (object != NULL);
1275
1276   tmp = *emissions;
1277   while (tmp)
1278     {
1279       emission = tmp->data;
1280
1281       if ((emission->object == object) &&
1282           (emission->signal_type == signal_type))
1283         {
1284           gtk_emission_destroy (emission);
1285           *emissions = g_list_remove_link (*emissions, tmp);
1286           g_list_free (tmp);
1287           break;
1288         }
1289
1290       tmp = tmp->next;
1291     }
1292 }
1293
1294 static gint
1295 gtk_emission_check (GList     *emissions,
1296                     GtkObject *object,
1297                     gint       signal_type)
1298 {
1299   GtkEmission *emission;
1300   GList *tmp;
1301
1302   g_return_val_if_fail (object != NULL, FALSE);
1303
1304   tmp = emissions;
1305   while (tmp)
1306     {
1307       emission = tmp->data;
1308       tmp = tmp->next;
1309
1310       if ((emission->object == object) &&
1311           (emission->signal_type == signal_type))
1312         return TRUE;
1313     }
1314   return FALSE;
1315 }
1316
1317 static gint
1318 gtk_handlers_run (GtkHandler     *handlers,
1319                   GtkHandlerInfo *info,
1320                   gint            after)
1321 {
1322   while (handlers)
1323     {
1324       GtkHandler *handlers_next;
1325   
1326       gtk_signal_handler_ref (handlers);
1327       
1328       if (handlers->signal_type != info->signal_type)
1329         {
1330           gtk_signal_handler_unref (handlers, info->object);
1331           return 0;
1332         }
1333       
1334       if (!handlers->blocked && (handlers->after == after))
1335         {
1336           if (handlers->func)
1337             {
1338               if (handlers->no_marshal)
1339                 (* (GtkCallbackMarshal)handlers->func) (info->object,
1340                                                         handlers->func_data,
1341                                                         info->nparams,
1342                                                         info->params);
1343               else if (handlers->object_signal)
1344                 (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
1345                                       handlers->func,
1346                                       handlers->func_data,
1347                                       info->params);
1348               else
1349                 (* info->marshaller) (info->object,
1350                                       handlers->func,
1351                                       handlers->func_data,
1352                                       info->params);
1353             }
1354           else if (marshal)
1355             (* marshal) (info->object,
1356                          handlers->func_data,
1357                          info->nparams,
1358                          info->params,
1359                          info->param_types,
1360                          info->return_val);
1361           
1362           if (gtk_emission_check (stop_emissions, info->object,
1363                                   info->signal_type))
1364             {
1365               gtk_emission_remove (&stop_emissions, info->object,
1366                                    info->signal_type);
1367               
1368               if (info->run_type & GTK_RUN_NO_RECURSE)
1369                 gtk_emission_remove (&restart_emissions, info->object,
1370                                      info->signal_type);
1371               gtk_signal_handler_unref (handlers, info->object);
1372               return DONE;
1373             }
1374           else if ((info->run_type & GTK_RUN_NO_RECURSE) &&
1375                    gtk_emission_check (restart_emissions, info->object,
1376                                        info->signal_type))
1377             {
1378               gtk_emission_remove (&restart_emissions, info->object,
1379                                    info->signal_type);
1380               gtk_signal_handler_unref (handlers, info->object);
1381               return RESTART;
1382             }
1383         }
1384       
1385       handlers_next = handlers->next;
1386       gtk_signal_handler_unref (handlers, info->object);
1387       handlers = handlers_next;
1388     }
1389   
1390   return 0;
1391 }
1392
1393 static void
1394 gtk_params_get (GtkArg         *params,
1395                 gint            nparams,
1396                 GtkType        *param_types,
1397                 GtkType         return_val,
1398                 va_list         args)
1399 {
1400   int i;
1401
1402   for (i = 0; i < nparams; i++)
1403     {
1404       params[i].type = param_types[i];
1405       params[i].name = NULL;
1406
1407       switch (GTK_FUNDAMENTAL_TYPE (param_types[i]))
1408         {
1409         case GTK_TYPE_INVALID:
1410           break;
1411         case GTK_TYPE_NONE:
1412           break;
1413         case GTK_TYPE_CHAR:
1414           GTK_VALUE_CHAR(params[i]) = va_arg (args, gint);
1415           break;
1416         case GTK_TYPE_BOOL:
1417           GTK_VALUE_BOOL(params[i]) = va_arg (args, gint);
1418           break;
1419         case GTK_TYPE_INT:
1420           GTK_VALUE_INT(params[i]) = va_arg (args, gint);
1421           break;
1422         case GTK_TYPE_UINT:
1423           GTK_VALUE_UINT(params[i]) = va_arg (args, guint);
1424           break;
1425         case GTK_TYPE_ENUM:
1426           GTK_VALUE_ENUM(params[i]) = va_arg (args, gint);
1427           break;
1428         case GTK_TYPE_FLAGS:
1429           GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint);
1430           break;
1431         case GTK_TYPE_LONG:
1432           GTK_VALUE_LONG(params[i]) = va_arg (args, glong);
1433           break;
1434         case GTK_TYPE_ULONG:
1435           GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong);
1436           break;
1437         case GTK_TYPE_FLOAT:
1438           GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat);
1439           break;
1440         case GTK_TYPE_DOUBLE:
1441           GTK_VALUE_DOUBLE(params[i]) = va_arg (args, gdouble);
1442           break;
1443         case GTK_TYPE_STRING:
1444           GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*);
1445           break;
1446         case GTK_TYPE_POINTER:
1447           GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer);
1448           break;
1449         case GTK_TYPE_BOXED:
1450           GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer);
1451           break;
1452         case GTK_TYPE_SIGNAL:
1453           GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction);
1454           GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer);
1455           break;
1456         case GTK_TYPE_FOREIGN:
1457           GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer);
1458           GTK_VALUE_FOREIGN(params[i]).notify = 
1459             va_arg (args, GtkDestroyNotify);
1460           break;
1461         case GTK_TYPE_CALLBACK:
1462           GTK_VALUE_CALLBACK(params[i]).marshal = 
1463             va_arg (args, GtkCallbackMarshal);
1464           GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer);
1465           GTK_VALUE_CALLBACK(params[i]).notify =
1466             va_arg (args, GtkDestroyNotify);
1467           break;
1468         case GTK_TYPE_C_CALLBACK:
1469           GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction);
1470           GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer);
1471           break;
1472         case GTK_TYPE_ARGS:
1473           GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, int);
1474           GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*);
1475           break;
1476         case GTK_TYPE_OBJECT:
1477           GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*);
1478           g_assert (GTK_VALUE_OBJECT(params[i]) == NULL ||
1479                     GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]),
1480                                     params[i].type));
1481           break;
1482         default:
1483           g_error ("unsupported type %s in signal arg",
1484                    gtk_type_name (params[i].type));
1485           break;
1486         }
1487     }
1488
1489   params[i].type = return_val;
1490   params[i].name = NULL;
1491
1492   switch (GTK_FUNDAMENTAL_TYPE (return_val))
1493     {
1494     case GTK_TYPE_INVALID:
1495       break;
1496     case GTK_TYPE_NONE:
1497       break;
1498     case GTK_TYPE_CHAR:
1499       params[i].d.pointer_data = va_arg (args, gchar*);
1500       break;
1501     case GTK_TYPE_BOOL:
1502       params[i].d.pointer_data = va_arg (args, gint*);
1503       break;
1504     case GTK_TYPE_INT:
1505       params[i].d.pointer_data = va_arg (args, gint*);
1506       break;
1507     case GTK_TYPE_UINT:
1508       params[i].d.pointer_data = va_arg (args, guint*);
1509       break;
1510     case GTK_TYPE_ENUM:
1511       params[i].d.pointer_data = va_arg (args, gint*);
1512       break;
1513     case GTK_TYPE_FLAGS:
1514       params[i].d.pointer_data = va_arg (args, gint*);
1515       break;
1516     case GTK_TYPE_LONG:
1517       params[i].d.pointer_data = va_arg (args, glong*);
1518       break;
1519     case GTK_TYPE_ULONG:
1520       params[i].d.pointer_data = va_arg (args, gulong*);
1521       break;
1522     case GTK_TYPE_FLOAT:
1523       params[i].d.pointer_data = va_arg (args, gfloat*);
1524       break;
1525     case GTK_TYPE_DOUBLE:
1526       params[i].d.pointer_data = va_arg (args, gdouble*);
1527       break;
1528     case GTK_TYPE_STRING:
1529       params[i].d.pointer_data = va_arg (args, gchar**);
1530       break;
1531     case GTK_TYPE_POINTER:
1532       params[i].d.pointer_data = va_arg (args, gpointer*);
1533       break;
1534     case GTK_TYPE_BOXED:
1535       params[i].d.pointer_data = va_arg (args, gpointer*);
1536       break;
1537     case GTK_TYPE_OBJECT:
1538       params[i].d.pointer_data = va_arg (args, GtkObject**);
1539       break;
1540     case GTK_TYPE_SIGNAL:
1541     case GTK_TYPE_FOREIGN:
1542     case GTK_TYPE_CALLBACK:
1543     case GTK_TYPE_C_CALLBACK:
1544     case GTK_TYPE_ARGS:
1545     default:
1546       g_error ("unsupported type %s in signal return",
1547                gtk_type_name (return_val));
1548       break;
1549     }
1550 }