source: trunk/third/gtk/gtk/gtksignal.c @ 14810

Revision 14810, 48.8 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14809, which included commits to RCS files with non-trunk default branches.
Line 
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
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20/*
21 * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22 * file for a list of people on the GTK+ Team.  See the ChangeLog
23 * files for a list of changes.  These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27#include <stdarg.h>
28#include <string.h>
29#include <stdio.h>
30#include "gtksignal.h"
31#include "gtkargcollector.c"
32
33
34#define SIGNAL_BLOCK_SIZE               (100)
35#define HANDLER_BLOCK_SIZE              (200)
36#define EMISSION_BLOCK_SIZE             (100)
37#define DISCONNECT_INFO_BLOCK_SIZE      (64)
38#define MAX_SIGNAL_PARAMS               (31)
39
40enum
41{
42  EMISSION_CONTINUE,
43  EMISSION_RESTART,
44  EMISSION_DONE
45};
46
47#define GTK_RUN_TYPE(x)  ((x) & GTK_RUN_BOTH)
48
49
50typedef struct _GtkSignal               GtkSignal;
51typedef struct _GtkSignalHash           GtkSignalHash;
52typedef struct _GtkHandler              GtkHandler;
53typedef struct _GtkEmission             GtkEmission;
54typedef struct _GtkEmissionHookData     GtkEmissionHookData;
55typedef struct _GtkDisconnectInfo       GtkDisconnectInfo;
56
57typedef void (*GtkSignalMarshaller0) (GtkObject *object,
58                                      gpointer   data);
59
60struct _GtkSignal
61{
62  guint               signal_id;
63  GtkType             object_type;
64  gchar              *name;
65  guint               function_offset;
66  GtkSignalMarshaller marshaller;
67  GtkType             return_val;
68  guint               signal_flags : 16;
69  guint               nparams : 16;
70  GtkType            *params;
71  GHookList          *hook_list;
72};
73
74struct _GtkSignalHash
75{
76  GtkType object_type;
77  GQuark  quark;
78  guint   signal_id;
79};
80
81struct _GtkHandler
82{
83  guint            id;
84  GtkHandler      *next;
85  GtkHandler      *prev;
86  guint            blocked : 20;
87  guint            object_signal : 1;
88  guint            after : 1;
89  guint            no_marshal : 1;
90  guint16          ref_count;
91  guint16          signal_id;
92  GtkSignalFunc    func;
93  gpointer         func_data;
94  GtkSignalDestroy destroy_func;
95};
96
97struct _GtkEmission
98{
99  GtkObject   *object;
100  guint16      signal_id;
101  guint        in_hook : 1;
102  GtkEmission *next;
103};
104
105struct _GtkEmissionHookData
106{
107  GtkObject *object;
108  guint signal_id;
109  guint n_params;
110  GtkArg *params;
111};
112
113struct _GtkDisconnectInfo
114{
115  GtkObject     *object1;
116  guint          disconnect_handler1;
117  guint          signal_handler;
118  GtkObject     *object2;
119  guint          disconnect_handler2;
120};
121
122
123static guint        gtk_signal_hash            (gconstpointer h);
124static gint         gtk_signal_compare         (gconstpointer h1,
125                                                gconstpointer h2);
126static GtkHandler*  gtk_signal_handler_new     (void);
127static void         gtk_signal_handler_ref     (GtkHandler    *handler);
128static void         gtk_signal_handler_unref   (GtkHandler    *handler,
129                                                GtkObject     *object);
130static void         gtk_signal_handler_insert  (GtkObject     *object,
131                                                GtkHandler    *handler);
132static void         gtk_signal_real_emit       (GtkObject     *object,
133                                                guint          signal_id,
134                                                GtkArg        *params);
135static guint        gtk_signal_connect_by_type (GtkObject     *object,
136                                                guint          signal_id,
137                                                GtkSignalFunc  func,
138                                                gpointer       func_data,
139                                                GtkSignalDestroy destroy_func,
140                                                gint           object_signal,
141                                                gint           after,
142                                                gint           no_marshal);
143static guint        gtk_alive_disconnecter     (GtkDisconnectInfo *info);
144static GtkEmission* gtk_emission_new           (void);
145static void         gtk_emission_add           (GtkEmission   **emissions,
146                                                GtkObject      *object,
147                                                guint           signal_type);
148static void         gtk_emission_remove        (GtkEmission   **emissions,
149                                                GtkObject      *object,
150                                                guint           signal_type);
151static gint         gtk_emission_check         (GtkEmission    *emissions,
152                                                GtkObject      *object,
153                                                guint           signal_type);
154static gint         gtk_handlers_run           (GtkHandler     *handlers,
155                                                GtkSignal      *signal,
156                                                GtkObject      *object,
157                                                GtkArg         *params,
158                                                gint            after);
159static gboolean gtk_emission_hook_marshaller   (GHook          *hook,
160                                                gpointer        data);
161static gboolean gtk_signal_collect_params      (GtkArg         *params,
162                                                guint           nparams,
163                                                GtkType        *param_types,
164                                                GtkType         return_type,
165                                                va_list         var_args);
166
167#define LOOKUP_SIGNAL_ID(signal_id)     ( \
168  signal_id > 0 && signal_id < _gtk_private_n_signals ? \
169    (GtkSignal*) _gtk_private_signals + signal_id : \
170    (GtkSignal*) 0 \
171)
172
173
174static GtkSignalMarshal global_marshaller = NULL;
175static GtkSignalDestroy global_destroy_notify = NULL;
176
177static guint                     gtk_handler_id = 1;
178static guint                     gtk_handler_quark = 0;
179static GHashTable               *gtk_signal_hash_table = NULL;
180       GtkSignal                *_gtk_private_signals = NULL;
181       guint                     _gtk_private_n_signals = 0;
182static GMemChunk                *gtk_signal_hash_mem_chunk = NULL;
183static GMemChunk                *gtk_disconnect_info_mem_chunk = NULL;
184static GtkHandler               *gtk_handler_free_list = NULL;
185static GtkEmission              *gtk_free_emissions = NULL;
186
187
188
189static GtkEmission *current_emissions = NULL;
190static GtkEmission *stop_emissions = NULL;
191static GtkEmission *restart_emissions = NULL;
192
193static GtkSignal*
194gtk_signal_next_and_invalidate (void)
195{
196  static guint gtk_n_free_signals = 0;
197  register GtkSignal *signal;
198  register guint new_signal_id;
199 
200  /* don't keep *any* GtkSignal pointers across invokation of this function!!!
201   */
202 
203  if (gtk_n_free_signals == 0)
204    {
205      register guint i;
206      register guint size;
207     
208      /* nearest pow
209       */
210      size = _gtk_private_n_signals + SIGNAL_BLOCK_SIZE;
211      size *= sizeof (GtkSignal);
212      i = 1;
213      while (i < size)
214        i <<= 1;
215      size = i;
216     
217      _gtk_private_signals = g_realloc (_gtk_private_signals, size);
218     
219      gtk_n_free_signals = size / sizeof (GtkSignal) - _gtk_private_n_signals;
220     
221      memset (_gtk_private_signals + _gtk_private_n_signals, 0, gtk_n_free_signals * sizeof (GtkSignal));
222    }
223 
224  new_signal_id = _gtk_private_n_signals++;
225  gtk_n_free_signals--;
226
227  g_assert (_gtk_private_n_signals < 65535);
228 
229  signal = LOOKUP_SIGNAL_ID (new_signal_id);
230  if (signal)
231    signal->signal_id = new_signal_id;
232 
233  return signal;
234}
235
236static inline GtkHandler*
237gtk_signal_get_handlers (GtkObject *object,
238                         guint      signal_id)
239{
240  GtkHandler *handlers;
241 
242  handlers = gtk_object_get_data_by_id (object, gtk_handler_quark);
243 
244  while (handlers)
245    {
246      if (handlers->signal_id == signal_id)
247        return handlers;
248      handlers = handlers->next;
249    }
250 
251  return NULL;
252}
253
254void
255gtk_signal_init (void)
256{
257  if (!gtk_handler_quark)
258    {
259      GtkSignal *zero;
260     
261      zero = gtk_signal_next_and_invalidate ();
262      g_assert (zero == NULL);
263     
264      gtk_handler_quark = g_quark_from_static_string ("gtk-signal-handlers");
265     
266      gtk_signal_hash_mem_chunk =
267        g_mem_chunk_new ("GtkSignalHash mem chunk",
268                         sizeof (GtkSignalHash),
269                         sizeof (GtkSignalHash) * SIGNAL_BLOCK_SIZE,
270                         G_ALLOC_ONLY);
271      gtk_disconnect_info_mem_chunk =
272        g_mem_chunk_new ("GtkDisconnectInfo mem chunk",
273                         sizeof (GtkDisconnectInfo),
274                         sizeof (GtkDisconnectInfo) * DISCONNECT_INFO_BLOCK_SIZE,
275                         G_ALLOC_AND_FREE);
276      gtk_handler_free_list = NULL;
277      gtk_free_emissions = NULL;
278     
279      gtk_signal_hash_table = g_hash_table_new (gtk_signal_hash,
280                                                gtk_signal_compare);
281    }
282}
283
284guint
285gtk_signal_newv (const gchar         *r_name,
286                 GtkSignalRunType     signal_flags,
287                 GtkType              object_type,
288                 guint                function_offset,
289                 GtkSignalMarshaller  marshaller,
290                 GtkType              return_val,
291                 guint                nparams,
292                 GtkType             *params)
293{
294  GtkSignal *signal;
295  GtkSignalHash *hash;
296  GQuark quark;
297  guint i;
298  gchar *name;
299 
300  g_return_val_if_fail (r_name != NULL, 0);
301  g_return_val_if_fail (marshaller != NULL, 0);
302  g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
303  if (nparams)
304    g_return_val_if_fail (params != NULL, 0);
305 
306  if (!gtk_handler_quark)
307    gtk_signal_init ();
308
309
310  name = g_strdup (r_name);
311  g_strdelimit (name, NULL, '_');
312
313  quark = gtk_signal_lookup (name, object_type);
314  if (quark)
315    {
316      g_warning ("gtk_signal_newv(): signal \"%s\" already exists in the `%s' class ancestry\n",
317                 r_name,
318                 gtk_type_name (object_type));
319      g_free (name);
320      return 0;
321    }
322 
323  if (return_val != GTK_TYPE_NONE &&
324      (signal_flags & GTK_RUN_BOTH) == GTK_RUN_FIRST)
325    {
326      g_warning ("gtk_signal_newv(): signal \"%s\" - return value `%s' incompatible with GTK_RUN_FIRST",
327                 name, gtk_type_name (return_val));
328      g_free (name);
329      return 0;
330    }
331 
332  signal = gtk_signal_next_and_invalidate ();
333 
334  /* signal->signal_id already set */
335 
336  signal->object_type = object_type;
337  signal->name = name;
338  signal->function_offset = function_offset;
339  signal->marshaller = marshaller;
340  signal->return_val = return_val;
341  signal->signal_flags = signal_flags;
342  signal->nparams = nparams;
343  signal->hook_list = NULL;
344 
345  if (nparams > 0)
346    {
347      signal->params = g_new (GtkType, nparams);
348     
349      for (i = 0; i < nparams; i++)
350        signal->params[i] = params[i];
351    }
352  else
353    signal->params = NULL;
354
355  /* insert "signal_name" into hash table
356   */
357  hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
358  hash->object_type = object_type;
359  hash->quark = g_quark_from_string (signal->name);
360  hash->signal_id = signal->signal_id;
361  g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
362
363  /* insert "signal-name" into hash table
364   */
365  g_strdelimit (signal->name, NULL, '-');
366  quark = g_quark_from_static_string (signal->name);
367  if (quark != hash->quark)
368    {
369      hash = g_chunk_new (GtkSignalHash, gtk_signal_hash_mem_chunk);
370      hash->object_type = object_type;
371      hash->quark = quark;
372      hash->signal_id = signal->signal_id;
373      g_hash_table_insert (gtk_signal_hash_table, hash, GUINT_TO_POINTER (hash->signal_id));
374    }
375 
376  return signal->signal_id;
377}
378
379guint
380gtk_signal_new (const gchar         *name,
381                GtkSignalRunType     signal_flags,
382                GtkType              object_type,
383                guint                function_offset,
384                GtkSignalMarshaller  marshaller,
385                GtkType              return_val,
386                guint                nparams,
387                ...)
388{
389  GtkType *params;
390  guint i;
391  va_list args;
392  guint signal_id;
393 
394  g_return_val_if_fail (nparams < MAX_SIGNAL_PARAMS, 0);
395 
396  if (nparams > 0)
397    {
398      params = g_new (GtkType, nparams);
399     
400      va_start (args, nparams);
401     
402      for (i = 0; i < nparams; i++)
403        params[i] = va_arg (args, GtkType);
404     
405      va_end (args);
406    }
407  else
408    params = NULL;
409 
410  signal_id = gtk_signal_newv (name,
411                               signal_flags,
412                               object_type,
413                               function_offset,
414                               marshaller,
415                               return_val,
416                               nparams,
417                               params);
418 
419  g_free (params);
420 
421  return signal_id;
422}
423
424guint
425gtk_signal_lookup (const gchar *name,
426                   GtkType      object_type)
427{
428  GtkSignalHash hash;
429  GtkType lookup_type;
430  gpointer class = NULL;
431
432  g_return_val_if_fail (name != NULL, 0);
433  g_return_val_if_fail (gtk_type_is_a (object_type, GTK_TYPE_OBJECT), 0);
434 
435 relookup:
436
437  lookup_type = object_type;
438  hash.quark = g_quark_try_string (name);
439  if (hash.quark)
440    {
441      while (lookup_type)
442        {
443          guint signal_id;
444         
445          hash.object_type = lookup_type;
446         
447          signal_id = GPOINTER_TO_UINT (g_hash_table_lookup (gtk_signal_hash_table, &hash));
448          if (signal_id)
449            return signal_id;
450         
451          lookup_type = gtk_type_parent (lookup_type);
452        }
453    }
454
455  if (!class)
456    {
457      class = gtk_type_class (object_type);
458      goto relookup;
459    }
460
461  return 0;
462}
463
464GtkSignalQuery*
465gtk_signal_query (guint signal_id)
466{
467  GtkSignalQuery *query;
468  GtkSignal *signal;
469 
470  g_return_val_if_fail (signal_id >= 1, NULL);
471 
472  signal = LOOKUP_SIGNAL_ID (signal_id);
473  if (signal)
474    {
475      query = g_new (GtkSignalQuery, 1);
476     
477      query->object_type = signal->object_type;
478      query->signal_id = signal_id;
479      query->signal_name = signal->name;
480      query->is_user_signal = signal->function_offset == 0;
481      query->signal_flags = signal->signal_flags;
482      query->return_val = signal->return_val;
483      query->nparams = signal->nparams;
484      query->params = signal->params;
485    }
486  else
487    query = NULL;
488 
489  return query;
490}
491
492gchar*
493gtk_signal_name (guint signal_id)
494{
495  GtkSignal *signal;
496 
497  g_return_val_if_fail (signal_id >= 1, NULL);
498 
499  signal = LOOKUP_SIGNAL_ID (signal_id);
500  if (signal)
501    return signal->name;
502 
503  return NULL;
504}
505
506void
507gtk_signal_emitv (GtkObject           *object,
508                  guint                signal_id,
509                  GtkArg              *params)
510{
511  GtkSignal *signal;
512
513  g_return_if_fail (object != NULL);
514  g_return_if_fail (signal_id >= 1);
515 
516  signal = LOOKUP_SIGNAL_ID (signal_id);
517  g_return_if_fail (signal != NULL);
518  g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
519
520  if (signal->nparams > 0)
521    g_return_if_fail (params != NULL);
522
523  gtk_signal_real_emit (object, signal_id, params);
524}
525
526void
527gtk_signal_emit (GtkObject *object,
528                 guint      signal_id,
529                 ...)
530{
531  GtkSignal *signal;
532  va_list    args;
533  GtkArg     params[MAX_SIGNAL_PARAMS + 1];
534  gboolean   abort;
535
536  g_return_if_fail (object != NULL);
537  g_return_if_fail (signal_id >= 1);
538 
539  signal = LOOKUP_SIGNAL_ID (signal_id);
540  g_return_if_fail (signal != NULL);
541  g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
542
543  va_start (args, signal_id);
544  abort = gtk_signal_collect_params (params,
545                                     signal->nparams,
546                                     signal->params,
547                                     signal->return_val,
548                                     args);
549  va_end (args);
550
551  if (!abort)
552    gtk_signal_real_emit (object, signal_id, params);
553}
554
555void
556gtk_signal_emitv_by_name (GtkObject           *object,
557                          const gchar         *name,
558                          GtkArg              *params)
559{
560  guint signal_id;
561 
562  g_return_if_fail (object != NULL);
563  g_return_if_fail (name != NULL);
564  g_return_if_fail (params != NULL);
565 
566  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
567 
568  if (signal_id >= 1)
569    {
570      GtkSignal *signal;
571     
572      signal = LOOKUP_SIGNAL_ID (signal_id);
573      g_return_if_fail (signal != NULL);
574      g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
575
576      gtk_signal_real_emit (object, signal_id, params);
577    }
578  else
579    {
580      g_warning ("gtk_signal_emitv_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
581                 name,
582                 gtk_type_name (GTK_OBJECT_TYPE (object)));
583    }
584}
585
586void
587gtk_signal_emit_by_name (GtkObject       *object,
588                         const gchar     *name,
589                         ...)
590{
591  guint signal_id;
592 
593  g_return_if_fail (object != NULL);
594  g_return_if_fail (name != NULL);
595 
596  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
597 
598  if (signal_id >= 1)
599    {
600      GtkSignal *signal;
601      GtkArg     params[MAX_SIGNAL_PARAMS + 1];
602      va_list    args;
603      gboolean   abort;
604     
605      signal = LOOKUP_SIGNAL_ID (signal_id);
606      g_return_if_fail (signal != NULL);
607      g_return_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->object_type));
608
609      va_start (args, name);
610      abort = gtk_signal_collect_params (params,
611                                         signal->nparams,
612                                         signal->params,
613                                         signal->return_val,
614                                         args);
615      va_end (args);
616
617      if (!abort)
618        gtk_signal_real_emit (object, signal_id, params);
619    }
620  else
621    {
622      g_warning ("gtk_signal_emit_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
623                 name,
624                 gtk_type_name (GTK_OBJECT_TYPE (object)));
625    }
626}
627
628void
629gtk_signal_emit_stop (GtkObject *object,
630                      guint       signal_id)
631{
632  gint state;
633
634  g_return_if_fail (object != NULL);
635  g_return_if_fail (signal_id >= 1);
636 
637  state = gtk_emission_check (current_emissions, object, signal_id);
638  if (state > 1)
639    g_warning ("gtk_signal_emit_stop(): emission (%u) for object `%s' cannot be stopped from emission hook",
640               signal_id,
641               gtk_type_name (GTK_OBJECT_TYPE (object)));
642  else if (state)
643    {
644      if (!gtk_emission_check (stop_emissions, object, signal_id))
645        gtk_emission_add (&stop_emissions, object, signal_id);
646    }
647  else
648    g_warning ("gtk_signal_emit_stop(): no current emission (%u) for object `%s'",
649               signal_id,
650               gtk_type_name (GTK_OBJECT_TYPE (object)));
651}
652
653void
654gtk_signal_emit_stop_by_name (GtkObject       *object,
655                              const gchar     *name)
656{
657  guint signal_id;
658 
659  g_return_if_fail (object != NULL);
660  g_return_if_fail (name != NULL);
661 
662  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
663  if (signal_id)
664    gtk_signal_emit_stop (object, signal_id);
665  else
666    g_warning ("gtk_signal_emit_stop_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
667               name,
668               gtk_type_name (GTK_OBJECT_TYPE (object)));
669}
670
671guint
672gtk_signal_n_emissions (GtkObject  *object,
673                        guint       signal_id)
674{
675  GtkEmission *emission;
676  guint n;
677 
678  g_return_val_if_fail (object != NULL, 0);
679  g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
680 
681  n = 0;
682  for (emission = current_emissions; emission; emission = emission->next)
683    {
684      if (emission->object == object && emission->signal_id == signal_id)
685        n++;
686    }
687 
688  return n;
689}
690
691guint
692gtk_signal_n_emissions_by_name (GtkObject       *object,
693                                const gchar     *name)
694{
695  guint signal_id;
696  guint n;
697 
698  g_return_val_if_fail (object != NULL, 0);
699  g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
700  g_return_val_if_fail (name != NULL, 0);
701 
702  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
703  if (signal_id)
704    n = gtk_signal_n_emissions (object, signal_id);
705  else
706    {
707      g_warning ("gtk_signal_n_emissions_by_name(): could not find signal \"%s\" in the `%s' class ancestry",
708                 name,
709                 gtk_type_name (GTK_OBJECT_TYPE (object)));
710      n = 0;
711    }
712 
713  return n;
714}
715
716guint
717gtk_signal_connect (GtkObject     *object,
718                    const gchar   *name,
719                    GtkSignalFunc  func,
720                    gpointer       func_data)
721{
722  guint signal_id;
723 
724  g_return_val_if_fail (object != NULL, 0);
725  g_return_val_if_fail (GTK_IS_OBJECT (object), 0);
726 
727  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
728  if (!signal_id)
729    {
730      g_warning ("gtk_signal_connect(): could not find signal \"%s\" in the `%s' class ancestry",
731                 name,
732                 gtk_type_name (GTK_OBJECT_TYPE (object)));
733      return 0;
734    }
735 
736  return gtk_signal_connect_by_type (object, signal_id,
737                                     func, func_data, NULL,
738                                     FALSE, FALSE, FALSE);
739}
740
741guint
742gtk_signal_connect_after (GtkObject     *object,
743                          const gchar   *name,
744                          GtkSignalFunc  func,
745                          gpointer       func_data)
746{
747  guint signal_id;
748 
749  g_return_val_if_fail (object != NULL, 0);
750 
751  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
752  if (!signal_id)
753    {
754      g_warning ("gtk_signal_connect_after(): could not find signal \"%s\" in the `%s' class ancestry",
755                 name,
756                 gtk_type_name (GTK_OBJECT_TYPE (object)));
757      return 0;
758    }
759 
760  return gtk_signal_connect_by_type (object, signal_id,
761                                     func, func_data, NULL,
762                                     FALSE, TRUE, FALSE);
763}
764
765guint   
766gtk_signal_connect_full (GtkObject           *object,
767                         const gchar         *name,
768                         GtkSignalFunc        func,
769                         GtkCallbackMarshal   marshal,
770                         gpointer             func_data,
771                         GtkDestroyNotify     destroy_func,
772                         gint                 object_signal,
773                         gint                 after)
774{
775  guint signal_id;
776 
777  g_return_val_if_fail (object != NULL, 0);
778 
779  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
780  if (!signal_id)
781    {
782      g_warning ("gtk_signal_connect_full(): could not find signal \"%s\" in the `%s' class ancestry",
783                 name,
784                 gtk_type_name (GTK_OBJECT_TYPE (object)));
785      return 0;
786    }
787 
788  if (marshal)
789    return gtk_signal_connect_by_type (object, signal_id, (GtkSignalFunc) marshal,
790                                       func_data, destroy_func,
791                                       object_signal, after, TRUE);
792  else
793    return gtk_signal_connect_by_type (object, signal_id, func,
794                                       func_data, destroy_func,
795                                       object_signal, after, FALSE);
796}
797
798guint
799gtk_signal_connect_object (GtkObject     *object,
800                           const gchar   *name,
801                           GtkSignalFunc  func,
802                           GtkObject     *slot_object)
803{
804  guint signal_id;
805 
806  g_return_val_if_fail (object != NULL, 0);
807  /* slot_object needs to be treated as ordinary pointer
808   */
809 
810  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
811  if (!signal_id)
812    {
813      g_warning ("gtk_signal_connect_object(): could not find signal \"%s\" in the `%s' class ancestry",
814                 name,
815                 gtk_type_name (GTK_OBJECT_TYPE (object)));
816      return 0;
817    }
818 
819  return gtk_signal_connect_by_type (object, signal_id,
820                                     func, slot_object, NULL,
821                                     TRUE, FALSE, FALSE);
822}
823
824guint
825gtk_signal_connect_object_after (GtkObject     *object,
826                                 const gchar   *name,
827                                 GtkSignalFunc  func,
828                                 GtkObject     *slot_object)
829{
830  guint signal_id;
831 
832  g_return_val_if_fail (object != NULL, 0);
833 
834  signal_id = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object));
835  if (!signal_id)
836    {
837      g_warning ("gtk_signal_connect_object_after(): could not find signal \"%s\" in the `%s' class ancestry",
838                 name,
839                 gtk_type_name (GTK_OBJECT_TYPE (object)));
840      return 0;
841    }
842 
843  return gtk_signal_connect_by_type (object, signal_id,
844                                     func, slot_object, NULL,
845                                     TRUE, TRUE, FALSE);
846}
847
848void
849gtk_signal_connect_while_alive (GtkObject        *object,
850                                const gchar      *signal,
851                                GtkSignalFunc     func,
852                                gpointer          func_data,
853                                GtkObject        *alive_object)
854{
855  GtkDisconnectInfo *info;
856 
857  g_return_if_fail (object != NULL);
858  g_return_if_fail (GTK_IS_OBJECT (object));
859  g_return_if_fail (signal != NULL);
860  g_return_if_fail (func != NULL);
861  g_return_if_fail (alive_object != NULL);
862  g_return_if_fail (GTK_IS_OBJECT (alive_object));
863 
864  info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
865  info->object1 = object;
866  info->object2 = alive_object;
867 
868  info->signal_handler = gtk_signal_connect (object, signal, func, func_data);
869  info->disconnect_handler1 =
870    gtk_signal_connect_object (info->object1,
871                               "destroy",
872                               GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
873                               (GtkObject*) info);
874  info->disconnect_handler2 =
875    gtk_signal_connect_object (info->object2,
876                               "destroy",
877                               GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
878                               (GtkObject*) info);
879}
880
881void
882gtk_signal_connect_object_while_alive (GtkObject        *object,
883                                       const gchar      *signal,
884                                       GtkSignalFunc     func,
885                                       GtkObject        *alive_object)
886{
887  GtkDisconnectInfo *info;
888 
889  g_return_if_fail (object != NULL);
890  g_return_if_fail (GTK_IS_OBJECT (object));
891  g_return_if_fail (signal != NULL);
892  g_return_if_fail (func != NULL);
893  g_return_if_fail (alive_object != NULL);
894  g_return_if_fail (GTK_IS_OBJECT (alive_object));
895 
896  info = g_chunk_new (GtkDisconnectInfo, gtk_disconnect_info_mem_chunk);
897  info->object1 = object;
898  info->object2 = alive_object;
899 
900  info->signal_handler = gtk_signal_connect_object (object, signal, func, alive_object);
901  info->disconnect_handler1 =
902    gtk_signal_connect_object (info->object1,
903                               "destroy",
904                               GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
905                               (GtkObject*) info);
906  info->disconnect_handler2 =
907    gtk_signal_connect_object (info->object2,
908                               "destroy",
909                               GTK_SIGNAL_FUNC (gtk_alive_disconnecter),
910                               (GtkObject*) info);
911}
912
913void
914gtk_signal_disconnect (GtkObject *object,
915                       guint      handler_id)
916{
917  GtkHandler *handler;
918 
919  g_return_if_fail (object != NULL);
920  g_return_if_fail (handler_id > 0);
921 
922  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
923 
924  while (handler)
925    {
926      if (handler->id == handler_id)
927        {
928          handler->id = 0;
929          handler->blocked += 1;
930          gtk_signal_handler_unref (handler, object);
931          return;
932        }
933      handler = handler->next;
934    }
935 
936  g_warning ("gtk_signal_disconnect(): could not find handler (%u)", handler_id);
937}
938
939void
940gtk_signal_disconnect_by_func (GtkObject     *object,
941                               GtkSignalFunc  func,
942                               gpointer       data)
943{
944  GtkHandler *handler;
945  gint found_one;
946 
947  g_return_if_fail (object != NULL);
948  g_return_if_fail (func != NULL);
949 
950  found_one = FALSE;
951  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
952 
953  while (handler)
954    {
955      GtkHandler *handler_next;
956     
957      handler_next = handler->next;
958      if ((handler->id > 0) &&
959          (handler->func == func) &&
960          (handler->func_data == data))
961        {
962          found_one = TRUE;
963          handler->id = 0;
964          handler->blocked += 1;
965          gtk_signal_handler_unref (handler, object);
966        }
967      handler = handler_next;
968    }
969 
970  if (!found_one)
971    g_warning ("gtk_signal_disconnect_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
972}
973
974void
975gtk_signal_disconnect_by_data (GtkObject *object,
976                               gpointer   data)
977{
978  GtkHandler *handler;
979  gint found_one;
980 
981  g_return_if_fail (object != NULL);
982 
983  found_one = FALSE;
984  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
985 
986  while (handler)
987    {
988      GtkHandler *handler_next;
989     
990      handler_next = handler->next;
991      if ((handler->id > 0) &&
992          (handler->func_data == data))
993        {
994          found_one = TRUE;
995          handler->id = 0;
996          handler->blocked += 1;
997          gtk_signal_handler_unref (handler, object);
998        }
999      handler = handler_next;
1000    }
1001 
1002  if (!found_one)
1003    g_warning ("gtk_signal_disconnect_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1004}
1005
1006void
1007gtk_signal_handler_block (GtkObject *object,
1008                          guint      handler_id)
1009{
1010  GtkHandler *handler;
1011 
1012  g_return_if_fail (object != NULL);
1013  g_return_if_fail (handler_id > 0);
1014 
1015  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1016 
1017  while (handler)
1018    {
1019      if (handler->id == handler_id)
1020        {
1021          handler->blocked += 1;
1022          return;
1023        }
1024      handler = handler->next;
1025    }
1026 
1027  g_warning ("gtk_signal_handler_block(): could not find handler (%u)", handler_id);
1028}
1029
1030void
1031gtk_signal_handler_block_by_func (GtkObject     *object,
1032                                  GtkSignalFunc  func,
1033                                  gpointer       data)
1034{
1035  GtkHandler *handler;
1036  gint found_one;
1037 
1038  g_return_if_fail (object != NULL);
1039  g_return_if_fail (func != NULL);
1040 
1041  found_one = FALSE;
1042  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1043 
1044  while (handler)
1045    {
1046      if ((handler->id > 0) &&
1047          (handler->func == func) &&
1048          (handler->func_data == data))
1049        {
1050          found_one = TRUE;
1051          handler->blocked += 1;
1052        }
1053      handler = handler->next;
1054    }
1055 
1056  if (!found_one)
1057    g_warning ("gtk_signal_handler_block_by_func(): could not find handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1058}
1059
1060void
1061gtk_signal_handler_block_by_data (GtkObject *object,
1062                                  gpointer   data)
1063{
1064  GtkHandler *handler;
1065  gint found_one;
1066 
1067  g_return_if_fail (object != NULL);
1068 
1069  found_one = FALSE;
1070  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1071 
1072  while (handler)
1073    {
1074      if ((handler->id > 0) &&
1075          (handler->func_data == data))
1076        {
1077          found_one = TRUE;
1078          handler->blocked += 1;
1079        }
1080      handler = handler->next;
1081    }
1082 
1083  if (!found_one)
1084    g_warning ("gtk_signal_handler_block_by_data(): could not find handler containing data (0x%0lX)", (long) data);
1085}
1086
1087void
1088gtk_signal_handler_unblock (GtkObject *object,
1089                            guint      handler_id)
1090{
1091  GtkHandler *handler;
1092 
1093  g_return_if_fail (object != NULL);
1094  g_return_if_fail (handler_id > 0);
1095 
1096  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1097 
1098  while (handler)
1099    {
1100      if (handler->id == handler_id)
1101        {
1102          if (handler->blocked > 0)
1103            handler->blocked -= 1;
1104          else
1105            g_warning ("gtk_signal_handler_unblock(): handler (%u) is not blocked", handler_id);
1106          return;
1107        }
1108      handler = handler->next;
1109    }
1110 
1111  g_warning ("gtk_signal_handler_unblock(): could not find handler (%u)", handler_id);
1112}
1113
1114void
1115gtk_signal_handler_unblock_by_func (GtkObject     *object,
1116                                    GtkSignalFunc  func,
1117                                    gpointer       data)
1118{
1119  GtkHandler *handler;
1120  gint found_one;
1121 
1122  g_return_if_fail (object != NULL);
1123  g_return_if_fail (func != NULL);
1124 
1125  found_one = FALSE;
1126  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1127 
1128  while (handler)
1129    {
1130      if ((handler->id > 0) &&
1131          (handler->func == func) &&
1132          (handler->func_data == data) &&
1133          (handler->blocked > 0))
1134        {
1135          handler->blocked -= 1;
1136          found_one = TRUE;
1137        }
1138      handler = handler->next;
1139    }
1140 
1141  if (!found_one)
1142    g_warning ("gtk_signal_handler_unblock_by_func(): could not find blocked handler (0x%0lX) containing data (0x%0lX)", (long) func, (long) data);
1143}
1144
1145void
1146gtk_signal_handler_unblock_by_data (GtkObject *object,
1147                                    gpointer   data)
1148{
1149  GtkHandler *handler;
1150  gint found_one;
1151 
1152  g_return_if_fail (object != NULL);
1153 
1154  found_one = FALSE;
1155  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1156 
1157  while (handler)
1158    {
1159      if ((handler->id > 0) &&
1160          (handler->func_data == data) &&
1161          (handler->blocked > 0))
1162        {
1163          handler->blocked -= 1;
1164          found_one = TRUE;
1165        }
1166      handler = handler->next;
1167    }
1168 
1169  if (!found_one)
1170    g_warning ("gtk_signal_handler_unblock_by_data(): could not find blocked handler containing data (0x%0lX)", (long) data);
1171}
1172
1173void
1174gtk_signal_handlers_destroy (GtkObject *object)
1175{
1176  GtkHandler *handler;
1177 
1178  /* we make the "optimization" of destroying the first handler in the last
1179   * place, since we don't want gtk_signal_handler_unref() to reset the objects
1180   * handler_key data on each removal
1181   */
1182 
1183  handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1184  if (handler)
1185    {
1186      handler = handler->next;
1187      while (handler)
1188        {
1189          GtkHandler *next;
1190         
1191          next = handler->next;
1192          if (handler->id > 0)
1193            {
1194              handler->id = 0;
1195              handler->blocked += 1;
1196              gtk_signal_handler_unref (handler, object);
1197            }
1198          handler = next;
1199        }
1200      handler = gtk_object_get_data_by_id (object, gtk_handler_quark);
1201      if (handler->id > 0)
1202        {
1203          handler->id = 0;
1204          handler->blocked += 1;
1205          gtk_signal_handler_unref (handler, object);
1206        }
1207    }
1208}
1209
1210void
1211gtk_signal_set_funcs (GtkSignalMarshal marshal_func,
1212                      GtkSignalDestroy destroy_func)
1213{
1214  global_marshaller = marshal_func;
1215  global_destroy_notify = destroy_func;
1216}
1217
1218static guint
1219gtk_signal_hash (gconstpointer h)
1220{
1221  register const GtkSignalHash *hash = h;
1222 
1223  return hash->object_type ^ hash->quark;
1224}
1225
1226static gint
1227gtk_signal_compare (gconstpointer h1,
1228                    gconstpointer h2)
1229{
1230  register const GtkSignalHash *hash1 = h1;
1231  register const GtkSignalHash *hash2 = h2;
1232 
1233  return (hash1->quark == hash2->quark &&
1234          hash1->object_type == hash2->object_type);
1235}
1236
1237static guint
1238gtk_alive_disconnecter (GtkDisconnectInfo *info)
1239{
1240  g_return_val_if_fail (info != NULL, 0);
1241 
1242  gtk_signal_disconnect (info->object1, info->disconnect_handler1);
1243  gtk_signal_disconnect (info->object1, info->signal_handler);
1244  gtk_signal_disconnect (info->object2, info->disconnect_handler2);
1245 
1246  g_mem_chunk_free (gtk_disconnect_info_mem_chunk, info);
1247 
1248  return 0;
1249}
1250
1251static GtkHandler*
1252gtk_signal_handler_new (void)
1253{
1254  GtkHandler *handler;
1255
1256  if (!gtk_handler_free_list)
1257    {
1258      GtkHandler *handler_block;
1259      guint i;
1260
1261      handler_block = g_new0 (GtkHandler, HANDLER_BLOCK_SIZE);
1262      for (i = 1; i < HANDLER_BLOCK_SIZE; i++)
1263        {
1264          (handler_block + i)->next = gtk_handler_free_list;
1265          gtk_handler_free_list = (handler_block + i);
1266        }
1267     
1268      handler = handler_block;
1269    }
1270  else
1271    {
1272      handler = gtk_handler_free_list;
1273      gtk_handler_free_list = handler->next;
1274    }
1275 
1276  handler->id = 0;
1277  handler->blocked = 0;
1278  handler->signal_id = 0;
1279  handler->object_signal = FALSE;
1280  handler->after = FALSE;
1281  handler->no_marshal = FALSE;
1282  handler->ref_count = 1;
1283  handler->func = NULL;
1284  handler->func_data = NULL;
1285  handler->destroy_func = NULL;
1286  handler->prev = NULL;
1287  handler->next = NULL;
1288 
1289  return handler;
1290}
1291
1292static void
1293gtk_signal_handler_ref (GtkHandler *handler)
1294{
1295  handler->ref_count += 1;
1296}
1297
1298static void
1299gtk_signal_handler_unref (GtkHandler *handler,
1300                          GtkObject  *object)
1301{
1302  if (!handler->ref_count)
1303    {
1304      /* FIXME: i wanna get removed somewhen */
1305      g_warning ("gtk_signal_handler_unref(): handler with ref_count==0!");
1306      return;
1307    }
1308 
1309  handler->ref_count -= 1;
1310 
1311  if (handler->ref_count == 0)
1312    {
1313      if (handler->destroy_func)
1314        (* handler->destroy_func) (handler->func_data);
1315      else if (!handler->func && global_destroy_notify)
1316        (* global_destroy_notify) (handler->func_data);
1317     
1318      if (handler->prev)
1319        handler->prev->next = handler->next;
1320      else if (handler->next)
1321        gtk_object_set_data_by_id (object, gtk_handler_quark, handler->next);
1322      else
1323        {
1324          GTK_OBJECT_UNSET_FLAGS (object, GTK_CONNECTED);
1325          gtk_object_set_data_by_id (object, gtk_handler_quark, NULL);
1326        }
1327      if (handler->next)
1328        handler->next->prev = handler->prev;
1329     
1330      handler->next = gtk_handler_free_list;
1331      gtk_handler_free_list = handler;
1332    }
1333}
1334
1335static void
1336gtk_signal_handler_insert (GtkObject  *object,
1337                           GtkHandler *handler)
1338{
1339  GtkHandler *tmp;
1340 
1341  /* FIXME: remove */ g_assert (handler->next == NULL);
1342  /* FIXME: remove */ g_assert (handler->prev == NULL);
1343 
1344  tmp = gtk_object_get_data_by_id (object, gtk_handler_quark);
1345  if (!tmp)
1346    {
1347      GTK_OBJECT_SET_FLAGS (object, GTK_CONNECTED);
1348      gtk_object_set_data_by_id (object, gtk_handler_quark, handler);
1349    }
1350  else
1351    while (tmp)
1352      {
1353        if (tmp->signal_id < handler->signal_id)
1354          {
1355            if (tmp->prev)
1356              {
1357                tmp->prev->next = handler;
1358                handler->prev = tmp->prev;
1359              }
1360            else
1361              gtk_object_set_data_by_id (object, gtk_handler_quark, handler);
1362            tmp->prev = handler;
1363            handler->next = tmp;
1364            break;
1365          }
1366       
1367        if (!tmp->next)
1368          {
1369            tmp->next = handler;
1370            handler->prev = tmp;
1371            break;
1372          }
1373        tmp = tmp->next;
1374      }
1375}
1376
1377
1378#ifdef  G_ENABLE_DEBUG
1379/* value typically set via gdb */
1380static GtkObject *gtk_trace_signal_object = NULL;
1381#endif  /* G_ENABLE_DEBUG */
1382
1383
1384static void
1385gtk_signal_real_emit (GtkObject *object,
1386                      guint      signal_id,
1387                      GtkArg    *params)
1388{
1389  GtkSignal     signal;
1390  GtkHandler    *handlers;
1391  GtkSignalFunc  signal_func;
1392  GtkEmission   *emission;
1393
1394  /* gtk_handlers_run() expects a reentrant GtkSignal*, so we allocate
1395   * it locally on the stack. we save some lookups ourselves with this as well.
1396   */
1397  signal = *LOOKUP_SIGNAL_ID (signal_id);
1398  if (signal.function_offset)
1399    signal_func = G_STRUCT_MEMBER (GtkSignalFunc, object->klass, signal.function_offset);
1400  else
1401    signal_func = NULL;
1402 
1403#ifdef  G_ENABLE_DEBUG
1404  if (gtk_debug_flags & GTK_DEBUG_SIGNALS ||
1405      object == gtk_trace_signal_object)
1406    g_message ("%s::%s emitted (object=%p class-method=%p)\n",
1407               gtk_type_name (GTK_OBJECT_TYPE (object)),
1408               signal.name,
1409               object,
1410               signal_func);
1411#endif  /* G_ENABLE_DEBUG */
1412 
1413  if (signal.signal_flags & GTK_RUN_NO_RECURSE)
1414    {
1415      gint state;
1416     
1417      state = gtk_emission_check (current_emissions, object, signal_id);
1418      if (state)
1419        {
1420          if (state > 1)
1421            g_warning ("gtk_signal_real_emit(): emission (%u) for object `%s' cannot be restarted from emission hook",
1422                       signal_id,
1423                       gtk_type_name (GTK_OBJECT_TYPE (object)));
1424          else if (!gtk_emission_check (restart_emissions, object, signal_id))
1425            gtk_emission_add (&restart_emissions, object, signal_id);
1426         
1427          return;
1428        }
1429    }
1430 
1431  gtk_object_ref (object);
1432 
1433  gtk_emission_add (&current_emissions, object, signal_id);
1434  emission = current_emissions;
1435 
1436 emission_restart:
1437 
1438  if (signal.signal_flags & GTK_RUN_FIRST && signal_func)
1439    {
1440      signal.marshaller (object, signal_func, NULL, params);
1441     
1442      if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1443        {
1444          gtk_emission_remove (&stop_emissions, object, signal_id);
1445          goto emission_done;
1446        }
1447      else if (restart_emissions &&
1448               signal.signal_flags & GTK_RUN_NO_RECURSE &&
1449               gtk_emission_check (restart_emissions, object, signal_id))
1450        {
1451          gtk_emission_remove (&restart_emissions, object, signal_id);
1452         
1453          goto emission_restart;
1454        }
1455    }
1456 
1457  if (signal.hook_list && !GTK_OBJECT_DESTROYED (object))
1458    {
1459      GtkEmissionHookData data;
1460
1461      data.object = object;
1462      data.n_params = signal.nparams;
1463      data.params = params;
1464      data.signal_id = signal_id;
1465      emission->in_hook = 1;
1466      g_hook_list_marshal_check (signal.hook_list, TRUE, gtk_emission_hook_marshaller, &data);
1467      emission->in_hook = 0;
1468    }
1469
1470  if (GTK_OBJECT_CONNECTED (object))
1471    {
1472      handlers = gtk_signal_get_handlers (object, signal_id);
1473      if (handlers)
1474        {
1475          gint return_val;
1476         
1477          return_val = gtk_handlers_run (handlers, &signal, object, params, FALSE);
1478          switch (return_val)
1479            {
1480            case EMISSION_CONTINUE:
1481              break;
1482            case EMISSION_RESTART:
1483              goto emission_restart;
1484            case EMISSION_DONE:
1485              goto emission_done;
1486            }
1487        }
1488    }
1489 
1490  if (signal.signal_flags & GTK_RUN_LAST && signal_func)
1491    {
1492      signal.marshaller (object, signal_func, NULL, params);
1493     
1494      if (stop_emissions && gtk_emission_check (stop_emissions, object, signal_id))
1495        {
1496          gtk_emission_remove (&stop_emissions, object, signal_id);
1497          goto emission_done;
1498        }
1499      else if (restart_emissions &&
1500               signal.signal_flags & GTK_RUN_NO_RECURSE &&
1501               gtk_emission_check (restart_emissions, object, signal_id))
1502        {
1503          gtk_emission_remove (&restart_emissions, object, signal_id);
1504         
1505          goto emission_restart;
1506        }
1507    }
1508 
1509  if (GTK_OBJECT_CONNECTED (object))
1510    {
1511      handlers = gtk_signal_get_handlers (object, signal_id);
1512      if (handlers)
1513        {
1514          gint return_val;
1515         
1516          return_val = gtk_handlers_run (handlers, &signal, object, params, TRUE);
1517          switch (return_val)
1518            {
1519            case  EMISSION_CONTINUE:
1520              break;
1521            case  EMISSION_RESTART:
1522              goto emission_restart;
1523            case  EMISSION_DONE:
1524              goto emission_done;
1525            }
1526        }
1527    }
1528 
1529 emission_done:
1530  if (restart_emissions && signal.signal_flags & GTK_RUN_NO_RECURSE)
1531    gtk_emission_remove (&restart_emissions, object, signal_id);
1532 
1533  gtk_emission_remove (&current_emissions, object, signal_id);
1534 
1535  gtk_object_unref (object);
1536}
1537
1538guint
1539gtk_signal_handler_pending (GtkObject           *object,
1540                            guint                signal_id,
1541                            gboolean             may_be_blocked)
1542{
1543  GtkHandler *handlers;
1544  guint handler_id;
1545 
1546  g_return_val_if_fail (object != NULL, 0);
1547  g_return_val_if_fail (signal_id >= 1, 0);
1548
1549  if (GTK_OBJECT_CONNECTED (object))
1550    handlers = gtk_signal_get_handlers (object, signal_id);
1551  else
1552    return 0;
1553 
1554  handler_id = 0;
1555  while (handlers && handlers->signal_id == signal_id)
1556    {
1557      if (handlers->id > 0 &&
1558          (may_be_blocked || handlers->blocked == FALSE))
1559        {
1560          handler_id = handlers->id;
1561          break;
1562        }
1563     
1564      handlers = handlers->next;
1565    }
1566 
1567  return handler_id;
1568}
1569
1570guint
1571gtk_signal_handler_pending_by_func (GtkObject           *object,
1572                                    guint                signal_id,
1573                                    gboolean             may_be_blocked,
1574                                    GtkSignalFunc        func,
1575                                    gpointer             data)
1576{
1577  GtkHandler *handlers;
1578  guint handler_id;
1579 
1580  g_return_val_if_fail (object != NULL, 0);
1581  g_return_val_if_fail (func != NULL, 0);
1582  g_return_val_if_fail (signal_id >= 1, 0);
1583
1584  if (GTK_OBJECT_CONNECTED (object))
1585    handlers = gtk_signal_get_handlers (object, signal_id);
1586  else
1587    return 0;
1588 
1589  handler_id = 0;
1590  while (handlers && handlers->signal_id == signal_id)
1591    {
1592      if (handlers->id > 0 &&
1593          handlers->func == func &&
1594          handlers->func_data == data &&
1595          (may_be_blocked || handlers->blocked == 0))
1596        {
1597          handler_id = handlers->id;
1598          break;
1599        }
1600     
1601      handlers = handlers->next;
1602    }
1603 
1604  return handler_id;
1605}
1606
1607gint
1608gtk_signal_handler_pending_by_id (GtkObject *object,
1609                                  guint      handler_id,
1610                                  gboolean   may_be_blocked)
1611{
1612  GtkHandler *handlers;
1613 
1614  g_return_val_if_fail (object != NULL, FALSE);
1615  g_return_val_if_fail (handler_id >= 1, FALSE);
1616
1617  if (GTK_OBJECT_CONNECTED (object))
1618    handlers = gtk_object_get_data_by_id (object, gtk_handler_quark);
1619  else
1620    return FALSE;
1621 
1622  while (handlers)
1623    {
1624      if (handlers->id == handler_id)
1625        return may_be_blocked || handlers->blocked == 0;
1626     
1627      handlers = handlers->next;
1628    }
1629 
1630  return FALSE;
1631}
1632
1633guint
1634gtk_signal_add_emission_hook (guint           signal_id,
1635                              GtkEmissionHook hook_func,
1636                              gpointer        data)
1637{
1638  return gtk_signal_add_emission_hook_full (signal_id, hook_func, data, NULL);
1639}
1640
1641guint
1642gtk_signal_add_emission_hook_full (guint           signal_id,
1643                                   GtkEmissionHook hook_func,
1644                                   gpointer        data,
1645                                   GDestroyNotify  destroy)
1646{
1647  static guint seq_hook_id = 1;
1648  GtkSignal *signal;
1649  GHook *hook;
1650
1651  g_return_val_if_fail (signal_id > 0, 0);
1652  g_return_val_if_fail (hook_func != NULL, 0);
1653 
1654  signal = LOOKUP_SIGNAL_ID (signal_id);
1655  g_return_val_if_fail (signal != NULL, 0);
1656  if (signal->signal_flags & GTK_RUN_NO_HOOKS)
1657    {
1658      g_warning ("gtk_signal_add_emission_hook_full(): signal \"%s\" does not support emission hooks",
1659                 signal->name);
1660      return 0;
1661    }
1662
1663  if (!signal->hook_list)
1664    {
1665      signal->hook_list = g_new (GHookList, 1);
1666      g_hook_list_init (signal->hook_list, sizeof (GHook));
1667    }
1668
1669  hook = g_hook_alloc (signal->hook_list);
1670  hook->data = data;
1671  hook->func = hook_func;
1672  hook->destroy = destroy;
1673
1674  signal->hook_list->seq_id = seq_hook_id;
1675  g_hook_prepend (signal->hook_list, hook);
1676  seq_hook_id = signal->hook_list->seq_id;
1677
1678  return hook->hook_id;
1679}
1680
1681void
1682gtk_signal_remove_emission_hook (guint signal_id,
1683                                 guint hook_id)
1684{
1685  GtkSignal *signal;
1686
1687  g_return_if_fail (signal_id > 0);
1688  g_return_if_fail (hook_id > 0);
1689
1690  signal = LOOKUP_SIGNAL_ID (signal_id);
1691  g_return_if_fail (signal != NULL);
1692
1693  if (!signal->hook_list || !g_hook_destroy (signal->hook_list, hook_id))
1694    g_warning ("gtk_signal_remove_emission_hook(): could not find hook (%u)", hook_id);
1695}
1696
1697static gboolean
1698gtk_emission_hook_marshaller (GHook   *hook,
1699                              gpointer data_p)
1700{
1701  GtkEmissionHookData *data = data_p;
1702  GtkEmissionHook func;
1703
1704  func = hook->func;
1705
1706  if (!GTK_OBJECT_DESTROYED (data->object))
1707    return func (data->object, data->signal_id,
1708                 data->n_params, data->params,
1709                 hook->data);
1710  else
1711    return TRUE;
1712}
1713
1714static guint
1715gtk_signal_connect_by_type (GtkObject       *object,
1716                            guint            signal_id,
1717                            GtkSignalFunc    func,
1718                            gpointer         func_data,
1719                            GtkSignalDestroy destroy_func,
1720                            gint             object_signal,
1721                            gint             after,
1722                            gint             no_marshal)
1723{
1724  GtkObjectClass *class;
1725  GtkHandler *handler;
1726  gint found_it;
1727  GtkSignal *signal;
1728 
1729  g_return_val_if_fail (object != NULL, 0);
1730  g_return_val_if_fail (object->klass != NULL, 0);
1731 
1732  signal = LOOKUP_SIGNAL_ID (signal_id);
1733
1734  /* Search through the signals for this object and make
1735   *  sure the one we are adding is valid. We need to perform
1736   *  the lookup on the objects parents as well. If it isn't
1737   *  valid then issue a warning and return.
1738   * As of now (1998-05-27) this lookup shouldn't be neccessarry
1739   *  anymore since gtk_signal_lookup() has been reworked to only
1740   *  return correct signal ids per class-branch.
1741   */
1742  found_it = FALSE;
1743  class = object->klass;
1744  while (class)
1745    {
1746      GtkType parent;
1747      guint *object_signals;
1748      guint nsignals;
1749      guint i;
1750     
1751      object_signals = class->signals;
1752      nsignals = class->nsignals;
1753     
1754      for (i = 0; i < nsignals; i++)
1755        if (object_signals[i] == signal_id)
1756          {
1757            found_it = TRUE;
1758            break;
1759          }
1760     
1761      parent = gtk_type_parent (class->type);
1762      if (parent)
1763        class = gtk_type_class (parent);
1764      else
1765        class = NULL;
1766    }
1767 
1768  if (!found_it)
1769    {
1770      g_warning ("gtk_signal_connect_by_type(): could not find signal id (%u) in the `%s' class ancestry",
1771                 signal_id,
1772                 gtk_type_name (object->klass->type));
1773      return 0;
1774    }
1775 
1776  handler = gtk_signal_handler_new ();
1777  handler->id = gtk_handler_id++;
1778  handler->signal_id = signal_id;
1779  handler->object_signal = object_signal != FALSE;
1780  handler->func = func;
1781  handler->func_data = func_data;
1782  handler->destroy_func = destroy_func;
1783  handler->after = after != FALSE;
1784  handler->no_marshal = no_marshal;
1785 
1786  gtk_signal_handler_insert (object, handler);
1787  return handler->id;
1788}
1789
1790static GtkEmission*
1791gtk_emission_new (void)
1792{
1793  GtkEmission *emission;
1794 
1795  if (!gtk_free_emissions)
1796    {
1797      GtkEmission *emission_block;
1798      guint i;
1799
1800      emission_block = g_new0 (GtkEmission, EMISSION_BLOCK_SIZE);
1801      for (i = 1; i < EMISSION_BLOCK_SIZE; i++)
1802        {
1803          (emission_block + i)->next = gtk_free_emissions;
1804          gtk_free_emissions = (emission_block + i);
1805        }
1806
1807      emission = emission_block;
1808    }
1809  else
1810    {
1811      emission = gtk_free_emissions;
1812      gtk_free_emissions = emission->next;
1813    }
1814
1815  emission->object = NULL;
1816  emission->signal_id = 0;
1817  emission->in_hook = 0;
1818  emission->next = NULL;
1819 
1820  return emission;
1821}
1822
1823static void
1824gtk_emission_add (GtkEmission **emissions,
1825                  GtkObject    *object,
1826                  guint         signal_id)
1827{
1828  GtkEmission *emission;
1829 
1830  g_return_if_fail (emissions != NULL);
1831  g_return_if_fail (object != NULL);
1832 
1833  emission = gtk_emission_new ();
1834  emission->object = object;
1835  emission->signal_id = signal_id;
1836
1837  emission->next = *emissions;
1838  *emissions = emission;
1839}
1840
1841static void
1842gtk_emission_remove (GtkEmission **emissions,
1843                     GtkObject    *object,
1844                     guint         signal_id)
1845{
1846  GtkEmission *emission, *last;
1847 
1848  g_return_if_fail (emissions != NULL);
1849
1850  last = NULL;
1851  emission = *emissions;
1852  while (emission)
1853    {
1854      if (emission->object == object && emission->signal_id == signal_id)
1855        {
1856          if (last)
1857            last->next = emission->next;
1858          else
1859            *emissions = emission->next;
1860
1861          emission->next = gtk_free_emissions;
1862          gtk_free_emissions = emission;
1863          break;
1864        }
1865
1866      last = emission;
1867      emission = last->next;
1868    }
1869}
1870
1871static gint
1872gtk_emission_check (GtkEmission *emission,
1873                    GtkObject   *object,
1874                    guint        signal_id)
1875{
1876  while (emission)
1877    {
1878      if (emission->object == object && emission->signal_id == signal_id)
1879        return 1 + emission->in_hook;
1880      emission = emission->next;
1881    }
1882  return FALSE;
1883}
1884
1885static gint
1886gtk_handlers_run (GtkHandler     *handlers,
1887                  GtkSignal      *signal,
1888                  GtkObject      *object,
1889                  GtkArg         *params,
1890                  gint            after)
1891{
1892  /* *signal is a local copy on the stack of gtk_signal_real_emit(),
1893   * so we don't need to look it up every time we invoked a function.
1894   */
1895  while (handlers && handlers->signal_id == signal->signal_id)
1896    {
1897      GtkHandler *handlers_next;
1898     
1899      gtk_signal_handler_ref (handlers);
1900     
1901      if (!handlers->blocked && handlers->after == after)
1902        {
1903          if (handlers->func)
1904            {
1905              if (handlers->no_marshal)
1906                (* (GtkCallbackMarshal) handlers->func) (object,
1907                                                         handlers->func_data,
1908                                                         signal->nparams,
1909                                                         params);
1910              else if (handlers->object_signal)
1911                /* don't cast with GTK_OBJECT () */
1912                (* signal->marshaller) ((GtkObject*) handlers->func_data,
1913                                        handlers->func,
1914                                        object,
1915                                        params);
1916              else
1917                (* signal->marshaller) (object,
1918                                        handlers->func,
1919                                        handlers->func_data,
1920                                        params);
1921            }
1922          else if (global_marshaller)
1923            (* global_marshaller) (object,
1924                                   handlers->func_data,
1925                                   signal->nparams,
1926                                   params,
1927                                   signal->params,
1928                                   signal->return_val);
1929         
1930          if (stop_emissions && gtk_emission_check (stop_emissions,
1931                                                    object,
1932                                                    signal->signal_id))
1933            {
1934              gtk_emission_remove (&stop_emissions, object, signal->signal_id);
1935             
1936              gtk_signal_handler_unref (handlers, object);
1937
1938              return EMISSION_DONE;
1939            }
1940          else if (restart_emissions &&
1941                   signal->signal_flags & GTK_RUN_NO_RECURSE &&
1942                   gtk_emission_check (restart_emissions, object, signal->signal_id))
1943            {
1944              gtk_emission_remove (&restart_emissions, object, signal->signal_id);
1945
1946              gtk_signal_handler_unref (handlers, object);
1947
1948              return EMISSION_RESTART;
1949            }
1950        }
1951     
1952      handlers_next = handlers->next;
1953      gtk_signal_handler_unref (handlers, object);
1954      handlers = handlers_next;
1955    }
1956 
1957  return EMISSION_CONTINUE;
1958}
1959
1960static gboolean
1961gtk_signal_collect_params (GtkArg              *params,
1962                           guint                n_params,
1963                           GtkType             *param_types,
1964                           GtkType              return_type,
1965                           va_list              var_args)
1966{
1967  register GtkArg *last_param;
1968  register gboolean failed = FALSE;
1969
1970  for (last_param = params + n_params; params < last_param; params++)
1971    {
1972      register gchar *error;
1973
1974      params->name = NULL;
1975      params->type = *(param_types++);
1976      GTK_ARG_COLLECT_VALUE (params,
1977                             var_args,
1978                             error);
1979      if (error)
1980        {
1981          failed = TRUE;
1982          g_warning ("gtk_signal_collect_params(): %s", error);
1983          g_free (error);
1984        }
1985    }
1986
1987  params->type = return_type;
1988  params->name = NULL;
1989
1990  return_type = GTK_FUNDAMENTAL_TYPE (return_type);
1991  if (return_type != GTK_TYPE_NONE)
1992    {
1993      if ((return_type >= GTK_TYPE_FLAT_FIRST &&
1994           return_type <= GTK_TYPE_FLAT_LAST) ||
1995          (return_type == GTK_TYPE_OBJECT))
1996        {
1997          GTK_VALUE_POINTER (*params) = va_arg (var_args, gpointer);
1998         
1999          if (GTK_VALUE_POINTER (*params) == NULL)
2000            {
2001              failed = TRUE;
2002              g_warning ("gtk_signal_collect_params(): invalid NULL pointer for return argument type `%s'",
2003                         gtk_type_name (params->type));
2004            }
2005        }
2006      else
2007        {
2008          failed = TRUE;
2009          g_warning ("gtk_signal_collect_params(): unsupported return argument type `%s'",
2010                     gtk_type_name (params->type));
2011        }
2012    }
2013  else
2014    GTK_VALUE_POINTER (*params) = NULL;
2015
2016  return failed;
2017}
Note: See TracBrowser for help on using the repository browser.