From 2d3d8cdce2e30978c259bdbc61c2af26ee081533 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 17 Feb 2015 08:39:05 +0100 Subject: [PATCH] gapplication: tune busy-binding g_application_bind_busy_property() had the restriction that only one property can be bound per object, so that NULL could be used to unbind. Even though this is enough for most uses, it is a weird API. Lift that restriction and add an explicit unbind function. https://bugzilla.gnome.org/show_bug.cgi?id=744565 --- docs/reference/gio/gio-sections.txt | 1 + gio/gapplication.c | 89 ++++++++++++++++++++++++------------- gio/gapplication.h | 5 +++ 3 files changed, 65 insertions(+), 30 deletions(-) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 6674c4c..adc7152 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -3151,6 +3151,7 @@ g_application_get_default g_application_mark_busy g_application_unmark_busy g_application_bind_busy_property +g_application_unbind_busy_property G_TYPE_APPLICATION G_APPLICATION diff --git a/gio/gapplication.c b/gio/gapplication.c index f4a65fe..e51f0cb 100644 --- a/gio/gapplication.c +++ b/gio/gapplication.c @@ -2711,15 +2711,11 @@ g_application_notify_busy_binding (GObject *object, * g_application_bind_busy_property: * @application: a #GApplication * @object: a #GObject - * @property: (allow-none): the name of a boolean property of @object + * @property: 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. @@ -2731,45 +2727,78 @@ g_application_bind_busy_property (GApplication *application, gpointer object, const gchar *property) { - GClosure *closure = NULL; guint notify_id; - gulong handler_id; + GQuark property_quark; + GParamSpec *pspec; + GApplicationBusyBinding *binding; + GClosure *closure; g_return_if_fail (G_IS_APPLICATION (application)); g_return_if_fail (G_IS_OBJECT (object)); + g_return_if_fail (property != NULL); notify_id = g_signal_lookup ("notify", G_TYPE_OBJECT); + property_quark = g_quark_from_string (property); + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property); - if (property != NULL) + g_return_if_fail (pspec != NULL && pspec->value_type == G_TYPE_BOOLEAN); + + if (g_signal_handler_find (object, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC, + notify_id, property_quark, NULL, g_application_notify_busy_binding, NULL) > 0) { - GParamSpec *pspec; - GApplicationBusyBinding *binding; + g_critical ("%s: '%s' is already bound to the busy state of the application", G_STRFUNC, property); + return; + } - 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; - binding = g_slice_new (GApplicationBusyBinding); - binding->app = g_object_ref (application); - binding->is_busy = FALSE; + closure = g_cclosure_new (G_CALLBACK (g_application_notify_busy_binding), binding, + g_application_busy_binding_destroy); + g_signal_connect_closure_by_id (object, notify_id, property_quark, closure, FALSE); - /* fetch the initial value */ - g_application_notify_busy_binding (object, pspec, binding); + /* 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); - } +/** + * g_application_unbind_busy_property: + * @application: a #GApplication + * @object: a #GObject + * @property: the name of a boolean property of @object + * + * Destroys a binding between @property and the busy state of + * @application that was previously created with + * g_application_bind_busy_property(). + * + * Since: 2.44 + */ +void +g_application_unbind_busy_property (GApplication *application, + gpointer object, + const gchar *property) +{ + guint notify_id; + GQuark property_quark; + gulong handler_id; - /* 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); + g_return_if_fail (G_IS_APPLICATION (application)); + g_return_if_fail (G_IS_OBJECT (object)); + g_return_if_fail (property != NULL); + + notify_id = g_signal_lookup ("notify", G_TYPE_OBJECT); + property_quark = g_quark_from_string (property); + + handler_id = g_signal_handler_find (object, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC, + notify_id, property_quark, NULL, g_application_notify_busy_binding, NULL); + if (handler_id == 0) + { + g_critical ("%s: '%s' is not bound to the busy state of the application", G_STRFUNC, property); + return; + } - if (closure) - g_signal_connect_closure_by_id (object, notify_id, g_quark_from_string (property), closure, FALSE); + g_signal_handler_disconnect (object, handler_id); } /* Epilogue {{{1 */ diff --git a/gio/gapplication.h b/gio/gapplication.h index a5e9712..98ceb90 100644 --- a/gio/gapplication.h +++ b/gio/gapplication.h @@ -231,6 +231,11 @@ void g_application_bind_busy_property (GApplic gpointer object, const gchar *property); +GLIB_AVAILABLE_IN_2_44 +void g_application_unbind_busy_property (GApplication *application, + gpointer object, + const gchar *property); + G_END_DECLS #endif /* __G_APPLICATION_H__ */ -- 2.7.4