您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

gobjectnotifyqueue.c 5.3 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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_OBJECT_NOTIFY_QUEUE_H__
  20. #define __G_OBJECT_NOTIFY_QUEUE_H__
  21. #include <string.h> /* memset */
  22. #include <glib-object.h>
  23. G_BEGIN_DECLS
  24. /* --- typedefs --- */
  25. typedef struct _GObjectNotifyContext GObjectNotifyContext;
  26. typedef struct _GObjectNotifyQueue GObjectNotifyQueue;
  27. typedef void (*GObjectNotifyQueueDispatcher) (GObject *object,
  28. guint n_pspecs,
  29. GParamSpec **pspecs);
  30. /* --- structures --- */
  31. struct _GObjectNotifyContext
  32. {
  33. GQuark quark_notify_queue;
  34. GObjectNotifyQueueDispatcher dispatcher;
  35. GTrashStack *_nqueue_trash; /* unused */
  36. };
  37. struct _GObjectNotifyQueue
  38. {
  39. GObjectNotifyContext *context;
  40. GSList *pspecs;
  41. guint16 n_pspecs;
  42. guint16 freeze_count;
  43. };
  44. G_LOCK_DEFINE_STATIC(notify_lock);
  45. /* --- functions --- */
  46. static void
  47. g_object_notify_queue_free (gpointer data)
  48. {
  49. GObjectNotifyQueue *nqueue = data;
  50. g_slist_free (nqueue->pspecs);
  51. g_slice_free (GObjectNotifyQueue, nqueue);
  52. }
  53. static inline GObjectNotifyQueue*
  54. g_object_notify_queue_freeze (GObject *object,
  55. GObjectNotifyContext *context)
  56. {
  57. GObjectNotifyQueue *nqueue;
  58. G_LOCK(notify_lock);
  59. nqueue = g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
  60. if (!nqueue)
  61. {
  62. nqueue = g_slice_new0 (GObjectNotifyQueue);
  63. nqueue->context = context;
  64. g_datalist_id_set_data_full (&object->qdata, context->quark_notify_queue,
  65. nqueue, g_object_notify_queue_free);
  66. }
  67. if (nqueue->freeze_count >= 65535)
  68. g_critical("Free queue for %s (%p) is larger than 65535,"
  69. " called g_object_freeze_notify() too often."
  70. " Forgot to call g_object_thaw_notify() or infinite loop",
  71. G_OBJECT_TYPE_NAME (object), object);
  72. else
  73. nqueue->freeze_count++;
  74. G_UNLOCK(notify_lock);
  75. return nqueue;
  76. }
  77. static inline void
  78. g_object_notify_queue_thaw (GObject *object,
  79. GObjectNotifyQueue *nqueue)
  80. {
  81. GObjectNotifyContext *context = nqueue->context;
  82. GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL;
  83. GSList *slist;
  84. guint n_pspecs = 0;
  85. g_return_if_fail (nqueue->freeze_count > 0);
  86. g_return_if_fail (g_atomic_int_get(&object->ref_count) > 0);
  87. G_LOCK(notify_lock);
  88. /* Just make sure we never get into some nasty race condition */
  89. if (G_UNLIKELY(nqueue->freeze_count == 0)) {
  90. G_UNLOCK(notify_lock);
  91. g_warning ("%s: property-changed notification for %s(%p) is not frozen",
  92. G_STRFUNC, G_OBJECT_TYPE_NAME (object), object);
  93. return;
  94. }
  95. nqueue->freeze_count--;
  96. if (nqueue->freeze_count) {
  97. G_UNLOCK(notify_lock);
  98. return;
  99. }
  100. pspecs = nqueue->n_pspecs > 16 ? free_me = g_new (GParamSpec*, nqueue->n_pspecs) : pspecs_mem;
  101. for (slist = nqueue->pspecs; slist; slist = slist->next)
  102. {
  103. pspecs[n_pspecs++] = slist->data;
  104. }
  105. g_datalist_id_set_data (&object->qdata, context->quark_notify_queue, NULL);
  106. G_UNLOCK(notify_lock);
  107. if (n_pspecs)
  108. context->dispatcher (object, n_pspecs, pspecs);
  109. g_free (free_me);
  110. }
  111. static inline void
  112. g_object_notify_queue_clear (GObject *object,
  113. GObjectNotifyQueue *nqueue)
  114. {
  115. g_return_if_fail (nqueue->freeze_count > 0);
  116. G_LOCK(notify_lock);
  117. g_slist_free (nqueue->pspecs);
  118. nqueue->pspecs = NULL;
  119. nqueue->n_pspecs = 0;
  120. G_UNLOCK(notify_lock);
  121. }
  122. static inline void
  123. g_object_notify_queue_add (GObject *object,
  124. GObjectNotifyQueue *nqueue,
  125. GParamSpec *pspec)
  126. {
  127. if (pspec->flags & G_PARAM_READABLE)
  128. {
  129. GParamSpec *redirect;
  130. G_LOCK(notify_lock);
  131. g_return_if_fail (nqueue->n_pspecs < 65535);
  132. redirect = g_param_spec_get_redirect_target (pspec);
  133. if (redirect)
  134. pspec = redirect;
  135. /* we do the deduping in _thaw */
  136. if (g_slist_find (nqueue->pspecs, pspec) == NULL)
  137. {
  138. nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);
  139. nqueue->n_pspecs++;
  140. }
  141. G_UNLOCK(notify_lock);
  142. }
  143. }
  144. /* NB: This function is not threadsafe, do not ever use it if
  145. * you need a threadsafe notify queue.
  146. * Use g_object_notify_queue_freeze() to acquire the queue and
  147. * g_object_notify_queue_thaw() after you are done instead.
  148. */
  149. static inline GObjectNotifyQueue*
  150. g_object_notify_queue_from_object (GObject *object,
  151. GObjectNotifyContext *context)
  152. {
  153. return g_datalist_id_get_data (&object->qdata, context->quark_notify_queue);
  154. }
  155. G_END_DECLS
  156. #endif /* __G_OBJECT_NOTIFY_QUEUE_H__ */