glib/gobject/gobjectnotifyqueue.c
changeset 18 47c74d1534e1
equal deleted inserted replaced
0:e4d67989cc36 18:47c74d1534e1
       
     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 #if (!EMULATOR)
       
    32 typedef struct _GObjectNotifyContext          GObjectNotifyContext;
       
    33 #endif
       
    34 typedef struct _GObjectNotifyQueue            GObjectNotifyQueue;
       
    35 #if (!EMULATOR)
       
    36 typedef void (*GObjectNotifyQueueDispatcher) (GObject     *object,
       
    37 					      guint        n_pspecs,
       
    38 					      GParamSpec **pspecs);
       
    39 
       
    40 
       
    41 /* --- structures --- */
       
    42 struct _GObjectNotifyContext
       
    43 {
       
    44   GQuark                       quark_notify_queue;
       
    45   GObjectNotifyQueueDispatcher dispatcher;
       
    46   GTrashStack                 *_nqueue_trash; /* unused */
       
    47 };
       
    48 #endif
       
    49 struct _GObjectNotifyQueue
       
    50 {
       
    51   GObjectNotifyContext *context;
       
    52   GSList               *pspecs;
       
    53   guint16               n_pspecs;
       
    54   guint16               freeze_count;
       
    55   /* currently, this structure abuses the GList allocation chain and thus
       
    56    * must be <= sizeof (GList)
       
    57    */
       
    58 };
       
    59 
       
    60 
       
    61 /* --- functions --- */
       
    62 static void
       
    63 g_object_notify_queue_free (gpointer data)
       
    64 {
       
    65   GObjectNotifyQueue *nqueue = data;
       
    66 
       
    67   g_slist_free (nqueue->pspecs);
       
    68   g_list_free_1 ((void*) nqueue);
       
    69 }
       
    70 
       
    71 static inline GObjectNotifyQueue*
       
    72 g_object_notify_queue_freeze (GObject		   *object,
       
    73 			      GObjectNotifyContext *context)
       
    74 {
       
    75   GObjectNotifyQueue *nqueue;
       
    76 
       
    77   nqueue = g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
       
    78   if (!nqueue)
       
    79     {
       
    80       nqueue = (void*) g_list_alloc ();
       
    81       memset (nqueue, 0, sizeof (*nqueue));
       
    82       nqueue->context = context;
       
    83       g_datalist_id_set_data_full (&object->qdata, context->quark_notify_queue,
       
    84 				   nqueue, g_object_notify_queue_free);
       
    85     }
       
    86 
       
    87   g_return_val_if_fail (nqueue->freeze_count < 65535, nqueue);
       
    88   nqueue->freeze_count++;
       
    89 
       
    90   return nqueue;
       
    91 }
       
    92 
       
    93 static inline void
       
    94 g_object_notify_queue_thaw (GObject            *object,
       
    95 			    GObjectNotifyQueue *nqueue)
       
    96 {
       
    97   GObjectNotifyContext *context = nqueue->context;
       
    98   GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL;
       
    99   GSList *slist;
       
   100   guint n_pspecs = 0;
       
   101 
       
   102   g_return_if_fail (nqueue->freeze_count > 0);
       
   103 
       
   104   nqueue->freeze_count--;
       
   105   if (nqueue->freeze_count)
       
   106     return;
       
   107   g_return_if_fail (object->ref_count > 0);
       
   108 
       
   109   pspecs = nqueue->n_pspecs > 16 ? free_me = g_new (GParamSpec*, nqueue->n_pspecs) : pspecs_mem;
       
   110   /* set first entry to NULL since it's checked unconditionally */
       
   111   pspecs[0] = NULL;
       
   112   for (slist = nqueue->pspecs; slist; slist = slist->next)
       
   113     {
       
   114       GParamSpec *pspec = slist->data;
       
   115       guint i = 0;
       
   116 
       
   117       /* dedup, make pspecs in the list unique */
       
   118     redo_dedup_check:
       
   119       if (pspecs[i] == pspec)
       
   120 	continue;
       
   121       if (++i < n_pspecs)
       
   122 	goto redo_dedup_check;
       
   123 
       
   124       pspecs[n_pspecs++] = pspec;
       
   125     }
       
   126   g_datalist_id_set_data (&object->qdata, context->quark_notify_queue, NULL);
       
   127 
       
   128   if (n_pspecs)
       
   129     context->dispatcher (object, n_pspecs, pspecs);
       
   130   g_free (free_me);
       
   131 }
       
   132 
       
   133 static inline void
       
   134 g_object_notify_queue_clear (GObject            *object,
       
   135 			     GObjectNotifyQueue *nqueue)
       
   136 {
       
   137   g_return_if_fail (nqueue->freeze_count > 0);
       
   138 
       
   139   g_slist_free (nqueue->pspecs);
       
   140   nqueue->pspecs = NULL;
       
   141   nqueue->n_pspecs = 0;
       
   142 }
       
   143 
       
   144 static inline void
       
   145 g_object_notify_queue_add (GObject            *object,
       
   146 			   GObjectNotifyQueue *nqueue,
       
   147 			   GParamSpec	      *pspec)
       
   148 {
       
   149   if (pspec->flags & G_PARAM_READABLE)
       
   150     {
       
   151       GParamSpec *redirect;
       
   152 
       
   153       g_return_if_fail (nqueue->n_pspecs < 65535);
       
   154 
       
   155       redirect = g_param_spec_get_redirect_target (pspec);
       
   156       if (redirect)
       
   157 	pspec = redirect;
       
   158 	    
       
   159       /* we do the deduping in _thaw */
       
   160       nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);
       
   161       nqueue->n_pspecs++;
       
   162     }
       
   163 }
       
   164 
       
   165 static inline GObjectNotifyQueue*
       
   166 g_object_notify_queue_from_object (GObject              *object,
       
   167 				   GObjectNotifyContext *context)
       
   168 {
       
   169   return g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
       
   170 }
       
   171 
       
   172 
       
   173 G_END_DECLS
       
   174 
       
   175 #endif /* __G_OBJECT_NOTIFY_QUEUE_H__ */