Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:17:39

0001 /* GObject - GLib Type, Object, Parameter and Signal Library
0002  * Copyright (C) 1998-1999, 2000-2001 Tim Janik and Red Hat, Inc.
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General
0017  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 /* WARNING:
0021  *
0022  *    This file is INSTALLED and other projects (outside of glib)
0023  *    #include its contents.
0024  */
0025 
0026 #ifndef __G_OBJECT_NOTIFY_QUEUE_H__
0027 #define __G_OBJECT_NOTIFY_QUEUE_H__
0028 
0029 #include <string.h> /* memset */
0030 
0031 #include <glib-object.h>
0032 
0033 G_BEGIN_DECLS
0034 
0035 
0036 /* --- typedefs --- */
0037 typedef struct _GObjectNotifyContext          GObjectNotifyContext;
0038 typedef struct _GObjectNotifyQueue            GObjectNotifyQueue;
0039 typedef void (*GObjectNotifyQueueDispatcher) (GObject     *object,
0040                           guint        n_pspecs,
0041                           GParamSpec **pspecs);
0042 
0043 
0044 /* --- structures --- */
0045 struct _GObjectNotifyContext
0046 {
0047   GQuark                       quark_notify_queue;
0048   GObjectNotifyQueueDispatcher dispatcher;
0049   GTrashStack                 *_nqueue_trash; /* unused */
0050 };
0051 struct _GObjectNotifyQueue
0052 {
0053   GObjectNotifyContext *context;
0054   GSList               *pspecs;
0055   guint16               n_pspecs;
0056   guint16               freeze_count;
0057 };
0058 
0059 G_LOCK_DEFINE_STATIC(notify_lock);
0060 
0061 /* --- functions --- */
0062 static void
0063 g_object_notify_queue_free (gpointer data)
0064 {
0065   GObjectNotifyQueue *nqueue = data;
0066 
0067   g_slist_free (nqueue->pspecs);
0068   g_slice_free (GObjectNotifyQueue, nqueue);
0069 }
0070 
0071 static inline GObjectNotifyQueue*
0072 g_object_notify_queue_freeze (GObject          *object,
0073                   GObjectNotifyContext *context)
0074 {
0075   GObjectNotifyQueue *nqueue;
0076 
0077   G_LOCK(notify_lock);
0078   nqueue = g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
0079   if (!nqueue)
0080     {
0081       nqueue = g_slice_new0 (GObjectNotifyQueue);
0082       nqueue->context = context;
0083       g_datalist_id_set_data_full (&object->qdata, context->quark_notify_queue,
0084                    nqueue, g_object_notify_queue_free);
0085     }
0086 
0087   if (nqueue->freeze_count >= 65535)
0088     g_critical("Free queue for %s (%p) is larger than 65535,"
0089                " called g_object_freeze_notify() too often."
0090                " Forgot to call g_object_thaw_notify() or infinite loop",
0091                G_OBJECT_TYPE_NAME (object), object);
0092   else
0093     nqueue->freeze_count++;
0094   G_UNLOCK(notify_lock);
0095 
0096   return nqueue;
0097 }
0098 
0099 static inline void
0100 g_object_notify_queue_thaw (GObject            *object,
0101                 GObjectNotifyQueue *nqueue)
0102 {
0103   GObjectNotifyContext *context = nqueue->context;
0104   GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL;
0105   GSList *slist;
0106   guint n_pspecs = 0;
0107 
0108   g_return_if_fail (nqueue->freeze_count > 0);
0109   g_return_if_fail (g_atomic_int_get(&object->ref_count) > 0);
0110 
0111   G_LOCK(notify_lock);
0112 
0113   /* Just make sure we never get into some nasty race condition */
0114   if (G_UNLIKELY(nqueue->freeze_count == 0)) {
0115     G_UNLOCK(notify_lock);
0116     g_critical ("%s: property-changed notification for %s(%p) is not frozen",
0117             G_STRFUNC, G_OBJECT_TYPE_NAME (object), object);
0118     return;
0119   }
0120 
0121   nqueue->freeze_count--;
0122   if (nqueue->freeze_count) {
0123     G_UNLOCK(notify_lock);
0124     return;
0125   }
0126 
0127   pspecs = nqueue->n_pspecs > 16 ? free_me = g_new (GParamSpec*, nqueue->n_pspecs) : pspecs_mem;
0128 
0129   for (slist = nqueue->pspecs; slist; slist = slist->next)
0130     {
0131       pspecs[n_pspecs++] = slist->data;
0132     }
0133   g_datalist_id_set_data (&object->qdata, context->quark_notify_queue, NULL);
0134 
0135   G_UNLOCK(notify_lock);
0136 
0137   if (n_pspecs)
0138     context->dispatcher (object, n_pspecs, pspecs);
0139   g_free (free_me);
0140 }
0141 
0142 static inline void
0143 g_object_notify_queue_clear (GObject            *object G_GNUC_UNUSED,
0144                  GObjectNotifyQueue *nqueue)
0145 {
0146   g_return_if_fail (nqueue->freeze_count > 0);
0147 
0148   G_LOCK(notify_lock);
0149 
0150   g_slist_free (nqueue->pspecs);
0151   nqueue->pspecs = NULL;
0152   nqueue->n_pspecs = 0;
0153 
0154   G_UNLOCK(notify_lock);
0155 }
0156 
0157 static inline void
0158 g_object_notify_queue_add (GObject            *object G_GNUC_UNUSED,
0159                GObjectNotifyQueue *nqueue,
0160                GParamSpec         *pspec)
0161 {
0162   if (pspec->flags & G_PARAM_READABLE)
0163     {
0164       GParamSpec *redirect;
0165 
0166       G_LOCK(notify_lock);
0167 
0168       g_return_if_fail (nqueue->n_pspecs < 65535);
0169 
0170       redirect = g_param_spec_get_redirect_target (pspec);
0171       if (redirect)
0172     pspec = redirect;
0173         
0174       /* we do the deduping in _thaw */
0175       if (g_slist_find (nqueue->pspecs, pspec) == NULL)
0176         {
0177           nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);
0178           nqueue->n_pspecs++;
0179         }
0180 
0181       G_UNLOCK(notify_lock);
0182     }
0183 }
0184 
0185 /* NB: This function is not threadsafe, do not ever use it if
0186  * you need a threadsafe notify queue.
0187  * Use g_object_notify_queue_freeze() to acquire the queue and
0188  * g_object_notify_queue_thaw() after you are done instead.
0189  */
0190 static inline GObjectNotifyQueue*
0191 g_object_notify_queue_from_object (GObject              *object,
0192                                    GObjectNotifyContext *context)
0193 {
0194   return g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
0195 }
0196 
0197 G_END_DECLS
0198 
0199 #endif /* __G_OBJECT_NOTIFY_QUEUE_H__ */