File indexing completed on 2025-12-16 10:17:39
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
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
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
0045 struct _GObjectNotifyContext
0046 {
0047 GQuark quark_notify_queue;
0048 GObjectNotifyQueueDispatcher dispatcher;
0049 GTrashStack *_nqueue_trash;
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
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
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
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
0186
0187
0188
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