]> Pileus Git - ~andy/gtk/commitdiff
Add functions to allow threadsafe handling of idles and timeouts wrt. to
authorMatthias Clasen <mclasen@redhat.com>
Fri, 22 Dec 2006 17:46:32 +0000 (17:46 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Fri, 22 Dec 2006 17:46:32 +0000 (17:46 +0000)
2006-12-22  Matthias Clasen  <mclasen@redhat.com>

        * gdk/gdk.symbols:
        * gdk/gdk.h:
        * gdk/gdk.c: Add functions to allow threadsafe handling
        of idles and timeouts wrt. to the GDK lock.  (#321886,
        Chris Wilson)

ChangeLog
docs/reference/ChangeLog
docs/reference/gdk/gdk-docs.sgml
docs/reference/gdk/gdk-sections.txt
gdk/gdk.c
gdk/gdk.h
gdk/gdk.symbols

index 02ff9dcb4521b65b41638554b8b2b3ba3b3bc8aa..f7afb996fff4d3ddc15ab4a1abec18fc25065217 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2006-12-22  Matthias Clasen  <mclasen@redhat.com>
+
+       * gdk/gdk.symbols:
+       * gdk/gdk.h:
+       * gdk/gdk.c: Add functions to allow threadsafe handling
+       of idles and timeouts wrt. to the GDK lock.  (#321886,
+       Chris Wilson)
+       
 2006-12-22  Matthias Clasen  <mclasen@redhat.com>
        
        * gdk/gdkpango.c: Use pango_cairo_show_error_underline.  
index 0d59523d793aa5a97351758d2a721fd293e6ebbc..9b4e8b732c75c59efb7c07f4ef6c0fd47f12bb77 100644 (file)
@@ -1,3 +1,8 @@
+2006-12-22  Matthias Clasen  <mclasen@redhat.com>
+
+       * gdk/gdk-sections.txt: Add new functions.
+       * gdk/gdk-docs.sgml: Add a "Since 2.12" index.
+
 Thu Dec 14 15:48:14 2006  Tim Janik  <timj@imendio.com>
 
        * gtk/gtk-sections.txt: added new docs.
index 6d83d0c6f07ff7bd9bb76df1bff717d32f2ba35a..806ec85cee5dec79c7d1dd87f5544e7d6f749942 100644 (file)
   <index role="2.10">
     <title>Index of new symbols in 2.10</title>
   </index>  
+  <index role="2.12">
+    <title>Index of new symbols in 2.12</title>
+  </index>  
 
 </book>
index dc89f088b6df0fbe35783e581f98a7f358731423..ffc2d98d97e386753c62f4daffe20846b8d4d82f 100644 (file)
@@ -953,6 +953,10 @@ gdk_threads_enter
 gdk_threads_leave
 gdk_threads_mutex
 gdk_threads_set_lock_functions
+gdk_threads_add_idle
+gdk_threads_add_idle_full
+gdk_threads_add_timeout
+gdk_threads_add_timeout_full
 
 <SUBSECTION Private>
 gdk_threads_lock
index 64be2ff90398e62f42c09f384378890f034a6466..11cea846027177bf7179912dff9f9daef7f4534a 100644 (file)
--- a/gdk/gdk.c
+++ b/gdk/gdk.c
@@ -46,6 +46,16 @@ struct _GdkPredicate
   gpointer data;
 };
 
+typedef struct _GdkThreadsDispatch GdkThreadsDispatch;
+
+struct _GdkThreadsDispatch
+{
+  GSourceFunc func;
+  gpointer data;
+  GDestroyNotify destroy;
+};
+
+
 /* Private variable declarations
  */
 static int gdk_initialized = 0;                            /* 1 if the library is initialized,
@@ -448,6 +458,231 @@ gdk_threads_set_lock_functions (GCallback enter_fn,
   gdk_threads_unlock = leave_fn;
 }
 
+static gboolean
+gdk_threads_dispatch (gpointer data)
+{
+  GdkThreadsDispatch *dispatch = data;
+  gboolean ret = FALSE;
+
+  GDK_THREADS_ENTER ();
+
+  if (!g_source_is_destroyed (g_main_current_source ()))
+    ret = dispatch->func (dispatch->data);
+
+  GDK_THREADS_LEAVE ();
+
+  return ret;
+}
+
+static void
+gdk_threads_dispatch_free (gpointer data)
+{
+  GdkThreadsDispatch *dispatch = data;
+
+  if (dispatch->destroy && dispatch->data)
+    dispatch->destroy (dispatch->data);
+
+  g_slice_free (GdkThreadsDispatch, data);
+}
+
+
+/**
+ * gdk_threads_add_idle_full:
+ * @priority: the priority of the idle source. Typically this will be in the
+ *            range btweeen #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE
+ * @function: function to call
+ * @data:     data to pass to @function
+ * @notify:   function to call when the idle is removed, or %NULL
+ *
+ * Adds a function to be called whenever there are no higher priority
+ * events pending.  If the function returns %FALSE it is automatically
+ * removed from the list of event sources and will not be called again.
+ *
+ * This variant of g_idle_add_full() calls @function with the GDK lock
+ * held. It can be thought of a MT-safe version for GTK+ widgets for the 
+ * following use case, where you have to worry about idle_callback()
+ * running in thread A and accessing @self after it has been finalized
+ * in thread B:
+ *
+ * <informalexample><programlisting>
+ * static gboolean idle_callback (gpointer data)
+ * {
+ *    SomeWidget *self = data;
+ * 
+ *    /<!-- -->* do stuff with self *<!-- -->/
+ * 
+ *    self->idle_id = 0;
+ * 
+ *    return FALSE;
+ * }
+ * 
+ * static void some_widget_do_stuff_later (SomeWidget *self)
+ * {
+ *    self->idle_id = g_idle_add (idle_callback, self)
+ * }
+ * 
+ * static void some_widget_finalize (GObject *object)
+ * {
+ *    SomeWidget *self = SOME_WIDGET(object);
+ * 
+ *    if (self->idle_id)
+ *      g_source_remove (self->idle_id);
+ * 
+ *    G_OBJECT_CLASS (parent_class)->finalize (object);
+ * }
+ * </programlisting></informalexample>
+ * 
+ * Return value: the ID (greater than 0) of the event source.
+ *
+ * Since: 2.12
+ */
+guint
+gdk_threads_add_idle_full (gint           priority,
+                          GSourceFunc    function,
+                          gpointer       data,
+                          GDestroyNotify notify)
+{
+  GdkThreadsDispatch *dispatch;
+
+  g_return_val_if_fail (function != NULL, 0);
+
+  dispatch = g_slice_new (GdkThreadsDispatch);
+  dispatch->func = function;
+  dispatch->data = data;
+  dispatch->destroy = notify;
+
+  return g_idle_add_full (priority,
+                          gdk_threads_dispatch, 
+                          dispatch, 
+                          gdk_threads_dispatch_free);
+}
+
+/**
+ * gdk_threads_add_idle:
+ * @function: function to call
+ * @data:     data to pass to @function
+ *
+ * A wrapper for the common usage of gdk_threads_add_idle_full() 
+ * assigning the default priority, #G_PRIORITY_DEFAULT_IDLE.
+ *
+ * See gdk_threads_add_idle_full().
+ * 
+ * Since: 2.12
+ */
+guint
+gdk_threads_add_idle (GSourceFunc    function,
+                     gpointer       data)
+{
+  return gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
+                                    function, data, NULL);
+}
+
+
+/**
+ * gdk_threads_add_timeout_full:
+ * @priority: the priority of the timeout source. Typically this will be in the
+ *            range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE.
+ * @interval: the time between calls to the function, in milliseconds
+ *             (1/1000ths of a second)
+ * @function: function to call
+ * @data:     data to pass to @function
+ * @notify:   function to call when the timeout is removed, or %NULL
+ *
+ * Sets a function to be called at regular intervals holding the GDK lock,
+ * with the given priority.  The function is called repeatedly until it 
+ * returns %FALSE, at which point the timeout is automatically destroyed 
+ * and the function will not be called again.  The @notify function is
+ * called when the timeout is destroyed.  The first call to the
+ * function will be at the end of the first @interval.
+ *
+ * Note that timeout functions may be delayed, due to the processing of other
+ * event sources. Thus they should not be relied on for precise timing.
+ * After each call to the timeout function, the time of the next
+ * timeout is recalculated based on the current time and the given interval
+ * (it does not try to 'catch up' time lost in delays).
+ *
+ * This variant of g_timeout_add_full() can be thought of a MT-safe version 
+ * for GTK+ widgets for the following use case:
+ *
+ * <example>
+ * static gboolean timeout_callback (gpointer data)
+ * {
+ *    SomeWidget *self = data;
+ * 
+ *    /<!-- -->* do stuff with self *<!-- -->/
+ * 
+ *    self->timeout_id = 0;
+ * 
+ *    return FALSE;
+ * }
+ * 
+ * static void some_widget_do_stuff_later (SomeWidget *self)
+ * {
+ *    self->timeout_id = g_timeout_add (timeout_callback, self)
+ * }
+ * 
+ * static void some_widget_finalize (GObject *object)
+ * {
+ *    SomeWidget *self = SOME_WIDGET(object);
+ * 
+ *    if (self->timeout_id)
+ *      g_source_remove (self->timeout_id);
+ * 
+ *    G_OBJECT_CLASS (parent_class)->finalize (object);
+ * }
+ * </example>
+ *
+ * Return value: the ID (greater than 0) of the event source.
+ * 
+ * Since: 2.12
+ */
+guint
+gdk_threads_add_timeout_full (gint           priority,
+                              guint          interval,
+                              GSourceFunc    function,
+                              gpointer       data,
+                              GDestroyNotify notify)
+{
+  GdkThreadsDispatch *dispatch;
+
+  g_return_val_if_fail (function != NULL, 0);
+
+  dispatch = g_slice_new (GdkThreadsDispatch);
+  dispatch->func = function;
+  dispatch->data = data;
+  dispatch->destroy = notify;
+
+  return g_timeout_add_full (priority, 
+                             interval,
+                             gdk_threads_dispatch, 
+                             dispatch, 
+                             gdk_threads_dispatch_free);
+}
+
+/**
+ * gdk_threads_add_timeout:
+ * @interval: the time between calls to the function, in milliseconds
+ *             (1/1000ths of a second)
+ * @function: function to call
+ * @data:     data to pass to @function
+ *
+ * A wrapper for the common usage of gdk_threads_add_timeout_full() 
+ * assigning the default priority, #G_PRIORITY_DEFAULT.
+ *
+ * See gdk_threads_add_timeout_full().
+ *
+ * Since: 2.12
+ */
+guint
+gdk_threads_add_timeout (guint       interval,
+                         GSourceFunc function,
+                         gpointer    data)
+{
+  return gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT,
+                                       interval, function, data, NULL);
+}
+
+
 G_CONST_RETURN char *
 gdk_get_program_class (void)
 {
index 7bec453a98210859e725d0adbd051324fea00269..861198d474470d4449ecb460e971284ba7828b3d 100644 (file)
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -193,6 +193,22 @@ void     gdk_threads_init                 (void);
 void     gdk_threads_set_lock_functions   (GCallback enter_fn,
                                           GCallback leave_fn);
 
+guint    gdk_threads_add_idle_full        (gint           priority,
+                                          GSourceFunc    function,
+                                          gpointer       data,
+                                          GDestroyNotify notify);
+guint    gdk_threads_add_idle             (GSourceFunc    function,
+                                          gpointer       data);
+guint    gdk_threads_add_timeout_full     (gint           priority,
+                                           guint          interval,
+                                           GSourceFunc    function,
+                                           gpointer       data,
+                                           GDestroyNotify notify);
+guint    gdk_threads_add_timeout          (guint          interval,
+                                           GSourceFunc    function,
+                                           gpointer       data);
+
+
 #ifdef G_THREADS_ENABLED
 #  define GDK_THREADS_ENTER()  G_STMT_START {  \
       if (gdk_threads_lock)                    \
index 34047da837127e3063984cb80d673072d5378aeb..94d977b6c92399ee5c9a3b63d90254425bbd1b46 100644 (file)
@@ -133,6 +133,10 @@ gdk_threads_enter
 gdk_threads_init
 gdk_threads_leave
 gdk_threads_set_lock_functions
+gdk_threads_add_idle
+gdk_threads_add_idle_full
+gdk_threads_add_timeout
+gdk_threads_add_timeout_full
 #endif
 #endif