up-device.c 19.2 KB
Newer Older
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
David Zeuthen's avatar
David Zeuthen committed
2
 *
David Zeuthen's avatar
David Zeuthen committed
3
 * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
4
 * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com>
David Zeuthen's avatar
David Zeuthen committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

22
#include "config.h"
David Zeuthen's avatar
David Zeuthen committed
23
24
25
26
27
28
29
30

#include <string.h>

#include <glib.h>
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
#include <glib-object.h>

31
32
33
#include "up-native.h"
#include "up-device.h"
#include "up-history.h"
34
35
#include "up-history-item.h"
#include "up-stats-item.h"
36

37
struct UpDevicePrivate
38
{
39
	UpDaemon		*daemon;
40
	UpHistory		*history;
41
	GObject			*native;
42
43
44
	gboolean		 has_ever_refresh;
};

45
G_DEFINE_TYPE_WITH_PRIVATE (UpDevice, up_device, UP_TYPE_EXPORTED_DEVICE_SKELETON)
46

47
48
#define UP_DEVICES_DBUS_PATH "/org/freedesktop/UPower/devices"

49
50
51
52
53
/* This needs to be called when one of those properties changes:
 * state
 * power_supply
 * percentage
 * time_to_empty
54
 * battery_level
55
56
 *
 * type should not change for non-display devices
57
58
59
60
 */
static void
update_warning_level (UpDevice *device)
{
61
	UpDeviceLevel warning_level, battery_level;
62
	UpExportedDevice *skeleton = UP_EXPORTED_DEVICE (device);
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
	/* If the battery level is available, and is critical,
	 * we need to fallback to calculations to get the warning
	 * level, as that might be "action" at this point */
	battery_level = up_exported_device_get_battery_level (skeleton);
	if (battery_level != UP_DEVICE_LEVEL_NONE &&
	    battery_level != UP_DEVICE_LEVEL_CRITICAL) {
		if (battery_level == UP_DEVICE_LEVEL_LOW)
			warning_level = battery_level;
		else
			warning_level = UP_DEVICE_LEVEL_NONE;
	} else {
		warning_level = up_daemon_compute_warning_level (device->priv->daemon,
								 up_exported_device_get_state (skeleton),
								 up_exported_device_get_type_ (skeleton),
								 up_exported_device_get_power_supply (skeleton),
								 up_exported_device_get_percentage (skeleton),
								 up_exported_device_get_time_to_empty (skeleton));
	}
82
83

	up_exported_device_set_warning_level (skeleton, warning_level);
84
85
}

Bastien Nocera's avatar
Bastien Nocera committed
86
87
88
89
90
91
92
93
94
95
/* This needs to be called when one of those properties changes:
 * type
 * state
 * percentage
 * is-present
 */
static void
update_icon_name (UpDevice *device)
{
	const gchar *icon_name = NULL;
96
	UpExportedDevice *skeleton = UP_EXPORTED_DEVICE (device);
Bastien Nocera's avatar
Bastien Nocera committed
97
98

	/* get the icon from some simple rules */
99
	if (up_exported_device_get_type_ (skeleton) == UP_DEVICE_KIND_LINE_POWER) {
Bastien Nocera's avatar
Bastien Nocera committed
100
101
102
		icon_name = "ac-adapter-symbolic";
	} else {

103
		if (!up_exported_device_get_is_present (skeleton)) {
Bastien Nocera's avatar
Bastien Nocera committed
104
105
106
			icon_name = "battery-missing-symbolic";

		} else {
107
			switch (up_exported_device_get_state (skeleton)) {
Bastien Nocera's avatar
Bastien Nocera committed
108
109
110
111
112
113
114
115
			case UP_DEVICE_STATE_EMPTY:
				icon_name = "battery-empty-symbolic";
				break;
			case UP_DEVICE_STATE_FULLY_CHARGED:
				icon_name = "battery-full-charged-symbolic";
				break;
			case UP_DEVICE_STATE_CHARGING:
			case UP_DEVICE_STATE_PENDING_CHARGE:
116
117
				icon_name = up_daemon_get_charge_icon (device->priv->daemon,
								       up_exported_device_get_percentage (skeleton),
118
								       up_exported_device_get_battery_level (skeleton),
119
								    TRUE);
Bastien Nocera's avatar
Bastien Nocera committed
120
121
122
				break;
			case UP_DEVICE_STATE_DISCHARGING:
			case UP_DEVICE_STATE_PENDING_DISCHARGE:
123
124
				icon_name = up_daemon_get_charge_icon (device->priv->daemon,
								       up_exported_device_get_percentage (skeleton),
125
								       up_exported_device_get_battery_level (skeleton),
126
								    FALSE);
Bastien Nocera's avatar
Bastien Nocera committed
127
128
129
130
131
132
133
				break;
			default:
				icon_name = "battery-missing-symbolic";
			}
		}
	}

134
	up_exported_device_set_icon_name (skeleton, icon_name);
135
136
}

David Zeuthen's avatar
David Zeuthen committed
137
static void
138
update_history (UpDevice *device)
David Zeuthen's avatar
David Zeuthen committed
139
{
140
141
142
143
144
145
146
147
	UpExportedDevice *skeleton = UP_EXPORTED_DEVICE (device);

	/* save new history */
	up_history_set_state (device->priv->history, up_exported_device_get_state (skeleton));
	up_history_set_charge_data (device->priv->history, up_exported_device_get_percentage (skeleton));
	up_history_set_rate_data (device->priv->history, up_exported_device_get_energy_rate (skeleton));
	up_history_set_time_full_data (device->priv->history, up_exported_device_get_time_to_full (skeleton));
	up_history_set_time_empty_data (device->priv->history, up_exported_device_get_time_to_empty (skeleton));
148
}
149

150
/**
151
 * up_device_notify:
152
153
 **/
static void
154
up_device_notify (GObject *object, GParamSpec *pspec)
155
{
156
	UpDevice *device = UP_DEVICE (object);
157

158
159
160
161
	/* Not finished setting up the object? */
	if (device->priv->daemon == NULL)
		return;

162
	G_OBJECT_CLASS (up_device_parent_class)->notify (object, pspec);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
163

164
165
	if (g_strcmp0 (pspec->name, "type") == 0 ||
	    g_strcmp0 (pspec->name, "is-present") == 0) {
Bastien Nocera's avatar
Bastien Nocera committed
166
		update_icon_name (device);
167
168
	} else if (g_strcmp0 (pspec->name, "power-supply") == 0 ||
		   g_strcmp0 (pspec->name, "time-to-empty") == 0) {
169
		update_warning_level (device);
170
	} else if (g_strcmp0 (pspec->name, "state") == 0 ||
171
172
		   g_strcmp0 (pspec->name, "percentage") == 0 ||
		   g_strcmp0 (pspec->name, "battery-level") == 0) {
173
		update_warning_level (device);
Bastien Nocera's avatar
Bastien Nocera committed
174
		update_icon_name (device);
175
176
	} else if (g_strcmp0 (pspec->name, "update-time") == 0) {
		update_history (device);
177
	}
David Zeuthen's avatar
David Zeuthen committed
178
179
}

180
/**
181
 * up_device_get_on_battery:
182
183
 *
 * Note: Only implement for system devices, i.e. ones supplying the system
184
185
 **/
gboolean
186
up_device_get_on_battery (UpDevice *device, gboolean *on_battery)
David Zeuthen's avatar
David Zeuthen committed
187
{
188
	UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device);
189

190
	g_return_val_if_fail (UP_IS_DEVICE (device), FALSE);
191

192
	/* no support */
193
	if (klass->get_on_battery == NULL)
194
195
		return FALSE;

196
	return klass->get_on_battery (device, on_battery);
David Zeuthen's avatar
David Zeuthen committed
197
198
}

199
/**
200
 * up_device_get_online:
201
202
203
204
 *
 * Note: Only implement for system devices, i.e. devices supplying the system
 **/
gboolean
205
up_device_get_online (UpDevice *device, gboolean *online)
206
{
207
	UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device);
208

209
	g_return_val_if_fail (UP_IS_DEVICE (device), FALSE);
210
211
212
213
214
215
216
217

	/* no support */
	if (klass->get_online == NULL)
		return FALSE;

	return klass->get_online (device, online);
}

218
/**
219
 * up_device_get_id:
220
221
 **/
static gchar *
222
up_device_get_id (UpDevice *device)
223
224
225
{
	GString *string;
	gchar *id = NULL;
Cosimo Cecchi's avatar
Cosimo Cecchi committed
226
227
	const char *model;
	const char *serial;
228
	UpExportedDevice *skeleton;
Cosimo Cecchi's avatar
Cosimo Cecchi committed
229

230
231
232
	skeleton = UP_EXPORTED_DEVICE (device);
	model = up_exported_device_get_model (skeleton);
	serial = up_exported_device_get_serial (skeleton);
233
234

	/* line power */
235
	if (up_exported_device_get_type_ (skeleton) == UP_DEVICE_KIND_LINE_POWER) {
236
237
238
		goto out;

	/* batteries */
239
	} else if (up_exported_device_get_type_ (skeleton) == UP_DEVICE_KIND_BATTERY) {
240
		/* we don't have an ID if we are not present */
241
		if (!up_exported_device_get_is_present (skeleton))
242
243
244
245
246
			goto out;

		string = g_string_new ("");

		/* in an ideal world, model-capacity-serial */
Cosimo Cecchi's avatar
Cosimo Cecchi committed
247
248
		if (model != NULL && strlen (model) > 2) {
			g_string_append (string, model);
249
250
			g_string_append_c (string, '-');
		}
251
		if (up_exported_device_get_energy_full_design (skeleton) > 0) {
252
			/* FIXME: this may not be stable if we are using voltage_now */
253
			g_string_append_printf (string, "%i", (guint) up_exported_device_get_energy_full_design (skeleton));
254
255
			g_string_append_c (string, '-');
		}
Cosimo Cecchi's avatar
Cosimo Cecchi committed
256
257
		if (serial != NULL && strlen (serial) > 2) {
			g_string_append (string, serial);
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
			g_string_append_c (string, '-');
		}

		/* make sure we are sane */
		if (string->len == 0) {
			/* just use something generic */
			g_string_append (string, "generic_id");
		} else {
			/* remove trailing '-' */
			g_string_set_size (string, string->len - 1);
		}

		/* the id may have invalid chars that need to be replaced */
		id = g_string_free (string, FALSE);

	} else {
274
275
		/* generic fallback, get what data we can */
		string = g_string_new ("");
276
277
		if (up_exported_device_get_vendor (skeleton) != NULL) {
			g_string_append (string, up_exported_device_get_vendor (skeleton));
278
279
			g_string_append_c (string, '-');
		}
Cosimo Cecchi's avatar
Cosimo Cecchi committed
280
281
		if (model != NULL) {
			g_string_append (string, model);
282
283
			g_string_append_c (string, '-');
		}
Cosimo Cecchi's avatar
Cosimo Cecchi committed
284
285
		if (serial != NULL) {
			g_string_append (string, serial);
286
287
288
289
290
291
292
293
294
295
296
297
298
299
			g_string_append_c (string, '-');
		}

		/* make sure we are sane */
		if (string->len == 0) {
			/* just use something generic */
			g_string_append (string, "generic_id");
		} else {
			/* remove trailing '-' */
			g_string_set_size (string, string->len - 1);
		}

		/* the id may have invalid chars that need to be replaced */
		id = g_string_free (string, FALSE);
300
301
302
303
304
305
306
307
	}

	g_strdelimit (id, "\\\t\"?' /,.", '_');

out:
	return id;
}

308
/**
309
 * up_device_get_daemon:
310
 *
311
 * Returns a refcounted #UpDaemon instance, or %NULL
312
 **/
313
UpDaemon *
314
up_device_get_daemon (UpDevice *device)
315
316
317
318
319
320
{
	if (device->priv->daemon == NULL)
		return NULL;
	return g_object_ref (device->priv->daemon);
}

321
322
323
324
325
326
327
static void
up_device_export_skeleton (UpDevice *device,
			   const gchar *object_path)
{
	GError *error = NULL;

	g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (device),
328
					  g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (device->priv->daemon)),
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
					  object_path,
					  &error);

	if (error != NULL) {
		g_critical ("error registering device on system bus: %s", error->message);
		g_error_free (error);
	}
}

/**
 * up_device_compute_object_path:
 **/
static gchar *
up_device_compute_object_path (UpDevice *device)
{
	gchar *basename;
	gchar *id;
	gchar *object_path;
	const gchar *native_path;
	const gchar *type;
	guint i;

	type = up_device_kind_to_string (up_exported_device_get_type_ (UP_EXPORTED_DEVICE (device)));
	native_path = up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device));
	basename = g_path_get_basename (native_path);
	id = g_strjoin ("_", type, basename, NULL);

	/* make DBUS valid path */
	for (i=0; id[i] != '\0'; i++) {
		if (id[i] == '-')
			id[i] = '_';
		if (id[i] == '.')
			id[i] = 'x';
		if (id[i] == ':')
			id[i] = 'o';
364
365
		if (id[i] == '@')
			id[i] = '_';
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
	}
	object_path = g_build_filename (UP_DEVICES_DBUS_PATH, id, NULL);

	g_free (basename);
	g_free (id);

	return object_path;
}

/**
 * up_device_register_device:
 **/
static gboolean
up_device_register_device (UpDevice *device)
{
	char *object_path = up_device_compute_object_path (device);
	g_debug ("object path = %s", object_path);
	up_device_export_skeleton (device, object_path);
	g_free (object_path);

	return TRUE;
}

389
/**
390
 * up_device_coldplug:
391
392
 *
 * Return %TRUE on success, %FALSE if we failed to get data and should be removed
393
394
 **/
gboolean
395
up_device_coldplug (UpDevice *device, UpDaemon *daemon, GObject *native)
396
397
398
{
	gboolean ret;
	const gchar *native_path;
399
	UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device);
400
	gchar *id = NULL;
401

402
	g_return_val_if_fail (UP_IS_DEVICE (device), FALSE);
403

404
	/* save */
405
	device->priv->native = g_object_ref (native);
406
407
	device->priv->daemon = g_object_ref (daemon);

408
	native_path = up_native_get_native_path (native);
409
	up_exported_device_set_native_path (UP_EXPORTED_DEVICE (device), native_path);
410
411

	/* coldplug source */
412
413
414
	if (klass->coldplug != NULL) {
		ret = klass->coldplug (device);
		if (!ret) {
Cosimo Cecchi's avatar
Cosimo Cecchi committed
415
			g_debug ("failed to coldplug %s", native_path);
416
			goto bail;
417
		}
418
	}
419

420
	/* force a refresh, although failure isn't fatal */
421
	ret = up_device_refresh_internal (device);
422
	if (!ret) {
Cosimo Cecchi's avatar
Cosimo Cecchi committed
423
		g_debug ("failed to refresh %s", native_path);
424

Bastien Nocera's avatar
Bastien Nocera committed
425
		/* TODO: refresh should really have separate
426
		 *       success _and_ changed parameters */
427
		goto out;
428
	}
429

430
	/* get the id so we can load the old history */
431
	id = up_device_get_id (device);
432
	if (id != NULL) {
433
		up_history_set_id (device->priv->history, id);
434
435
		g_free (id);
	}
436
out:
437
438
439
	/* only put on the bus if we succeeded */
	ret = up_device_register_device (device);
	if (!ret) {
Cosimo Cecchi's avatar
Cosimo Cecchi committed
440
		g_warning ("failed to register device %s", native_path);
441
442
		goto out;
	}
443
bail:
444
445
446
	return ret;
}

447
448
449
450
451
452
453
454
455
456
/**
 * up_device_unplug:
 *
 * Initiates destruction of %UpDevice, undoing the effects of
 * up_device_coldplug.
 */
void
up_device_unplug (UpDevice *device)
{
	/* break circular dependency */
457
	g_clear_object (&device->priv->daemon);
458
459
}

460
/**
461
 * up_device_get_statistics:
462
 **/
Cosimo Cecchi's avatar
Cosimo Cecchi committed
463
464
465
466
467
static gboolean
up_device_get_statistics (UpExportedDevice *skeleton,
			  GDBusMethodInvocation *invocation,
			  const gchar *type,
			  UpDevice *device)
468
{
469
	GPtrArray *array = NULL;
470
	UpStatsItem *item;
471
	guint i;
Cosimo Cecchi's avatar
Cosimo Cecchi committed
472
	GVariantBuilder builder;
473
474

	/* doesn't even try to support this */
Cosimo Cecchi's avatar
Cosimo Cecchi committed
475
476
477
478
	if (!up_exported_device_get_has_statistics (skeleton)) {
		g_dbus_method_invocation_return_error_literal (invocation,
							       UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
							       "device does not support getting stats");
479
480
481
		goto out;
	}

482
	/* get the correct data */
Richard Hughes's avatar
Richard Hughes committed
483
	if (g_strcmp0 (type, "charging") == 0)
484
		array = up_history_get_profile_data (device->priv->history, TRUE);
Richard Hughes's avatar
Richard Hughes committed
485
	else if (g_strcmp0 (type, "discharging") == 0)
486
		array = up_history_get_profile_data (device->priv->history, FALSE);
487

488
489
	/* maybe the device doesn't support histories */
	if (array == NULL) {
Cosimo Cecchi's avatar
Cosimo Cecchi committed
490
491
492
		g_dbus_method_invocation_return_error_literal (invocation,
							       UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
							       "device has no statistics");
493
494
495
		goto out;
	}

496
497
	/* always 101 items of data */
	if (array->len != 101) {
Cosimo Cecchi's avatar
Cosimo Cecchi committed
498
499
500
		g_dbus_method_invocation_return_error (invocation,
						       UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
						       "statistics invalid as have %i items", array->len);
501
502
503
504
		goto out;
	}

	/* copy data to dbus struct */
Cosimo Cecchi's avatar
Cosimo Cecchi committed
505
506
	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(dd)"));
	for (i = 0; i < array->len; i++) {
507
		item = (UpStatsItem *) g_ptr_array_index (array, i);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
508
509
510
		g_variant_builder_add (&builder, "(dd)",
				       up_stats_item_get_value (item),
				       up_stats_item_get_accuracy (item));
511
512
	}

Cosimo Cecchi's avatar
Cosimo Cecchi committed
513
514
	up_exported_device_complete_get_statistics (skeleton, invocation,
						    g_variant_builder_end (&builder));
515
out:
516
517
	if (array != NULL)
		g_ptr_array_unref (array);
518
519
520
521
	return TRUE;
}

/**
522
 * up_device_get_history:
523
 **/
Cosimo Cecchi's avatar
Cosimo Cecchi committed
524
525
526
527
528
529
530
static gboolean
up_device_get_history (UpExportedDevice *skeleton,
		       GDBusMethodInvocation *invocation,
		       const gchar *type_string,
		       guint timespan,
		       guint resolution,
		       UpDevice *device)
531
{
532
	GPtrArray *array = NULL;
533
	UpHistoryItem *item;
534
	guint i;
535
	UpHistoryType type = UP_HISTORY_TYPE_UNKNOWN;
Cosimo Cecchi's avatar
Cosimo Cecchi committed
536
	GVariantBuilder builder;
537

538
	/* doesn't even try to support this */
Cosimo Cecchi's avatar
Cosimo Cecchi committed
539
540
541
542
	if (!up_exported_device_get_has_history (skeleton)) {
		g_dbus_method_invocation_return_error_literal (invocation,
							       UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
							       "device does not support getting history");
543
544
545
		goto out;
	}

546
	/* get the correct data */
Richard Hughes's avatar
Richard Hughes committed
547
	if (g_strcmp0 (type_string, "rate") == 0)
548
		type = UP_HISTORY_TYPE_RATE;
Richard Hughes's avatar
Richard Hughes committed
549
	else if (g_strcmp0 (type_string, "charge") == 0)
550
		type = UP_HISTORY_TYPE_CHARGE;
Richard Hughes's avatar
Richard Hughes committed
551
	else if (g_strcmp0 (type_string, "time-full") == 0)
552
		type = UP_HISTORY_TYPE_TIME_FULL;
Richard Hughes's avatar
Richard Hughes committed
553
	else if (g_strcmp0 (type_string, "time-empty") == 0)
554
		type = UP_HISTORY_TYPE_TIME_EMPTY;
555
556

	/* something recognised */
557
558
	if (type != UP_HISTORY_TYPE_UNKNOWN)
		array = up_history_get_data (device->priv->history, type, timespan, resolution);
559
560

	/* maybe the device doesn't have any history */
561
	if (array == NULL) {
Cosimo Cecchi's avatar
Cosimo Cecchi committed
562
563
564
		g_dbus_method_invocation_return_error_literal (invocation,
							       UP_DAEMON_ERROR, UP_DAEMON_ERROR_GENERAL,
							       "device has no history");
565
566
		goto out;
	}
David Zeuthen's avatar
David Zeuthen committed
567

568
	/* copy data to dbus struct */
Cosimo Cecchi's avatar
Cosimo Cecchi committed
569
570
	g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(udu)"));
	for (i = 0; i < array->len; i++) {
571
		item = (UpHistoryItem *) g_ptr_array_index (array, i);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
572
573
574
575
		g_variant_builder_add (&builder, "(udu)",
				       up_history_item_get_time (item),
				       up_history_item_get_value (item),
				       up_history_item_get_state (item));
576
	}
577

Cosimo Cecchi's avatar
Cosimo Cecchi committed
578
579
580
	up_exported_device_complete_get_history (skeleton, invocation,
						 g_variant_builder_end (&builder));

581
out:
582
	if (array != NULL)
583
		g_ptr_array_unref (array);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
	return TRUE;
}

/**
 * up_device_refresh:
 *
 * Return %TRUE on success, %FALSE if we failed to refresh or no data
 **/
static gboolean
up_device_refresh (UpExportedDevice *skeleton,
		   GDBusMethodInvocation *invocation,
		   UpDevice *device)
{
	up_device_refresh_internal (device);
	up_exported_device_complete_refresh (skeleton, invocation);
	return TRUE;
}

/**
 * up_device_register_display_device:
 **/
gboolean
up_device_register_display_device (UpDevice *device,
				   UpDaemon *daemon)
{
609
610
	char *object_path;

Cosimo Cecchi's avatar
Cosimo Cecchi committed
611
612
613
	g_return_val_if_fail (UP_IS_DEVICE (device), FALSE);

	device->priv->daemon = g_object_ref (daemon);
614
615
616
	object_path = g_build_filename (UP_DEVICES_DBUS_PATH, "DisplayDevice", NULL);
	up_device_export_skeleton (device, object_path);
	g_free (object_path);
Cosimo Cecchi's avatar
Cosimo Cecchi committed
617

618
619
620
621
	return TRUE;
}

/**
622
 * up_device_refresh_internal:
623
624
625
626
 *
 * NOTE: if you're calling this function you have to ensure you're doing the
 * the changed signals on the right interfaces, although by monitoring
 * notify::update-time this should be mostly done.
627
 **/
628
gboolean
629
up_device_refresh_internal (UpDevice *device)
630
{
631
	gboolean ret = FALSE;
632
	UpDeviceClass *klass = UP_DEVICE_GET_CLASS (device);
633

634
635
636
637
	/* not implemented */
	if (klass->refresh == NULL)
		goto out;

638
	/* do the refresh */
639
640
	ret = klass->refresh (device);
	if (!ret) {
641
		g_debug ("no changes");
642
		goto out;
643
	}
644
645
646

	/* the first time, print all properties */
	if (!device->priv->has_ever_refresh) {
647
		g_debug ("added native-path: %s", up_exported_device_get_native_path (UP_EXPORTED_DEVICE (device)));
648
649
650
651
		device->priv->has_ever_refresh = TRUE;
		goto out;
	}
out:
652
	return ret;
653
654
}

655
/**
656
 * up_device_get_object_path:
657
 **/
658
const gchar *
659
up_device_get_object_path (UpDevice *device)
David Zeuthen's avatar
David Zeuthen committed
660
{
661
	g_return_val_if_fail (UP_IS_DEVICE (device), NULL);
662
	return g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (device));
663
664
}

665
GObject *
666
up_device_get_native (UpDevice *device)
667
{
668
	g_return_val_if_fail (UP_IS_DEVICE (device), NULL);
669
	return device->priv->native;
David Zeuthen's avatar
David Zeuthen committed
670
}
671

672
/**
673
 * up_device_init:
674
675
 **/
static void
676
up_device_init (UpDevice *device)
677
{
678
679
	UpExportedDevice *skeleton;

680
	device->priv = up_device_get_instance_private (device);
681
	device->priv->history = up_history_new ();
682

683
684
685
	skeleton = UP_EXPORTED_DEVICE (device);
	up_exported_device_set_battery_level (skeleton, UP_DEVICE_LEVEL_NONE);

686
	g_signal_connect (device, "handle-get-history",
Cosimo Cecchi's avatar
Cosimo Cecchi committed
687
			  G_CALLBACK (up_device_get_history), device);
688
	g_signal_connect (device, "handle-get-statistics",
Cosimo Cecchi's avatar
Cosimo Cecchi committed
689
			  G_CALLBACK (up_device_get_statistics), device);
690
	g_signal_connect (device, "handle-refresh",
Cosimo Cecchi's avatar
Cosimo Cecchi committed
691
			  G_CALLBACK (up_device_refresh), device);
692
693
694
}

/**
695
 * up_device_finalize:
696
697
 **/
static void
698
up_device_finalize (GObject *object)
699
{
700
	UpDevice *device;
701
702

	g_return_if_fail (object != NULL);
703
	g_return_if_fail (UP_IS_DEVICE (object));
704

705
	device = UP_DEVICE (object);
706
	g_return_if_fail (device->priv != NULL);
707
708
	g_clear_object (&device->priv->native);
	g_clear_object (&device->priv->daemon);
709
	g_object_unref (device->priv->history);
710

711
	G_OBJECT_CLASS (up_device_parent_class)->finalize (object);
712
713
714
}

/**
715
 * up_device_class_init:
716
717
 **/
static void
718
up_device_class_init (UpDeviceClass *klass)
719
720
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
721
	object_class->notify = up_device_notify;
722
	object_class->finalize = up_device_finalize;
723
724
}

725
/**
726
 * up_device_new:
727
 **/
728
729
UpDevice *
up_device_new (void)
730
{
731
	return UP_DEVICE (g_object_new (UP_TYPE_DEVICE, NULL));
732
}