]> Pileus Git - ~andy/gtk/blob - gtk/gtksignal.c
ec115bf1b92e7966163a130920b5f7519f648fee
[~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                                                 gint           object_signal,
112                                                 GtkSignalFunc  func,
113                                                 gpointer       func_data,
114                                                 GtkSignalDestroy destroy_func,
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 ("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 }
371
372 void
373 gtk_signal_emit_stop (GtkObject *object,
374                       gint       signal_type)
375 {
376   g_return_if_fail (object != NULL);
377   g_return_if_fail (signal_type >= 1);
378
379   if (initialize)
380     gtk_signal_init ();
381
382   if (gtk_emission_check (current_emissions, object, signal_type))
383     gtk_emission_add (&stop_emissions, object, signal_type);
384 }
385
386 void
387 gtk_signal_emit_stop_by_name (GtkObject       *object,
388                               const gchar     *name)
389 {
390   gint type;
391
392   g_return_if_fail (object != NULL);
393   g_return_if_fail (name != NULL);
394
395   if (initialize)
396     gtk_signal_init ();
397
398   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
399   if (type)
400     gtk_signal_emit_stop (object, type);
401 }
402
403 gint
404 gtk_signal_connect (GtkObject     *object,
405                     const gchar   *name,
406                     GtkSignalFunc  func,
407                     gpointer       func_data)
408 {
409   gint type;
410
411   g_return_val_if_fail (object != NULL, 0);
412
413   if (initialize)
414     gtk_signal_init ();
415
416   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
417   if (!type)
418     {
419       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
420                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
421       return 0;
422     }
423
424   return gtk_signal_connect_by_type (object, type, FALSE,
425                                      func, func_data, NULL,
426                                      FALSE, FALSE);
427 }
428
429 gint
430 gtk_signal_connect_after (GtkObject     *object,
431                           const gchar   *name,
432                           GtkSignalFunc  func,
433                           gpointer       func_data)
434 {
435   gint type;
436
437   g_return_val_if_fail (object != NULL, 0);
438
439   if (initialize)
440     gtk_signal_init ();
441
442   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
443   if (!type)
444     {
445       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
446                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
447       return 0;
448     }
449
450   return gtk_signal_connect_by_type (object, type, FALSE,
451                                      func, func_data, NULL,
452                                      TRUE, FALSE);
453 }
454
455 gint
456 gtk_signal_connect_interp (GtkObject         *object,
457                            gchar             *name,
458                            GtkCallbackMarshal func,
459                            gpointer           func_data,
460                            GtkDestroyNotify   destroy_func,
461                            gint               after)
462 {
463   gint type;
464
465   g_return_val_if_fail (object != NULL, 0);
466
467   if (initialize)
468     gtk_signal_init ();
469
470   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
471   if (!type)
472     {
473       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
474                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
475       return 0;
476     }
477
478   return gtk_signal_connect_by_type (object, type, FALSE,
479                                      (GtkSignalFunc) func, func_data,
480                                      destroy_func, after, TRUE);
481 }
482
483 gint
484 gtk_signal_connect_object (GtkObject     *object,
485                            const gchar   *name,
486                            GtkSignalFunc  func,
487                            GtkObject     *slot_object)
488 {
489   gint type;
490
491   g_return_val_if_fail (object != NULL, 0);
492   /* slot_object needs to be treated as ordinary pointer */
493
494   if (initialize)
495     gtk_signal_init ();
496
497   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
498   if (!type)
499     {
500       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
501                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
502       return 0;
503     }
504
505   return gtk_signal_connect_by_type (object, type, TRUE,
506                                      func, slot_object, NULL,
507                                      FALSE, FALSE);
508 }
509
510 gint
511 gtk_signal_connect_object_after (GtkObject     *object,
512                                  const gchar   *name,
513                                  GtkSignalFunc  func,
514                                  GtkObject     *slot_object)
515 {
516   gint type;
517
518   g_return_val_if_fail (object != NULL, 0);
519
520   if (initialize)
521     gtk_signal_init ();
522
523   type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
524   if (!type)
525     {
526       g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry",
527                  name, gtk_type_name (GTK_OBJECT_TYPE (object)));
528       return 0;
529     }
530
531   return gtk_signal_connect_by_type (object, type, TRUE,
532                                      func, slot_object, NULL,
533                                      TRUE, FALSE);
534 }
535
536 typedef struct _GtkDisconnectInfo       GtkDisconnectInfo;
537 struct _GtkDisconnectInfo
538 {
539   GtkObject     *object1;
540   gint          disconnect_handler1;
541   gint          signal_handler;
542   GtkObject     *object2;
543   gint          disconnect_handler2;
544 };
545
546 static gint
547 gtk_alive_disconnecter (GtkDisconnectInfo *info)
548 {
549   g_return_val_if_fail (info != NULL, 0);
550
551   gtk_signal_disconnect (info->object1, info->disconnect_handler1);
552   gtk_signal_disconnect (info->object1, info->signal_handler);
553   gtk_signal_disconnect (info->object2, info->disconnect_handler2);
554   g_free (info);
555
556   return 0;
557 }
558
559 void
560 gtk_signal_connect_while_alive (GtkObject        *object,
561                                 const gchar      *signal,
562                                 GtkSignalFunc     func,
563                                 gpointer          func_data,
564                                 GtkObject        *alive_object)
565 {
566   GtkDisconnectInfo *info;
567
568   g_return_if_fail (object != NULL);
569   g_return_if_fail (GTK_IS_OBJECT (object));
570   g_return_if_fail (signal != NULL);
571   g_return_if_fail (func != NULL);
572   g_return_if_fail (alive_object != NULL);
573   g_return_if_fail (GTK_IS_OBJECT (alive_object));
574
575   info = g_new (GtkDisconnectInfo, 1);
576   info->object1 = object;
577   info->object2 = alive_object;
578
579   info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
580   info->disconnect_handler1 = gtk_signal_connect_object (info->object1,
581                                                          "destroy",
582                                                          GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
583                                                          (GtkObject*) info);
584   info->disconnect_handler2 = gtk_signal_connect_object (info->object2,
585                                                          "destroy",
586                                                          GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
587                                                          (GtkObject*) info);
588 }
589
590 void
591 gtk_signal_connect_object_while_alive (GtkObject        *object,
592                                        const gchar      *signal,
593                                        GtkSignalFunc     func,
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 (object, signal, func, alive_object);
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_disconnect (GtkObject *object,
622                        gint       an_id)
623 {
624   GtkHandler *handler;
625
626   g_return_if_fail (object != NULL);
627   g_return_if_fail (an_id > 0);
628
629   handler = gtk_object_get_data (object, handler_key);
630
631   while (handler)
632     {
633       if (handler->id == an_id)
634         {
635           handler->id = 0;
636           handler->blocked = TRUE;
637           gtk_signal_handler_unref (handler, object);
638           return;
639         }
640       handler = handler->next;
641     }
642
643   g_warning ("gtk_signal_disconnect(): could not find handler (%d)", an_id);
644 }
645
646 void
647 gtk_signal_disconnect_by_data (GtkObject *object,
648                                gpointer   data)
649 {
650   GtkHandler *handler;
651   gint found_one;
652
653   g_return_if_fail (object != NULL);
654
655   found_one = FALSE;
656   handler = gtk_object_get_data (object, handler_key);
657
658   while (handler)
659     {
660       GtkHandler *handler_next;
661
662       handler_next = handler->next;
663       if (handler->func_data == data &&
664           handler->id > 0)
665         {
666           found_one = TRUE;
667           handler->id = 0;
668           handler->blocked = TRUE;
669           gtk_signal_handler_unref (handler, object);
670         }
671       handler = handler_next;
672     }
673
674   if (!found_one)
675     g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
676 }
677
678 void
679 gtk_signal_handler_block (GtkObject *object,
680                           gint       an_id)
681 {
682   GtkHandler *tmp;
683
684   g_return_if_fail (object != NULL);
685   g_return_if_fail (an_id > 0);
686
687   tmp = gtk_object_get_data (object, handler_key);
688
689   while (tmp)
690     {
691       if (tmp->id == an_id)
692         {
693           tmp->blocked = TRUE;
694           return;
695         }
696
697       tmp = tmp->next;
698     }
699
700   g_warning ("gtk_signal_handler_block(): could not find handler (%d)", an_id);
701 }
702
703 void
704 gtk_signal_handler_block_by_data (GtkObject *object,
705                                   gpointer   data)
706 {
707   GtkHandler *handler;
708   gint found_one;
709
710   g_return_if_fail (object != NULL);
711
712   if (initialize)
713     gtk_signal_init ();
714
715   found_one = FALSE;
716   handler = gtk_object_get_data (object, handler_key);
717
718   while (handler)
719     {
720       if (handler->func_data == data &&
721           handler->id > 0)
722         {
723           found_one = TRUE;
724           handler->blocked = TRUE;
725         }
726
727       handler = handler->next;
728     }
729
730   if (!found_one)
731     g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
732 }
733
734 void
735 gtk_signal_handler_unblock (GtkObject *object,
736                             gint       an_id)
737 {
738   GtkHandler *handler;
739
740   g_return_if_fail (object != NULL);
741   g_return_if_fail (an_id > 0);
742
743   if (initialize)
744     gtk_signal_init ();
745
746   handler = gtk_object_get_data (object, handler_key);
747
748   while (handler)
749     {
750       if (handler->id == an_id)
751         {
752           handler->blocked = FALSE;
753           return;
754         }
755
756       handler = handler->next;
757     }
758
759   g_warning ("gtk_signal_handler_unblock(): could not find handler (%d)", an_id);
760 }
761
762 void
763 gtk_signal_handler_unblock_by_data (GtkObject *object,
764                                     gpointer   data)
765 {
766   GtkHandler *handler;
767   gint found_one;
768
769   g_return_if_fail (object != NULL);
770
771   if (initialize)
772     gtk_signal_init ();
773
774   found_one = FALSE;
775   handler = gtk_object_get_data (object, handler_key);
776
777   while (handler)
778     {
779       if (handler->func_data == data &&
780           handler->id > 0)
781         {
782           found_one = TRUE;
783           handler->blocked = FALSE;
784         }
785
786       handler = handler->next;
787     }
788
789   if (!found_one)
790     g_warning ("gtk_signal_handler_unblock_by_data(): could not find handler containing data (0x%0lX)", (long) data);
791 }
792
793 void
794 gtk_signal_handlers_destroy (GtkObject *object)
795 {
796   GtkHandler *handler;
797
798   /* we make the "optimization" of destroying the first handler in the last
799    * place, since we don't want gtk_signal_handler_unref() to reset the objects
800    * handler_key data on each removal
801    */
802
803   handler = gtk_object_get_data (object, handler_key);
804   if (handler)
805     {
806       handler = handler->next;
807       while (handler)
808         {
809           GtkHandler *next;
810
811           next = handler->next;
812           gtk_signal_handler_unref (handler, object);
813           handler = next;
814         }
815       handler = gtk_object_get_data (object, handler_key);
816       gtk_signal_handler_unref (handler, object);
817     }
818 }
819
820 void
821 gtk_signal_default_marshaller (GtkObject      *object,
822                                GtkSignalFunc   func,
823                                gpointer        func_data,
824                                GtkArg         *params)
825 {
826   GtkSignalMarshaller0 rfunc;
827
828   rfunc = (GtkSignalMarshaller0) func;
829
830   (* rfunc) (object, func_data);
831 }
832
833 void
834 gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
835                       GtkSignalDestroy destroy_func)
836 {
837   marshal = marshal_func;
838   destroy = destroy_func;
839 }
840
841
842 static void
843 gtk_signal_init ()
844 {
845   if (initialize)
846     {
847       initialize = FALSE;
848       signal_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_hash,
849                                             (GCompareFunc) gtk_signal_compare);
850       signal_info_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_info_hash,
851                                                  (GCompareFunc) gtk_signal_info_compare);
852     }
853 }
854
855 static guint
856 gtk_signal_hash (gint *key)
857 {
858   return (guint) *key;
859 }
860
861 static gint
862 gtk_signal_compare (gint *a,
863                     gint *b)
864 {
865   return (*a == *b);
866 }
867
868 static guint
869 gtk_signal_info_hash (GtkSignalInfo *a)
870 {
871   return (g_str_hash (a->name) + a->object_type);
872 }
873
874 static gint
875 gtk_signal_info_compare (GtkSignalInfo *a,
876                          GtkSignalInfo *b)
877 {
878   return ((a->object_type == b->object_type) &&
879           g_str_equal (a->name, b->name));
880 }
881
882 static GtkHandler*
883 gtk_signal_handler_new ()
884 {
885   GtkHandler *handler;
886
887   if (!handler_mem_chunk)
888     handler_mem_chunk = g_mem_chunk_new ("handler mem chunk", sizeof (GtkHandler),
889                                          1024, G_ALLOC_AND_FREE);
890
891   handler = g_chunk_new (GtkHandler, handler_mem_chunk);
892
893   handler->id = 0;
894   handler->ref_count = 1;
895   handler->signal_type = 0;
896   handler->blocked = FALSE;
897   handler->object_signal = FALSE;
898   handler->after = FALSE;
899   handler->no_marshal = FALSE;
900   handler->func = NULL;
901   handler->func_data = NULL;
902   handler->destroy_func = NULL;
903   handler->prev = NULL;
904   handler->next = NULL;
905
906   return handler;
907 }
908
909 static void
910 gtk_signal_handler_ref (GtkHandler *handler)
911 {
912   handler->ref_count += 1;
913 }
914
915 static void
916 gtk_signal_handler_unref (GtkHandler *handler,
917                           GtkObject  *object)
918 {
919   if (!handler->ref_count)
920     {
921       /* FIXME: i wanna get removed some when (maybe at gtk+-1.0?) */
922       g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
923       return;
924     }
925
926   handler->ref_count -= 1;
927   if (handler->ref_count == 0)
928     {
929       if (!handler->func && destroy)
930         (* destroy) (handler->func_data);
931       else if (handler->destroy_func)
932         (* handler->destroy_func) (handler->func_data);
933
934
935       if (handler->prev)
936         handler->prev->next = handler->next;
937       else
938         gtk_object_set_data (object, handler_key, handler->next);
939       if (handler->next)
940         handler->next->prev = handler->prev;
941
942       g_mem_chunk_free (handler_mem_chunk, handler);
943     }
944 }
945
946 static void
947 gtk_signal_handler_insert (GtkObject  *object,
948                            GtkHandler *handler)
949 {
950   GtkHandler *tmp;
951   
952   /* FIXME: remove */ g_assert (handler->next == NULL);
953   /* FIXME: remove */ g_assert (handler->prev == NULL);
954   
955   tmp = gtk_object_get_data (object, handler_key);
956   if (!tmp)
957     gtk_object_set_data (object, handler_key, handler);
958   else
959     while (tmp)
960       {
961         if (tmp->signal_type < handler->signal_type)
962           {
963             if (tmp->prev)
964               {
965                 tmp->prev->next = handler;
966                 handler->prev = tmp->prev;
967               }
968             else
969               gtk_object_set_data (object, handler_key, handler);
970             tmp->prev = handler;
971             handler->next = tmp;
972             break;
973           }
974
975         if (!tmp->next)
976           {
977             tmp->next = handler;
978             handler->prev = tmp;
979             break;
980           }
981         tmp = tmp->next;
982       }
983 }
984
985 static void
986 gtk_signal_real_emit (GtkObject *object,
987                       gint       signal_type,
988                       va_list    args)
989 {
990   GtkSignal *signal;
991   GtkHandler *handlers;
992   GtkHandlerInfo info;
993   guchar **signal_func_offset;
994   GtkArg         params[MAX_PARAMS];
995   
996   g_return_if_fail (object != NULL);
997   g_return_if_fail (signal_type >= 1);
998   
999   signal = g_hash_table_lookup (signal_hash_table, &signal_type);
1000   g_return_if_fail (signal != NULL);
1001   g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object),
1002                                    signal->info.object_type));
1003   
1004   if ((signal->run_type & GTK_RUN_NO_RECURSE) &&
1005       gtk_emission_check (current_emissions, object, signal_type))
1006     {
1007       gtk_emission_add (&restart_emissions, object, signal_type);
1008       return;
1009     }
1010   
1011   gtk_params_get (params, signal->nparams, signal->params,
1012                   signal->return_val, args);
1013   
1014   gtk_emission_add (&current_emissions, object, signal_type);
1015   
1016   gtk_object_ref (object);
1017   
1018 restart:
1019   if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST && signal->function_offset != 0)
1020     {
1021       signal_func_offset = (guchar**) ((guchar*) object->klass +
1022                                        signal->function_offset);
1023       if (*signal_func_offset)
1024         (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1025                                 NULL, params);
1026     }
1027   
1028   info.object = object;
1029   info.marshaller = signal->marshaller;
1030   info.params = params;
1031   info.param_types = signal->params;
1032   info.return_val = signal->return_val;
1033   info.nparams = signal->nparams;
1034   info.run_type = signal->run_type;
1035   info.signal_type = signal_type;
1036   
1037   handlers = gtk_signal_get_handlers (object, signal_type);
1038   switch (gtk_handlers_run (handlers, &info, FALSE))
1039     {
1040     case DONE:
1041       goto done;
1042     case RESTART:
1043       goto restart;
1044     }
1045   
1046   if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST  && signal->function_offset != 0)
1047     {
1048       signal_func_offset = (guchar**) ((guchar*) object->klass +
1049                                        signal->function_offset);
1050       if (*signal_func_offset)
1051         (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset,
1052                                 NULL, params);
1053     }
1054   
1055   handlers = gtk_signal_get_handlers (object, signal_type);
1056   switch (gtk_handlers_run (handlers, &info, TRUE))
1057     {
1058     case DONE:
1059       goto done;
1060     case RESTART:
1061       goto restart;
1062     }
1063   
1064 done:
1065   
1066   gtk_emission_remove (&current_emissions, object, signal_type);
1067   
1068   if (signal->run_type & GTK_RUN_NO_RECURSE)
1069     gtk_emission_remove (&restart_emissions, object, signal_type);
1070   
1071   gtk_object_unref (object);
1072 }
1073
1074 static GtkHandler*
1075 gtk_signal_get_handlers (GtkObject *object,
1076                          gint       signal_type)
1077 {
1078   GtkHandler *handlers;
1079
1080   g_return_val_if_fail (object != NULL, NULL);
1081   g_return_val_if_fail (signal_type >= 1, NULL);
1082
1083   handlers = gtk_object_get_data (object, handler_key);
1084
1085   while (handlers)
1086     {
1087       if (handlers->signal_type == signal_type)
1088         return handlers;
1089       handlers = handlers->next;
1090     }
1091
1092   return NULL;
1093 }
1094
1095 guint
1096 gtk_signal_handler_pending (GtkObject           *object,
1097                             gint                 signal_type,
1098                             gboolean             may_be_blocked)
1099 {
1100   GtkHandler *handlers;
1101   guint handler_id;
1102   
1103   g_return_val_if_fail (object != NULL, 0);
1104   g_return_val_if_fail (signal_type >= 1, 0);
1105   
1106   handlers = gtk_signal_get_handlers (object, signal_type);
1107   
1108   handler_id = 0;
1109   while (handlers && handlers->signal_type == signal_type)
1110     {
1111       if (handlers->id > 0 &&
1112           (may_be_blocked ||
1113            !handlers->blocked))
1114         {
1115           handler_id = handlers->id;
1116           break;
1117         }
1118       
1119       handlers = handlers->next;
1120     }
1121   
1122   return handler_id;
1123 }
1124
1125 static gint
1126 gtk_signal_connect_by_type (GtkObject       *object,
1127                             gint             signal_type,
1128                             gint             object_signal,
1129                             GtkSignalFunc    func,
1130                             gpointer         func_data,
1131                             GtkSignalDestroy destroy_func,
1132                             gint             after,
1133                             gint             no_marshal)
1134 {
1135   GtkObjectClass *class;
1136   GtkHandler *handler;
1137   gint found_it;
1138
1139   g_return_val_if_fail (object != NULL, 0);
1140   g_return_val_if_fail (object->klass != NULL, 0);
1141
1142   /* Search through the signals for this object and make
1143    *  sure the one we are adding is valid. We need to perform
1144    *  the lookup on the objects parents as well. If it isn't
1145    *  valid then issue a warning and return.
1146    */
1147   found_it = FALSE;
1148   class = object->klass;
1149   while (class)
1150     {
1151       GtkType parent;
1152       gint *object_signals;
1153       gint  nsignals;
1154       guint i;
1155       
1156       object_signals = class->signals;
1157       nsignals = class->nsignals;
1158       
1159       for (i = 0; i < nsignals; i++)
1160         if (object_signals[i] == signal_type)
1161           {
1162             found_it = TRUE;
1163             break;
1164           }
1165       
1166       parent = gtk_type_parent (class->type);
1167       if (parent)
1168         class = gtk_type_class (parent);
1169       else
1170         class = NULL;
1171     }
1172   
1173   if (!found_it)
1174     {
1175       g_warning ("could not find signal (%d) in object's list of signals", signal_type);
1176       return 0;
1177     }
1178
1179   handler = gtk_signal_handler_new ();
1180   handler->id = next_handler_id++;
1181   handler->signal_type = signal_type;
1182   handler->object_signal = object_signal;
1183   handler->func = func;
1184   handler->func_data = func_data;
1185   handler->destroy_func = destroy_func;
1186   handler->after = after != FALSE;
1187   handler->no_marshal = no_marshal;
1188
1189   gtk_signal_handler_insert (object, handler);
1190   return handler->id;
1191 }
1192
1193 static GtkEmission*
1194 gtk_emission_new ()
1195 {
1196   GtkEmission *emission;
1197
1198   if (!emission_mem_chunk)
1199     emission_mem_chunk = g_mem_chunk_new ("emission mem chunk", sizeof (GtkEmission),
1200                                           1024, G_ALLOC_AND_FREE);
1201
1202   emission = g_chunk_new (GtkEmission, emission_mem_chunk);
1203
1204   emission->object = NULL;
1205   emission->signal_type = 0;
1206
1207   return emission;
1208 }
1209
1210 static void
1211 gtk_emission_destroy (GtkEmission *emission)
1212 {
1213   g_mem_chunk_free (emission_mem_chunk, emission);
1214 }
1215
1216 static void
1217 gtk_emission_add (GList     **emissions,
1218                   GtkObject  *object,
1219                   gint        signal_type)
1220 {
1221   GtkEmission *emission;
1222
1223   g_return_if_fail (emissions != NULL);
1224   g_return_if_fail (object != NULL);
1225
1226   emission = gtk_emission_new ();
1227   emission->object = object;
1228   emission->signal_type = signal_type;
1229
1230   *emissions = g_list_prepend (*emissions, emission);
1231 }
1232
1233 static void
1234 gtk_emission_remove (GList     **emissions,
1235                      GtkObject  *object,
1236                      gint        signal_type)
1237 {
1238   GtkEmission *emission;
1239   GList *tmp;
1240
1241   g_return_if_fail (emissions != NULL);
1242   g_return_if_fail (object != NULL);
1243
1244   tmp = *emissions;
1245   while (tmp)
1246     {
1247       emission = tmp->data;
1248
1249       if ((emission->object == object) &&
1250           (emission->signal_type == signal_type))
1251         {
1252           gtk_emission_destroy (emission);
1253           *emissions = g_list_remove_link (*emissions, tmp);
1254           g_list_free (tmp);
1255           break;
1256         }
1257
1258       tmp = tmp->next;
1259     }
1260 }
1261
1262 static gint
1263 gtk_emission_check (GList     *emissions,
1264                     GtkObject *object,
1265                     gint       signal_type)
1266 {
1267   GtkEmission *emission;
1268   GList *tmp;
1269
1270   g_return_val_if_fail (object != NULL, FALSE);
1271
1272   tmp = emissions;
1273   while (tmp)
1274     {
1275       emission = tmp->data;
1276       tmp = tmp->next;
1277
1278       if ((emission->object == object) &&
1279           (emission->signal_type == signal_type))
1280         return TRUE;
1281     }
1282   return FALSE;
1283 }
1284
1285 static gint
1286 gtk_handlers_run (GtkHandler     *handlers,
1287                   GtkHandlerInfo *info,
1288                   gint            after)
1289 {
1290   while (handlers)
1291     {
1292       GtkHandler *handlers_next;
1293   
1294       gtk_signal_handler_ref (handlers);
1295       
1296       if (handlers->signal_type != info->signal_type)
1297         {
1298           gtk_signal_handler_unref (handlers, info->object);
1299           return 0;
1300         }
1301       
1302       if (!handlers->blocked && (handlers->after == after))
1303         {
1304           if (handlers->func)
1305             {
1306               if (handlers->no_marshal)
1307                 (* (GtkCallbackMarshal)handlers->func) (info->object,
1308                                                         handlers->func_data,
1309                                                         info->nparams,
1310                                                         info->params);
1311               else if (handlers->object_signal)
1312                 (* info->marshaller) ((GtkObject*) handlers->func_data, /* don't GTK_OBJECT() cast */
1313                                       handlers->func,
1314                                       handlers->func_data,
1315                                       info->params);
1316               else
1317                 (* info->marshaller) (info->object,
1318                                       handlers->func,
1319                                       handlers->func_data,
1320                                       info->params);
1321             }
1322           else if (marshal)
1323             (* marshal) (info->object,
1324                          handlers->func_data,
1325                          info->nparams,
1326                          info->params,
1327                          info->param_types,
1328                          info->return_val);
1329           
1330           if (gtk_emission_check (stop_emissions, info->object,
1331                                   info->signal_type))
1332             {
1333               gtk_emission_remove (&stop_emissions, info->object,
1334                                    info->signal_type);
1335               
1336               if (info->run_type & GTK_RUN_NO_RECURSE)
1337                 gtk_emission_remove (&restart_emissions, info->object,
1338                                      info->signal_type);
1339               gtk_signal_handler_unref (handlers, info->object);
1340               return DONE;
1341             }
1342           else if ((info->run_type & GTK_RUN_NO_RECURSE) &&
1343                    gtk_emission_check (restart_emissions, info->object,
1344                                        info->signal_type))
1345             {
1346               gtk_emission_remove (&restart_emissions, info->object,
1347                                    info->signal_type);
1348               gtk_signal_handler_unref (handlers, info->object);
1349               return RESTART;
1350             }
1351         }
1352       
1353       handlers_next = handlers->next;
1354       gtk_signal_handler_unref (handlers, info->object);
1355       handlers = handlers_next;
1356     }
1357   
1358   return 0;
1359 }
1360
1361 static void
1362 gtk_params_get (GtkArg         *params,
1363                 gint            nparams,
1364                 GtkType        *param_types,
1365                 GtkType         return_val,
1366                 va_list         args)
1367 {
1368   int i;
1369
1370   for (i = 0; i < nparams; i++)
1371     {
1372       params[i].type = param_types[i];
1373       params[i].name = NULL;
1374
1375       switch (GTK_FUNDAMENTAL_TYPE (param_types[i]))
1376         {
1377         case GTK_TYPE_INVALID:
1378           break;
1379         case GTK_TYPE_NONE:
1380           break;
1381         case GTK_TYPE_CHAR:
1382           GTK_VALUE_CHAR(params[i]) = va_arg (args, gint);
1383           break;
1384         case GTK_TYPE_BOOL:
1385           GTK_VALUE_BOOL(params[i]) = va_arg (args, gint);
1386           break;
1387         case GTK_TYPE_INT:
1388           GTK_VALUE_INT(params[i]) = va_arg (args, gint);
1389           break;
1390         case GTK_TYPE_UINT:
1391           GTK_VALUE_UINT(params[i]) = va_arg (args, guint);
1392           break;
1393         case GTK_TYPE_ENUM:
1394           GTK_VALUE_ENUM(params[i]) = va_arg (args, gint);
1395           break;
1396         case GTK_TYPE_FLAGS:
1397           GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint);
1398           break;
1399         case GTK_TYPE_LONG:
1400           GTK_VALUE_LONG(params[i]) = va_arg (args, glong);
1401           break;
1402         case GTK_TYPE_ULONG:
1403           GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong);
1404           break;
1405         case GTK_TYPE_FLOAT:
1406           GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat);
1407           break;
1408         case GTK_TYPE_DOUBLE:
1409           GTK_VALUE_DOUBLE(params[i]) = va_arg (args, gdouble);
1410           break;
1411         case GTK_TYPE_STRING:
1412           GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*);
1413           break;
1414         case GTK_TYPE_POINTER:
1415           GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer);
1416           break;
1417         case GTK_TYPE_BOXED:
1418           GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer);
1419           break;
1420         case GTK_TYPE_SIGNAL:
1421           GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction);
1422           GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer);
1423           break;
1424         case GTK_TYPE_FOREIGN:
1425           GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer);
1426           GTK_VALUE_FOREIGN(params[i]).notify = 
1427             va_arg (args, GtkDestroyNotify);
1428           break;
1429         case GTK_TYPE_CALLBACK:
1430           GTK_VALUE_CALLBACK(params[i]).marshal = 
1431             va_arg (args, GtkCallbackMarshal);
1432           GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer);
1433           GTK_VALUE_CALLBACK(params[i]).notify =
1434             va_arg (args, GtkDestroyNotify);
1435           break;
1436         case GTK_TYPE_C_CALLBACK:
1437           GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction);
1438           GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer);
1439           break;
1440         case GTK_TYPE_ARGS:
1441           GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, int);
1442           GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*);
1443           break;
1444         case GTK_TYPE_OBJECT:
1445           GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*);
1446           g_assert (GTK_VALUE_OBJECT(params[i]) == NULL ||
1447                     GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]),
1448                                     params[i].type));
1449           break;
1450         default:
1451           g_error ("unsupported type %s in signal arg",
1452                    gtk_type_name (params[i].type));
1453           break;
1454         }
1455     }
1456
1457   params[i].type = return_val;
1458   params[i].name = NULL;
1459
1460   switch (GTK_FUNDAMENTAL_TYPE (return_val))
1461     {
1462     case GTK_TYPE_INVALID:
1463       break;
1464     case GTK_TYPE_NONE:
1465       break;
1466     case GTK_TYPE_CHAR:
1467       params[i].d.pointer_data = va_arg (args, gchar*);
1468       break;
1469     case GTK_TYPE_BOOL:
1470       params[i].d.pointer_data = va_arg (args, gint*);
1471       break;
1472     case GTK_TYPE_INT:
1473       params[i].d.pointer_data = va_arg (args, gint*);
1474       break;
1475     case GTK_TYPE_UINT:
1476       params[i].d.pointer_data = va_arg (args, guint*);
1477       break;
1478     case GTK_TYPE_ENUM:
1479       params[i].d.pointer_data = va_arg (args, gint*);
1480       break;
1481     case GTK_TYPE_FLAGS:
1482       params[i].d.pointer_data = va_arg (args, gint*);
1483       break;
1484     case GTK_TYPE_LONG:
1485       params[i].d.pointer_data = va_arg (args, glong*);
1486       break;
1487     case GTK_TYPE_ULONG:
1488       params[i].d.pointer_data = va_arg (args, gulong*);
1489       break;
1490     case GTK_TYPE_FLOAT:
1491       params[i].d.pointer_data = va_arg (args, gfloat*);
1492       break;
1493     case GTK_TYPE_DOUBLE:
1494       params[i].d.pointer_data = va_arg (args, gdouble*);
1495       break;
1496     case GTK_TYPE_STRING:
1497       params[i].d.pointer_data = va_arg (args, gchar**);
1498       break;
1499     case GTK_TYPE_POINTER:
1500       params[i].d.pointer_data = va_arg (args, gpointer*);
1501       break;
1502     case GTK_TYPE_BOXED:
1503       params[i].d.pointer_data = va_arg (args, gpointer*);
1504       break;
1505     case GTK_TYPE_OBJECT:
1506       params[i].d.pointer_data = va_arg (args, GtkObject**);
1507       break;
1508     case GTK_TYPE_SIGNAL:
1509     case GTK_TYPE_FOREIGN:
1510     case GTK_TYPE_CALLBACK:
1511     case GTK_TYPE_C_CALLBACK:
1512     case GTK_TYPE_ARGS:
1513     default:
1514       g_error ("unsupported type %s in signal return",
1515                gtk_type_name (return_val));
1516       break;
1517     }
1518 }