[glib] gmain: add g_clear_handle_id API



commit 5ebd8f6e88734c2a1c8574ff4af681a2eb9c74a5
Author: Cosimo Cecchi <cosimo endlessm com>
Date:   Sat Sep 30 21:09:37 2017 -0700

    gmain: add g_clear_handle_id API
    
    It's a very common pattern to see code that looks like this in
    dispose() or finalize() implementations:
    
    if (priv->source_id > 0)
      {
        g_source_remove (priv->source_id);
        priv->source_id = 0;
      }
    
    This API allows to accomplish the same goal with a single line:
    
    g_clear_handle_id (&priv->source_id, (GClearHandleFunc) g_source_remove);
    
    Thanks to Emmanuele Bassi <ebassi gnome org> for making the patch
    generic.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=788489

 docs/reference/glib/glib-sections.txt |    2 +
 glib/gmain.c                          |   34 +++++++++++++++++++++++++++++++++
 glib/gmain.h                          |   32 +++++++++++++++++++++++++++++++
 glib/tests/utils.c                    |   26 +++++++++++++++++++++++++
 4 files changed, 94 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 56376c0..1aaaf60 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -633,6 +633,8 @@ g_source_get_current_time
 g_source_remove
 g_source_remove_by_funcs_user_data
 g_source_remove_by_user_data
+GClearHandleFunc
+g_clear_handle_id
 
 <SUBSECTION Private>
 GLIB_HAVE_ALLOCA_H
diff --git a/glib/gmain.c b/glib/gmain.c
index 3be0afc..bd77508 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -2413,6 +2413,40 @@ g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
     return FALSE;
 }
 
+/**
+ * g_clear_handle_id: (skip)
+ * @tag_ptr: (not nullable): a pointer to the handler ID
+ * @clear_func: (not nullable): the function to call to clear the handler
+ *
+ * Clears a numeric handler, such as a #GSource ID.
+ *
+ * @tag_ptr must be a valid pointer to the variable holding the handler.
+ *
+ * If the ID is zero then this function does nothing.
+ * Otherwise, clear_func() is called with the ID as a parameter, and the tag is
+ * set to zero.
+ *
+ * A macro is also included that allows this function to be used without
+ * pointer casts.
+ *
+ * Since: 2.56
+ */
+#undef g_clear_handle_id
+void
+g_clear_handle_id (guint            *tag_ptr,
+                   GClearHandleFunc  clear_func)
+{
+  guint _handle_id;
+
+  _handle_id = *tag_ptr;
+  if (_handle_id > 0)
+    {
+      *tag_ptr = 0;
+      if (clear_func != NULL)
+        clear_func (_handle_id);
+    }
+}
+
 #ifdef G_OS_UNIX
 /**
  * g_source_add_unix_fd:
diff --git a/glib/gmain.h b/glib/gmain.h
index 4979927..efd7052 100644
--- a/glib/gmain.h
+++ b/glib/gmain.h
@@ -563,6 +563,38 @@ GLIB_AVAILABLE_IN_ALL
 gboolean g_source_remove_by_funcs_user_data  (GSourceFuncs  *funcs,
                                               gpointer       user_data);
 
+/**
+ * GClearHandleFunc:
+ * @handle_id: the handle ID to clear
+ *
+ * Specifies the type of function passed to g_clear_handle_id().
+ * The implementation is expected to free the resource identified
+ * by @handle_id; for instance, if @handle_id is a #GSource ID,
+ * g_source_remove() can be used.
+ *
+ * Since: 2.56
+ */
+typedef void (* GClearHandleFunc) (guint handle_id);
+
+GLIB_AVAILABLE_IN_2_56
+void    g_clear_handle_id (guint           *tag_ptr,
+                           GClearHandleFunc clear_func);
+
+#define g_clear_handle_id(tag_ptr, clear_func)             \
+  G_STMT_START {                                           \
+    G_STATIC_ASSERT (sizeof *(tag_ptr) == sizeof (guint)); \
+    guint *_tag_ptr = (guint *) (tag_ptr);                 \
+    guint _handle_id;                                      \
+                                                           \
+    _handle_id = *_tag_ptr;                                \
+    if (_handle_id > 0)                                    \
+      {                                                    \
+        *_tag_ptr = 0;                                     \
+        if (clear_func != NULL)                            \
+          clear_func (_handle_id);                         \
+      }                                                    \
+  } G_STMT_END
+
 /* Idles, child watchers and timeouts */
 GLIB_AVAILABLE_IN_ALL
 guint    g_timeout_add_full         (gint            priority,
diff --git a/glib/tests/utils.c b/glib/tests/utils.c
index c7a1f6e..7f8edd8 100644
--- a/glib/tests/utils.c
+++ b/glib/tests/utils.c
@@ -478,6 +478,31 @@ test_desktop_special_dir (void)
   g_assert (dir2 != NULL);
 }
 
+static gboolean
+source_test (gpointer data)
+{
+  g_assert_not_reached ();
+  return G_SOURCE_REMOVE;
+}
+
+static void
+test_clear_source (void)
+{
+  guint id;
+
+  id = g_idle_add (source_test, NULL);
+  g_assert_cmpuint (id, >, 0);
+
+  g_clear_handle_id (&id, g_source_remove);
+  g_assert_cmpuint (id, ==, 0);
+
+  id = g_timeout_add (100, source_test, NULL);
+  g_assert_cmpuint (id, >, 0);
+
+  g_clear_handle_id (&id, g_source_remove);
+  g_assert_cmpuint (id, ==, 0);
+}
+
 static void
 test_clear_pointer (void)
 {
@@ -632,6 +657,7 @@ main (int   argc,
   g_test_add_func ("/utils/specialdir/desktop", test_desktop_special_dir);
   g_test_add_func ("/utils/clear-pointer", test_clear_pointer);
   g_test_add_func ("/utils/take-pointer", test_take_pointer);
+  g_test_add_func ("/utils/clear-source", test_clear_source);
   g_test_add_func ("/utils/misc-mem", test_misc_mem);
   g_test_add_func ("/utils/nullify", test_nullify);
   g_test_add_func ("/utils/atexit", test_atexit);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]