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
This commit is contained in:
Lars Uebernickel 2015-02-15 18:54:13 +01:00
parent c59d195dd2
commit 0f2b54142a
3 changed files with 110 additions and 0 deletions

View File

@ -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

View File

@ -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: */

View File

@ -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__ */