[evolution-data-server] ECalClient: Create view objects in the D-Bus thread.



commit ebcde635024cd486706507e57ef219b3ed8df974
Author: Matthew Barnes <mbarnes redhat com>
Date:   Wed Feb 27 18:42:46 2013 -0500

    ECalClient: Create view objects in the D-Bus thread.
    
    Flip-flop the sync/async implementations.  The view object should be
    instantiated from the dedicated D-Bus thread so its underlying proxy
    object shares the same main loop context as the client's proxy.
    
    Have the view object schedule idle callbacks on the client object's
    main loop context to emit change notification signals, so as not to
    expose the dedicated D-Bus thread to external signal handlers.

 calendar/libecal/e-cal-client-view.c |  241 ++++++++++++++++++++++++++++-----
 calendar/libecal/e-cal-client.c      |  101 ++++++++-------
 2 files changed, 259 insertions(+), 83 deletions(-)
---
diff --git a/calendar/libecal/e-cal-client-view.c b/calendar/libecal/e-cal-client-view.c
index 00b9841..43a0f64 100644
--- a/calendar/libecal/e-cal-client-view.c
+++ b/calendar/libecal/e-cal-client-view.c
@@ -39,6 +39,8 @@
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_CAL_CLIENT_VIEW, ECalClientViewPrivate))
 
+typedef struct _SignalClosure SignalClosure;
+
 struct _ECalClientViewPrivate {
        ECalClient *client;
        GDBusProxy *dbus_proxy;
@@ -53,6 +55,15 @@ struct _ECalClientViewPrivate {
        gulong complete_handler_id;
 };
 
+struct _SignalClosure {
+       ECalClientView *client_view;
+       GSList *component_list;
+       GSList *component_id_list;
+       gchar *message;
+       guint percent;
+       GError *error;
+};
+
 enum {
        PROP_0,
        PROP_CLIENT,
@@ -82,6 +93,27 @@ G_DEFINE_TYPE_WITH_CODE (
                G_TYPE_INITABLE,
                e_cal_client_view_initable_init))
 
+static void
+signal_closure_free (SignalClosure *signal_closure)
+{
+       g_object_unref (signal_closure->client_view);
+
+       g_slist_free_full (
+               signal_closure->component_list,
+               (GDestroyNotify) icalcomponent_free);
+
+       g_slist_free_full (
+               signal_closure->component_id_list,
+               (GDestroyNotify) e_cal_component_free_id);
+
+       g_free (signal_closure->message);
+
+       if (signal_closure->error != NULL)
+               g_error_free (signal_closure->error);
+
+       g_slice_free (SignalClosure, signal_closure);
+}
+
 static GSList *
 build_object_list (const gchar * const *seq)
 {
@@ -131,97 +163,232 @@ build_id_list (const gchar * const *seq)
        return g_slist_reverse (list);
 }
 
+static gboolean
+cal_client_view_emit_objects_added_idle_cb (gpointer user_data)
+{
+       SignalClosure *signal_closure = user_data;
+
+       g_signal_emit (
+               signal_closure->client_view,
+               signals[OBJECTS_ADDED], 0,
+               signal_closure->component_list);
+
+       return FALSE;
+}
+
+static gboolean
+cal_client_view_emit_objects_modified_idle_cb (gpointer user_data)
+{
+       SignalClosure *signal_closure = user_data;
+
+       g_signal_emit (
+               signal_closure->client_view,
+               signals[OBJECTS_MODIFIED], 0,
+               signal_closure->component_list);
+
+       return FALSE;
+}
+
+static gboolean
+cal_client_view_emit_objects_removed_idle_cb (gpointer user_data)
+{
+       SignalClosure *signal_closure = user_data;
+
+       g_signal_emit (
+               signal_closure->client_view,
+               signals[OBJECTS_REMOVED], 0,
+               signal_closure->component_id_list);
+
+       return FALSE;
+}
+
+static gboolean
+cal_client_view_emit_progress_idle_cb (gpointer user_data)
+{
+       SignalClosure *signal_closure = user_data;
+
+       g_signal_emit (
+               signal_closure->client_view,
+               signals[PROGRESS], 0,
+               signal_closure->percent,
+               signal_closure->message);
+
+       return FALSE;
+}
+
+static gboolean
+cal_client_view_emit_complete_idle_cb (gpointer user_data)
+{
+       SignalClosure *signal_closure = user_data;
+
+       g_signal_emit (
+               signal_closure->client_view,
+               signals[COMPLETE], 0,
+               signal_closure->error);
+
+       return FALSE;
+}
+
 static void
 cal_client_view_objects_added_cb (EGdbusCalView *dbus_proxy,
                                   const gchar * const *objects,
-                                  ECalClientView *view)
+                                  ECalClientView *client_view)
 {
-       GSList *list;
+       ECalClient *client;
+       GSource *idle_source;
+       GMainContext *main_context;
+       SignalClosure *signal_closure;
 
-       if (!view->priv->running)
+       if (!client_view->priv->running)
                return;
 
-       g_object_ref (view);
+       signal_closure = g_slice_new0 (SignalClosure);
+       signal_closure->client_view = g_object_ref (client_view);
+       signal_closure->component_list = build_object_list (objects);
 
-       list = build_object_list (objects);
+       client = e_cal_client_view_get_client (client_view);
+       main_context = e_client_ref_main_context (E_CLIENT (client));
 
-       g_signal_emit (view, signals[OBJECTS_ADDED], 0, list);
+       idle_source = g_idle_source_new ();
+       g_source_set_callback (
+               idle_source,
+               cal_client_view_emit_objects_added_idle_cb,
+               signal_closure,
+               (GDestroyNotify) signal_closure_free);
+       g_source_attach (idle_source, main_context);
+       g_source_unref (idle_source);
 
-       g_slist_free_full (list, (GDestroyNotify) icalcomponent_free);
-
-       g_object_unref (view);
+       g_main_context_unref (main_context);
 }
 
 static void
 cal_client_view_objects_modified_cb (EGdbusCalView *dbus_proxy,
                                      const gchar * const *objects,
-                                     ECalClientView *view)
+                                     ECalClientView *client_view)
 {
-       GSList *list;
+       ECalClient *client;
+       GSource *idle_source;
+       GMainContext *main_context;
+       SignalClosure *signal_closure;
 
-       if (!view->priv->running)
+       if (!client_view->priv->running)
                return;
 
-       g_object_ref (view);
-
-       list = build_object_list (objects);
+       signal_closure = g_slice_new0 (SignalClosure);
+       signal_closure->client_view = g_object_ref (client_view);
+       signal_closure->component_list = build_object_list (objects);
 
-       g_signal_emit (view, signals[OBJECTS_MODIFIED], 0, list);
+       client = e_cal_client_view_get_client (client_view);
+       main_context = e_client_ref_main_context (E_CLIENT (client));
 
-       g_slist_free_full (list, (GDestroyNotify) icalcomponent_free);
+       idle_source = g_idle_source_new ();
+       g_source_set_callback (
+               idle_source,
+               cal_client_view_emit_objects_modified_idle_cb,
+               signal_closure,
+               (GDestroyNotify) signal_closure_free);
+       g_source_attach (idle_source, main_context);
+       g_source_unref (idle_source);
 
-       g_object_unref (view);
+       g_main_context_unref (main_context);
 }
 
 static void
 cal_client_view_objects_removed_cb (EGdbusCalView *dbus_proxy,
                                     const gchar * const *uids,
-                                    ECalClientView *view)
+                                    ECalClientView *client_view)
 {
-       GSList *list;
+       ECalClient *client;
+       GSource *idle_source;
+       GMainContext *main_context;
+       SignalClosure *signal_closure;
 
-       if (!view->priv->running)
+       if (!client_view->priv->running)
                return;
 
-       g_object_ref (view);
-
-       list = build_id_list (uids);
+       signal_closure = g_slice_new0 (SignalClosure);
+       signal_closure->client_view = g_object_ref (client_view);
+       signal_closure->component_id_list = build_id_list (uids);
 
-       g_signal_emit (view, signals[OBJECTS_REMOVED], 0, list);
+       client = e_cal_client_view_get_client (client_view);
+       main_context = e_client_ref_main_context (E_CLIENT (client));
 
-       g_slist_free_full (list, (GDestroyNotify) e_cal_component_free_id);
+       idle_source = g_idle_source_new ();
+       g_source_set_callback (
+               idle_source,
+               cal_client_view_emit_objects_removed_idle_cb,
+               signal_closure,
+               (GDestroyNotify) signal_closure_free);
+       g_source_attach (idle_source, main_context);
+       g_source_unref (idle_source);
 
-       g_object_unref (view);
+       g_main_context_unref (main_context);
 }
 
 static void
 cal_client_view_progress_cb (EGdbusCalView *dbus_proxy,
                              guint percent,
                              const gchar *message,
-                             ECalClientView *view)
+                             ECalClientView *client_view)
 {
-       if (!view->priv->running)
+       ECalClient *client;
+       GSource *idle_source;
+       GMainContext *main_context;
+       SignalClosure *signal_closure;
+
+       if (!client_view->priv->running)
                return;
 
-       g_signal_emit (G_OBJECT (view), signals[PROGRESS], 0, percent, message);
+       signal_closure = g_slice_new0 (SignalClosure);
+       signal_closure->client_view = g_object_ref (client_view);
+       signal_closure->message = g_strdup (message);
+       signal_closure->percent = percent;
+
+       client = e_cal_client_view_get_client (client_view);
+       main_context = e_client_ref_main_context (E_CLIENT (client));
+
+       idle_source = g_idle_source_new ();
+       g_source_set_callback (
+               idle_source,
+               cal_client_view_emit_progress_idle_cb,
+               signal_closure,
+               (GDestroyNotify) signal_closure_free);
+       g_source_attach (idle_source, main_context);
+       g_source_unref (idle_source);
+
+       g_main_context_unref (main_context);
 }
 
 static void
 cal_client_view_complete_cb (EGdbusCalView *dbus_proxy,
                              const gchar * const *arg_error,
-                             ECalClientView *view)
+                             ECalClientView *client_view)
 {
-       GError *error = NULL;
+       ECalClient *client;
+       GSource *idle_source;
+       GMainContext *main_context;
+       SignalClosure *signal_closure;
 
-       if (!view->priv->running)
+       if (!client_view->priv->running)
                return;
 
-       g_return_if_fail (e_gdbus_templates_decode_error (arg_error, &error));
+       signal_closure = g_slice_new0 (SignalClosure);
+       signal_closure->client_view = g_object_ref (client_view);
+       e_gdbus_templates_decode_error (arg_error, &signal_closure->error);
+
+       client = e_cal_client_view_get_client (client_view);
+       main_context = e_client_ref_main_context (E_CLIENT (client));
 
-       g_signal_emit (G_OBJECT (view), signals[COMPLETE], 0, error);
+       idle_source = g_idle_source_new ();
+       g_source_set_callback (
+               idle_source,
+               cal_client_view_emit_complete_idle_cb,
+               signal_closure,
+               (GDestroyNotify) signal_closure_free);
+       g_source_attach (idle_source, main_context);
+       g_source_unref (idle_source);
 
-       if (error != NULL)
-               g_error_free (error);
+       g_main_context_unref (main_context);
 }
 
 static void
diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c
index 020af32..1468b85 100644
--- a/calendar/libecal/e-cal-client.c
+++ b/calendar/libecal/e-cal-client.c
@@ -5913,20 +5913,55 @@ e_cal_client_discard_alarm_sync (ECalClient *client,
 
 /* Helper for e_cal_client_get_view() */
 static void
-cal_client_get_view_thread (GSimpleAsyncResult *simple,
-                            GObject *source_object,
-                            GCancellable *cancellable)
+cal_client_get_view_in_dbus_thread (GSimpleAsyncResult *simple,
+                                    GObject *source_object,
+                                    GCancellable *cancellable)
 {
+       ECalClient *client = E_CAL_CLIENT (source_object);
        AsyncContext *async_context;
+       gchar *utf8_sexp;
+       gchar *object_path = NULL;
        GError *error = NULL;
 
        async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-       e_cal_client_get_view_sync (
-               E_CAL_CLIENT (source_object),
-               async_context->sexp,
-               &async_context->client_view,
-               cancellable, &error);
+       utf8_sexp = e_util_utf8_make_valid (async_context->sexp);
+
+       e_dbus_calendar_call_get_view_sync (
+               client->priv->dbus_proxy, utf8_sexp,
+               &object_path, cancellable, &error);
+
+       g_free (utf8_sexp);
+
+       /* Sanity check. */
+       g_return_if_fail (
+               ((object_path != NULL) && (error == NULL)) ||
+               ((object_path == NULL) && (error != NULL)));
+
+       if (object_path != NULL) {
+               GDBusConnection *connection;
+               ECalClientView *client_view;
+
+               connection = g_dbus_proxy_get_connection (
+                       G_DBUS_PROXY (client->priv->dbus_proxy));
+
+               client_view = g_initable_new (
+                       E_TYPE_CAL_CLIENT_VIEW,
+                       cancellable, &error,
+                       "client", client,
+                       "connection", connection,
+                       "object-path", object_path,
+                       NULL);
+
+               /* Sanity check. */
+               g_return_if_fail (
+                       ((client_view != NULL) && (error == NULL)) ||
+                       ((client_view == NULL) && (error != NULL)));
+
+               async_context->client_view = client_view;
+
+               g_free (object_path);
+       }
 
        if (error != NULL)
                g_simple_async_result_take_error (simple, error);
@@ -5971,8 +6006,8 @@ e_cal_client_get_view (ECalClient *client,
        g_simple_async_result_set_op_res_gpointer (
                simple, async_context, (GDestroyNotify) async_context_free);
 
-       g_simple_async_result_run_in_thread (
-               simple, cal_client_get_view_thread,
+       cal_client_run_in_dbus_thread (
+               simple, cal_client_get_view_in_dbus_thread,
                G_PRIORITY_DEFAULT, cancellable);
 
        g_object_unref (simple);
@@ -6044,52 +6079,26 @@ e_cal_client_get_view_sync (ECalClient *client,
                             GCancellable *cancellable,
                             GError **error)
 {
-       gchar *utf8_sexp;
-       gchar *object_path = NULL;
+       EAsyncClosure *closure;
+       GAsyncResult *result;
        gboolean success;
 
        g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
        g_return_val_if_fail (sexp != NULL, FALSE);
        g_return_val_if_fail (out_view != NULL, FALSE);
 
-       utf8_sexp = e_util_utf8_make_valid (sexp);
-
-       success = e_dbus_calendar_call_get_view_sync (
-               client->priv->dbus_proxy, utf8_sexp,
-               &object_path, cancellable, error);
-
-       g_free (utf8_sexp);
-
-       /* Sanity check. */
-       g_return_val_if_fail (
-               (success && (object_path != NULL)) ||
-               (!success && (object_path == NULL)), FALSE);
-
-       if (object_path != NULL) {
-               GDBusConnection *connection;
-               ECalClientView *client_view;
+       closure = e_async_closure_new ();
 
-               connection = g_dbus_proxy_get_connection (
-                       G_DBUS_PROXY (client->priv->dbus_proxy));
+       e_cal_client_get_view (
+               client, sexp, cancellable,
+               e_async_closure_callback, closure);
 
-               client_view = g_initable_new (
-                       E_TYPE_CAL_CLIENT_VIEW,
-                       cancellable, error,
-                       "client", client,
-                       "connection", connection,
-                       "object-path", object_path,
-                       NULL);
+       result = e_async_closure_wait (closure);
 
-               /* XXX Would have been easier to return the
-                *     EBookClientView directly rather than
-                *     through an "out" parameter. */
-               if (client_view != NULL)
-                       *out_view = client_view;
-               else
-                       success = FALSE;
+       success = e_cal_client_get_view_finish (
+               client, result, out_view, error);
 
-               g_free (object_path);
-       }
+       e_async_closure_free (closure);
 
        return success;
 }


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