glib/libgobject/src/gclosure.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /* GObject - GLib Type, Object, Parameter and Signal Library
       
     2  * Copyright (C) 2000-2001 Red Hat, Inc.
       
     3  * Copyright (C) 2005 Imendio AB
       
     4  * Portions copyright (c) 2006 Nokia Corporation.  All rights reserved.
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Lesser General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Lesser General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Lesser General
       
    17  * Public License along with this library; if not, write to the
       
    18  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
       
    19  * Boston, MA 02111-1307, USA.
       
    20  */
       
    21 #include	"gclosure.h"
       
    22 
       
    23 /*
       
    24  * MT safe with regards to reference counting.
       
    25  */
       
    26 
       
    27 #include	"gvalue.h"
       
    28 #include 	"gobjectalias.h"
       
    29 #include	<string.h>
       
    30 
       
    31 
       
    32 #define	CLOSURE_MAX_REF_COUNT		((1 << 15) - 1)
       
    33 #define	CLOSURE_MAX_N_GUARDS		((1 << 1) - 1)
       
    34 #define	CLOSURE_MAX_N_FNOTIFIERS	((1 << 2) - 1)
       
    35 #define	CLOSURE_MAX_N_INOTIFIERS	((1 << 8) - 1)
       
    36 #define	CLOSURE_N_MFUNCS(cl)		((cl)->meta_marshal + \
       
    37                                          ((cl)->n_guards << 1L))
       
    38 /* same as G_CLOSURE_N_NOTIFIERS() (keep in sync) */
       
    39 #define	CLOSURE_N_NOTIFIERS(cl)		(CLOSURE_N_MFUNCS (cl) + \
       
    40                                          (cl)->n_fnotifiers + \
       
    41                                          (cl)->n_inotifiers)
       
    42 
       
    43 typedef union {
       
    44   GClosure closure;
       
    45   volatile gint vint;
       
    46 } ClosureInt;
       
    47 
       
    48 #define CHANGE_FIELD(_closure, _field, _OP, _value, _must_set, _SET_OLD, _SET_NEW)      \
       
    49 G_STMT_START {                                                                          \
       
    50   ClosureInt *cunion = (ClosureInt*) _closure;                 		                \
       
    51   gint new_int, old_int, success;                              		                \
       
    52   do                                                    		                \
       
    53     {                                                   		                \
       
    54       ClosureInt tmp;                                   		                \
       
    55       tmp.vint = old_int = cunion->vint;                		                \
       
    56       _SET_OLD tmp.closure._field;                                                      \
       
    57       tmp.closure._field _OP _value;                      		                \
       
    58       _SET_NEW tmp.closure._field;                                                      \
       
    59       new_int = tmp.vint;                               		                \
       
    60       success = g_atomic_int_compare_and_exchange (FIX_CASTING(int *)&cunion->vint, old_int, new_int);    \
       
    61     }                                                   		                \
       
    62   while (!success && _must_set);                                                        \
       
    63 } G_STMT_END
       
    64 
       
    65 #define SWAP(_closure, _field, _value, _oldv)   CHANGE_FIELD (_closure, _field, =, _value, TRUE, *(_oldv) =,     (void) )
       
    66 #define SET(_closure, _field, _value)           CHANGE_FIELD (_closure, _field, =, _value, TRUE,     (void),     (void) )
       
    67 #define INC(_closure, _field)                   CHANGE_FIELD (_closure, _field, +=,     1, TRUE,     (void),     (void) )
       
    68 #define INC_ASSIGN(_closure, _field, _newv)     CHANGE_FIELD (_closure, _field, +=,     1, TRUE,     (void), *(_newv) = )
       
    69 #define DEC(_closure, _field)                   CHANGE_FIELD (_closure, _field, -=,     1, TRUE,     (void),     (void) )
       
    70 #define DEC_ASSIGN(_closure, _field, _newv)     CHANGE_FIELD (_closure, _field, -=,     1, TRUE,     (void), *(_newv) = )
       
    71 
       
    72 #if 0   /* for non-thread-safe closures */
       
    73 #define SWAP(cl,f,v,o)     (void) (*(o) = cl->f, cl->f = v)
       
    74 #define SET(cl,f,v)        (void) (cl->f = v)
       
    75 #define INC(cl,f)          (void) (cl->f += 1)
       
    76 #define INC_ASSIGN(cl,f,n) (void) (cl->f += 1, *(n) = cl->f)
       
    77 #define DEC(cl,f)          (void) (cl->f -= 1)
       
    78 #define DEC_ASSIGN(cl,f,n) (void) (cl->f -= 1, *(n) = cl->f)
       
    79 #endif
       
    80 
       
    81 enum {
       
    82   FNOTIFY,
       
    83   INOTIFY,
       
    84   PRE_NOTIFY,
       
    85   POST_NOTIFY
       
    86 };
       
    87 
       
    88 
       
    89 /* --- functions --- */
       
    90 EXPORT_C GClosure*
       
    91 g_closure_new_simple (guint           sizeof_closure,
       
    92 		      gpointer        data)
       
    93 {
       
    94   GClosure *closure;
       
    95 
       
    96   g_return_val_if_fail (sizeof_closure >= sizeof (GClosure), NULL);
       
    97   closure = g_malloc0 (sizeof_closure);
       
    98   SET (closure, ref_count, 1);
       
    99   SET (closure, meta_marshal, 0);
       
   100   SET (closure, n_guards, 0);
       
   101   SET (closure, n_fnotifiers, 0);
       
   102   SET (closure, n_inotifiers, 0);
       
   103   SET (closure, in_inotify, FALSE);
       
   104   SET (closure, floating, TRUE);
       
   105   SET (closure, derivative_flag, 0);
       
   106   SET (closure, in_marshal, FALSE);
       
   107   SET (closure, is_invalid, FALSE);
       
   108   closure->marshal = NULL;
       
   109   closure->data = data;
       
   110   closure->notifiers = NULL;
       
   111   memset (G_STRUCT_MEMBER_P (closure, sizeof (*closure)), 0, sizeof_closure - sizeof (*closure));
       
   112 
       
   113   return closure;
       
   114 }
       
   115 
       
   116 static inline void
       
   117 closure_invoke_notifiers (GClosure *closure,
       
   118 			  guint     notify_type)
       
   119 {
       
   120   /* notifier layout:
       
   121    *     meta_marshal  n_guards    n_guards     n_fnotif.  n_inotifiers
       
   122    * ->[[meta_marshal][pre_guards][post_guards][fnotifiers][inotifiers]]
       
   123    *
       
   124    * CLOSURE_N_MFUNCS(cl)    = meta_marshal + n_guards + n_guards;
       
   125    * CLOSURE_N_NOTIFIERS(cl) = CLOSURE_N_MFUNCS(cl) + n_fnotifiers + n_inotifiers
       
   126    *
       
   127    * constrains/catches:
       
   128    * - closure->notifiers may be reloacted during callback
       
   129    * - closure->n_fnotifiers and closure->n_inotifiers may change during callback
       
   130    * - i.e. callbacks can be removed/added during invocation
       
   131    * - must prepare for callback removal during FNOTIFY and INOTIFY (done via ->marshal= & ->data=)
       
   132    * - must distinguish (->marshal= & ->data=) for INOTIFY vs. FNOTIFY (via ->in_inotify)
       
   133    * + closure->n_guards is const during PRE_NOTIFY & POST_NOTIFY
       
   134    * + closure->meta_marshal is const for all cases
       
   135    * + none of the callbacks can cause recursion
       
   136    * + closure->n_inotifiers is const 0 during FNOTIFY
       
   137    */
       
   138   switch (notify_type)
       
   139     {
       
   140       GClosureNotifyData *ndata;
       
   141       guint i, offs;
       
   142     case FNOTIFY:
       
   143       while (closure->n_fnotifiers)
       
   144 	{
       
   145           guint n;
       
   146 	  DEC_ASSIGN (closure, n_fnotifiers, &n);
       
   147 
       
   148 	  ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + n;
       
   149 	  closure->marshal = (GClosureMarshal) ndata->notify;
       
   150 	  closure->data = ndata->data;
       
   151 	  ndata->notify (ndata->data, closure);
       
   152 	}
       
   153       closure->marshal = NULL;
       
   154       closure->data = NULL;
       
   155       break;
       
   156     case INOTIFY:
       
   157       SET (closure, in_inotify, TRUE);
       
   158       while (closure->n_inotifiers)
       
   159 	{
       
   160           guint n;
       
   161           DEC_ASSIGN (closure, n_inotifiers, &n);
       
   162 
       
   163 	  ndata = closure->notifiers + CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + n;
       
   164 	  closure->marshal = (GClosureMarshal) ndata->notify;
       
   165 	  closure->data = ndata->data;
       
   166 	  ndata->notify (ndata->data, closure);
       
   167 	}
       
   168       closure->marshal = NULL;
       
   169       closure->data = NULL;
       
   170       SET (closure, in_inotify, FALSE);
       
   171       break;
       
   172     case PRE_NOTIFY:
       
   173       i = closure->n_guards;
       
   174       offs = closure->meta_marshal;
       
   175       while (i--)
       
   176 	{
       
   177 	  ndata = closure->notifiers + offs + i;
       
   178 	  ndata->notify (ndata->data, closure);
       
   179 	}
       
   180       break;
       
   181     case POST_NOTIFY:
       
   182       i = closure->n_guards;
       
   183       offs = closure->meta_marshal + i;
       
   184       while (i--)
       
   185 	{
       
   186 	  ndata = closure->notifiers + offs + i;
       
   187 	  ndata->notify (ndata->data, closure);
       
   188 	}
       
   189       break;
       
   190     }
       
   191 }
       
   192 
       
   193 EXPORT_C void
       
   194 g_closure_set_meta_marshal (GClosure       *closure,
       
   195 			    gpointer        marshal_data,
       
   196 			    GClosureMarshal meta_marshal)
       
   197 {
       
   198   GClosureNotifyData *notifiers;
       
   199 
       
   200   g_return_if_fail (closure != NULL);
       
   201   g_return_if_fail (meta_marshal != NULL);
       
   202   g_return_if_fail (closure->is_invalid == FALSE);
       
   203   g_return_if_fail (closure->in_marshal == FALSE);
       
   204   g_return_if_fail (closure->meta_marshal == 0);
       
   205 
       
   206   notifiers = closure->notifiers;
       
   207   closure->notifiers = g_renew (GClosureNotifyData, NULL, CLOSURE_N_NOTIFIERS (closure) + 1);
       
   208   if (notifiers)
       
   209     {
       
   210       /* usually the meta marshal will be setup right after creation, so the
       
   211        * g_memmove() should be rare-case scenario
       
   212        */
       
   213       g_memmove (closure->notifiers + 1, notifiers, CLOSURE_N_NOTIFIERS (closure) * sizeof (notifiers[0]));
       
   214       g_free (notifiers);
       
   215     }
       
   216   closure->notifiers[0].data = marshal_data;
       
   217   closure->notifiers[0].notify = (GClosureNotify) meta_marshal;
       
   218   SET (closure, meta_marshal, 1);
       
   219 }
       
   220 
       
   221 EXPORT_C void
       
   222 g_closure_add_marshal_guards (GClosure      *closure,
       
   223 			      gpointer       pre_marshal_data,
       
   224 			      GClosureNotify pre_marshal_notify,
       
   225 			      gpointer       post_marshal_data,
       
   226 			      GClosureNotify post_marshal_notify)
       
   227 {
       
   228   guint i;
       
   229 
       
   230   g_return_if_fail (closure != NULL);
       
   231   g_return_if_fail (pre_marshal_notify != NULL);
       
   232   g_return_if_fail (post_marshal_notify != NULL);
       
   233   g_return_if_fail (closure->is_invalid == FALSE);
       
   234   g_return_if_fail (closure->in_marshal == FALSE);
       
   235   g_return_if_fail (closure->n_guards < CLOSURE_MAX_N_GUARDS);
       
   236   closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 2);
       
   237   
       
   238   if (closure->n_inotifiers)
       
   239     closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   240 			closure->n_fnotifiers +
       
   241 			closure->n_inotifiers + 1)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   242 									  closure->n_fnotifiers + 0)];
       
   243   if (closure->n_inotifiers > 1)
       
   244     closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   245 			closure->n_fnotifiers +
       
   246 			closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   247 								      closure->n_fnotifiers + 1)];
       
   248   if (closure->n_fnotifiers)
       
   249     closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   250 			closure->n_fnotifiers + 1)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 0];
       
   251   if (closure->n_fnotifiers > 1)
       
   252     closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   253 			closure->n_fnotifiers)] = closure->notifiers[CLOSURE_N_MFUNCS (closure) + 1];
       
   254   if (closure->n_guards)
       
   255     closure->notifiers[(closure->meta_marshal +
       
   256 			closure->n_guards +
       
   257 			closure->n_guards + 1)] = closure->notifiers[closure->meta_marshal + closure->n_guards];
       
   258   i = closure->n_guards;
       
   259   closure->notifiers[closure->meta_marshal + i].data = pre_marshal_data;
       
   260   closure->notifiers[closure->meta_marshal + i].notify = pre_marshal_notify;
       
   261   closure->notifiers[closure->meta_marshal + i + 1].data = post_marshal_data;
       
   262   closure->notifiers[closure->meta_marshal + i + 1].notify = post_marshal_notify;
       
   263   INC (closure, n_guards);
       
   264 }
       
   265 
       
   266 EXPORT_C void
       
   267 g_closure_add_finalize_notifier (GClosure      *closure,
       
   268 				 gpointer       notify_data,
       
   269 				 GClosureNotify notify_func)
       
   270 {
       
   271   guint i;
       
   272 
       
   273   g_return_if_fail (closure != NULL);
       
   274   g_return_if_fail (notify_func != NULL);
       
   275   g_return_if_fail (closure->n_fnotifiers < CLOSURE_MAX_N_FNOTIFIERS);
       
   276   closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1);
       
   277   if (closure->n_inotifiers)
       
   278     closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   279 			closure->n_fnotifiers +
       
   280 			closure->n_inotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   281 								      closure->n_fnotifiers + 0)];
       
   282   i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers;
       
   283   closure->notifiers[i].data = notify_data;
       
   284   closure->notifiers[i].notify = notify_func;
       
   285   INC (closure, n_fnotifiers);
       
   286 }
       
   287 
       
   288 EXPORT_C void
       
   289 g_closure_add_invalidate_notifier (GClosure      *closure,
       
   290 				   gpointer       notify_data,
       
   291 				   GClosureNotify notify_func)
       
   292 {
       
   293   guint i;
       
   294 
       
   295   g_return_if_fail (closure != NULL);
       
   296   g_return_if_fail (notify_func != NULL);
       
   297   g_return_if_fail (closure->is_invalid == FALSE);
       
   298   g_return_if_fail (closure->n_inotifiers < CLOSURE_MAX_N_INOTIFIERS);
       
   299   closure->notifiers = g_renew (GClosureNotifyData, closure->notifiers, CLOSURE_N_NOTIFIERS (closure) + 1);
       
   300   i = CLOSURE_N_MFUNCS (closure) + closure->n_fnotifiers + closure->n_inotifiers;
       
   301   closure->notifiers[i].data = notify_data;
       
   302   closure->notifiers[i].notify = notify_func;
       
   303   INC (closure, n_inotifiers);
       
   304 }
       
   305 
       
   306 static inline gboolean
       
   307 closure_try_remove_inotify (GClosure       *closure,
       
   308 			    gpointer       notify_data,
       
   309 			    GClosureNotify notify_func)
       
   310 {
       
   311   GClosureNotifyData *ndata, *nlast;
       
   312 
       
   313   nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - 1;
       
   314   for (ndata = nlast + 1 - closure->n_inotifiers; ndata <= nlast; ndata++)
       
   315     if (ndata->notify == notify_func && ndata->data == notify_data)
       
   316       {
       
   317 	DEC (closure, n_inotifiers);
       
   318 	if (ndata < nlast)
       
   319 	  *ndata = *nlast;
       
   320 
       
   321 	return TRUE;
       
   322       }
       
   323   return FALSE;
       
   324 }
       
   325 
       
   326 static inline gboolean
       
   327 closure_try_remove_fnotify (GClosure       *closure,
       
   328 			    gpointer       notify_data,
       
   329 			    GClosureNotify notify_func)
       
   330 {
       
   331   GClosureNotifyData *ndata, *nlast;
       
   332 
       
   333   nlast = closure->notifiers + CLOSURE_N_NOTIFIERS (closure) - closure->n_inotifiers - 1;
       
   334   for (ndata = nlast + 1 - closure->n_fnotifiers; ndata <= nlast; ndata++)
       
   335     if (ndata->notify == notify_func && ndata->data == notify_data)
       
   336       {
       
   337 	DEC (closure, n_fnotifiers);
       
   338 	if (ndata < nlast)
       
   339 	  *ndata = *nlast;
       
   340 	if (closure->n_inotifiers)
       
   341 	  closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   342 			      closure->n_fnotifiers)] = closure->notifiers[(CLOSURE_N_MFUNCS (closure) +
       
   343 									    closure->n_fnotifiers +
       
   344 									    closure->n_inotifiers)];
       
   345 	return TRUE;
       
   346       }
       
   347   return FALSE;
       
   348 }
       
   349 
       
   350 EXPORT_C GClosure*
       
   351 g_closure_ref (GClosure *closure)
       
   352 {
       
   353   guint new_ref_count;
       
   354   g_return_val_if_fail (closure != NULL, NULL);
       
   355   g_return_val_if_fail (closure->ref_count > 0, NULL);
       
   356   g_return_val_if_fail (closure->ref_count < CLOSURE_MAX_REF_COUNT, NULL);
       
   357 
       
   358   INC_ASSIGN (closure, ref_count, &new_ref_count);
       
   359   g_return_val_if_fail (new_ref_count > 1, NULL);
       
   360 
       
   361   return closure;
       
   362 }
       
   363 
       
   364 EXPORT_C void
       
   365 g_closure_invalidate (GClosure *closure)
       
   366 {
       
   367   g_return_if_fail (closure != NULL);
       
   368 
       
   369   if (!closure->is_invalid)
       
   370     {
       
   371       gboolean was_invalid;
       
   372       g_closure_ref (closure);           /* preserve floating flag */
       
   373       SWAP (closure, is_invalid, TRUE, &was_invalid);
       
   374       /* invalidate only once */
       
   375       if (!was_invalid)
       
   376         closure_invoke_notifiers (closure, INOTIFY);
       
   377       g_closure_unref (closure);
       
   378     }
       
   379 }
       
   380 
       
   381 EXPORT_C void
       
   382 g_closure_unref (GClosure *closure)
       
   383 {
       
   384   guint new_ref_count;
       
   385 
       
   386   g_return_if_fail (closure != NULL);
       
   387   g_return_if_fail (closure->ref_count > 0);
       
   388 
       
   389   if (closure->ref_count == 1)	/* last unref, invalidate first */
       
   390     g_closure_invalidate (closure);
       
   391 
       
   392   DEC_ASSIGN (closure, ref_count, &new_ref_count);
       
   393 
       
   394   if (new_ref_count == 0)
       
   395     {
       
   396       closure_invoke_notifiers (closure, FNOTIFY);
       
   397       g_free (closure->notifiers);
       
   398       g_free (closure);
       
   399     }
       
   400 }
       
   401 
       
   402 EXPORT_C void
       
   403 g_closure_sink (GClosure *closure)
       
   404 {
       
   405   g_return_if_fail (closure != NULL);
       
   406   g_return_if_fail (closure->ref_count > 0);
       
   407 
       
   408   /* floating is basically a kludge to avoid creating closures
       
   409    * with a ref_count of 0. so the intial ref_count a closure has
       
   410    * is unowned. with invoking g_closure_sink() code may
       
   411    * indicate that it takes over that intiial ref_count.
       
   412    */
       
   413   if (closure->floating)
       
   414     {
       
   415       gboolean was_floating;
       
   416       SWAP (closure, floating, FALSE, &was_floating);
       
   417       /* unref floating flag only once */
       
   418       if (was_floating)
       
   419         g_closure_unref (closure);
       
   420     }
       
   421 }
       
   422 
       
   423 EXPORT_C void
       
   424 g_closure_remove_invalidate_notifier (GClosure      *closure,
       
   425 				      gpointer       notify_data,
       
   426 				      GClosureNotify notify_func)
       
   427 {
       
   428   g_return_if_fail (closure != NULL);
       
   429   g_return_if_fail (notify_func != NULL);
       
   430 
       
   431   if (closure->is_invalid && closure->in_inotify && /* account removal of notify_func() while its called */
       
   432       ((gpointer) closure->marshal) == ((gpointer) notify_func) &&
       
   433       closure->data == notify_data)
       
   434     closure->marshal = NULL;
       
   435   else if (!closure_try_remove_inotify (closure, notify_data, notify_func))
       
   436     g_warning (G_STRLOC ": unable to remove uninstalled invalidation notifier: %p (%p)",
       
   437 	       notify_func, notify_data);
       
   438 }
       
   439 
       
   440 EXPORT_C void
       
   441 g_closure_remove_finalize_notifier (GClosure      *closure,
       
   442 				    gpointer       notify_data,
       
   443 				    GClosureNotify notify_func)
       
   444 {
       
   445   g_return_if_fail (closure != NULL);
       
   446   g_return_if_fail (notify_func != NULL);
       
   447 
       
   448   if (closure->is_invalid && !closure->in_inotify && /* account removal of notify_func() while its called */
       
   449       ((gpointer) closure->marshal) == ((gpointer) notify_func) &&
       
   450       closure->data == notify_data)
       
   451     closure->marshal = NULL;
       
   452   else if (!closure_try_remove_fnotify (closure, notify_data, notify_func))
       
   453     g_warning (G_STRLOC ": unable to remove uninstalled finalization notifier: %p (%p)",
       
   454                notify_func, notify_data);
       
   455 }
       
   456 
       
   457 EXPORT_C void
       
   458 g_closure_invoke (GClosure       *closure,
       
   459 		  GValue /*out*/ *return_value,
       
   460 		  guint           n_param_values,
       
   461 		  const GValue   *param_values,
       
   462 		  gpointer        invocation_hint)
       
   463 {
       
   464   g_return_if_fail (closure != NULL);
       
   465 
       
   466   g_closure_ref (closure);      /* preserve floating flag */
       
   467   if (!closure->is_invalid)
       
   468     {
       
   469       GClosureMarshal marshal;
       
   470       gpointer marshal_data;
       
   471       gboolean in_marshal = closure->in_marshal;
       
   472 
       
   473       g_return_if_fail (closure->marshal || closure->meta_marshal);
       
   474 
       
   475       SET (closure, in_marshal, TRUE);
       
   476       if (closure->meta_marshal)
       
   477 	{
       
   478 	  marshal_data = closure->notifiers[0].data;
       
   479 	  marshal = (GClosureMarshal) closure->notifiers[0].notify;
       
   480 	}
       
   481       else
       
   482 	{
       
   483 	  marshal_data = NULL;
       
   484 	  marshal = closure->marshal;
       
   485 	}
       
   486       if (!in_marshal)
       
   487 	closure_invoke_notifiers (closure, PRE_NOTIFY);
       
   488       marshal (closure,
       
   489 	       return_value,
       
   490 	       n_param_values, param_values,
       
   491 	       invocation_hint,
       
   492 	       marshal_data);
       
   493       if (!in_marshal)
       
   494 	closure_invoke_notifiers (closure, POST_NOTIFY);
       
   495       SET (closure, in_marshal, in_marshal);
       
   496     }
       
   497   g_closure_unref (closure);
       
   498 }
       
   499 
       
   500 EXPORT_C void
       
   501 g_closure_set_marshal (GClosure       *closure,
       
   502 		       GClosureMarshal marshal)
       
   503 {
       
   504   g_return_if_fail (closure != NULL);
       
   505   g_return_if_fail (marshal != NULL);
       
   506 
       
   507   if (closure->marshal && closure->marshal != marshal)
       
   508     g_warning ("attempt to override closure->marshal (%p) with new marshal (%p)",
       
   509 	       closure->marshal, marshal);
       
   510   else
       
   511     closure->marshal = marshal;
       
   512 }
       
   513 
       
   514 EXPORT_C GClosure*
       
   515 g_cclosure_new (GCallback      callback_func,
       
   516 		gpointer       user_data,
       
   517 		GClosureNotify destroy_data)
       
   518 {
       
   519   GClosure *closure;
       
   520   
       
   521   g_return_val_if_fail (callback_func != NULL, NULL);
       
   522   
       
   523   closure = g_closure_new_simple (sizeof (GCClosure), user_data);
       
   524   if (destroy_data)
       
   525     g_closure_add_finalize_notifier (closure, user_data, destroy_data);
       
   526   ((GCClosure*) closure)->callback = (gpointer) callback_func;
       
   527   
       
   528   return closure;
       
   529 }
       
   530 
       
   531 EXPORT_C GClosure*
       
   532 g_cclosure_new_swap (GCallback      callback_func,
       
   533 		     gpointer       user_data,
       
   534 		     GClosureNotify destroy_data)
       
   535 {
       
   536   GClosure *closure;
       
   537   
       
   538   g_return_val_if_fail (callback_func != NULL, NULL);
       
   539   
       
   540   closure = g_closure_new_simple (sizeof (GCClosure), user_data);
       
   541   if (destroy_data)
       
   542     g_closure_add_finalize_notifier (closure, user_data, destroy_data);
       
   543   ((GCClosure*) closure)->callback = (gpointer) callback_func;
       
   544   SET (closure, derivative_flag, TRUE);
       
   545   
       
   546   return closure;
       
   547 }
       
   548 
       
   549 static void
       
   550 g_type_class_meta_marshal (GClosure       *closure,
       
   551 			   GValue /*out*/ *return_value,
       
   552 			   guint           n_param_values,
       
   553 			   const GValue   *param_values,
       
   554 			   gpointer        invocation_hint,
       
   555 			   gpointer        marshal_data)
       
   556 {
       
   557   GTypeClass *class;
       
   558   gpointer callback;
       
   559   /* GType itype = (GType) closure->data; */
       
   560   guint offset = GPOINTER_TO_UINT (marshal_data);
       
   561   
       
   562   class = G_TYPE_INSTANCE_GET_CLASS (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
       
   563   callback = G_STRUCT_MEMBER (gpointer, class, offset);
       
   564   if (callback)
       
   565     closure->marshal (closure,
       
   566 		      return_value,
       
   567 		      n_param_values, param_values,
       
   568 		      invocation_hint,
       
   569 		      callback);
       
   570 }
       
   571 
       
   572 static void
       
   573 g_type_iface_meta_marshal (GClosure       *closure,
       
   574 			   GValue /*out*/ *return_value,
       
   575 			   guint           n_param_values,
       
   576 			   const GValue   *param_values,
       
   577 			   gpointer        invocation_hint,
       
   578 			   gpointer        marshal_data)
       
   579 {
       
   580   GTypeClass *class;
       
   581   gpointer callback;
       
   582   GType itype = (GType) closure->data;
       
   583   guint offset = GPOINTER_TO_UINT (marshal_data);
       
   584   
       
   585   class = G_TYPE_INSTANCE_GET_INTERFACE (g_value_peek_pointer (param_values + 0), itype, GTypeClass);
       
   586   callback = G_STRUCT_MEMBER (gpointer, class, offset);
       
   587   if (callback)
       
   588     closure->marshal (closure,
       
   589 		      return_value,
       
   590 		      n_param_values, param_values,
       
   591 		      invocation_hint,
       
   592 		      callback);
       
   593 }
       
   594 
       
   595 EXPORT_C GClosure*
       
   596 g_signal_type_cclosure_new (GType    itype,
       
   597 			    guint    struct_offset)
       
   598 {
       
   599   GClosure *closure;
       
   600   
       
   601   g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL);
       
   602   g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL);
       
   603   
       
   604   closure = g_closure_new_simple (sizeof (GClosure), (gpointer) itype);
       
   605   if (G_TYPE_IS_INTERFACE (itype))
       
   606     g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal);
       
   607   else
       
   608     g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
       
   609   
       
   610   return closure;
       
   611 }
       
   612 
       
   613 #define __G_CLOSURE_C__
       
   614 #include "gobjectaliasdef.c"