[gnome-color-manager] Allow UDEV and CUPS coldplug to be done multi-threaded



commit 5368e6d8e11edbf874b7ab835d4200df977ce217
Author: Richard Hughes <richard hughsie com>
Date:   Thu Feb 11 17:49:31 2010 +0000

    Allow UDEV and CUPS coldplug to be done multi-threaded

 src/gcm-client.c |  132 +++++++++++++++++++++++++++++++++++++++++++++++++----
 src/gcm-client.h |    2 +
 src/gcm-dbus.c   |    1 +
 src/gcm-prefs.c  |   48 +++++++++++++-------
 4 files changed, 157 insertions(+), 26 deletions(-)
---
diff --git a/src/gcm-client.c b/src/gcm-client.c
index 7a6e32c..671867c 100644
--- a/src/gcm-client.c
+++ b/src/gcm-client.c
@@ -62,11 +62,16 @@ struct _GcmClientPrivate
 	GUdevClient			*gudev_client;
 	GcmScreen			*screen;
 	http_t				*http;
+	gboolean			 loading;
+	guint				 loading_refcount;
+	gboolean			 use_threads;
 };
 
 enum {
 	PROP_0,
 	PROP_DISPLAY_NAME,
+	PROP_LOADING,
+	PROP_USE_THREADS,
 	PROP_LAST
 };
 
@@ -81,6 +86,43 @@ static guint signals[SIGNAL_LAST] = { 0 };
 G_DEFINE_TYPE (GcmClient, gcm_client, G_TYPE_OBJECT)
 
 /**
+ * gcm_client_set_use_threads:
+ **/
+void
+gcm_client_set_use_threads (GcmClient *client, gboolean use_threads)
+{
+	client->priv->use_threads = use_threads;
+	g_object_notify (G_OBJECT (client), "use-threads");
+}
+
+/**
+ * gcm_client_set_loading:
+ **/
+static void
+gcm_client_set_loading (GcmClient *client, gboolean ret)
+{
+	client->priv->loading = ret;
+	g_object_notify (G_OBJECT (client), "loading");
+	egg_debug ("loading: %i", ret);
+}
+
+/**
+ * gcm_client_done_loading:
+ **/
+static void
+gcm_client_done_loading (GcmClient *client)
+{
+	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+	/* decrement refcount, with a lock */
+	g_static_mutex_lock (&mutex);
+	client->priv->loading_refcount--;
+	if (client->priv->loading_refcount == 0)
+		gcm_client_set_loading (client, FALSE);
+	g_static_mutex_unlock (&mutex);
+}
+
+/**
  * gcm_client_get_devices:
  *
  * @client: a valid %GcmClient instance
@@ -283,10 +325,23 @@ gcm_client_add_connected_devices_udev (GcmClient *client, GError **error)
 
 	g_list_foreach (devices, (GFunc) g_object_unref, NULL);
 	g_list_free (devices);
+
+	/* inform the UI */
+	gcm_client_done_loading (client);
 	return TRUE;
 }
 
 /**
+ * gcm_client_add_connected_devices_udev_thrd:
+ **/
+static gpointer
+gcm_client_add_connected_devices_udev_thrd (GcmClient *client)
+{
+	gcm_client_add_connected_devices_udev (client, NULL);
+	return NULL;
+}
+
+/**
  * gcm_client_get_device_by_window_covered:
  **/
 static gfloat
@@ -555,10 +610,23 @@ gcm_client_add_connected_devices_cups (GcmClient *client, GError **error)
 	for (i = 0; i < num_dests; i++)
 		gcm_client_cups_add (client, dests[i]);
 	cupsFreeDests (num_dests, dests);
+
+	/* inform the UI */
+	gcm_client_done_loading (client);
 	return TRUE;
 }
 
 /**
+ * gcm_client_add_connected_devices_cups_thrd:
+ **/
+static gpointer
+gcm_client_add_connected_devices_cups_thrd (GcmClient *client)
+{
+	gcm_client_add_connected_devices_cups (client, NULL);
+	return NULL;
+}
+
+/**
  * gcm_client_add_unconnected_device:
  **/
 static void
@@ -686,23 +754,40 @@ gboolean
 gcm_client_add_connected (GcmClient *client, GError **error)
 {
 	gboolean ret;
+	GThread *thread;
 
 	g_return_val_if_fail (GCM_IS_CLIENT (client), FALSE);
 
-	/* udev */
-	ret = gcm_client_add_connected_devices_udev (client, error);
-	if (!ret)
-		goto out;
-
-	/* xrandr */
+	/* XRandR */
 	ret = gcm_client_add_connected_devices_xrandr (client, error);
 	if (!ret)
 		goto out;
 
-	/* cups */
-	ret = gcm_client_add_connected_devices_cups (client, error);
-	if (!ret)
-		goto out;
+	/* inform UI if we are loading devces still */
+	client->priv->loading_refcount = 2;
+	gcm_client_set_loading (client, TRUE);
+
+	/* UDEV */
+	if (client->priv->use_threads) {
+		thread = g_thread_create ((GThreadFunc) gcm_client_add_connected_devices_udev_thrd, client, FALSE, error);
+		if (thread == NULL)
+			goto out;
+	} else {
+		ret = gcm_client_add_connected_devices_udev (client, error);
+		if (!ret)
+			goto out;
+	}
+
+	/* CUPS */
+	if (client->priv->use_threads) {
+		thread = g_thread_create ((GThreadFunc) gcm_client_add_connected_devices_cups_thrd, client, FALSE, error);
+		if (thread == NULL)
+			goto out;
+	} else {
+		ret = gcm_client_add_connected_devices_cups (client, error);
+		if (!ret)
+			goto out;
+	}
 out:
 	return ret;
 }
@@ -797,6 +882,12 @@ gcm_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSp
 	case PROP_DISPLAY_NAME:
 		g_value_set_string (value, priv->display_name);
 		break;
+	case PROP_LOADING:
+		g_value_set_boolean (value, priv->loading);
+		break;
+	case PROP_USE_THREADS:
+		g_value_set_boolean (value, priv->use_threads);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -817,6 +908,9 @@ gcm_client_set_property (GObject *object, guint prop_id, const GValue *value, GP
 		g_free (priv->display_name);
 		priv->display_name = g_strdup (g_value_get_string (value));
 		break;
+	case PROP_USE_THREADS:
+		priv->use_threads = g_value_get_boolean (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -861,6 +955,22 @@ gcm_client_class_init (GcmClientClass *klass)
 	g_object_class_install_property (object_class, PROP_DISPLAY_NAME, pspec);
 
 	/**
+	 * GcmClient:loading:
+	 */
+	pspec = g_param_spec_boolean ("loading", NULL, NULL,
+				      TRUE,
+				      G_PARAM_READABLE);
+	g_object_class_install_property (object_class, PROP_LOADING, pspec);
+
+	/**
+	 * GcmClient:use-threads:
+	 */
+	pspec = g_param_spec_boolean ("use-threads", NULL, NULL,
+				      TRUE,
+				      G_PARAM_READWRITE);
+	g_object_class_install_property (object_class, PROP_USE_THREADS, pspec);
+
+	/**
 	 * GcmClient::added
 	 **/
 	signals[SIGNAL_ADDED] =
@@ -893,6 +1003,8 @@ gcm_client_init (GcmClient *client)
 
 	client->priv = GCM_CLIENT_GET_PRIVATE (client);
 	client->priv->display_name = NULL;
+	client->priv->loading_refcount = 0;
+	client->priv->use_threads = FALSE;
 	client->priv->array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
 	client->priv->screen = gcm_screen_new ();
 	g_signal_connect (client->priv->screen, "outputs-changed",
diff --git a/src/gcm-client.h b/src/gcm-client.h
index 1638aea..147a753 100644
--- a/src/gcm-client.h
+++ b/src/gcm-client.h
@@ -74,6 +74,8 @@ gboolean	 gcm_client_add_connected			(GcmClient		*client,
 gboolean	 gcm_client_add_saved				(GcmClient		*client,
 								 GError			**error);
 GPtrArray	*gcm_client_get_devices				(GcmClient		*client);
+void		 gcm_client_set_use_threads			(GcmClient		*client,
+								 gboolean		 use_threads);
 
 G_END_DECLS
 
diff --git a/src/gcm-dbus.c b/src/gcm-dbus.c
index b8e3d5a..2a1d5bb 100644
--- a/src/gcm-dbus.c
+++ b/src/gcm-dbus.c
@@ -498,6 +498,7 @@ gcm_dbus_init (GcmDbus *dbus)
 	dbus->priv = GCM_DBUS_GET_PRIVATE (dbus);
 	dbus->priv->gconf_client = gconf_client_get_default ();
 	dbus->priv->client = gcm_client_new ();
+	gcm_client_set_use_threads (dbus->priv->client, TRUE);
 	dbus->priv->profile_store = gcm_profile_store_new ();
 	dbus->priv->timer = g_timer_new ();
 
diff --git a/src/gcm-prefs.c b/src/gcm-prefs.c
index 7368cad..8dd8e6c 100644
--- a/src/gcm-prefs.c
+++ b/src/gcm-prefs.c
@@ -59,7 +59,6 @@ static gboolean setting_up_device = FALSE;
 static GtkWidget *info_bar = NULL;
 static GtkWidget *cie_widget = NULL;
 static GtkWidget *trc_widget = NULL;
-static guint loading_refcount = 0;
 static GConfClient *gconf_client = NULL;
 
 enum {
@@ -2453,8 +2452,6 @@ static gboolean
 gcm_prefs_added_idle_cb (GcmDevice *device)
 {
 	GcmDeviceTypeEnum type;
-	GtkTreePath *path;
-	GtkWidget *widget;
 	egg_debug ("added: %s", gcm_device_get_id (device));
 
 	/* remove the saved device if it's already there */
@@ -2471,17 +2468,6 @@ gcm_prefs_added_idle_cb (GcmDevice *device)
 	else
 		gcm_prefs_add_device_type (device);
 
-	/* clear loading widget */
-	if (--loading_refcount == 0) {
-		gtk_widget_hide (info_bar);
-
-		/* set the cursor on the first device */
-		widget = GTK_WIDGET (gtk_builder_get_object (builder, "treeview_devices"));
-		path = gtk_tree_path_new_from_string ("0");
-		gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE);
-		gtk_tree_path_free (path);
-	}
-
 	/* unref the instance */
 	g_object_unref (device);
 	return FALSE;
@@ -2493,9 +2479,7 @@ gcm_prefs_added_idle_cb (GcmDevice *device)
 static void
 gcm_prefs_added_cb (GcmClient *gcm_client_, GcmDevice *gcm_device, gpointer user_data)
 {
-	gtk_widget_show (info_bar);
 	g_idle_add ((GSourceFunc) gcm_prefs_added_idle_cb, g_object_ref (gcm_device));
-	loading_refcount++;
 }
 
 /**
@@ -2890,6 +2874,35 @@ gcm_prefs_profile_store_changed_cb (GcmProfileStore *_profile_store, gpointer us
 }
 
 /**
+ * gcm_prefs_client_notify_loading_cb:
+ **/
+static void
+gcm_prefs_client_notify_loading_cb (GcmClient *client, GParamSpec *pspec, gpointer data)
+{
+	gboolean loading;
+	GtkTreePath *path;
+	GtkWidget *widget;
+
+	/* get the new state */
+	g_object_get (client, "loading", &loading, NULL);
+
+	/*if loading show the bar */
+	if (loading) {
+		gtk_widget_show (info_bar);
+		return;
+	}
+
+	/* otherwise clear the loading widget */
+	gtk_widget_hide (info_bar);
+
+	/* set the cursor on the first device */
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, "treeview_devices"));
+	path = gtk_tree_path_new_from_string ("0");
+	gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE);
+	gtk_tree_path_free (path);
+}
+
+/**
  * main:
  **/
 int
@@ -3127,8 +3140,11 @@ main (int argc, char **argv)
 
 	/* use a device client array */
 	gcm_client = gcm_client_new ();
+	gcm_client_set_use_threads (gcm_client, TRUE);
 	g_signal_connect (gcm_client, "added", G_CALLBACK (gcm_prefs_added_cb), NULL);
 	g_signal_connect (gcm_client, "removed", G_CALLBACK (gcm_prefs_removed_cb), NULL);
+	g_signal_connect (gcm_client, "notify::loading",
+			  G_CALLBACK (gcm_prefs_client_notify_loading_cb), NULL);
 
 	/* use the color device */
 	color_device = gcm_color_device_new ();



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