[glib] gapplication: add bind_busy_property()



commit 0f2b54142a455dd7f31aa9f3795b9173edd8fb1d
Author: Lars Uebernickel <lars uebernickel canonical com>
Date:   Sun Feb 15 18:54:13 2015 +0100

    gapplication: add bind_busy_property()
    
    Balancing g_application_{un,}mark_busy() is non-trivial in some cases.
    
    Make it a bit more convenient by allowing to bind multiple boolean
    properties (from different objects) to the busy state. As long as these
    properties are true, the application is marked as busy.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=744565

 docs/reference/gio/gio-sections.txt |    1 +
 gio/gapplication.c                  |  104 +++++++++++++++++++++++++++++++++++
 gio/gapplication.h                  |    5 ++
 3 files changed, 110 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 4e5e907..5c186c0 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -3136,6 +3136,7 @@ g_application_get_default
 <SUBSECTION>
 g_application_mark_busy
 g_application_unmark_busy
+g_application_bind_busy_property
 <SUBSECTION Standard>
 G_TYPE_APPLICATION
 G_APPLICATION
diff --git a/gio/gapplication.c b/gio/gapplication.c
index d09cdb0..7533ae2 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -2679,5 +2679,109 @@ g_application_withdraw_notification (GApplication *application,
     g_notification_backend_withdraw_notification (application->priv->notifications, id);
 }
 
+/* Busy binding {{{1 */
+
+typedef struct
+{
+  GApplication *app;
+  gboolean is_busy;
+} GApplicationBusyBinding;
+
+static void
+g_application_busy_binding_destroy (gpointer  data,
+                                    GClosure *closure)
+{
+  GApplicationBusyBinding *binding = data;
+
+  if (binding->is_busy)
+    g_application_unmark_busy (binding->app);
+
+  g_object_unref (binding->app);
+  g_slice_free (GApplicationBusyBinding, binding);
+}
+
+static void
+g_application_notify_busy_binding (GObject    *object,
+                                   GParamSpec *pspec,
+                                   gpointer    user_data)
+{
+  GApplicationBusyBinding *binding = user_data;
+  gboolean is_busy;
+
+  g_object_get (object, pspec->name, &is_busy, NULL);
+
+  if (is_busy && !binding->is_busy)
+    g_application_mark_busy (binding->app);
+  else if (!is_busy && binding->is_busy)
+    g_application_unmark_busy (binding->app);
+
+  binding->is_busy = is_busy;
+}
+
+/**
+ * g_application_bind_busy_property:
+ * @application: a #GApplication
+ * @object: a #GObject
+ * @property: (allow-none): the name of a boolean property of @object
+ *
+ * Marks @application as busy (see g_application_mark_busy()) while
+ * @property on @object is %TRUE.
+ *
+ * Multiple such bindings can exist, but only one property can be bound
+ * per object. Calling this function again for the same object replaces
+ * a previous binding. If @property is %NULL, the binding is destroyed.
+ *
+ * The binding holds a reference to @application while it is active, but
+ * not to @object. Instead, the binding is destroyed when @object is
+ * finalized.
+ *
+ * Since: 2.44
+ */
+void
+g_application_bind_busy_property (GApplication *application,
+                                  gpointer      object,
+                                  const gchar  *property)
+{
+  GClosure *closure = NULL;
+  guint notify_id;
+  gulong handler_id;
+
+  g_return_if_fail (G_IS_APPLICATION (application));
+  g_return_if_fail (G_IS_OBJECT (object));
+
+  notify_id = g_signal_lookup ("notify", G_TYPE_OBJECT);
+
+  if (property != NULL)
+    {
+      GParamSpec *pspec;
+      GApplicationBusyBinding *binding;
+
+      pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property);
+      g_return_if_fail (pspec != NULL && pspec->value_type == G_TYPE_BOOLEAN);
+
+      binding = g_slice_new (GApplicationBusyBinding);
+      binding->app = g_object_ref (application);
+      binding->is_busy = FALSE;
+
+      /* fetch the initial value */
+      g_application_notify_busy_binding (object, pspec, binding);
+
+      closure = g_cclosure_new (G_CALLBACK (g_application_notify_busy_binding), binding,
+                                g_application_busy_binding_destroy);
+    }
+
+  /* unset a previous binding after fetching the new initial value, so
+   * that we don't switch to FALSE for a brief moment when both the
+   * old and the new property are set to TRUE
+   */
+  handler_id = g_signal_handler_find (object, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC, notify_id,
+                                      0, NULL, g_application_notify_busy_binding, NULL);
+  if (handler_id > 0)
+    g_signal_handler_disconnect (object, handler_id);
+
+  if (closure)
+    g_signal_connect_closure_by_id (object, notify_id, g_quark_from_string (property), closure, FALSE);
+}
+
 /* Epilogue {{{1 */
 /* vim:set foldmethod=marker: */
diff --git a/gio/gapplication.h b/gio/gapplication.h
index 658c633..a5e9712 100644
--- a/gio/gapplication.h
+++ b/gio/gapplication.h
@@ -226,6 +226,11 @@ GLIB_AVAILABLE_IN_2_40
 void                    g_application_withdraw_notification             (GApplication             
*application,
                                                                          const gchar              *id);
 
+GLIB_AVAILABLE_IN_2_44
+void                    g_application_bind_busy_property                (GApplication             
*application,
+                                                                         gpointer                  object,
+                                                                         const gchar              *property);
+
 G_END_DECLS
 
 #endif /* __G_APPLICATION_H__ */


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