1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2010-2013 Richard Hughes <richard@hughsie.com>
4  *
5  * Licensed under the GNU Lesser General Public License Version 2.1
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
20  */
21 
22 /**
23  * SECTION:cd-client
24  * @short_description: Main client object for accessing the colord daemon
25  *
26  * A helper GObject to use for accessing colord information, and to be notified
27  * when it is changed.
28  *
29  * See also: #CdDevice
30  */
31 
32 #include "config.h"
33 
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 
40 #include <gio/gio.h>
41 #ifdef __unix__
42 #include <gio/gunixfdlist.h>
43 #endif
44 #include <glib/gstdio.h>
45 #include <glib.h>
46 
47 #include "cd-enum.h"
48 #include "cd-client.h"
49 #include "cd-client-sync.h"
50 #include "cd-device.h"
51 #include "cd-device-sync.h"
52 #include "cd-sensor.h"
53 #include "cd-profile-sync.h"
54 
55 static void	cd_client_class_init	(CdClientClass	*klass);
56 static void	cd_client_init		(CdClient	*client);
57 static void	cd_client_finalize	(GObject	*object);
58 
59 #define GET_PRIVATE(o) (cd_client_get_instance_private (o))
60 
61 #define CD_CLIENT_MESSAGE_TIMEOUT	15000 /* ms */
62 #define CD_CLIENT_IMPORT_DAEMON_TIMEOUT	5000 /* ms */
63 #define COLORD_DBUS_SERVICE		"org.freedesktop.ColorManager"
64 #define COLORD_DBUS_PATH		"/org/freedesktop/ColorManager"
65 #define COLORD_DBUS_INTERFACE		"org.freedesktop.ColorManager"
66 
67 /**
68  * CdClientPrivate:
69  *
70  * Private #CdClient data
71  **/
72 typedef struct
73 {
74 	GDBusProxy		*proxy;
75 	gchar			*daemon_version;
76 	gchar			*system_vendor;
77 	gchar			*system_model;
78 } CdClientPrivate;
79 
80 enum {
81 	SIGNAL_CHANGED,
82 	SIGNAL_DEVICE_ADDED,
83 	SIGNAL_DEVICE_REMOVED,
84 	SIGNAL_DEVICE_CHANGED,
85 	SIGNAL_PROFILE_ADDED,
86 	SIGNAL_PROFILE_REMOVED,
87 	SIGNAL_PROFILE_CHANGED,
88 	SIGNAL_SENSOR_ADDED,
89 	SIGNAL_SENSOR_REMOVED,
90 	SIGNAL_SENSOR_CHANGED,
91 	SIGNAL_LAST
92 };
93 
94 enum {
95 	PROP_0,
96 	PROP_DAEMON_VERSION,
97 	PROP_CONNECTED,
98 	PROP_SYSTEM_VENDOR,
99 	PROP_SYSTEM_MODEL,
100 	PROP_LAST
101 };
102 
103 static guint signals [SIGNAL_LAST] = { 0 };
104 static gpointer cd_client_object = NULL;
105 
G_DEFINE_TYPE_WITH_PRIVATE(CdClient,cd_client,G_TYPE_OBJECT)106 G_DEFINE_TYPE_WITH_PRIVATE (CdClient, cd_client, G_TYPE_OBJECT)
107 
108 /**
109  * cd_client_error_quark:
110  *
111  * Return value: An error quark.
112  *
113  * Since: 0.1.0
114  **/
115 GQuark
116 cd_client_error_quark (void)
117 {
118 	static GQuark quark = 0;
119 	if (!quark) {
120 		quark = g_quark_from_static_string ("cd_client_error");
121 		g_dbus_error_register_error (quark,
122 					     CD_CLIENT_ERROR_INTERNAL,
123 					     COLORD_DBUS_SERVICE ".Failed");
124 		g_dbus_error_register_error (quark,
125 					     CD_CLIENT_ERROR_ALREADY_EXISTS,
126 					     COLORD_DBUS_SERVICE ".AlreadyExists");
127 	}
128 	return quark;
129 }
130 
131 /**
132  * cd_client_get_daemon_version:
133  * @client: a #CdClient instance.
134  *
135  * Get colord daemon version.
136  *
137  * Return value: string containing the daemon version, e.g. "0.1.0"
138  *
139  * Since: 0.1.0
140  **/
141 const gchar *
cd_client_get_daemon_version(CdClient * client)142 cd_client_get_daemon_version (CdClient *client)
143 {
144 	CdClientPrivate *priv = GET_PRIVATE (client);
145 	g_return_val_if_fail (CD_IS_CLIENT (client), NULL);
146 	g_return_val_if_fail (priv->proxy != NULL, NULL);
147 	return priv->daemon_version;
148 }
149 
150 /**
151  * cd_client_get_system_vendor:
152  * @client: a #CdClient instance.
153  *
154  * Get system vendor.
155  *
156  * Return value: string containing the system vendor, e.g. "Lenovo"
157  *
158  * Since: 1.0.2
159  **/
160 const gchar *
cd_client_get_system_vendor(CdClient * client)161 cd_client_get_system_vendor (CdClient *client)
162 {
163 	CdClientPrivate *priv = GET_PRIVATE (client);
164 	g_return_val_if_fail (CD_IS_CLIENT (client), NULL);
165 	g_return_val_if_fail (priv->proxy != NULL, NULL);
166 	return priv->system_vendor;
167 }
168 
169 /**
170  * cd_client_get_system_model:
171  * @client: a #CdClient instance.
172  *
173  * Get system model.
174  *
175  * Return value: string containing the system model, e.g. "T61"
176  *
177  * Since: 1.0.2
178  **/
179 const gchar *
cd_client_get_system_model(CdClient * client)180 cd_client_get_system_model (CdClient *client)
181 {
182 	CdClientPrivate *priv = GET_PRIVATE (client);
183 	g_return_val_if_fail (CD_IS_CLIENT (client), NULL);
184 	g_return_val_if_fail (priv->proxy != NULL, NULL);
185 	return priv->system_model;
186 }
187 
188 /**
189  * cd_client_get_connected:
190  * @client: a #CdClient instance.
191  *
192  * Gets if the client has been connected.
193  *
194  * Return value: %TRUE if properties are valid
195  *
196  * Since: 0.1.9
197  **/
198 gboolean
cd_client_get_connected(CdClient * client)199 cd_client_get_connected (CdClient *client)
200 {
201 	CdClientPrivate *priv = GET_PRIVATE (client);
202 	g_return_val_if_fail (CD_IS_CLIENT (client), FALSE);
203 	return priv->proxy != NULL;
204 }
205 
206 /**
207  * cd_client_get_has_server:
208  * @client: a #CdClient instance.
209  *
210  * Gets if the colord server is currently running.
211  * WARNING: This function may block for up to 5 seconds waiting for the daemon
212  * to start if it is not already running.
213  *
214  * Return value: %TRUE if the colord process is running
215  *
216  * Since: 0.1.12
217  **/
218 gboolean
cd_client_get_has_server(CdClient * client)219 cd_client_get_has_server (CdClient *client)
220 {
221 	g_autofree gchar *name_owner = NULL;
222 	g_autoptr(GDBusProxy) proxy = NULL;
223 
224 	g_return_val_if_fail (CD_IS_CLIENT (client), FALSE);
225 
226 	/* get name owner */
227 	proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
228 					       G_DBUS_PROXY_FLAGS_NONE,
229 					       NULL,
230 					       COLORD_DBUS_SERVICE,
231 					       COLORD_DBUS_PATH,
232 					       COLORD_DBUS_INTERFACE,
233 					       NULL,
234 					       NULL);
235 	if (proxy == NULL)
236 		return FALSE;
237 	name_owner = g_dbus_proxy_get_name_owner (proxy);
238 	if (name_owner == NULL)
239 		return FALSE;
240 
241 	/* just assume it's ready for use */
242 	return TRUE;
243 }
244 
245 /**********************************************************************/
246 
247 /**
248  * cd_client_dbus_signal_cb:
249  **/
250 static void
cd_client_dbus_signal_cb(GDBusProxy * proxy,gchar * sender_name,gchar * signal_name,GVariant * parameters,CdClient * client)251 cd_client_dbus_signal_cb (GDBusProxy *proxy,
252 			  gchar      *sender_name,
253 			  gchar      *signal_name,
254 			  GVariant   *parameters,
255 			  CdClient   *client)
256 {
257 	g_autofree gchar *object_path_tmp = NULL;
258 	g_autoptr(CdDevice) device = NULL;
259 	g_autoptr(CdProfile) profile = NULL;
260 	g_autoptr(CdSensor) sensor = NULL;
261 
262 	if (g_strcmp0 (signal_name, "Changed") == 0) {
263 		g_warning ("changed");
264 	} else if (g_strcmp0 (signal_name, "DeviceAdded") == 0) {
265 		g_variant_get (parameters, "(o)", &object_path_tmp);
266 		device = cd_device_new_with_object_path (object_path_tmp);
267 		g_signal_emit (client, signals[SIGNAL_DEVICE_ADDED], 0,
268 			       device);
269 	} else if (g_strcmp0 (signal_name, "DeviceRemoved") == 0) {
270 		g_variant_get (parameters, "(o)", &object_path_tmp);
271 		device = cd_device_new_with_object_path (object_path_tmp);
272 		g_signal_emit (client, signals[SIGNAL_DEVICE_REMOVED], 0,
273 			       device);
274 	} else if (g_strcmp0 (signal_name, "DeviceChanged") == 0) {
275 		g_variant_get (parameters, "(o)", &object_path_tmp);
276 		device = cd_device_new_with_object_path (object_path_tmp);
277 		g_signal_emit (client, signals[SIGNAL_DEVICE_CHANGED], 0,
278 			       device);
279 	} else if (g_strcmp0 (signal_name, "ProfileAdded") == 0) {
280 		g_variant_get (parameters, "(o)", &object_path_tmp);
281 		profile = cd_profile_new_with_object_path (object_path_tmp);
282 		g_signal_emit (client, signals[SIGNAL_PROFILE_ADDED], 0,
283 			       profile);
284 	} else if (g_strcmp0 (signal_name, "ProfileRemoved") == 0) {
285 		g_variant_get (parameters, "(o)", &object_path_tmp);
286 		profile = cd_profile_new_with_object_path (object_path_tmp);
287 		g_signal_emit (client, signals[SIGNAL_PROFILE_REMOVED], 0,
288 			       profile);
289 	} else if (g_strcmp0 (signal_name, "ProfileChanged") == 0) {
290 		g_variant_get (parameters, "(o)", &object_path_tmp);
291 		profile = cd_profile_new_with_object_path (object_path_tmp);
292 		g_signal_emit (client, signals[SIGNAL_PROFILE_CHANGED], 0,
293 			       profile);
294 	} else if (g_strcmp0 (signal_name, "SensorAdded") == 0) {
295 		g_variant_get (parameters, "(o)", &object_path_tmp);
296 		sensor = cd_sensor_new_with_object_path (object_path_tmp);
297 		g_signal_emit (client, signals[SIGNAL_SENSOR_ADDED], 0,
298 			       sensor);
299 	} else if (g_strcmp0 (signal_name, "SensorRemoved") == 0) {
300 		g_variant_get (parameters, "(o)", &object_path_tmp);
301 		sensor = cd_sensor_new_with_object_path (object_path_tmp);
302 		g_signal_emit (client, signals[SIGNAL_SENSOR_REMOVED], 0,
303 			       sensor);
304 	} else if (g_strcmp0 (signal_name, "SensorChanged") == 0) {
305 		g_variant_get (parameters, "(o)", &object_path_tmp);
306 		sensor = cd_sensor_new_with_object_path (object_path_tmp);
307 		g_signal_emit (client, signals[SIGNAL_SENSOR_CHANGED], 0,
308 			       sensor);
309 	} else {
310 		g_warning ("unhandled signal '%s'", signal_name);
311 	}
312 }
313 
314 /**
315  * cd_client_owner_notify_cb:
316  **/
317 static void
cd_client_owner_notify_cb(GObject * object,GParamSpec * pspec,CdClient * client)318 cd_client_owner_notify_cb (GObject *object,
319 			   GParamSpec *pspec,
320 			   CdClient *client)
321 {
322 	/* daemon has quit, clearing caches */
323 }
324 
325 /**********************************************************************/
326 
327 /**
328  * cd_client_connect_finish:
329  * @client: a #CdClient instance.
330  * @res: the #GAsyncResult
331  * @error: A #GError or %NULL
332  *
333  * Gets the result from the asynchronous function.
334  *
335  * Return value: success
336  *
337  * Since: 0.1.6
338  **/
339 gboolean
cd_client_connect_finish(CdClient * client,GAsyncResult * res,GError ** error)340 cd_client_connect_finish (CdClient *client,
341 			  GAsyncResult *res,
342 			  GError **error)
343 {
344 	g_return_val_if_fail (g_task_is_valid (res, client), FALSE);
345 	return g_task_propagate_boolean (G_TASK (res), error);
346 }
347 
348 static void
cd_client_connect_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)349 cd_client_connect_cb (GObject *source_object,
350 		      GAsyncResult *res,
351 		      gpointer user_data)
352 {
353 	g_autoptr(GError) error = NULL;
354 	g_autoptr(GTask) task = G_TASK (user_data);
355 	g_autoptr(GVariant) daemon_version = NULL;
356 	g_autoptr(GVariant) system_model = NULL;
357 	g_autoptr(GVariant) system_vendor = NULL;
358 	CdClient *client = CD_CLIENT (g_task_get_source_object (task));
359 	CdClientPrivate *priv = GET_PRIVATE (client);
360 
361 	/* get result */
362 	priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
363 	if (priv->proxy == NULL) {
364 		g_task_return_new_error (task,
365 					 CD_CLIENT_ERROR,
366 					 CD_CLIENT_ERROR_INTERNAL,
367 					 "%s",
368 					 error->message);
369 		return;
370 	}
371 
372 	/* get daemon version */
373 	daemon_version = g_dbus_proxy_get_cached_property (priv->proxy,
374 							   CD_CLIENT_PROPERTY_DAEMON_VERSION);
375 	if (daemon_version != NULL) {
376 		g_free (priv->daemon_version);
377 		priv->daemon_version = g_variant_dup_string (daemon_version, NULL);
378 	}
379 
380 	/* get system info */
381 	system_vendor = g_dbus_proxy_get_cached_property (priv->proxy,
382 							  CD_CLIENT_PROPERTY_SYSTEM_VENDOR);
383 	if (system_vendor != NULL) {
384 		g_free (priv->system_vendor);
385 		priv->system_vendor = g_variant_dup_string (system_vendor, NULL);
386 	}
387 
388 	/* get system model */
389 	system_model = g_dbus_proxy_get_cached_property (priv->proxy,
390 							 CD_CLIENT_PROPERTY_SYSTEM_MODEL);
391 	if (system_model != NULL) {
392 		g_free (priv->system_model);
393 		priv->system_model = g_variant_dup_string (system_model, NULL);
394 	}
395 
396 	/* get signals from DBus */
397 	g_signal_connect_object (priv->proxy,
398 				 "g-signal",
399 				 G_CALLBACK (cd_client_dbus_signal_cb),
400 				 client, 0);
401 
402 	/* watch to see if it's fallen off the bus */
403 	g_signal_connect_object (priv->proxy,
404 				 "notify::g-name-owner",
405 				 G_CALLBACK (cd_client_owner_notify_cb),
406 				 client, 0);
407 
408 	/* success */
409 	g_task_return_boolean (task, TRUE);
410 }
411 
412 /**
413  * cd_client_connect:
414  * @client: a #CdClient instance
415  * @cancellable: a #GCancellable or %NULL
416  * @callback: the function to run on completion
417  * @user_data: the data to pass to @callback
418  *
419  * Connects to the colord daemon.
420  *
421  * Since: 0.1.6
422  **/
423 void
cd_client_connect(CdClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)424 cd_client_connect (CdClient *client,
425 		   GCancellable *cancellable,
426 		   GAsyncReadyCallback callback,
427 		   gpointer user_data)
428 {
429 	CdClientPrivate *priv = GET_PRIVATE (client);
430 	GTask *task = NULL;
431 
432 	g_return_if_fail (CD_IS_CLIENT (client));
433 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
434 
435 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
436 
437 	/* already connected */
438 	if (priv->proxy != NULL) {
439 		g_task_return_boolean (task, TRUE);
440 		g_object_unref (task);
441 		return;
442 	}
443 
444 	/* connect async */
445 	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
446 				  G_DBUS_PROXY_FLAGS_NONE,
447 				  NULL,
448 				  COLORD_DBUS_SERVICE,
449 				  COLORD_DBUS_PATH,
450 				  COLORD_DBUS_INTERFACE,
451 				  cancellable,
452 				  cd_client_connect_cb,
453 				  task);
454 }
455 
456 /**********************************************************************/
457 
458 /**
459  * cd_client_create_device_finish:
460  * @client: a #CdClient instance.
461  * @res: the #GAsyncResult
462  * @error: A #GError or %NULL
463  *
464  * Gets the result from the asynchronous function.
465  *
466  * Return value: (transfer full): a #CdDevice or %NULL
467  *
468  * Since: 0.1.8
469  **/
470 CdDevice *
cd_client_create_device_finish(CdClient * client,GAsyncResult * res,GError ** error)471 cd_client_create_device_finish (CdClient *client,
472 				GAsyncResult *res,
473 				GError **error)
474 {
475 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
476 	return g_task_propagate_pointer (G_TASK (res), error);
477 }
478 
479 /**
480  * cd_client_fixup_dbus_error:
481  **/
482 static void
cd_client_fixup_dbus_error(GError * error)483 cd_client_fixup_dbus_error (GError *error)
484 {
485 	g_autofree gchar *name = NULL;
486 
487 	g_return_if_fail (error != NULL);
488 
489 	/* is a remote error? */
490 	if (!g_dbus_error_is_remote_error (error))
491 		return;
492 
493 	/* parse the remote error */
494 	name = g_dbus_error_get_remote_error (error);
495 	error->domain = CD_CLIENT_ERROR;
496 	error->code = cd_client_error_from_string (name);
497 	g_dbus_error_strip_remote_error (error);
498 }
499 
500 static void
cd_client_create_device_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)501 cd_client_create_device_cb (GObject *source_object,
502 			    GAsyncResult *res,
503 			    gpointer user_data)
504 {
505 	CdDevice *device;
506 	g_autoptr(GError) error = NULL;
507 	g_autofree gchar *object_path = NULL;
508 	g_autoptr(GTask) task = G_TASK (user_data);
509 	g_autoptr(GVariant) result = NULL;
510 
511 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
512 					   res,
513 					   &error);
514 	if (result == NULL) {
515 		cd_client_fixup_dbus_error (error);
516 		g_task_return_error (task, error);
517 		error = NULL;
518 		return;
519 	}
520 
521 	/* create CdDevice object */
522 	g_variant_get (result, "(o)", &object_path);
523 	device = cd_device_new ();
524 	cd_device_set_object_path (device, object_path);
525 
526 	/* success */
527 	g_task_return_pointer (task, device, (GDestroyNotify) g_object_unref);
528 }
529 
530 /**
531  * cd_client_create_device:
532  * @client: a #CdClient instance.
533  * @id: identifier for the device
534  * @scope: the scope of the device
535  * @properties: (element-type utf8 utf8) (allow-none): properties to
536  *   set on the device, or %NULL
537  * @cancellable: a #GCancellable, or %NULL
538  * @callback: the function to run on completion
539  * @user_data: the data to pass to @callback
540  *
541  * Creates a color device.
542  *
543  * Since: 0.1.8
544  **/
545 void
cd_client_create_device(CdClient * client,const gchar * id,CdObjectScope scope,GHashTable * properties,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)546 cd_client_create_device (CdClient *client,
547 			 const gchar *id,
548 			 CdObjectScope scope,
549 			 GHashTable *properties,
550 			 GCancellable *cancellable,
551 			 GAsyncReadyCallback callback,
552 			 gpointer user_data)
553 {
554 	CdClientPrivate *priv = GET_PRIVATE (client);
555 	const gchar *value;
556 	GTask *task = NULL;
557 	GVariantBuilder builder;
558 	GList *list, *l;
559 
560 	g_return_if_fail (CD_IS_CLIENT (client));
561 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
562 	g_return_if_fail (priv->proxy != NULL);
563 
564 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
565 
566 	/* add properties */
567 	g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
568 	if (properties != NULL) {
569 		list = g_hash_table_get_keys (properties);
570 		for (l = list; l != NULL; l = l->next) {
571 			value = g_hash_table_lookup (properties, l->data);
572 			g_variant_builder_add (&builder,
573 					       "{ss}",
574 					       l->data,
575 					       value != NULL ? value : "");
576 		}
577 		g_list_free (list);
578 	} else {
579 		/* just fake something here */
580 		g_variant_builder_add (&builder,
581 				       "{ss}",
582 				       CD_DEVICE_PROPERTY_KIND,
583 				       "unknown");
584 	}
585 
586 	g_dbus_proxy_call (priv->proxy,
587 			   "CreateDevice",
588 			   g_variant_new ("(ssa{ss})",
589 					  id,
590 					  cd_object_scope_to_string (scope),
591 					  &builder),
592 			   G_DBUS_CALL_FLAGS_NONE,
593 			   -1,
594 			   cancellable,
595 			   cd_client_create_device_cb,
596 			   task);
597 }
598 
599 /**********************************************************************/
600 
601 /**
602  * cd_client_create_profile_finish:
603  * @client: a #CdClient instance.
604  * @res: the #GAsyncResult
605  * @error: A #GError or %NULL
606  *
607  * Gets the result from the asynchronous function.
608  *
609  * Return value: (transfer full): a #CdProfile or %NULL
610  *
611  * Since: 0.1.8
612  **/
613 CdProfile *
cd_client_create_profile_finish(CdClient * client,GAsyncResult * res,GError ** error)614 cd_client_create_profile_finish (CdClient *client,
615 				 GAsyncResult *res,
616 				 GError **error)
617 {
618 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
619 	return g_task_propagate_pointer (G_TASK (res), error);
620 }
621 
622 static void
cd_client_create_profile_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)623 cd_client_create_profile_cb (GObject *source_object,
624 			     GAsyncResult *res,
625 			     gpointer user_data)
626 {
627 	CdProfile *profile;
628 	g_autoptr(GError) error = NULL;
629 	g_autofree gchar *object_path = NULL;
630 	g_autoptr(GDBusMessage) reply = NULL;
631 	g_autoptr(GTask) task = G_TASK (user_data);
632 
633 	reply = g_dbus_connection_send_message_with_reply_finish (G_DBUS_CONNECTION (source_object),
634 								  res,
635 								  &error);
636 	if (reply == NULL) {
637 		cd_client_fixup_dbus_error (error);
638 		g_task_return_error (task, error);
639 		error = NULL;
640 		return;
641 	}
642 
643 	/* this is an error message */
644 	if (g_dbus_message_get_message_type (reply) == G_DBUS_MESSAGE_TYPE_ERROR) {
645 		g_dbus_message_to_gerror (reply, &error);
646 		cd_client_fixup_dbus_error (error);
647 		g_task_return_error (task, error);
648 		error = NULL;
649 		return;
650 	}
651 
652 	/* create thick CdDevice object */
653 	g_variant_get (g_dbus_message_get_body (reply), "(o)",
654 		       &object_path);
655 	profile = cd_profile_new ();
656 	cd_profile_set_object_path (profile, object_path);
657 
658 	/* success */
659 	g_task_return_pointer (task, profile, (GDestroyNotify) g_object_unref);
660 }
661 
662 /**
663  * cd_client_create_profile:
664  * @client: a #CdClient instance.
665  * @id: identifier for the profile
666  * @scope: the scope of the profile
667  * @properties: (element-type utf8 utf8) (allow-none): properties to
668  *   set on the profile, or %NULL
669  * @cancellable: a #GCancellable, or %NULL
670  * @callback: the function to run on completion
671  * @user_data: the data to pass to @callback
672  *
673  * Creates a color profile.
674  *
675  * Since: 0.1.8
676  **/
677 void
cd_client_create_profile(CdClient * client,const gchar * id,CdObjectScope scope,GHashTable * properties,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)678 cd_client_create_profile (CdClient *client,
679 			  const gchar *id,
680 			  CdObjectScope scope,
681 			  GHashTable *properties,
682 			  GCancellable *cancellable,
683 			  GAsyncReadyCallback callback,
684 			  gpointer user_data)
685 {
686 	CdClientPrivate *priv = GET_PRIVATE (client);
687 	GDBusConnection *connection;
688 	gint fd = -1;
689 	GList *list, *l;
690 	GVariant *body;
691 	GVariantBuilder builder;
692 	GTask *task = NULL;
693 	g_autoptr(GDBusMessage) request = NULL;
694 	g_autoptr(GUnixFDList) fd_list = NULL;
695 
696 	g_return_if_fail (CD_IS_CLIENT (client));
697 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
698 	g_return_if_fail (priv->proxy != NULL);
699 	g_return_if_fail (id != NULL);
700 
701 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
702 
703 	/* add properties */
704 	g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
705 	if (properties != NULL &&
706 	    g_hash_table_size (properties) > 0) {
707 		list = g_hash_table_get_keys (properties);
708 		for (l = list; l != NULL; l = l->next) {
709 			g_variant_builder_add (&builder,
710 					       "{ss}",
711 					       l->data,
712 					       g_hash_table_lookup (properties,
713 								    l->data));
714 		}
715 		g_list_free (list);
716 	} else {
717 		/* just fake something here */
718 		g_variant_builder_add (&builder,
719 				       "{ss}",
720 				       CD_PROFILE_PROPERTY_QUALIFIER,
721 				       "");
722 	}
723 
724 	/* do low level call */
725 	request = g_dbus_message_new_method_call (COLORD_DBUS_SERVICE,
726 						  COLORD_DBUS_PATH,
727 						  COLORD_DBUS_INTERFACE,
728 						  "CreateProfileWithFd");
729 
730 	/* get fd if possible top avoid open() in daemon */
731 #ifdef __unix__
732 	if (properties != NULL) {
733 		const gchar *filename;
734 		filename = g_hash_table_lookup (properties,
735 						CD_PROFILE_PROPERTY_FILENAME);
736 		if (filename != NULL) {
737 			gint retval;
738 			fd = open (filename, O_RDONLY);
739 			if (fd < 0) {
740 				g_task_return_new_error (task,
741 							 CD_CLIENT_ERROR,
742 							 CD_CLIENT_ERROR_INTERNAL,
743 							 "Failed to open %s",
744 							 filename);
745 				return;
746 			}
747 
748 			/* set out of band file descriptor */
749 			fd_list = g_unix_fd_list_new ();
750 			retval = g_unix_fd_list_append (fd_list, fd, NULL);
751 			g_assert (retval != -1);
752 			g_dbus_message_set_unix_fd_list (request, fd_list);
753 
754 			/* g_unix_fd_list_append did a dup() already */
755 			close (fd);
756 		}
757 	}
758 #endif
759 
760 	/* set parameters */
761 	body = g_variant_new ("(ssha{ss})",
762 			      id,
763 			      cd_object_scope_to_string (scope),
764 			      fd > -1 ? 0 : -1,
765 			      &builder);
766 	g_dbus_message_set_body (request, body);
767 
768 	/* send sync message to the bus */
769 	connection = g_dbus_proxy_get_connection (priv->proxy);
770 	g_dbus_connection_send_message_with_reply (connection,
771 						   request,
772 						   G_DBUS_SEND_MESSAGE_FLAGS_NONE,
773 						   CD_CLIENT_MESSAGE_TIMEOUT,
774 						   NULL,
775 						   cancellable,
776 						   cd_client_create_profile_cb,
777 						   task);
778 }
779 
780 /**********************************************************************/
781 /**
782  * cd_client_create_profile_for_icc:
783  * @client: a #CdClient instance.
784  * @icc: #CdIcc object
785  * @scope: the scope of the profile
786  * @cancellable: a #GCancellable, or %NULL
787  * @callback: the function to run on completion
788  * @user_data: the data to pass to @callback
789  *
790  * Creates a color profile for an #CdIcc Object.
791  *
792  * Since: 1.1.1
793  **/
794 void
cd_client_create_profile_for_icc(CdClient * client,CdIcc * icc,CdObjectScope scope,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)795 cd_client_create_profile_for_icc (CdClient *client,
796 				  CdIcc *icc,
797 				  CdObjectScope scope,
798 				  GCancellable *cancellable,
799 				  GAsyncReadyCallback callback,
800 				  gpointer user_data)
801 {
802 	const gchar *checksum;
803 	const gchar *filename;
804 	g_autofree gchar *profile_id = NULL;
805 	g_autoptr(GHashTable) profile_props = NULL;
806 
807 	g_return_if_fail (CD_IS_CLIENT (client));
808 	g_return_if_fail (CD_IS_ICC (icc));
809 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
810 
811 	/* generate ID */
812 	checksum = cd_icc_get_checksum (icc);
813 	filename = cd_icc_get_filename (icc);
814 	profile_id = g_strdup_printf ("icc-%s", checksum);
815 	profile_props = g_hash_table_new_full (g_str_hash, g_str_equal,
816 					       NULL, NULL);
817 	g_hash_table_insert (profile_props,
818 			     (gpointer) CD_PROFILE_PROPERTY_FILENAME,
819 			     (gpointer) filename);
820 	g_hash_table_insert (profile_props,
821 			     (gpointer) CD_PROFILE_METADATA_FILE_CHECKSUM,
822 			     (gpointer) checksum);
823 	cd_client_create_profile (client,
824 				  profile_id,
825 				  scope,
826 				  profile_props,
827 				  NULL,
828 				  callback,
829 				  user_data);
830 }
831 
832 
833 /**
834  * cd_client_create_profile_for_icc_finish:
835  * @client: a #CdClient instance.
836  * @res: the #GAsyncResult
837  * @error: A #GError or %NULL
838  *
839  * Gets the result from the asynchronous function.
840  *
841  * Return value: (transfer full): a #CdProfile or %NULL
842  *
843  * Since: 1.1.1
844  **/
845 CdProfile *
cd_client_create_profile_for_icc_finish(CdClient * client,GAsyncResult * res,GError ** error)846 cd_client_create_profile_for_icc_finish (CdClient *client,
847 					 GAsyncResult *res,
848 					 GError **error)
849 {
850 	return cd_client_create_profile_finish (client, res, error);
851 }
852 
853 /**********************************************************************/
854 
855 /**
856  * cd_client_import_get_profile_destination:
857  **/
858 static GFile *
cd_client_import_get_profile_destination(GFile * file)859 cd_client_import_get_profile_destination (GFile *file)
860 {
861 	g_autofree gchar *basename = NULL;
862 	g_autofree gchar *destination = NULL;
863 
864 	g_return_val_if_fail (file != NULL, NULL);
865 
866 	/* get destination filename for this source file */
867 	basename = g_file_get_basename (file);
868 	destination = g_build_filename (g_get_user_data_dir (), "icc", basename, NULL);
869 	return g_file_new_for_path (destination);
870 }
871 
872 /**
873  * cd_client_import_mkdir_and_copy:
874  **/
875 static gboolean
cd_client_import_mkdir_and_copy(GFile * source,GFile * destination,GCancellable * cancellable,GError ** error)876 cd_client_import_mkdir_and_copy (GFile *source,
877 				 GFile *destination,
878 				 GCancellable *cancellable,
879 				 GError **error)
880 {
881 	g_autoptr(GFile) parent = NULL;
882 
883 	g_return_val_if_fail (source != NULL, FALSE);
884 	g_return_val_if_fail (destination != NULL, FALSE);
885 
886 	/* get parent */
887 	parent = g_file_get_parent (destination);
888 
889 	/* create directory */
890 	if (!g_file_query_exists (parent, cancellable)) {
891 		if (!g_file_make_directory_with_parents (parent, cancellable, error))
892 			return FALSE;
893 	}
894 
895 	/* do the copy */
896 	return g_file_copy (source, destination,
897 			    G_FILE_COPY_OVERWRITE,
898 			    cancellable, NULL, NULL, error);
899 }
900 
901 typedef struct {
902 	GFile			*dest;
903 	GFile			*file;
904 	guint			 hangcheck_id;
905 	guint			 profile_added_id;
906 } CdClientImportTaskData;
907 
908 /**
909  * cd_client_import_profile_finish:
910  * @client: a #CdClient instance.
911  * @res: the #GAsyncResult
912  * @error: A #GError or %NULL
913  *
914  * Gets the result from the asynchronous function.
915  *
916  * Return value: (transfer full): a #CdProfile or %NULL
917  *
918  * Since: 0.1.12
919  **/
920 CdProfile *
cd_client_import_profile_finish(CdClient * client,GAsyncResult * res,GError ** error)921 cd_client_import_profile_finish (CdClient *client,
922 				 GAsyncResult *res,
923 				 GError **error)
924 {
925 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
926 	return g_task_propagate_pointer (G_TASK (res), error);
927 }
928 
929 static void
cd_client_import_task_data_free(CdClientImportTaskData * tdata)930 cd_client_import_task_data_free (CdClientImportTaskData *tdata)
931 {
932 	g_object_unref (tdata->file);
933 	g_object_unref (tdata->dest);
934 //	if (tdata->profile_added_id > 0)
935 //		g_signal_handler_disconnect (tdata->client, tdata->profile_added_id);
936 	if (tdata->hangcheck_id > 0)
937 		g_source_remove (tdata->hangcheck_id);
938 	g_free (tdata);
939 }
940 
941 static void
cd_client_import_profile_added_cb(CdClient * client,CdProfile * profile,gpointer user_data)942 cd_client_import_profile_added_cb (CdClient *client,
943 				   CdProfile *profile,
944 				   gpointer user_data)
945 {
946 	GTask *task = G_TASK (user_data);
947 	g_task_return_pointer (task, g_object_ref (profile), (GDestroyNotify) g_object_unref);
948 	g_object_unref (task);
949 }
950 
951 static gboolean
cd_client_import_hangcheck_cb(gpointer user_data)952 cd_client_import_hangcheck_cb (gpointer user_data)
953 {
954 	GTask *task = G_TASK (user_data);
955 	CdClientImportTaskData *tdata = g_task_get_task_data (task);
956 	g_task_return_new_error (task,
957 				 CD_CLIENT_ERROR,
958 				 CD_CLIENT_ERROR_INTERNAL,
959 				 "The profile was not added in time");
960 	tdata->hangcheck_id = 0;
961 	g_object_unref (task);
962 	return G_SOURCE_REMOVE;
963 }
964 
965 static void
cd_client_import_profile_find_filename_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)966 cd_client_import_profile_find_filename_cb (GObject *source_object,
967 					   GAsyncResult *res,
968 					   gpointer user_data)
969 {
970 	GTask *task = G_TASK (user_data);
971 	CdClient *client = CD_CLIENT (source_object);
972 	CdClientImportTaskData *tdata = g_task_get_task_data (task);
973 	gboolean ret;
974 	g_autoptr(GError) error = NULL;
975 	g_autoptr(CdProfile) profile = NULL;
976 
977 	/* does the profile already exist */
978 	profile = cd_client_find_profile_by_filename_finish (client, res, &error);
979 	if (profile != NULL) {
980 		g_autofree gchar *filename = NULL;
981 		filename = g_file_get_path (tdata->dest);
982 		g_task_return_new_error (task,
983 					 CD_CLIENT_ERROR,
984 					 CD_CLIENT_ERROR_ALREADY_EXISTS,
985 					 "The profile %s already exists",
986 					 filename);
987 		g_object_unref (task);
988 		return;
989 	}
990 	if (!g_error_matches (error,
991 			      CD_CLIENT_ERROR,
992 			      CD_CLIENT_ERROR_NOT_FOUND)) {
993 		cd_client_fixup_dbus_error (error);
994 		g_task_return_error (task, error);
995 		g_object_unref (task);
996 		return;
997 	}
998 
999 	/* reset the error */
1000 	g_clear_error (&error);
1001 
1002 	/* watch for a new profile to be detected and added,
1003 	 * but time out after a couple of seconds */
1004 	tdata->hangcheck_id = g_timeout_add (CD_CLIENT_IMPORT_DAEMON_TIMEOUT,
1005 					     cd_client_import_hangcheck_cb,
1006 					     task);
1007 	tdata->profile_added_id = g_signal_connect (client, "profile-added",
1008 						    G_CALLBACK (cd_client_import_profile_added_cb),
1009 						    task);
1010 
1011 	/* copy profile to the correct place */
1012 	ret = cd_client_import_mkdir_and_copy (tdata->file,
1013 					       tdata->dest,
1014 					       g_task_get_cancellable (task),
1015 					       &error);
1016 	if (!ret) {
1017 		g_task_return_new_error (task,
1018 					 CD_CLIENT_ERROR,
1019 					 CD_CLIENT_ERROR_INTERNAL,
1020 					 "Failed to copy: %s",
1021 					 error->message);
1022 		g_object_unref (task);
1023 	}
1024 }
1025 
1026 static void
cd_client_import_profile_query_info_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1027 cd_client_import_profile_query_info_cb (GObject *source_object,
1028 					GAsyncResult *res,
1029 					gpointer user_data)
1030 {
1031 	GTask *task = G_TASK (user_data);
1032 	CdClient *client = CD_CLIENT (g_task_get_source_object (task));
1033 	CdClientImportTaskData *tdata = g_task_get_task_data (task);
1034 	const gchar *type;
1035 	g_autoptr(GError) error = NULL;
1036 	g_autofree gchar *filename = NULL;
1037 	g_autoptr(GFileInfo) info = NULL;
1038 
1039 	/* get the file info */
1040 	filename = g_file_get_path (tdata->dest);
1041 	info = g_file_query_info_finish (G_FILE (source_object),
1042 					 res,
1043 					 &error);
1044 	if (info == NULL) {
1045 		g_task_return_new_error (task,
1046 					 CD_CLIENT_ERROR,
1047 					 CD_CLIENT_ERROR_INTERNAL,
1048 					 "Cannot get content type for %s: %s",
1049 					 filename,
1050 					 error->message);
1051 		g_object_unref (task);
1052 		return;
1053 	}
1054 
1055 	/* check the content type */
1056 	type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
1057 	if (g_strcmp0 (type, "application/vnd.iccprofile") != 0) {
1058 		g_task_return_new_error (task,
1059 					 CD_CLIENT_ERROR,
1060 					 CD_CLIENT_ERROR_FILE_INVALID,
1061 					 "Incorrect content type for %s, got %s",
1062 					 filename, type);
1063 		g_object_unref (task);
1064 		return;
1065 	}
1066 
1067 	/* does this profile already exist? */
1068 	cd_client_find_profile_by_filename (client,
1069 					    filename,
1070 					    g_task_get_cancellable (task),
1071 					    cd_client_import_profile_find_filename_cb,
1072 					    task);
1073 }
1074 
1075 /**
1076  * cd_client_import_profile:
1077  * @client: a #CdClient instance.
1078  * @file: a #GFile
1079  * @cancellable: a #GCancellable, or %NULL
1080  * @callback: the function to run on completion
1081  * @user_data: the data to pass to @callback
1082  *
1083  * Imports a color profile into the users home directory.
1084  *
1085  * If the profile should be accessable for all users, then call
1086  * cd_profile_install_system_wide() on the result.
1087  *
1088  * Since: 0.1.12
1089  **/
1090 void
cd_client_import_profile(CdClient * client,GFile * file,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1091 cd_client_import_profile (CdClient *client,
1092 			  GFile *file,
1093 			  GCancellable *cancellable,
1094 			  GAsyncReadyCallback callback,
1095 			  gpointer user_data)
1096 {
1097 	CdClientImportTaskData *tdata;
1098 	GTask *task;
1099 
1100 	g_return_if_fail (CD_IS_CLIENT (client));
1101 	g_return_if_fail (G_IS_FILE (file));
1102 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1103 
1104 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1105 	tdata = g_new0 (CdClientImportTaskData, 1);
1106 	tdata->file = g_object_ref (file);
1107 	tdata->dest = cd_client_import_get_profile_destination (file);
1108 	g_task_set_task_data (task, tdata, (GDestroyNotify) cd_client_import_task_data_free);
1109 
1110 	/* check the file really is an ICC file */
1111 	g_file_query_info_async (tdata->file,
1112 				 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1113 				 G_FILE_QUERY_INFO_NONE,
1114 				 G_PRIORITY_DEFAULT,
1115 				 cancellable,
1116 				 cd_client_import_profile_query_info_cb,
1117 				 task);
1118 }
1119 
1120 /**********************************************************************/
1121 
1122 /**
1123  * cd_client_delete_device_finish:
1124  * @client: a #CdClient instance.
1125  * @res: the #GAsyncResult
1126  * @error: A #GError or %NULL
1127  *
1128  * Gets the result from the asynchronous function.
1129  *
1130  * Return value: success
1131  *
1132  * Since: 0.1.8
1133  **/
1134 gboolean
cd_client_delete_device_finish(CdClient * client,GAsyncResult * res,GError ** error)1135 cd_client_delete_device_finish (CdClient *client,
1136 				GAsyncResult *res,
1137 				GError **error)
1138 {
1139 	g_return_val_if_fail (g_task_is_valid (res, client), FALSE);
1140 	return g_task_propagate_boolean (G_TASK (res), error);
1141 }
1142 
1143 static void
cd_client_delete_device_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1144 cd_client_delete_device_cb (GObject *source_object,
1145 			    GAsyncResult *res,
1146 			    gpointer user_data)
1147 {
1148 	g_autoptr(GError) error = NULL;
1149 	g_autoptr(GTask) task = G_TASK (user_data);
1150 	g_autoptr(GVariant) result = NULL;
1151 
1152 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1153 					   res,
1154 					   &error);
1155 	if (result == NULL) {
1156 		cd_client_fixup_dbus_error (error);
1157 		g_task_return_error (task, error);
1158 		error = NULL;
1159 		return;
1160 	}
1161 
1162 	/* success */
1163 	g_task_return_boolean (task, TRUE);
1164 }
1165 
1166 /**
1167  * cd_client_delete_device:
1168  * @client: a #CdClient instance.
1169  * @device: a #CdDevice
1170  * @cancellable: a #GCancellable, or %NULL
1171  * @callback: the function to run on completion
1172  * @user_data: the data to pass to @callback
1173  *
1174  * Deletes a device.
1175  *
1176  * Since: 0.1.8
1177  **/
1178 void
cd_client_delete_device(CdClient * client,CdDevice * device,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1179 cd_client_delete_device (CdClient *client,
1180 			 CdDevice *device,
1181 			 GCancellable *cancellable,
1182 			 GAsyncReadyCallback callback,
1183 			 gpointer user_data)
1184 {
1185 	CdClientPrivate *priv = GET_PRIVATE (client);
1186 	GTask *task = NULL;
1187 
1188 	g_return_if_fail (CD_IS_CLIENT (client));
1189 	g_return_if_fail (CD_IS_DEVICE (device));
1190 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1191 	g_return_if_fail (priv->proxy != NULL);
1192 
1193 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1194 	g_dbus_proxy_call (priv->proxy,
1195 			   "DeleteDevice",
1196 			   g_variant_new ("(o)",
1197 			   		  cd_device_get_object_path (device)),
1198 			   G_DBUS_CALL_FLAGS_NONE,
1199 			   -1,
1200 			   cancellable,
1201 			   cd_client_delete_device_cb,
1202 			   task);
1203 }
1204 
1205 /**********************************************************************/
1206 
1207 /**
1208  * cd_client_delete_profile_finish:
1209  * @client: a #CdClient instance.
1210  * @res: the #GAsyncResult
1211  * @error: A #GError or %NULL
1212  *
1213  * Gets the result from the asynchronous function.
1214  *
1215  * Return value: success
1216  *
1217  * Since: 0.1.8
1218  **/
1219 gboolean
cd_client_delete_profile_finish(CdClient * client,GAsyncResult * res,GError ** error)1220 cd_client_delete_profile_finish (CdClient *client,
1221 				 GAsyncResult *res,
1222 				 GError **error)
1223 {
1224 	g_return_val_if_fail (g_task_is_valid (res, client), FALSE);
1225 	return g_task_propagate_boolean (G_TASK (res), error);
1226 }
1227 
1228 static void
cd_client_delete_profile_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1229 cd_client_delete_profile_cb (GObject *source_object,
1230 			    GAsyncResult *res,
1231 			    gpointer user_data)
1232 {
1233 	g_autoptr(GError) error = NULL;
1234 	g_autoptr(GTask) task = G_TASK (user_data);
1235 	g_autoptr(GVariant) result = NULL;
1236 
1237 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1238 					   res,
1239 					   &error);
1240 	if (result == NULL) {
1241 		cd_client_fixup_dbus_error (error);
1242 		g_task_return_error (task, error);
1243 		error = NULL;
1244 		return;
1245 	}
1246 
1247 	/* success */
1248 	g_task_return_boolean (task, TRUE);
1249 }
1250 
1251 /**
1252  * cd_client_delete_profile:
1253  * @client: a #CdClient instance.
1254  * @profile: a #CdProfile
1255  * @cancellable: a #GCancellable, or %NULL
1256  * @callback: the function to run on completion
1257  * @user_data: the data to pass to @callback
1258  *
1259  * Deletes a profile.
1260  *
1261  * Since: 0.1.8
1262  **/
1263 void
cd_client_delete_profile(CdClient * client,CdProfile * profile,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1264 cd_client_delete_profile (CdClient *client,
1265 			  CdProfile *profile,
1266 			  GCancellable *cancellable,
1267 			  GAsyncReadyCallback callback,
1268 			  gpointer user_data)
1269 {
1270 	CdClientPrivate *priv = GET_PRIVATE (client);
1271 	GTask *task = NULL;
1272 
1273 	g_return_if_fail (CD_IS_CLIENT (client));
1274 	g_return_if_fail (CD_IS_PROFILE (profile));
1275 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1276 	g_return_if_fail (priv->proxy != NULL);
1277 
1278 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1279 	g_dbus_proxy_call (priv->proxy,
1280 			   "DeleteProfile",
1281 			   g_variant_new ("(o)",
1282 			   		  cd_profile_get_object_path (profile)),
1283 			   G_DBUS_CALL_FLAGS_NONE,
1284 			   -1,
1285 			   cancellable,
1286 			   cd_client_delete_profile_cb,
1287 			   task);
1288 }
1289 
1290 /**********************************************************************/
1291 
1292 /**
1293  * cd_client_find_device_finish:
1294  * @client: a #CdClient instance.
1295  * @res: the #GAsyncResult
1296  * @error: A #GError or %NULL
1297  *
1298  * Gets the result from the asynchronous function.
1299  *
1300  * Return value: (transfer full): a #CdDevice or %NULL
1301  *
1302  * Since: 0.1.8
1303  **/
1304 CdDevice *
cd_client_find_device_finish(CdClient * client,GAsyncResult * res,GError ** error)1305 cd_client_find_device_finish (CdClient *client,
1306 			      GAsyncResult *res,
1307 			      GError **error)
1308 {
1309 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
1310 	return g_task_propagate_pointer (G_TASK (res), error);
1311 }
1312 
1313 static void
cd_client_find_device_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1314 cd_client_find_device_cb (GObject *source_object,
1315 			    GAsyncResult *res,
1316 			    gpointer user_data)
1317 {
1318 	CdDevice *device;
1319 	g_autoptr(GError) error = NULL;
1320 	g_autofree gchar *object_path = NULL;
1321 	g_autoptr(GTask) task = G_TASK (user_data);
1322 	g_autoptr(GVariant) result = NULL;
1323 
1324 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1325 					   res,
1326 					   &error);
1327 	if (result == NULL) {
1328 		cd_client_fixup_dbus_error (error);
1329 		g_task_return_error (task, error);
1330 		error = NULL;
1331 		return;
1332 	}
1333 
1334 	/* create a device object */
1335 	g_variant_get (result, "(o)", &object_path);
1336 	device = cd_device_new ();
1337 	cd_device_set_object_path (device, object_path);
1338 
1339 	/* success */
1340 	g_task_return_pointer (task, device, (GDestroyNotify) g_object_unref);
1341 }
1342 
1343 /**
1344  * cd_client_find_device:
1345  * @client: a #CdClient instance.
1346  * @id: a device id
1347  * @cancellable: a #GCancellable, or %NULL
1348  * @callback: the function to run on completion
1349  * @user_data: the data to pass to @callback
1350  *
1351  * Finds a device by an ID.
1352  *
1353  * Since: 0.1.8
1354  **/
1355 void
cd_client_find_device(CdClient * client,const gchar * id,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1356 cd_client_find_device (CdClient *client,
1357 		       const gchar *id,
1358 		       GCancellable *cancellable,
1359 		       GAsyncReadyCallback callback,
1360 		       gpointer user_data)
1361 {
1362 	CdClientPrivate *priv = GET_PRIVATE (client);
1363 	GTask *task = NULL;
1364 
1365 	g_return_if_fail (CD_IS_CLIENT (client));
1366 	g_return_if_fail (id != NULL);
1367 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1368 	g_return_if_fail (priv->proxy != NULL);
1369 
1370 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1371 	g_dbus_proxy_call (priv->proxy,
1372 			   "FindDeviceById",
1373 			   g_variant_new ("(s)", id),
1374 			   G_DBUS_CALL_FLAGS_NONE,
1375 			   -1,
1376 			   cancellable,
1377 			   cd_client_find_device_cb,
1378 			   task);
1379 }
1380 
1381 /**********************************************************************/
1382 
1383 /**
1384  * cd_client_find_device_by_property_finish:
1385  * @client: a #CdClient instance.
1386  * @res: the #GAsyncResult
1387  * @error: A #GError or %NULL
1388  *
1389  * Gets the result from the asynchronous function.
1390  *
1391  * Return value: (transfer full): a #CdDevice or %NULL
1392  *
1393  * Since: 0.1.8
1394  **/
1395 CdDevice *
cd_client_find_device_by_property_finish(CdClient * client,GAsyncResult * res,GError ** error)1396 cd_client_find_device_by_property_finish (CdClient *client,
1397 					  GAsyncResult *res,
1398 					  GError **error)
1399 {
1400 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
1401 	return g_task_propagate_pointer (G_TASK (res), error);
1402 }
1403 
1404 static void
cd_client_find_device_by_property_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1405 cd_client_find_device_by_property_cb (GObject *source_object,
1406 				      GAsyncResult *res,
1407 				      gpointer user_data)
1408 {
1409 	CdDevice *device;
1410 	g_autoptr(GError) error = NULL;
1411 	g_autofree gchar *object_path = NULL;
1412 	g_autoptr(GTask) task = G_TASK (user_data);
1413 	g_autoptr(GVariant) result = NULL;
1414 
1415 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1416 					   res,
1417 					   &error);
1418 	if (result == NULL) {
1419 		cd_client_fixup_dbus_error (error);
1420 		g_task_return_error (task, error);
1421 		error = NULL;
1422 		return;
1423 	}
1424 
1425 	/* create a device object */
1426 	g_variant_get (result, "(o)", &object_path);
1427 	device = cd_device_new ();
1428 	cd_device_set_object_path (device, object_path);
1429 
1430 	/* success */
1431 	g_task_return_pointer (task, device, (GDestroyNotify) g_object_unref);
1432 }
1433 
1434 /**
1435  * cd_client_find_device_by_property:
1436  * @client: a #CdClient instance.
1437  * @key: the device property key
1438  * @value: the device property value
1439  * @cancellable: a #GCancellable, or %NULL
1440  * @callback: the function to run on completion
1441  * @user_data: the data to pass to @callback
1442  *
1443  * Finds a color device that has a property value.
1444  *
1445  * Since: 0.1.8
1446  **/
1447 void
cd_client_find_device_by_property(CdClient * client,const gchar * key,const gchar * value,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1448 cd_client_find_device_by_property (CdClient *client,
1449 				   const gchar *key,
1450 				   const gchar *value,
1451 				   GCancellable *cancellable,
1452 				   GAsyncReadyCallback callback,
1453 				   gpointer user_data)
1454 {
1455 	CdClientPrivate *priv = GET_PRIVATE (client);
1456 	GTask *task = NULL;
1457 
1458 	g_return_if_fail (CD_IS_CLIENT (client));
1459 	g_return_if_fail (key != NULL);
1460 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1461 	g_return_if_fail (priv->proxy != NULL);
1462 
1463 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1464 	g_dbus_proxy_call (priv->proxy,
1465 			   "FindDeviceByProperty",
1466 			   g_variant_new ("(ss)", key, value),
1467 			   G_DBUS_CALL_FLAGS_NONE,
1468 			   -1,
1469 			   cancellable,
1470 			   cd_client_find_device_by_property_cb,
1471 			   task);
1472 }
1473 
1474 /**********************************************************************/
1475 
1476 /**
1477  * cd_client_find_profile_finish:
1478  * @client: a #CdClient instance.
1479  * @res: the #GAsyncResult
1480  * @error: A #GError or %NULL
1481  *
1482  * Gets the result from the asynchronous function.
1483  *
1484  * Return value: (transfer full): a #CdProfile or %NULL
1485  *
1486  * Since: 0.1.8
1487  **/
1488 CdProfile *
cd_client_find_profile_finish(CdClient * client,GAsyncResult * res,GError ** error)1489 cd_client_find_profile_finish (CdClient *client,
1490 			       GAsyncResult *res,
1491 			       GError **error)
1492 {
1493 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
1494 	return g_task_propagate_pointer (G_TASK (res), error);
1495 }
1496 
1497 static void
cd_client_find_profile_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1498 cd_client_find_profile_cb (GObject *source_object,
1499 			   GAsyncResult *res,
1500 			   gpointer user_data)
1501 {
1502 	CdProfile *profile;
1503 	g_autoptr(GError) error = NULL;
1504 	g_autofree gchar *object_path = NULL;
1505 	g_autoptr(GTask) task = G_TASK (user_data);
1506 	g_autoptr(GVariant) result = NULL;
1507 
1508 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1509 					   res,
1510 					   &error);
1511 	if (result == NULL) {
1512 		cd_client_fixup_dbus_error (error);
1513 		g_task_return_error (task, error);
1514 		error = NULL;
1515 		return;
1516 	}
1517 
1518 	/* create a profile object */
1519 	g_variant_get (result, "(o)", &object_path);
1520 	profile = cd_profile_new ();
1521 	cd_profile_set_object_path (profile, object_path);
1522 
1523 	/* success */
1524 	g_task_return_pointer (task, profile, (GDestroyNotify) g_object_unref);
1525 }
1526 
1527 /**
1528  * cd_client_find_profile:
1529  * @client: a #CdClient instance.
1530  * @id: a profile id
1531  * @cancellable: a #GCancellable, or %NULL
1532  * @callback: the function to run on completion
1533  * @user_data: the data to pass to @callback
1534  *
1535  * Finds a profile by an ID.
1536  *
1537  * Since: 0.1.8
1538  **/
1539 void
cd_client_find_profile(CdClient * client,const gchar * id,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1540 cd_client_find_profile (CdClient *client,
1541 			const gchar *id,
1542 			GCancellable *cancellable,
1543 			GAsyncReadyCallback callback,
1544 			gpointer user_data)
1545 {
1546 	CdClientPrivate *priv = GET_PRIVATE (client);
1547 	GTask *task = NULL;
1548 
1549 	g_return_if_fail (CD_IS_CLIENT (client));
1550 	g_return_if_fail (id != NULL);
1551 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1552 	g_return_if_fail (priv->proxy != NULL);
1553 
1554 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1555 	g_dbus_proxy_call (priv->proxy,
1556 			   "FindProfileById",
1557 			   g_variant_new ("(s)", id),
1558 			   G_DBUS_CALL_FLAGS_NONE,
1559 			   -1,
1560 			   cancellable,
1561 			   cd_client_find_profile_cb,
1562 			   task);
1563 }
1564 
1565 /**********************************************************************/
1566 
1567 /**
1568  * cd_client_find_profile_by_filename_finish:
1569  * @client: a #CdClient instance.
1570  * @res: the #GAsyncResult
1571  * @error: A #GError or %NULL
1572  *
1573  * Gets the result from the asynchronous function.
1574  *
1575  * Return value: (transfer full): a #CdProfile or %NULL
1576  *
1577  * Since: 0.1.8
1578  **/
1579 CdProfile *
cd_client_find_profile_by_filename_finish(CdClient * client,GAsyncResult * res,GError ** error)1580 cd_client_find_profile_by_filename_finish (CdClient *client,
1581 					   GAsyncResult *res,
1582 					   GError **error)
1583 {
1584 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
1585 	return g_task_propagate_pointer (G_TASK (res), error);
1586 }
1587 
1588 static void
cd_client_find_profile_by_filename_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1589 cd_client_find_profile_by_filename_cb (GObject *source_object,
1590 				       GAsyncResult *res,
1591 				       gpointer user_data)
1592 {
1593 	CdProfile *profile;
1594 	g_autoptr(GError) error = NULL;
1595 	g_autofree gchar *object_path = NULL;
1596 	g_autoptr(GTask) task = G_TASK (user_data);
1597 	g_autoptr(GVariant) result = NULL;
1598 
1599 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1600 					   res,
1601 					   &error);
1602 	if (result == NULL) {
1603 		cd_client_fixup_dbus_error (error);
1604 		g_task_return_error (task, error);
1605 		error = NULL;
1606 		return;
1607 	}
1608 
1609 	/* create a profile object */
1610 	g_variant_get (result, "(o)", &object_path);
1611 	profile = cd_profile_new ();
1612 	cd_profile_set_object_path (profile, object_path);
1613 
1614 	/* success */
1615 	g_task_return_pointer (task, profile, (GDestroyNotify) g_object_unref);
1616 }
1617 
1618 /**
1619  * cd_client_find_profile_by_filename:
1620  * @client: a #CdClient instance.
1621  * @filename: a profile filename
1622  * @cancellable: a #GCancellable, or %NULL
1623  * @callback: the function to run on completion
1624  * @user_data: the data to pass to @callback
1625  *
1626  * Finds a profile by a filename.
1627  *
1628  * Since: 0.1.8
1629  **/
1630 void
cd_client_find_profile_by_filename(CdClient * client,const gchar * filename,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1631 cd_client_find_profile_by_filename (CdClient *client,
1632 				    const gchar *filename,
1633 				    GCancellable *cancellable,
1634 				    GAsyncReadyCallback callback,
1635 				    gpointer user_data)
1636 {
1637 	CdClientPrivate *priv = GET_PRIVATE (client);
1638 	GTask *task = NULL;
1639 
1640 	g_return_if_fail (CD_IS_CLIENT (client));
1641 	g_return_if_fail (filename != NULL);
1642 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1643 	g_return_if_fail (priv->proxy != NULL);
1644 
1645 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1646 	g_dbus_proxy_call (priv->proxy,
1647 			   "FindProfileByFilename",
1648 			   g_variant_new ("(s)", filename),
1649 			   G_DBUS_CALL_FLAGS_NONE,
1650 			   -1,
1651 			   cancellable,
1652 			   cd_client_find_profile_by_filename_cb,
1653 			   task);
1654 }
1655 
1656 /**********************************************************************/
1657 
1658 /**
1659  * cd_client_get_standard_space_finish:
1660  * @client: a #CdClient instance.
1661  * @res: the #GAsyncResult
1662  * @error: A #GError or %NULL
1663  *
1664  * Gets the result from the asynchronous function.
1665  *
1666  * Return value: (transfer full): a #CdProfile or %NULL
1667  *
1668  * Since: 0.1.8
1669  **/
1670 CdProfile *
cd_client_get_standard_space_finish(CdClient * client,GAsyncResult * res,GError ** error)1671 cd_client_get_standard_space_finish (CdClient *client,
1672 				     GAsyncResult *res,
1673 				     GError **error)
1674 {
1675 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
1676 	return g_task_propagate_pointer (G_TASK (res), error);
1677 }
1678 
1679 static void
cd_client_get_standard_space_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1680 cd_client_get_standard_space_cb (GObject *source_object,
1681 				 GAsyncResult *res,
1682 				 gpointer user_data)
1683 {
1684 	CdProfile *profile;
1685 	g_autoptr(GError) error = NULL;
1686 	g_autofree gchar *object_path = NULL;
1687 	g_autoptr(GTask) task = G_TASK (user_data);
1688 	g_autoptr(GVariant) result = NULL;
1689 
1690 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1691 					   res,
1692 					   &error);
1693 	if (result == NULL) {
1694 		cd_client_fixup_dbus_error (error);
1695 		g_task_return_error (task, error);
1696 		error = NULL;
1697 		return;
1698 	}
1699 
1700 	/* create a profile object */
1701 	g_variant_get (result, "(o)", &object_path);
1702 	profile = cd_profile_new ();
1703 	cd_profile_set_object_path (profile, object_path);
1704 
1705 	/* success */
1706 	g_task_return_pointer (task, profile, (GDestroyNotify) g_object_unref);
1707 }
1708 
1709 /**
1710  * cd_client_get_standard_space:
1711  * @client: a #CdStandardSpace instance.
1712  * @standard_space: a profile id
1713  * @cancellable: a #GCancellable, or %NULL
1714  * @callback: the function to run on completion
1715  * @user_data: the data to pass to @callback
1716  *
1717  * Finds a standard profile space.
1718  *
1719  * Since: 0.1.8
1720  **/
1721 void
cd_client_get_standard_space(CdClient * client,CdStandardSpace standard_space,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1722 cd_client_get_standard_space (CdClient *client,
1723 			      CdStandardSpace standard_space,
1724 			      GCancellable *cancellable,
1725 			      GAsyncReadyCallback callback,
1726 			      gpointer user_data)
1727 {
1728 	CdClientPrivate *priv = GET_PRIVATE (client);
1729 	GTask *task = NULL;
1730 
1731 	g_return_if_fail (CD_IS_CLIENT (client));
1732 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1733 	g_return_if_fail (priv->proxy != NULL);
1734 
1735 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1736 	g_dbus_proxy_call (priv->proxy,
1737 			   "GetStandardSpace",
1738 			   g_variant_new ("(s)",
1739 			   		  cd_standard_space_to_string (standard_space)),
1740 			   G_DBUS_CALL_FLAGS_NONE,
1741 			   -1,
1742 			   cancellable,
1743 			   cd_client_get_standard_space_cb,
1744 			   task);
1745 }
1746 
1747 /**********************************************************************/
1748 
1749 /**
1750  * cd_client_get_device_array_from_variant:
1751  **/
1752 static GPtrArray *
cd_client_get_device_array_from_variant(CdClient * client,GVariant * result)1753 cd_client_get_device_array_from_variant (CdClient *client,
1754 					 GVariant *result)
1755 {
1756 	CdDevice *device;
1757 	GPtrArray *array = NULL;
1758 	GVariantIter iter;
1759 	guint i;
1760 	guint len;
1761 	g_autoptr(GVariant) child = NULL;
1762 
1763 	/* add each device */
1764 	array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
1765 	child = g_variant_get_child_value (result, 0);
1766 	len = g_variant_iter_init (&iter, child);
1767 	for (i = 0; i < len; i++) {
1768 		g_autofree gchar *object_path_tmp = NULL;
1769 		g_variant_get_child (child, i,
1770 				     "o", &object_path_tmp);
1771 		device = cd_device_new_with_object_path (object_path_tmp);
1772 		g_ptr_array_add (array, device);
1773 	}
1774 	return array;
1775 }
1776 
1777 /**
1778  * cd_client_get_devices_finish:
1779  * @client: a #CdClient instance.
1780  * @res: the #GAsyncResult
1781  * @error: A #GError or %NULL
1782  *
1783  * Gets the result from the asynchronous function.
1784  *
1785  * Return value: (element-type CdDevice) (transfer full): the devices
1786  *
1787  * Since: 0.1.8
1788  **/
1789 GPtrArray *
cd_client_get_devices_finish(CdClient * client,GAsyncResult * res,GError ** error)1790 cd_client_get_devices_finish (CdClient *client,
1791 			      GAsyncResult *res,
1792 			      GError **error)
1793 {
1794 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
1795 	return g_task_propagate_pointer (G_TASK (res), error);
1796 }
1797 
1798 static void
cd_client_get_devices_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1799 cd_client_get_devices_cb (GObject *source_object,
1800 			  GAsyncResult *res,
1801 			  gpointer user_data)
1802 {
1803 	CdClient *client;
1804 	GPtrArray *array;
1805 	g_autoptr(GError) error = NULL;
1806 	g_autofree gchar *object_path = NULL;
1807 	g_autoptr(GTask) task = G_TASK (user_data);
1808 	g_autoptr(GVariant) result = NULL;
1809 
1810 	client = CD_CLIENT (g_task_get_source_object (task));
1811 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1812 					   res,
1813 					   &error);
1814 	if (result == NULL) {
1815 		cd_client_fixup_dbus_error (error);
1816 		g_task_return_error (task, error);
1817 		error = NULL;
1818 		return;
1819 	}
1820 
1821 	/* create a profile object */
1822 	array = cd_client_get_device_array_from_variant (client, result);
1823 
1824 	/* success */
1825 	g_task_return_pointer (task, array, (GDestroyNotify) g_ptr_array_unref);
1826 }
1827 
1828 /**
1829  * cd_client_get_devices:
1830  * @client: a #CdClient instance.
1831  * @cancellable: a #GCancellable, or %NULL
1832  * @callback: the function to run on completion
1833  * @user_data: the data to pass to @callback
1834  *
1835  * Gets an array of color devices.
1836  *
1837  * Since: 0.1.8
1838  **/
1839 void
cd_client_get_devices(CdClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1840 cd_client_get_devices (CdClient *client,
1841 		       GCancellable *cancellable,
1842 		       GAsyncReadyCallback callback,
1843 		       gpointer user_data)
1844 {
1845 	CdClientPrivate *priv = GET_PRIVATE (client);
1846 	GTask *task = NULL;
1847 
1848 	g_return_if_fail (CD_IS_CLIENT (client));
1849 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1850 	g_return_if_fail (priv->proxy != NULL);
1851 
1852 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1853 	g_dbus_proxy_call (priv->proxy,
1854 			   "GetDevices",
1855 			   NULL,
1856 			   G_DBUS_CALL_FLAGS_NONE,
1857 			   -1,
1858 			   cancellable,
1859 			   cd_client_get_devices_cb,
1860 			   task);
1861 }
1862 
1863 /**********************************************************************/
1864 
1865 /**
1866  * cd_client_get_devices_by_kind_finish:
1867  * @client: a #CdClient instance.
1868  * @res: the #GAsyncResult
1869  * @error: A #GError or %NULL
1870  *
1871  * Gets the result from the asynchronous function.
1872  *
1873  * Return value: (element-type CdDevice) (transfer full): the devices
1874  *
1875  * Since: 0.1.8
1876  **/
1877 GPtrArray *
cd_client_get_devices_by_kind_finish(CdClient * client,GAsyncResult * res,GError ** error)1878 cd_client_get_devices_by_kind_finish (CdClient *client,
1879 				      GAsyncResult *res,
1880 				      GError **error)
1881 {
1882 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
1883 	return g_task_propagate_pointer (G_TASK (res), error);
1884 }
1885 
1886 static void
cd_client_get_devices_by_kind_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1887 cd_client_get_devices_by_kind_cb (GObject *source_object,
1888 				  GAsyncResult *res,
1889 				  gpointer user_data)
1890 {
1891 	CdClient *client;
1892 	GPtrArray *array;
1893 	g_autoptr(GError) error = NULL;
1894 	g_autofree gchar *object_path = NULL;
1895 	g_autoptr(GTask) task = G_TASK (user_data);
1896 	g_autoptr(GVariant) result = NULL;
1897 
1898 	client = CD_CLIENT (g_task_get_source_object (task));
1899 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
1900 					   res,
1901 					   &error);
1902 	if (result == NULL) {
1903 		cd_client_fixup_dbus_error (error);
1904 		g_task_return_error (task, error);
1905 		error = NULL;
1906 		return;
1907 	}
1908 
1909 	/* create a profile object */
1910 	array = cd_client_get_device_array_from_variant (client, result);
1911 
1912 	/* success */
1913 	g_task_return_pointer (task, array, (GDestroyNotify) g_ptr_array_unref);
1914 }
1915 
1916 /**
1917  * cd_client_get_devices_by_kind:
1918  * @client: a #CdClient instance.
1919  * @kind: the type of device.
1920  * @cancellable: a #GCancellable, or %NULL
1921  * @callback: the function to run on completion
1922  * @user_data: the data to pass to @callback
1923  *
1924  * Gets an array of color devices.
1925  *
1926  * Since: 0.1.8
1927  **/
1928 void
cd_client_get_devices_by_kind(CdClient * client,CdDeviceKind kind,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1929 cd_client_get_devices_by_kind (CdClient *client,
1930 			       CdDeviceKind kind,
1931 			       GCancellable *cancellable,
1932 			       GAsyncReadyCallback callback,
1933 			       gpointer user_data)
1934 {
1935 	CdClientPrivate *priv = GET_PRIVATE (client);
1936 	GTask *task = NULL;
1937 
1938 	g_return_if_fail (CD_IS_CLIENT (client));
1939 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1940 	g_return_if_fail (priv->proxy != NULL);
1941 
1942 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
1943 	g_dbus_proxy_call (priv->proxy,
1944 			   "GetDevicesByKind",
1945 			   g_variant_new ("(s)",
1946 			   		  cd_device_kind_to_string (kind)),
1947 			   G_DBUS_CALL_FLAGS_NONE,
1948 			   -1,
1949 			   cancellable,
1950 			   cd_client_get_devices_by_kind_cb,
1951 			   task);
1952 }
1953 
1954 /**********************************************************************/
1955 
1956 /**
1957  * cd_client_get_profile_array_from_variant:
1958  **/
1959 static GPtrArray *
cd_client_get_profile_array_from_variant(CdClient * client,GVariant * result)1960 cd_client_get_profile_array_from_variant (CdClient *client,
1961 					 GVariant *result)
1962 {
1963 	CdProfile *profile;
1964 	GPtrArray *array = NULL;
1965 	GVariantIter iter;
1966 	guint i;
1967 	guint len;
1968 	g_autoptr(GVariant) child = NULL;
1969 
1970 	/* add each profile */
1971 	array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
1972 	child = g_variant_get_child_value (result, 0);
1973 	len = g_variant_iter_init (&iter, child);
1974 	for (i = 0; i < len; i++) {
1975 		g_autofree gchar *object_path_tmp = NULL;
1976 		g_variant_get_child (child, i,
1977 				     "o", &object_path_tmp);
1978 		profile = cd_profile_new_with_object_path (object_path_tmp);
1979 		g_ptr_array_add (array, profile);
1980 	}
1981 	return array;
1982 }
1983 
1984 /**
1985  * cd_client_get_profiles_finish:
1986  * @client: a #CdClient instance.
1987  * @res: the #GAsyncResult
1988  * @error: A #GError or %NULL
1989  *
1990  * Gets the result from the asynchronous function.
1991  *
1992  * Return value: (element-type CdProfile) (transfer full): the profiles
1993  *
1994  * Since: 0.1.8
1995  **/
1996 GPtrArray *
cd_client_get_profiles_finish(CdClient * client,GAsyncResult * res,GError ** error)1997 cd_client_get_profiles_finish (CdClient *client,
1998 			       GAsyncResult *res,
1999 			       GError **error)
2000 {
2001 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
2002 	return g_task_propagate_pointer (G_TASK (res), error);
2003 }
2004 
2005 static void
cd_client_get_profiles_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2006 cd_client_get_profiles_cb (GObject *source_object,
2007 			   GAsyncResult *res,
2008 			   gpointer user_data)
2009 {
2010 	CdClient *client;
2011 	GPtrArray *array;
2012 	g_autoptr(GError) error = NULL;
2013 	g_autofree gchar *object_path = NULL;
2014 	g_autoptr(GTask) task = G_TASK (user_data);
2015 	g_autoptr(GVariant) result = NULL;
2016 
2017 	client = CD_CLIENT (g_task_get_source_object (task));
2018 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
2019 					   res,
2020 					   &error);
2021 	if (result == NULL) {
2022 		cd_client_fixup_dbus_error (error);
2023 		g_task_return_error (task, error);
2024 		error = NULL;
2025 		return;
2026 	}
2027 
2028 	/* create a profile object */
2029 	array = cd_client_get_profile_array_from_variant (client, result);
2030 
2031 	/* success */
2032 	g_task_return_pointer (task, array, (GDestroyNotify) g_ptr_array_unref);
2033 }
2034 
2035 /**
2036  * cd_client_get_profiles:
2037  * @client: a #CdClient instance.
2038  * @cancellable: a #GCancellable, or %NULL
2039  * @callback: the function to run on completion
2040  * @user_data: the data to pass to @callback
2041  *
2042  * Gets an array of color profiles.
2043  *
2044  * Since: 0.1.8
2045  **/
2046 void
cd_client_get_profiles(CdClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2047 cd_client_get_profiles (CdClient *client,
2048 			GCancellable *cancellable,
2049 			GAsyncReadyCallback callback,
2050 			gpointer user_data)
2051 {
2052 	CdClientPrivate *priv = GET_PRIVATE (client);
2053 	GTask *task = NULL;
2054 
2055 	g_return_if_fail (CD_IS_CLIENT (client));
2056 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2057 	g_return_if_fail (priv->proxy != NULL);
2058 
2059 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
2060 	g_dbus_proxy_call (priv->proxy,
2061 			   "GetProfiles",
2062 			   NULL,
2063 			   G_DBUS_CALL_FLAGS_NONE,
2064 			   -1,
2065 			   cancellable,
2066 			   cd_client_get_profiles_cb,
2067 			   task);
2068 }
2069 
2070 /**********************************************************************/
2071 
2072 /**
2073  * cd_client_get_sensor_array_from_variant:
2074  **/
2075 static GPtrArray *
cd_client_get_sensor_array_from_variant(CdClient * client,GVariant * result)2076 cd_client_get_sensor_array_from_variant (CdClient *client,
2077 					 GVariant *result)
2078 {
2079 	CdSensor *sensor;
2080 	GPtrArray *array = NULL;
2081 	GVariantIter iter;
2082 	guint i;
2083 	guint len;
2084 	g_autoptr(GVariant) child = NULL;
2085 
2086 	/* add each sensor */
2087 	array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
2088 	child = g_variant_get_child_value (result, 0);
2089 	len = g_variant_iter_init (&iter, child);
2090 	for (i = 0; i < len; i++) {
2091 		g_autofree gchar *object_path_tmp = NULL;
2092 		g_variant_get_child (child, i,
2093 				     "o", &object_path_tmp);
2094 		sensor = cd_sensor_new_with_object_path (object_path_tmp);
2095 		g_ptr_array_add (array, sensor);
2096 	}
2097 	return array;
2098 }
2099 
2100 /**
2101  * cd_client_get_sensors_finish:
2102  * @client: a #CdClient instance.
2103  * @res: the #GAsyncResult
2104  * @error: A #GError or %NULL
2105  *
2106  * Gets the result from the asynchronous function.
2107  *
2108  * Return value: (element-type CdSensor) (transfer full): the sensors
2109  *
2110  * Since: 0.1.8
2111  **/
2112 GPtrArray *
cd_client_get_sensors_finish(CdClient * client,GAsyncResult * res,GError ** error)2113 cd_client_get_sensors_finish (CdClient *client,
2114 			      GAsyncResult *res,
2115 			      GError **error)
2116 {
2117 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
2118 	return g_task_propagate_pointer (G_TASK (res), error);
2119 }
2120 
2121 static void
cd_client_get_sensors_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2122 cd_client_get_sensors_cb (GObject *source_object,
2123 			  GAsyncResult *res,
2124 			  gpointer user_data)
2125 {
2126 	GPtrArray *array;
2127 	g_autoptr(GError) error = NULL;
2128 	g_autofree gchar *object_path = NULL;
2129 	g_autoptr(GTask) task = G_TASK (user_data);
2130 	g_autoptr(GVariant) result = NULL;
2131 	CdClient *client = CD_CLIENT (g_task_get_source_object (task));
2132 
2133 	client = CD_CLIENT (g_task_get_source_object (task));
2134 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
2135 					   res,
2136 					   &error);
2137 	if (result == NULL) {
2138 		cd_client_fixup_dbus_error (error);
2139 		g_task_return_error (task, error);
2140 		error = NULL;
2141 		return;
2142 	}
2143 
2144 	/* create a sensor object */
2145 	array = cd_client_get_sensor_array_from_variant (client, result);
2146 
2147 	/* success */
2148 	g_task_return_pointer (task, array, (GDestroyNotify) g_ptr_array_unref);
2149 }
2150 
2151 /**
2152  * cd_client_get_sensors:
2153  * @client: a #CdClient instance.
2154  * @cancellable: a #GCancellable, or %NULL
2155  * @callback: the function to run on completion
2156  * @user_data: the data to pass to @callback
2157  *
2158  * Gets an array of color sensors.
2159  *
2160  * Since: 0.1.8
2161  **/
2162 void
cd_client_get_sensors(CdClient * client,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2163 cd_client_get_sensors (CdClient *client,
2164 		       GCancellable *cancellable,
2165 		       GAsyncReadyCallback callback,
2166 		       gpointer user_data)
2167 {
2168 	CdClientPrivate *priv = GET_PRIVATE (client);
2169 	GTask *task = NULL;
2170 
2171 	g_return_if_fail (CD_IS_CLIENT (client));
2172 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2173 	g_return_if_fail (priv->proxy != NULL);
2174 
2175 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
2176 	g_dbus_proxy_call (priv->proxy,
2177 			   "GetSensors",
2178 			   NULL,
2179 			   G_DBUS_CALL_FLAGS_NONE,
2180 			   -1,
2181 			   cancellable,
2182 			   cd_client_get_sensors_cb,
2183 			   task);
2184 }
2185 
2186 /**********************************************************************/
2187 
2188 /**
2189  * cd_client_find_profile_by_property_finish:
2190  * @client: a #CdClient instance.
2191  * @res: the #GAsyncResult
2192  * @error: A #GError or %NULL
2193  *
2194  * Gets the result from the asynchronous function.
2195  *
2196  * Return value: (transfer full): a #CdProfile or %NULL
2197  *
2198  * Since: 0.1.24
2199  **/
2200 CdProfile *
cd_client_find_profile_by_property_finish(CdClient * client,GAsyncResult * res,GError ** error)2201 cd_client_find_profile_by_property_finish (CdClient *client,
2202 					   GAsyncResult *res,
2203 					   GError **error)
2204 {
2205 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
2206 	return g_task_propagate_pointer (G_TASK (res), error);
2207 }
2208 
2209 static void
cd_client_find_profile_by_property_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2210 cd_client_find_profile_by_property_cb (GObject *source_object,
2211 				       GAsyncResult *res,
2212 				       gpointer user_data)
2213 {
2214 	CdProfile *profile;
2215 	g_autoptr(GError) error = NULL;
2216 	g_autofree gchar *object_path = NULL;
2217 	g_autoptr(GTask) task = G_TASK (user_data);
2218 	g_autoptr(GVariant) result = NULL;
2219 
2220 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
2221 					   res,
2222 					   &error);
2223 	if (result == NULL) {
2224 		cd_client_fixup_dbus_error (error);
2225 		g_task_return_error (task, error);
2226 		error = NULL;
2227 		return;
2228 	}
2229 
2230 	/* create a profile object */
2231 	g_variant_get (result, "(o)", &object_path);
2232 	profile = cd_profile_new ();
2233 	cd_profile_set_object_path (profile, object_path);
2234 
2235 	/* success */
2236 	g_task_return_pointer (task, profile, (GDestroyNotify) g_object_unref);
2237 }
2238 
2239 /**
2240  * cd_client_find_profile_by_property:
2241  * @client: a #CdClient instance.
2242  * @key: the profile property key
2243  * @value: the profile property value
2244  * @cancellable: a #GCancellable, or %NULL
2245  * @callback: the function to run on completion
2246  * @user_data: the data to pass to @callback
2247  *
2248  * Finds a color profile that has a property value.
2249  *
2250  * Since: 0.1.24
2251  **/
2252 void
cd_client_find_profile_by_property(CdClient * client,const gchar * key,const gchar * value,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2253 cd_client_find_profile_by_property (CdClient *client,
2254 				    const gchar *key,
2255 				    const gchar *value,
2256 				    GCancellable *cancellable,
2257 				    GAsyncReadyCallback callback,
2258 				    gpointer user_data)
2259 {
2260 	CdClientPrivate *priv = GET_PRIVATE (client);
2261 	GTask *task = NULL;
2262 
2263 	g_return_if_fail (CD_IS_CLIENT (client));
2264 	g_return_if_fail (key != NULL);
2265 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2266 	g_return_if_fail (priv->proxy != NULL);
2267 
2268 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
2269 	g_dbus_proxy_call (priv->proxy,
2270 			   "FindProfileByProperty",
2271 			   g_variant_new ("(ss)", key, value),
2272 			   G_DBUS_CALL_FLAGS_NONE,
2273 			   -1,
2274 			   cancellable,
2275 			   cd_client_find_profile_by_property_cb,
2276 			   task);
2277 }
2278 
2279 /**********************************************************************/
2280 
2281 /**
2282  * cd_client_find_sensor_finish:
2283  * @client: a #CdClient instance.
2284  * @res: the #GAsyncResult
2285  * @error: A #GError or %NULL
2286  *
2287  * Gets the result from the asynchronous function.
2288  *
2289  * Return value: (transfer full): a #CdSensor or %NULL
2290  *
2291  * Since: 0.1.26
2292  **/
2293 CdSensor *
cd_client_find_sensor_finish(CdClient * client,GAsyncResult * res,GError ** error)2294 cd_client_find_sensor_finish (CdClient *client,
2295 			      GAsyncResult *res,
2296 			      GError **error)
2297 {
2298 	g_return_val_if_fail (g_task_is_valid (res, client), NULL);
2299 	return g_task_propagate_pointer (G_TASK (res), error);
2300 }
2301 
2302 static void
cd_client_find_sensor_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2303 cd_client_find_sensor_cb (GObject *source_object,
2304 			    GAsyncResult *res,
2305 			    gpointer user_data)
2306 {
2307 	CdSensor *sensor;
2308 	g_autoptr(GError) error = NULL;
2309 	g_autofree gchar *object_path = NULL;
2310 	g_autoptr(GTask) task = G_TASK (user_data);
2311 	g_autoptr(GVariant) result = NULL;
2312 
2313 	result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
2314 					   res,
2315 					   &error);
2316 	if (result == NULL) {
2317 		cd_client_fixup_dbus_error (error);
2318 		g_task_return_error (task, error);
2319 		error = NULL;
2320 		return;
2321 	}
2322 
2323 	/* create a sensor object */
2324 	g_variant_get (result, "(o)", &object_path);
2325 	sensor = cd_sensor_new ();
2326 	cd_sensor_set_object_path (sensor, object_path);
2327 
2328 	/* success */
2329 	g_task_return_pointer (task, sensor, (GDestroyNotify) g_object_unref);
2330 }
2331 
2332 /**
2333  * cd_client_find_sensor:
2334  * @client: a #CdClient instance.
2335  * @id: a sensor id
2336  * @cancellable: a #GCancellable, or %NULL
2337  * @callback: the function to run on completion
2338  * @user_data: the data to pass to @callback
2339  *
2340  * Finds a sensor by an ID.
2341  *
2342  * Since: 0.1.26
2343  **/
2344 void
cd_client_find_sensor(CdClient * client,const gchar * id,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2345 cd_client_find_sensor (CdClient *client,
2346 		       const gchar *id,
2347 		       GCancellable *cancellable,
2348 		       GAsyncReadyCallback callback,
2349 		       gpointer user_data)
2350 {
2351 	CdClientPrivate *priv = GET_PRIVATE (client);
2352 	GTask *task = NULL;
2353 
2354 	g_return_if_fail (CD_IS_CLIENT (client));
2355 	g_return_if_fail (id != NULL);
2356 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
2357 	g_return_if_fail (priv->proxy != NULL);
2358 
2359 	task = g_task_new (G_OBJECT (client), cancellable, callback, user_data);
2360 	g_dbus_proxy_call (priv->proxy,
2361 			   "FindSensorById",
2362 			   g_variant_new ("(s)", id),
2363 			   G_DBUS_CALL_FLAGS_NONE,
2364 			   -1,
2365 			   cancellable,
2366 			   cd_client_find_sensor_cb,
2367 			   task);
2368 }
2369 
2370 /**********************************************************************/
2371 
2372 /*
2373  * cd_client_get_property:
2374  */
2375 static void
cd_client_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2376 cd_client_get_property (GObject *object,
2377 			guint prop_id,
2378 			GValue *value,
2379 			GParamSpec *pspec)
2380 {
2381 	CdClient *client = CD_CLIENT (object);
2382 	CdClientPrivate *priv = GET_PRIVATE (client);
2383 
2384 	switch (prop_id) {
2385 	case PROP_DAEMON_VERSION:
2386 		g_value_set_string (value, priv->daemon_version);
2387 		break;
2388 	case PROP_SYSTEM_VENDOR:
2389 		g_value_set_string (value, priv->system_vendor);
2390 		break;
2391 	case PROP_SYSTEM_MODEL:
2392 		g_value_set_string (value, priv->system_model);
2393 		break;
2394 	case PROP_CONNECTED:
2395 		g_value_set_boolean (value, priv->proxy != NULL);
2396 		break;
2397 	default:
2398 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2399 		break;
2400 	}
2401 }
2402 
2403 /*
2404  * cd_client_class_init:
2405  */
2406 static void
cd_client_class_init(CdClientClass * klass)2407 cd_client_class_init (CdClientClass *klass)
2408 {
2409 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
2410 
2411 	object_class->get_property = cd_client_get_property;
2412 	object_class->finalize = cd_client_finalize;
2413 
2414 	/**
2415 	 * CdClient:daemon-version:
2416 	 *
2417 	 * The daemon version.
2418 	 *
2419 	 * Since: 0.1.0
2420 	 */
2421 	g_object_class_install_property (object_class,
2422 					 PROP_DAEMON_VERSION,
2423 					 g_param_spec_string ("daemon-version",
2424 							      "Daemon version",
2425 							      NULL,
2426 							      NULL,
2427 							      G_PARAM_READABLE));
2428 	/**
2429 	 * CdClient:system-vendor:
2430 	 *
2431 	 * The system vendor.
2432 	 *
2433 	 * Since: 1.0.2
2434 	 */
2435 	g_object_class_install_property (object_class,
2436 					 PROP_SYSTEM_VENDOR,
2437 					 g_param_spec_string ("system-vendor",
2438 							      "System Vendor",
2439 							      NULL,
2440 							      NULL,
2441 							      G_PARAM_READABLE));
2442 	/**
2443 	 * CdClient:system-model:
2444 	 *
2445 	 * The system model.
2446 	 *
2447 	 * Since: 1.0.2
2448 	 */
2449 	g_object_class_install_property (object_class,
2450 					 PROP_SYSTEM_MODEL,
2451 					 g_param_spec_string ("system-model",
2452 							      "System model",
2453 							      NULL,
2454 							      NULL,
2455 							      G_PARAM_READABLE));
2456 	/**
2457 	 * CdClient:connected:
2458 	 *
2459 	 * The if the object path has been connected as is valid for use.
2460 	 *
2461 	 * Since: 0.1.9
2462 	 **/
2463 	g_object_class_install_property (object_class,
2464 					 PROP_CONNECTED,
2465 					 g_param_spec_string ("connected",
2466 							      NULL, NULL,
2467 							      NULL,
2468 							      G_PARAM_READABLE));
2469 
2470 	/**
2471 	 * CdClient::device-added:
2472 	 * @client: the #CdClient instance that emitted the signal
2473 	 * @device: the #CdDevice that was added.
2474 	 *
2475 	 * The ::device-added signal is emitted when a device is added.
2476 	 *
2477 	 * Since: 0.1.0
2478 	 **/
2479 	signals [SIGNAL_DEVICE_ADDED] =
2480 		g_signal_new ("device-added",
2481 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2482 			      G_STRUCT_OFFSET (CdClientClass, device_added),
2483 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2484 			      G_TYPE_NONE, 1, CD_TYPE_DEVICE);
2485 
2486 	/**
2487 	 * CdClient::device-removed:
2488 	 * @client: the #CdClient instance that emitted the signal
2489 	 * @device: the #CdDevice that was removed.
2490 	 *
2491 	 * The ::device-added signal is emitted when a device is removed.
2492 	 *
2493 	 * Since: 0.1.0
2494 	 **/
2495 	signals [SIGNAL_DEVICE_REMOVED] =
2496 		g_signal_new ("device-removed",
2497 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2498 			      G_STRUCT_OFFSET (CdClientClass, device_removed),
2499 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2500 			      G_TYPE_NONE, 1, CD_TYPE_DEVICE);
2501 	/**
2502 	 * CdClient::device-changed:
2503 	 * @client: the #CdClient instance that emitted the signal
2504 	 * @device: the #CdDevice that was changed.
2505 	 *
2506 	 * The ::device-changed signal is emitted when a device is changed.
2507 	 *
2508 	 * Since: 0.1.2
2509 	 **/
2510 	signals [SIGNAL_DEVICE_CHANGED] =
2511 		g_signal_new ("device-changed",
2512 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2513 			      G_STRUCT_OFFSET (CdClientClass, device_changed),
2514 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2515 			      G_TYPE_NONE, 1, CD_TYPE_DEVICE);
2516 	/**
2517 	 * CdClient::profile-added:
2518 	 * @client: the #CdClient instance that emitted the signal
2519 	 * @profile: the #CdProfile that was added.
2520 	 *
2521 	 * The ::profile-added signal is emitted when a profile is added.
2522 	 *
2523 	 * Since: 0.1.2
2524 	 **/
2525 	signals [SIGNAL_PROFILE_ADDED] =
2526 		g_signal_new ("profile-added",
2527 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2528 			      G_STRUCT_OFFSET (CdClientClass, profile_added),
2529 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2530 			      G_TYPE_NONE, 1, CD_TYPE_PROFILE);
2531 
2532 	/**
2533 	 * CdClient::profile-removed:
2534 	 * @client: the #CdClient instance that emitted the signal
2535 	 * @profile: the #CdProfile that was removed.
2536 	 *
2537 	 * The ::profile-added signal is emitted when a profile is removed.
2538 	 *
2539 	 * Since: 0.1.2
2540 	 **/
2541 	signals [SIGNAL_PROFILE_REMOVED] =
2542 		g_signal_new ("profile-removed",
2543 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2544 			      G_STRUCT_OFFSET (CdClientClass, profile_removed),
2545 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2546 			      G_TYPE_NONE, 1, CD_TYPE_PROFILE);
2547 	/**
2548 	 * CdClient::profile-changed:
2549 	 * @client: the #CdClient instance that emitted the signal
2550 	 * @profile: the #CdProfile that was removed.
2551 	 *
2552 	 * The ::profile-changed signal is emitted when a profile is changed.
2553 	 *
2554 	 * Since: 0.1.2
2555 	 **/
2556 	signals [SIGNAL_PROFILE_CHANGED] =
2557 		g_signal_new ("profile-changed",
2558 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2559 			      G_STRUCT_OFFSET (CdClientClass, profile_changed),
2560 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2561 			      G_TYPE_NONE, 1, CD_TYPE_PROFILE);
2562 
2563 	/**
2564 	 * CdClient::sensor-added:
2565 	 * @client: the #CdClient instance that emitted the signal
2566 	 * @sensor: the #CdSensor that was added.
2567 	 *
2568 	 * The ::sensor-added signal is emitted when a sensor is added.
2569 	 *
2570 	 * Since: 0.1.6
2571 	 **/
2572 	signals [SIGNAL_SENSOR_ADDED] =
2573 		g_signal_new ("sensor-added",
2574 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2575 			      G_STRUCT_OFFSET (CdClientClass, sensor_added),
2576 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2577 			      G_TYPE_NONE, 1, CD_TYPE_SENSOR);
2578 
2579 	/**
2580 	 * CdClient::sensor-removed:
2581 	 * @client: the #CdClient instance that emitted the signal
2582 	 * @sensor: the #CdSensor that was removed.
2583 	 *
2584 	 * The ::sensor-added signal is emitted when a sensor is removed.
2585 	 *
2586 	 * Since: 0.1.6
2587 	 **/
2588 	signals [SIGNAL_SENSOR_REMOVED] =
2589 		g_signal_new ("sensor-removed",
2590 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2591 			      G_STRUCT_OFFSET (CdClientClass, sensor_removed),
2592 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2593 			      G_TYPE_NONE, 1, CD_TYPE_SENSOR);
2594 	/**
2595 	 * CdClient::sensor-changed:
2596 	 * @client: the #CdClient instance that emitted the signal
2597 	 * @sensor: the #CdSensor that was removed.
2598 	 *
2599 	 * The ::sensor-changed signal is emitted when a sensor is changed.
2600 	 *
2601 	 * Since: 0.1.6
2602 	 **/
2603 	signals [SIGNAL_SENSOR_CHANGED] =
2604 		g_signal_new ("sensor-changed",
2605 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2606 			      G_STRUCT_OFFSET (CdClientClass, sensor_changed),
2607 			      NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
2608 			      G_TYPE_NONE, 1, CD_TYPE_SENSOR);
2609 
2610 	/**
2611 	 * CdClient::changed:
2612 	 * @client: the #CdDevice instance that emitted the signal
2613 	 *
2614 	 * The ::changed signal is emitted when properties may have changed.
2615 	 *
2616 	 * Since: 0.1.0
2617 	 **/
2618 	signals [SIGNAL_CHANGED] =
2619 		g_signal_new ("changed",
2620 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
2621 			      G_STRUCT_OFFSET (CdClientClass, changed),
2622 			      NULL, NULL, g_cclosure_marshal_VOID__VOID,
2623 			      G_TYPE_NONE, 0);
2624 }
2625 
2626 /*
2627  * cd_client_init:
2628  */
2629 static void
cd_client_init(CdClient * client)2630 cd_client_init (CdClient *client)
2631 {
2632 	/* ensure the remote errors are registered */
2633 	cd_client_error_quark ();
2634 }
2635 
2636 /*
2637  * cd_client_finalize:
2638  */
2639 static void
cd_client_finalize(GObject * object)2640 cd_client_finalize (GObject *object)
2641 {
2642 	CdClient *client = CD_CLIENT (object);
2643 	CdClientPrivate *priv = GET_PRIVATE (client);
2644 
2645 	g_return_if_fail (CD_IS_CLIENT (object));
2646 
2647 	g_free (priv->daemon_version);
2648 	g_free (priv->system_vendor);
2649 	g_free (priv->system_model);
2650 	if (priv->proxy != NULL)
2651 		g_object_unref (priv->proxy);
2652 
2653 	G_OBJECT_CLASS (cd_client_parent_class)->finalize (object);
2654 }
2655 
2656 /**
2657  * cd_client_new:
2658  *
2659  * Creates a new #CdClient object.
2660  *
2661  * Return value: a new CdClient object.
2662  *
2663  * Since: 0.1.0
2664  **/
2665 CdClient *
cd_client_new(void)2666 cd_client_new (void)
2667 {
2668 	if (cd_client_object != NULL) {
2669 		g_object_ref (cd_client_object);
2670 	} else {
2671 		cd_client_object = g_object_new (CD_TYPE_CLIENT, NULL);
2672 		g_object_add_weak_pointer (cd_client_object, &cd_client_object);
2673 	}
2674 	return CD_CLIENT (cd_client_object);
2675 }
2676 
2677