source: trunk/third/glib2/gobject/gobjectnotifyqueue.c @ 20721

Revision 20721, 4.6 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20720, which included commits to RCS files with non-trunk default branches.
Line 
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#ifndef __G_NOTIFY_H__
20#define __G_NOTIFY_H__
21
22#include        <string.h> /* memset */
23#include        <glib-object.h>
24
25G_BEGIN_DECLS
26
27
28/* --- typedefs --- */
29typedef struct _GObjectNotifyContext          GObjectNotifyContext;
30typedef struct _GObjectNotifyQueue            GObjectNotifyQueue;
31typedef void (*GObjectNotifyQueueDispatcher) (GObject     *object,
32                                              guint        n_pspecs,
33                                              GParamSpec **pspecs);
34
35
36/* --- structures --- */
37struct _GObjectNotifyContext
38{
39  GQuark                       quark_notify_queue;
40  GObjectNotifyQueueDispatcher dispatcher;
41  GTrashStack                 *_nqueue_trash; /* unused */
42};
43struct _GObjectNotifyQueue
44{
45  GObjectNotifyContext *context;
46  GSList               *pspecs;
47  guint16               n_pspecs;
48  guint16               freeze_count;
49  /* currently, this structure abuses the GList allocation chain and thus
50   * must be <= sizeof (GList)
51   */
52};
53
54
55/* --- functions --- */
56static void
57g_object_notify_queue_free (gpointer data)
58{
59  GObjectNotifyQueue *nqueue = data;
60
61  g_slist_free (nqueue->pspecs);
62  g_list_free_1 ((void*) nqueue);
63}
64
65static inline GObjectNotifyQueue*
66g_object_notify_queue_freeze (GObject              *object,
67                              GObjectNotifyContext *context)
68{
69  GObjectNotifyQueue *nqueue;
70
71  nqueue = g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
72  if (!nqueue)
73    {
74      nqueue = (void*) g_list_alloc ();
75      memset (nqueue, 0, sizeof (*nqueue));
76      nqueue->context = context;
77      g_datalist_id_set_data_full (&object->qdata, context->quark_notify_queue,
78                                   nqueue, g_object_notify_queue_free);
79    }
80
81  g_return_val_if_fail (nqueue->freeze_count < 65535, nqueue);
82  nqueue->freeze_count++;
83
84  return nqueue;
85}
86
87static inline void
88g_object_notify_queue_thaw (GObject            *object,
89                            GObjectNotifyQueue *nqueue)
90{
91  GObjectNotifyContext *context = nqueue->context;
92  GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL;
93  GSList *slist;
94  guint n_pspecs = 0;
95
96  g_return_if_fail (nqueue->freeze_count > 0);
97
98  nqueue->freeze_count--;
99  if (nqueue->freeze_count)
100    return;
101  g_return_if_fail (object->ref_count > 0);
102
103  pspecs = nqueue->n_pspecs > 16 ? free_me = g_new (GParamSpec*, nqueue->n_pspecs) : pspecs_mem;
104  /* set first entry to NULL since it's checked unconditionally */
105  pspecs[0] = NULL;
106  for (slist = nqueue->pspecs; slist; slist = slist->next)
107    {
108      GParamSpec *pspec = slist->data;
109      gint i = 0;
110
111      /* dedup, make pspecs in the list unique */
112    redo_dedup_check:
113      if (pspecs[i] == pspec)
114        continue;
115      if (++i < n_pspecs)
116        goto redo_dedup_check;
117
118      pspecs[n_pspecs++] = pspec;
119    }
120  g_datalist_id_set_data (&object->qdata, context->quark_notify_queue, NULL);
121
122  if (n_pspecs)
123    context->dispatcher (object, n_pspecs, pspecs);
124  g_free (free_me);
125}
126
127static inline void
128g_object_notify_queue_clear (GObject            *object,
129                             GObjectNotifyQueue *nqueue)
130{
131  g_return_if_fail (nqueue->freeze_count > 0);
132
133  g_slist_free (nqueue->pspecs);
134  nqueue->pspecs = NULL;
135  nqueue->n_pspecs = 0;
136}
137
138static inline void
139g_object_notify_queue_add (GObject            *object,
140                           GObjectNotifyQueue *nqueue,
141                           GParamSpec         *pspec)
142{
143  if (pspec->flags & G_PARAM_READABLE)
144    {
145      GParamSpec *redirect;
146
147      g_return_if_fail (nqueue->n_pspecs < 65535);
148
149      redirect = g_param_spec_get_redirect_target (pspec);
150      if (redirect)
151        pspec = redirect;
152           
153      /* we do the deduping in _thaw */
154      nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);
155      nqueue->n_pspecs++;
156    }
157}
158
159static inline GObjectNotifyQueue*
160g_object_notify_queue_from_object (GObject              *object,
161                                   GObjectNotifyContext *context)
162{
163  return g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
164}
165
166
167G_END_DECLS
168
169#endif /* __G_OBJECT_H__ */
Note: See TracBrowser for help on using the repository browser.