Home | History | Annotate | Download | only in gobject
      1 /* GObject - GLib Type, Object, Parameter and Signal Library
      2  * Copyright (C) 1998-1999, 2000-2001 Tim Janik and Red Hat, Inc.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General
     15  * Public 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 #ifndef __G_OBJECT_NOTIFY_QUEUE_H__
     21 #define __G_OBJECT_NOTIFY_QUEUE_H__
     22 
     23 #include <string.h> /* memset */
     24 
     25 #include <glib-object.h>
     26 
     27 G_BEGIN_DECLS
     28 
     29 
     30 /* --- typedefs --- */
     31 typedef struct _GObjectNotifyContext          GObjectNotifyContext;
     32 typedef struct _GObjectNotifyQueue            GObjectNotifyQueue;
     33 typedef void (*GObjectNotifyQueueDispatcher) (GObject     *object,
     34 					      guint        n_pspecs,
     35 					      GParamSpec **pspecs);
     36 
     37 
     38 /* --- structures --- */
     39 struct _GObjectNotifyContext
     40 {
     41   GQuark                       quark_notify_queue;
     42   GObjectNotifyQueueDispatcher dispatcher;
     43   GTrashStack                 *_nqueue_trash; /* unused */
     44 };
     45 struct _GObjectNotifyQueue
     46 {
     47   GObjectNotifyContext *context;
     48   GSList               *pspecs;
     49   guint16               n_pspecs;
     50   guint16               freeze_count;
     51   /* currently, this structure abuses the GList allocation chain and thus
     52    * must be <= sizeof (GList)
     53    */
     54 };
     55 
     56 
     57 /* --- functions --- */
     58 static void
     59 g_object_notify_queue_free (gpointer data)
     60 {
     61   GObjectNotifyQueue *nqueue = data;
     62 
     63   g_slist_free (nqueue->pspecs);
     64   g_list_free_1 ((void*) nqueue);
     65 }
     66 
     67 static inline GObjectNotifyQueue*
     68 g_object_notify_queue_freeze (GObject		   *object,
     69 			      GObjectNotifyContext *context)
     70 {
     71   GObjectNotifyQueue *nqueue;
     72 
     73   nqueue = g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
     74   if (!nqueue)
     75     {
     76       nqueue = (void*) g_list_alloc ();
     77       memset (nqueue, 0, sizeof (*nqueue));
     78       nqueue->context = context;
     79       g_datalist_id_set_data_full (&object->qdata, context->quark_notify_queue,
     80 				   nqueue, g_object_notify_queue_free);
     81     }
     82 
     83   g_return_val_if_fail (nqueue->freeze_count < 65535, nqueue);
     84   nqueue->freeze_count++;
     85 
     86   return nqueue;
     87 }
     88 
     89 static inline void
     90 g_object_notify_queue_thaw (GObject            *object,
     91 			    GObjectNotifyQueue *nqueue)
     92 {
     93   GObjectNotifyContext *context = nqueue->context;
     94   GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL;
     95   GSList *slist;
     96   guint n_pspecs = 0;
     97 
     98   g_return_if_fail (nqueue->freeze_count > 0);
     99 
    100   nqueue->freeze_count--;
    101   if (nqueue->freeze_count)
    102     return;
    103   g_return_if_fail (object->ref_count > 0);
    104 
    105   pspecs = nqueue->n_pspecs > 16 ? free_me = g_new (GParamSpec*, nqueue->n_pspecs) : pspecs_mem;
    106   /* set first entry to NULL since it's checked unconditionally */
    107   pspecs[0] = NULL;
    108   for (slist = nqueue->pspecs; slist; slist = slist->next)
    109     {
    110       GParamSpec *pspec = slist->data;
    111       guint i = 0;
    112 
    113       /* dedup, make pspecs in the list unique */
    114     redo_dedup_check:
    115       if (pspecs[i] == pspec)
    116 	continue;
    117       if (++i < n_pspecs)
    118 	goto redo_dedup_check;
    119 
    120       pspecs[n_pspecs++] = pspec;
    121     }
    122   g_datalist_id_set_data (&object->qdata, context->quark_notify_queue, NULL);
    123 
    124   if (n_pspecs)
    125     context->dispatcher (object, n_pspecs, pspecs);
    126   g_free (free_me);
    127 }
    128 
    129 static inline void
    130 g_object_notify_queue_clear (GObject            *object,
    131 			     GObjectNotifyQueue *nqueue)
    132 {
    133   g_return_if_fail (nqueue->freeze_count > 0);
    134 
    135   g_slist_free (nqueue->pspecs);
    136   nqueue->pspecs = NULL;
    137   nqueue->n_pspecs = 0;
    138 }
    139 
    140 static inline void
    141 g_object_notify_queue_add (GObject            *object,
    142 			   GObjectNotifyQueue *nqueue,
    143 			   GParamSpec	      *pspec)
    144 {
    145   if (pspec->flags & G_PARAM_READABLE)
    146     {
    147       GParamSpec *redirect;
    148 
    149       g_return_if_fail (nqueue->n_pspecs < 65535);
    150 
    151       redirect = g_param_spec_get_redirect_target (pspec);
    152       if (redirect)
    153 	pspec = redirect;
    154 
    155       /* we do the deduping in _thaw */
    156       nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);
    157       nqueue->n_pspecs++;
    158     }
    159 }
    160 
    161 static inline GObjectNotifyQueue*
    162 g_object_notify_queue_from_object (GObject              *object,
    163 				   GObjectNotifyContext *context)
    164 {
    165   return g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
    166 }
    167 
    168 
    169 G_END_DECLS
    170 
    171 #endif /* __G_OBJECT_NOTIFY_QUEUE_H__ */
    172