[evolution-data-server] Bug #627788 - EDataCalView is never freed in a factory process



commit a65b1d94415326418dd9663cbae041abc51f4a47
Author: Milan Crha <mcrha redhat com>
Date:   Thu Jan 13 18:46:16 2011 +0100

    Bug #627788 - EDataCalView is never freed in a factory process

 addressbook/tests/ebook/test-stress-bookviews.c |    1 +
 calendar/libecal/e-cal-view.c                   |   15 ++-
 calendar/libedata-cal/e-cal-backend.c           |   22 +--
 calendar/libedata-cal/e-data-cal-factory.c      |   11 ++
 calendar/libedata-cal/e-data-cal-view.c         |   12 ++
 calendar/libedata-cal/e-data-cal-view.xml       |    4 +
 calendar/libegdbus/e-gdbus-egdbuscalview.c      |  169 +++++++++++++++++++++++
 calendar/libegdbus/e-gdbus-egdbuscalview.h      |   24 ++++
 8 files changed, 239 insertions(+), 19 deletions(-)
---
diff --git a/addressbook/tests/ebook/test-stress-bookviews.c b/addressbook/tests/ebook/test-stress-bookviews.c
index 92ff79f..13b3833 100644
--- a/addressbook/tests/ebook/test-stress-bookviews.c
+++ b/addressbook/tests/ebook/test-stress-bookviews.c
@@ -100,6 +100,7 @@ main (gint argc, gchar **argv)
 	g_object_unref (view);
 
 	e_book_query_unref (query);
+	g_object_unref (book);
 
 	return 0;
 }
diff --git a/calendar/libecal/e-cal-view.c b/calendar/libecal/e-cal-view.c
index ec50375..9a2c9eb 100644
--- a/calendar/libecal/e-cal-view.c
+++ b/calendar/libecal/e-cal-view.c
@@ -193,10 +193,8 @@ e_cal_view_set_property (GObject *object, guint property_id, const GValue *value
 
 	switch (property_id) {
 	case PROP_VIEW:
-		if (priv->gdbus_calview != NULL) {
-			g_signal_handlers_disconnect_matched (priv->gdbus_calview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
-			g_object_unref (priv->gdbus_calview);
-		}
+		/* gdbus_calview can be set only once */
+		g_return_if_fail (priv->gdbus_calview == NULL);
 
 		priv->gdbus_calview = g_object_ref (g_value_get_pointer (value));
 		g_signal_connect (priv->gdbus_calview, "objects-added", G_CALLBACK (objects_added_cb), view);
@@ -250,8 +248,17 @@ e_cal_view_finalize (GObject *object)
 	priv = view->priv;
 
 	if (priv->gdbus_calview != NULL) {
+		GError *error = NULL;
+
 		g_signal_handlers_disconnect_matched (priv->gdbus_calview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
+		e_gdbus_cal_view_call_dispose_sync (priv->gdbus_calview, NULL, &error);
 		g_object_unref (priv->gdbus_calview);
+		priv->gdbus_calview = NULL;
+
+		if (error) {
+			g_warning ("Failed to dispose cal view: %s", error->message);
+			g_error_free (error);
+		}
 	}
 
 	g_object_unref (priv->client);
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index eb2cc0f..f654c24 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -44,8 +44,6 @@
 struct _ECalBackendPrivate {
 	/* The source for this backend */
 	ESource *source;
-	/* signal handler ID for source's 'changed' signal */
-	gulong source_changed_id;
 
 	/* URI, from source. This is cached, since we return const. */
 	gchar *uri;
@@ -161,17 +159,12 @@ cal_backend_set_source (ECalBackend *backend,
                         ESource *source)
 {
 	if (backend->priv->source != NULL) {
-		if (backend->priv->source_changed_id > 0) {
-			g_signal_handler_disconnect (
-				backend->priv->source,
-				backend->priv->source_changed_id);
-			backend->priv->source_changed_id = 0;
-		}
+		g_signal_handlers_disconnect_matched (backend->priv->source, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, source_changed_cb, backend);
 		g_object_unref (backend->priv->source);
 	}
 
 	if (source != NULL)
-		backend->priv->source_changed_id = g_signal_connect (
+		g_signal_connect (
 			g_object_ref (source), "changed",
 			G_CALLBACK (source_changed_cb), backend);
 
@@ -283,11 +276,10 @@ cal_backend_finalize (GObject *object)
 	g_free (priv->uri);
 	g_free (priv->cache_dir);
 
-	if (priv->source_changed_id && priv->source) {
-		g_signal_handler_disconnect (priv->source, priv->source_changed_id);
-		priv->source_changed_id = 0;
+	if (priv->source) {
+		g_signal_handlers_disconnect_matched (priv->source, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object);
+		g_object_unref (priv->source);
 	}
-	g_object_unref (priv->source);
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_cal_backend_parent_class)->finalize (object);
@@ -376,8 +368,8 @@ e_cal_backend_init (ECalBackend *backend)
 	backend->priv->clients_mutex = g_mutex_new ();
 
 	backend->priv->queries = e_list_new (
-		(EListCopyFunc) g_object_ref,
-		(EListFreeFunc) g_object_unref, NULL);
+		(EListCopyFunc) NULL,
+		(EListFreeFunc) NULL, NULL);
 	backend->priv->queries_mutex = g_mutex_new ();
 }
 
diff --git a/calendar/libedata-cal/e-data-cal-factory.c b/calendar/libedata-cal/e-data-cal-factory.c
index 4345c85..379b066 100644
--- a/calendar/libedata-cal/e-data-cal-factory.c
+++ b/calendar/libedata-cal/e-data-cal-factory.c
@@ -558,6 +558,15 @@ e_data_cal_factory_init (EDataCalFactory *factory)
 }
 
 static void
+unref_backend_cb (gpointer key, gpointer value, gpointer user_data)
+{
+	ECalBackend *backend = value;
+
+	if (backend)
+		g_object_unref (backend);
+}
+
+static void
 e_data_cal_factory_finalize (GObject *object)
 {
 	EDataCalFactory *factory = E_DATA_CAL_FACTORY (object);
@@ -566,6 +575,8 @@ e_data_cal_factory_finalize (GObject *object)
 
 	g_object_unref (factory->priv->gdbus_object);
 
+	g_hash_table_foreach (factory->priv->backends, unref_backend_cb, NULL);
+
 	g_hash_table_destroy (factory->priv->methods);
 	g_hash_table_destroy (factory->priv->backends);
 	g_hash_table_destroy (factory->priv->calendars);
diff --git a/calendar/libedata-cal/e-data-cal-view.c b/calendar/libedata-cal/e-data-cal-view.c
index 7fed039..a8cb142 100644
--- a/calendar/libedata-cal/e-data-cal-view.c
+++ b/calendar/libedata-cal/e-data-cal-view.c
@@ -333,6 +333,16 @@ impl_DataCalView_stop (EGdbusCalView *object, GDBusMethodInvocation *invocation,
 	return TRUE;
 }
 
+static gboolean
+impl_DataCalView_dispose (EGdbusCalView *object, GDBusMethodInvocation *invocation, EDataCalView *query)
+{
+	e_gdbus_cal_view_complete_dispose (object, invocation);
+
+	g_object_unref (query);
+
+	return TRUE;
+}
+
 static void
 e_data_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
 {
@@ -388,6 +398,7 @@ e_data_cal_view_init (EDataCalView *query)
 	priv->gdbus_object = e_gdbus_cal_view_stub_new ();
 	g_signal_connect (priv->gdbus_object, "handle-start", G_CALLBACK (impl_DataCalView_start), query);
 	g_signal_connect (priv->gdbus_object, "handle-stop", G_CALLBACK (impl_DataCalView_stop), query);
+	g_signal_connect (priv->gdbus_object, "handle-dispose", G_CALLBACK (impl_DataCalView_dispose), query);
 
 	priv->backend = NULL;
 	priv->started = FALSE;
@@ -418,6 +429,7 @@ e_data_cal_view_dispose (GObject *object)
 	priv = query->priv;
 
 	if (priv->backend) {
+		e_cal_backend_remove_query (priv->backend, query);
 		g_object_unref (priv->backend);
 		priv->backend = NULL;
 	}
diff --git a/calendar/libedata-cal/e-data-cal-view.xml b/calendar/libedata-cal/e-data-cal-view.xml
index 44ed68a..beb32d9 100644
--- a/calendar/libedata-cal/e-data-cal-view.xml
+++ b/calendar/libedata-cal/e-data-cal-view.xml
@@ -11,6 +11,10 @@
     <method name="stop">
       <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_EDataCalView_stop"/>
     </method>
+
+    <method name="dispose">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_EDataCalView_dispose"/>
+    </method>
     
     <signal name="ObjectsAdded">
       <arg name="objects" type="as"/>
diff --git a/calendar/libegdbus/e-gdbus-egdbuscalview.c b/calendar/libegdbus/e-gdbus-egdbuscalview.c
index 065cd5b..c917c90 100644
--- a/calendar/libegdbus/e-gdbus-egdbuscalview.c
+++ b/calendar/libegdbus/e-gdbus-egdbuscalview.c
@@ -71,6 +71,7 @@ enum
   __DONE_SIGNAL,
   __START_METHOD,
   __STOP_METHOD,
+  __DISPOSE_METHOD,
   __LAST_SIGNAL
 };
 
@@ -345,6 +346,7 @@ e_gdbus_cal_view_default_init (EGdbusCalViewIface *iface)
   _property_name_to_gname = g_hash_table_new (g_str_hash, g_str_equal);
   g_hash_table_insert (_method_name_to_id, (gpointer) "start", GUINT_TO_POINTER (__START_METHOD));
   g_hash_table_insert (_method_name_to_id, (gpointer) "stop", GUINT_TO_POINTER (__STOP_METHOD));
+  g_hash_table_insert (_method_name_to_id, (gpointer) "dispose", GUINT_TO_POINTER (__DISPOSE_METHOD));
   g_hash_table_insert (_signal_name_to_id, (gpointer) "ObjectsAdded", GUINT_TO_POINTER (__OBJECTS_ADDED_SIGNAL));
   g_hash_table_insert (_signal_name_to_id, (gpointer) "ObjectsModified", GUINT_TO_POINTER (__OBJECTS_MODIFIED_SIGNAL));
   g_hash_table_insert (_signal_name_to_id, (gpointer) "ObjectsRemoved", GUINT_TO_POINTER (__OBJECTS_REMOVED_SIGNAL));
@@ -556,6 +558,31 @@ e_gdbus_cal_view_default_init (EGdbusCalViewIface *iface)
                   1,
                   G_TYPE_DBUS_METHOD_INVOCATION);
 
+  /**
+   * EGdbusCalView::handle-dispose:
+   * @object: The exported object emitting the signal.
+   * @invocation: A #GDBusMethodInvocation object that can be used to return a value or error.
+   *
+   * On exported objects, this signal is emitted when a remote process (identified by @invocation) invokes the <literal>dispose</literal> D-Bus method on @object. Use e_gdbus_cal_view_complete_dispose() to return a value or g_dbus_method_invocation_return_error() to return an error.
+   *
+   * The signal is emitted in the thread-default main loop of the thread that e_gdbus_cal_view_register_object() was called from.
+   *
+   * On proxies, this signal is never emitted.
+   *
+   * Returns: %TRUE if you want to handle the method call (will stop further handlers from being called), %FALSE otherwise.
+   */
+  signals[__DISPOSE_METHOD] =
+    g_signal_new ("handle-dispose",
+                  G_TYPE_FROM_INTERFACE (iface),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (EGdbusCalViewIface, handle_dispose),
+                  g_signal_accumulator_true_handled,
+                  NULL,
+                  _e_gdbus_gdbus_cclosure_marshaller_BOOLEAN__OBJECT,
+                  G_TYPE_BOOLEAN,
+                  1,
+                  G_TYPE_DBUS_METHOD_INVOCATION);
+
   /* GObject property definitions for D-Bus properties: */
 }
 
@@ -762,6 +789,106 @@ _out:
 }
 
 /**
+ * e_gdbus_cal_view_call_dispose:
+ * @proxy: A #EGdbusCalView.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't care about the result of the method invocation.
+ * @user_data: Data to pass to @callback.
+ *
+ * Invokes the <literal>org.gnome.evolution.dataserver.calendar.CalView.dispose</literal>
+ * D-Bus method on the remote object represented by @proxy.
+ *
+ * This is an asynchronous method. When the operation is finished,
+ * callback will be invoked in the thread-default main loop of the
+ * thread you are calling this method from. You can then call
+ * e_gdbus_cal_view_call_dispose_finish() to get the result of the operation.
+ *
+ * See e_gdbus_cal_view_call_dispose_sync() for the synchronous version of this method.
+ */
+void e_gdbus_cal_view_call_dispose (
+        EGdbusCalView *proxy,
+        GCancellable *cancellable,
+        GAsyncReadyCallback callback,
+        gpointer user_data)
+{
+  GVariant *_params;
+  _params = NULL;
+  g_dbus_proxy_call (G_DBUS_PROXY (proxy),
+                     "dispose",
+                     _params,
+                     G_DBUS_CALL_FLAGS_NONE,
+                     -1,
+                     cancellable,
+                     callback,
+                     user_data);
+}
+
+/**
+ * e_gdbus_cal_view_call_dispose_finish:
+ * @proxy: A #EGdbusCalView.
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to e_gdbus_cal_view_call_dispose().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes invoking the <literal>org.gnome.evolution.dataserver.calendar.CalView.dispose</literal>
+ * D-Bus method on the remote object represented by @proxy.
+ *
+ * Returns: %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean e_gdbus_cal_view_call_dispose_finish (
+        EGdbusCalView *proxy,
+        GAsyncResult *res,
+        GError **error)
+{
+  gboolean _ret = FALSE;
+  GVariant *_result;
+  _result = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, error);
+  if (_result == NULL)
+    goto _out;
+  g_variant_unref (_result);
+  _ret = TRUE;
+_out:
+  return _ret;
+}
+
+/**
+ * e_gdbus_cal_view_call_dispose_sync:
+ * @proxy: A #EGdbusCalView.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Synchronously invokes the <literal>org.gnome.evolution.dataserver.calendar.CalView.dispose</literal>
+ * D-Bus method on the remote object represented by @proxy.
+ *
+ * The calling thread is blocked until a reply is received. See
+ * e_gdbus_cal_view_call_dispose() for the asynchronous version of this method.
+ *
+ * Returns: %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean e_gdbus_cal_view_call_dispose_sync (
+        EGdbusCalView *proxy,
+        GCancellable *cancellable,
+        GError **error)
+{
+  gboolean _ret = FALSE;
+  GVariant *_params;
+  GVariant *_result;
+  _params = NULL;
+  _result = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy),
+                                   "dispose",
+                                   _params,
+                                   G_DBUS_CALL_FLAGS_NONE,
+                                   -1,
+                                   cancellable,
+                                   error);
+  if (_result == NULL)
+    goto _out;
+  g_variant_unref (_result);
+  _ret = TRUE;
+_out:
+  return _ret;
+}
+
+/**
  * e_gdbus_cal_view_complete_start:
  * @object: A #EGdbusCalView.
  * @invocation: A #GDBusMethodInvocation.
@@ -802,6 +929,26 @@ void e_gdbus_cal_view_complete_stop (
 }
 
 /**
+ * e_gdbus_cal_view_complete_dispose:
+ * @object: A #EGdbusCalView.
+ * @invocation: A #GDBusMethodInvocation.
+ *
+ * Completes handling the <literal>org.gnome.evolution.dataserver.calendar.CalView.dispose</literal>
+ * D-Bus method invocation by returning a value.
+ *
+ * If you want to return an error, use g_dbus_method_invocation_return_error()
+ * or similar instead.
+ *
+ * This method will free @invocation, you cannot use it afterwards.
+ */
+void e_gdbus_cal_view_complete_dispose (
+        EGdbusCalView *object,
+        GDBusMethodInvocation *invocation)
+{
+  g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+/**
  * e_gdbus_cal_view_emit_objects_added:
  * @object: A #EGdbusCalView.
  * @arg_objects: Signal parameter.
@@ -1029,10 +1176,20 @@ static const GDBusMethodInfo e_gdbus_cal_view_method_stop =
   (GDBusAnnotationInfo **) NULL,
 };
 
+static const GDBusMethodInfo e_gdbus_cal_view_method_dispose =
+{
+  -1,
+  (gchar *) "dispose",
+  (GDBusArgInfo **) NULL,
+  (GDBusArgInfo **) NULL,
+  (GDBusAnnotationInfo **) NULL,
+};
+
 static const GDBusMethodInfo * const e_gdbus_cal_view_method_info_pointers[] =
 {
   &e_gdbus_cal_view_method_start,
   &e_gdbus_cal_view_method_stop,
+  &e_gdbus_cal_view_method_dispose,
   NULL
 };
 
@@ -1083,6 +1240,18 @@ handle_method_call (GDBusConnection       *connection,
       }
       break;
 
+    case __DISPOSE_METHOD:
+      {
+        EGdbusCalView *object = E_GDBUS_CAL_VIEW (user_data);
+        gboolean handled;
+        g_signal_emit (object,
+                       signals[method_id],
+                       0, invocation, &handled);
+        if (!handled)
+          goto not_implemented;
+      }
+      break;
+
     default:
 not_implemented:
       g_dbus_method_invocation_return_error (invocation,
diff --git a/calendar/libegdbus/e-gdbus-egdbuscalview.h b/calendar/libegdbus/e-gdbus-egdbuscalview.h
index 2dde043..b3361d0 100644
--- a/calendar/libegdbus/e-gdbus-egdbuscalview.h
+++ b/calendar/libegdbus/e-gdbus-egdbuscalview.h
@@ -35,6 +35,7 @@ typedef struct _EGdbusCalView EGdbusCalView; /* Dummy typedef */
  * @done: Handler for the #EGdbusCalView::done signal.
  * @handle_start: Handler for the #EGdbusCalView::handle-start signal.
  * @handle_stop: Handler for the #EGdbusCalView::handle-stop signal.
+ * @handle_dispose: Handler for the #EGdbusCalView::handle-dispose signal.
  *
  * Virtual table.
  */
@@ -189,6 +190,9 @@ struct _EGdbusCalViewIface
   gboolean (*handle_stop) (
         EGdbusCalView *object,
         GDBusMethodInvocation *invocation);
+  gboolean (*handle_dispose) (
+        EGdbusCalView *object,
+        GDBusMethodInvocation *invocation);
 };
 
 /* C Bindings for properties */
@@ -226,6 +230,22 @@ gboolean e_gdbus_cal_view_call_stop_sync (
         GCancellable *cancellable,
         GError **error);
 
+void e_gdbus_cal_view_call_dispose (
+        EGdbusCalView *proxy,
+        GCancellable *cancellable,
+        GAsyncReadyCallback callback,
+        gpointer user_data);
+
+gboolean e_gdbus_cal_view_call_dispose_finish (
+        EGdbusCalView *proxy,
+        GAsyncResult *res,
+        GError **error);
+
+gboolean e_gdbus_cal_view_call_dispose_sync (
+        EGdbusCalView *proxy,
+        GCancellable *cancellable,
+        GError **error);
+
 /* D-Bus Methods Completion Helpers */
 void e_gdbus_cal_view_complete_start (
         EGdbusCalView *object,
@@ -235,6 +255,10 @@ void e_gdbus_cal_view_complete_stop (
         EGdbusCalView *object,
         GDBusMethodInvocation *invocation);
 
+void e_gdbus_cal_view_complete_dispose (
+        EGdbusCalView *object,
+        GDBusMethodInvocation *invocation);
+
 /* D-Bus Signal Emission Helpers */
 void e_gdbus_cal_view_emit_objects_added (
         EGdbusCalView *object,



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