Merge lp:~charlesk/indicator-power/coverage into lp:indicator-power/12.10

Proposed by Charles Kerr
Status: Merged
Merged at revision: 142
Proposed branch: lp:~charlesk/indicator-power/coverage
Merge into: lp:indicator-power/12.10
Diff against target: 3858 lines (+2749/-712)
16 files modified
Makefile.am (+8/-27)
configure.ac (+26/-1)
m4/gtest.m4 (+63/-0)
po/POTFILES.in (+2/-0)
src/Makefile.am (+36/-0)
src/dbus-listener.c (+247/-0)
src/dbus-listener.h (+82/-0)
src/device.c (+666/-0)
src/device.h (+107/-0)
src/indicator-power.c (+202/-684)
src/indicator-power.h (+58/-0)
tests/Makefile.am (+62/-0)
tests/Makefile.am.strings (+38/-0)
tests/test-dbus-listener.cc (+370/-0)
tests/test-device.cc (+470/-0)
tests/test-indicator.cc (+312/-0)
To merge this branch: bzr merge lp:~charlesk/indicator-power/coverage
Reviewer Review Type Date Requested Status
jenkins (community) continuous-integration Approve
Lars Karlitski (community) Approve
Review via email: mp+109028@code.launchpad.net

This proposal supersedes a proposal from 2012-06-04.

Commit message

charles brings the code-coverage of this project above 90%.

Description of the change

revised to use most of lars' great suggestions

To post a comment you must log in.
Revision history for this message
Lars Karlitski (larsu) wrote : Posted in a previous version of this proposal

Very nice work! And impressive test coverage.

Note: I couldn't test it yet, as I'm still on precise. /me ducks.

src/Makefile.am:207:
  * any reason you're using noinst_HEADERS instead of listing the headers
    in the libraries sources? (the latter is recommended for programs and
    convenience libs in the automake docs)

dbus-listener.c
  * afaict, it could have been written by gdbus-codegen
  * 305: g_signal_new is passed one too many arguments. Please add the
    docstring with the number and names of parameters to it [1]
  * dispose() is missing g_bus_unwatch_name (priv->watcher_id)
  * get_devices_cb:144: trailing whitespace ;)
  * the cancellable is passed into all functions and unreffed in dispose()
    is the cancellable cancelled on unref or do we need to do that explicitely?
    (I can't find anything in the docs)

dbus-listener.h:
  * 50: the signal name is overly complicated (it doesn't need to be namespaced
    to the class)
  * indicator_power_dbus_listener_new is declared but not defined in the .c

device.c:
  * class_init: I prefer saving all pspecs in a static array and installing
    them all at once with g_object_class_install_properties. This also allows
    using g_object_notify_by_pspec
  * finalize doesn't chain up to the parent class
  * get/set_property:
     - use G_OBJECT_WARN_INVALID_PROPERTY_ID in the 'default' switch case
     - PROP_ICON is not handled
     - kind and state should check for sane input values
  * 260 ff: I don't think we can use Richard's code (indicators are CA, right?)
  * indicator_power_device_new_from_variant: check whether the input variant
    has the correct type before calling g_variant_get
  * 298: reference functions with 'function_name()' instead of #function_name
    in doc strings

device.h:
  * 43 ff: no need to namespace gobject properties (tbh, I wouldn't even
    #define them, but simply use the strings)

indicator-power.c:
  * 119: ah, that's why you didn't notice the implementation of
    indicator_power_dbus_listener_new was missing :)
  * ref the floating widgets in the private struct
    (just something I noticed, it has nothing to do with this work)

indicator-power.h:
  * device.h include is superfluous

test/test-dbus-{listener,device}.cc:
  * ensure_glib_initalized: g_type_init can be called multiple times

[1] http://developer.gnome.org/gtk-doc-manual/stable/documenting_symbols.html.en
    Section 3.3.4

review: Needs Fixing
Revision history for this message
Charles Kerr (charlesk) wrote : Posted in a previous version of this proposal

Lars, thanks for the great review!

> any reason you're using noinst_HEADERS instead of listing the headers
> in the libraries sources? (the latter is recommended for programs and
> convenience libs in the automake docs)

Fixed r204

> dbus-listener.c
>
> 305: g_signal_new is passed one too many arguments. Please add the
> docstring with the number and names of parameters to it [1]

Fixed r205

> dispose() is missing g_bus_unwatch_name (priv->watcher_id)

Fixed r206

> get_devices_cb:144: trailing whitespace ;)

Fixed r207

> the cancellable is passed into all functions and unreffed in dispose()
> is the cancellable cancelled on unref or do we need to do that explicitely?
> (I can't find anything in the docs)

This is a great catch. Looking at the gio code, my assumption was wrong,
it needs to be done explicitly.

Fixed r208

> dbus-listener.h:
> * 50: the signal name is overly complicated (it doesn't need to be namespaced
> to the class)

Fixed r209

> * indicator_power_dbus_listener_new is declared but not defined in the .c

Fixed r210

> device.c:
> class_init: I prefer saving all pspecs in a static array and installing
> them all at once with g_object_class_install_properties. This also allows
> using g_object_notify_by_pspec

Interesting, I don't see that in any of the other indicator code. TIL.

Changed r211

> * finalize doesn't chain up to the parent class

Fixed r212

> * get/set_property:
> - use G_OBJECT_WARN_INVALID_PROPERTY_ID in the 'default' switch case

Fixed r213

> PROP_ICON is not handled

PROP_ICON was cruft, removed r211

> kind and state should check for sane input values

This is already done by glib's plumbing because the pspec defined the sane range. (No change)

> 260 ff: I don't think we can use Richard's code (indicators are CA, right?)

Before my refactoring, i-power was already doing this. One difference is now I'm giving proper attribution. (No change, but maybe a ted question?)

> indicator_power_device_new_from_variant: check whether the input variant has the correct type before calling g_variant_get

Fixed r214.

> 298: reference functions with 'function_name()' instead of #function_name in doc strings

Fixed r215.

> device.h: 43 ff: no need to namespace gobject properties (tbh, I wouldn't even #define them, but simply use the strings)

Fixed r216.

However I've kept the #defines since that idiom catches misspelled keys at compile time...

> indicator-power.c:
> * ref the floating widgets in the private struct
> (just something I noticed, it has nothing to do with this work)

Agreed, but unchanged for this pass...

> indicator-power.h:
> * device.h include is superfluous

Fixed r217

> test/test-dbus-{listener,device}.cc:
> * ensure_glib_initalized: g_type_init can be called multiple times

I don't think this is correct. Are you sure?

Revision history for this message
Charles Kerr (charlesk) wrote :

>> 260 ff: I don't think we can use Richard's code (indicators are CA, right?)
>
> Before my refactoring, i-power was already doing this. One difference is now I'm giving proper attribution. (No change, but maybe a ted question?)

Sure enough. Fixed r218.

Revision history for this message
Lars Karlitski (larsu) wrote : Posted in a previous version of this proposal

Thanks for the quick fixes!

On 06/06/2012 10:28 PM, Charles Kerr wrote:
>> the cancellable is passed into all functions and unreffed in dispose()
>> is the cancellable cancelled on unref or do we need to do that explicitely?
>> (I can't find anything in the docs)
>
> This is a great catch. Looking at the gio code, my assumption was wrong,
> it needs to be done explicitly.
>
> Fixed r208

Thanks for checking.

> [...]
>> kind and state should check for sane input values
>
> This is already done by glib's plumbing because the pspec defined the sane range. (No change)

You're right of course. Sorry.

>> 260 ff: I don't think we can use Richard's code (indicators are CA, right?)
>
> Before my refactoring, i-power was already doing this. One difference is now I'm giving proper attribution. (No change, but maybe a ted question?)

Definitely a Ted question.

>> indicator_power_device_new_from_variant: check whether the input variant has the correct type before calling g_variant_get
>
> Fixed r214.

Hm, I was thinking more along the lines of

  g_variant_is_of_type (v, G_VARIANT_TYPE ("(susdut)"));

The fix in r214 only checks for a tuple with the correct number of elements.

>> test/test-dbus-{listener,device}.cc:
>> * ensure_glib_initalized: g_type_init can be called multiple times
>
> I don't think this is correct. Are you sure?

I'm not sure. Actually, I think you might be right.

Revision history for this message
Charles Kerr (charlesk) wrote :

> Hm, I was thinking more along the lines of
>
> g_variant_is_of_type (v, G_VARIANT_TYPE ("(susdut)"));

Oh yes, that is better. Fixed r219

Keep it up, I love these improvements :)

Revision history for this message
Lars Karlitski (larsu) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 06/07/2012 04:01 PM, Charles Kerr wrote:
>> Hm, I was thinking more along the lines of
>>
>> g_variant_is_of_type (v, G_VARIANT_TYPE ("(susdut)"));
>
> Oh yes, that is better. Fixed r219

Very cool, thanks.

> Keep it up, I love these improvements :)

:)

 review approve

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJP0LcbAAoJEAbD1bcyW6kF0r4H/iQccWs8wGW1Wr/cWBUQFzOb
+xwhmXR5UnR0MX+Lk+V/VwxTR1sMIWb/ye4t641dv58RgG9HORq0K6A8AMASXz6v
jThP3+3Y/gUmJ3wiJX3SKxUH7gRkskPO39Q5WEUyR6NnARMpXg6ySMMZP/TWZVMr
eeQo5FfoN2WIJf2oK9mod0nKvdBsmuLOVX4c2jwqJKAcj5UaZ1v+1YISG+qHXjYy
NI9LXjaJgJXSKwl+LuGbAL+86sSCo07G0EM3bDpYSK8W82CCuj4yqUfLix5Y8xEF
JS/dfmM93pEkkshTYHhWGjbp7Vx90Dlf4MNLDE73xzd662NAUiidVKPmc1iDmnQ=
=Xwze
-----END PGP SIGNATURE-----

review: Approve
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
No commit message was specified.
http://s-jenkins:8080/job/indicator-power-autolanding/1/

review: Disapprove (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

PASSED: Continuous integration, rev:220
http://s-jenkins:8080/job/indicator-power-ci/2/

review: Approve (continuous-integration)
Revision history for this message
Allan LeSage (allanlesage) wrote :

Attempting to kick off autolanding again. . . .

Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://s-jenkins:8080/job/indicator-power-autolanding/2/

review: Disapprove (continuous-integration)
221. By Charles Kerr

disable test-dbus-listener for now

Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile.am'
2--- Makefile.am 2012-03-27 20:34:42 +0000
3+++ Makefile.am 2012-07-11 17:08:19 +0000
4@@ -1,30 +1,11 @@
5-ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
6-
7-SUBDIRS = \
8- po \
9- data
10-
11-###################
12-# Indicator Stuff
13-###################
14-
15-powerlibdir = $(INDICATORDIR)
16-powerlib_LTLIBRARIES = libpower.la
17-libpower_la_SOURCES = \
18- src/indicator-power.c
19-libpower_la_CFLAGS = \
20- $(UPOWER_CFLAGS) \
21- $(INDICATOR_CFLAGS) \
22- $(COVERAGE_CFLAGS) \
23- -Wall -Werror \
24- -DG_LOG_DOMAIN=\"Indicator-Power\"
25-libpower_la_LIBADD = \
26- $(UPOWER_LIBS) \
27- $(INDICATOR_LIBS)
28-libpower_la_LDFLAGS = \
29- $(COVERAGE_LDFLAGS) \
30- -module \
31- -avoid-version
32+SUBDIRS = po data src
33+
34+if BUILD_TESTS
35+SUBDIRS += tests
36+# build src first
37+tests: src
38+endif
39+
40
41 ############################################################
42
43
44=== modified file 'configure.ac'
45--- configure.ac 2012-04-11 15:02:18 +0000
46+++ configure.ac 2012-07-11 17:08:19 +0000
47@@ -11,7 +11,7 @@
48 AC_CONFIG_MACRO_DIR([m4])
49 AC_CONFIG_AUX_DIR([build-aux])
50
51-AM_INIT_AUTOMAKE([1.11 -Wall foreign subdir-objects dist-xz])
52+AM_INIT_AUTOMAKE([1.11 -Wall foreign dist-xz])
53 AM_MAINTAINER_MODE([enable])
54
55 AM_SILENT_RULES([yes])
56@@ -19,6 +19,7 @@
57 # Check for programs
58 AC_PROG_CC
59 AM_PROG_CC_C_O
60+AC_PROG_CXX
61
62 # Initialize libtool
63 LT_PREREQ([2.2.6])
64@@ -48,6 +49,26 @@
65 GLIB_GSETTINGS
66
67 ###########################
68+# Google Test framework
69+###########################
70+
71+AC_ARG_ENABLE([tests],
72+ [AS_HELP_STRING([--disable-tests], [Disable test scripts and tools (default=auto)])],
73+ [enable_tests=${enableval}],
74+ [enable_tests=auto])
75+if test "x$enable_tests" != "xno"; then
76+ m4_include([m4/gtest.m4])
77+ CHECK_GTEST
78+ CHECK_XORG_GTEST
79+ if test "x$enable_tests" = "xauto"; then
80+ enable_tests=${have_gtest}
81+ elif test "x$enable_tests" = "xyes" && test "x$have_gtest" != "xyes"; then
82+ AC_MSG_ERROR([tests were requested but gtest is not installed.])
83+ fi
84+fi
85+AM_CONDITIONAL([BUILD_TESTS],[test "x$enable_tests" = "xyes"])
86+
87+###########################
88 # gcov coverage reporting
89 ###########################
90
91@@ -119,6 +140,8 @@
92 Makefile
93 po/Makefile.in
94 data/Makefile
95+src/Makefile
96+tests/Makefile
97 ])
98 AC_OUTPUT
99
100@@ -132,5 +155,7 @@
101
102 Prefix: $prefix
103 Local Install: $with_localinstall
104+ Unit Tests: $enable_tests
105 gcov: $use_gcov
106+
107 ])
108
109=== added file 'm4/gtest.m4'
110--- m4/gtest.m4 1970-01-01 00:00:00 +0000
111+++ m4/gtest.m4 2012-07-11 17:08:19 +0000
112@@ -0,0 +1,63 @@
113+# Copyright (C) 2012 Canonical, Ltd.
114+#
115+# Permission is hereby granted, free of charge, to any person obtaining a copy
116+# of this software and associated documentation files (the "Software"), to deal
117+# in the Software without restriction, including without limitation the rights
118+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
119+# copies of the Software, and to permit persons to whom the Software is
120+# furnished to do so, subject to the following conditions:
121+#
122+# The above copyright notice and this permission notice (including the next
123+# paragraph) shall be included in all copies or substantial portions of the
124+# Software.
125+#
126+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
127+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
128+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
129+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
130+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
131+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
132+# SOFTWARE.
133+
134+# Checks whether the gtest source is available on the system. Allows for
135+# adjusting the include and source path. Sets have_gtest=yes if the source is
136+# present. Sets GTEST_CPPFLAGS and GTEST_SOURCE to the preprocessor flags and
137+# source location respectively.
138+AC_DEFUN([CHECK_GTEST],
139+[
140+ AC_ARG_WITH([gtest-include-path],
141+ [AS_HELP_STRING([--with-gtest-include-path],
142+ [location of the Google test headers])],
143+ [GTEST_CPPFLAGS="-I$withval"])
144+
145+ AC_ARG_WITH([gtest-source-path],
146+ [AS_HELP_STRING([--with-gtest-source-path],
147+ [location of the Google test sources, defaults to /usr/src/gtest])],
148+ [GTEST_SOURCE="$withval"],
149+ [GTEST_SOURCE="/usr/src/gtest"])
150+
151+ GTEST_CPPFLAGS="$GTEST_CPPFLAGS -I$GTEST_SOURCE"
152+
153+ AC_LANG_PUSH([C++])
154+
155+ tmp_CPPFLAGS="$CPPFLAGS"
156+ CPPFLAGS="$CPPFLAGS $GTEST_CPPFLAGS"
157+
158+ AC_CHECK_HEADER([gtest/gtest.h])
159+
160+ CPPFLAGS="$tmp_CPPFLAGS"
161+
162+ AC_LANG_POP
163+
164+ AC_CHECK_FILES([$GTEST_SOURCE/src/gtest-all.cc]
165+ [$GTEST_SOURCE/src/gtest_main.cc],
166+ [have_gtest_source=yes],
167+ [have_gtest_source=no])
168+
169+ AS_IF([test "x$ac_cv_header_gtest_gtest_h" = xyes -a \
170+ "x$have_gtest_source" = xyes],
171+ [have_gtest=yes]
172+ [AC_SUBST(GTEST_CPPFLAGS)]
173+ [AC_SUBST(GTEST_SOURCE)],
174+ [have_gtest=no])
175+]) # CHECK_GTEST
176
177=== modified file 'po/POTFILES.in'
178--- po/POTFILES.in 2011-09-23 17:13:42 +0000
179+++ po/POTFILES.in 2012-07-11 17:08:19 +0000
180@@ -1,2 +1,4 @@
181 data/com.canonical.indicator.power.gschema.xml.in
182+src/device.c
183+src/dbus-listener.c
184 src/indicator-power.c
185
186=== added file 'src/Makefile.am'
187--- src/Makefile.am 1970-01-01 00:00:00 +0000
188+++ src/Makefile.am 2012-07-11 17:08:19 +0000
189@@ -0,0 +1,36 @@
190+CLEANFILES =
191+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
192+
193+###################
194+# Indicator Stuff
195+###################
196+
197+powerlibdir = $(INDICATORDIR)
198+powerlib_LTLIBRARIES = libpower.la
199+
200+libpower_la_SOURCES = \
201+ dbus-listener.c \
202+ dbus-listener.h \
203+ device.c \
204+ device.h \
205+ indicator-power.h \
206+ indicator-power.c
207+
208+CLEANFILES += .libs/*.gcda .libs/*.gcno *.gcda *.gcno
209+
210+libpower_la_CFLAGS = \
211+ $(UPOWER_CFLAGS) \
212+ $(INDICATOR_CFLAGS) \
213+ $(COVERAGE_CFLAGS) \
214+ -Wall -Werror \
215+ -DG_LOG_DOMAIN=\"Indicator-Power\"
216+
217+libpower_la_LIBADD = \
218+ $(UPOWER_LIBS) \
219+ $(INDICATOR_LIBS)
220+
221+libpower_la_LDFLAGS = \
222+ $(COVERAGE_LDFLAGS) \
223+ -module \
224+ -avoid-version
225+
226
227=== added file 'src/dbus-listener.c'
228--- src/dbus-listener.c 1970-01-01 00:00:00 +0000
229+++ src/dbus-listener.c 2012-07-11 17:08:19 +0000
230@@ -0,0 +1,247 @@
231+/*
232+
233+Listens on DBus for Power changes and passes them to an IndicatorPower
234+
235+Copyright 2012 Canonical Ltd.
236+
237+Authors:
238+ Charles Kerr <charles.kerr@canonical.com>
239+
240+This library is free software; you can redistribute it and/or
241+modify it under the terms of the GNU General Public License
242+version 3.0 as published by the Free Software Foundation.
243+
244+This library is distributed in the hope that it will be useful,
245+but WITHOUT ANY WARRANTY; without even the implied warranty of
246+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
247+GNU General Public License version 3.0 for more details.
248+
249+You should have received a copy of the GNU General Public
250+License along with this library. If not, see
251+<http://www.gnu.org/licenses/>.
252+*/
253+
254+#include "dbus-listener.h"
255+#include "device.h"
256+
257+struct _IndicatorPowerDbusListenerPrivate
258+{
259+ GCancellable * cancellable;
260+ GDBusProxy * proxy;
261+ guint watcher_id;
262+};
263+
264+#define INDICATOR_POWER_DBUS_LISTENER_GET_PRIVATE(o) (INDICATOR_POWER_DBUS_LISTENER(o)->priv)
265+
266+/* Signals */
267+enum {
268+ SIGNAL_DEVICES,
269+ SIGNAL_LAST
270+};
271+static guint signals[SIGNAL_LAST] = { 0 };
272+
273+
274+/* GObject stuff */
275+static void indicator_power_dbus_listener_class_init (IndicatorPowerDbusListenerClass *klass);
276+static void indicator_power_dbus_listener_init (IndicatorPowerDbusListener *self);
277+static void indicator_power_dbus_listener_dispose (GObject *object);
278+static void indicator_power_dbus_listener_finalize (GObject *object);
279+
280+static void gsd_appeared_callback (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data);
281+
282+/* LCOV_EXCL_START */
283+G_DEFINE_TYPE (IndicatorPowerDbusListener, indicator_power_dbus_listener, G_TYPE_OBJECT);
284+/* LCOV_EXCL_STOP */
285+
286+static void
287+indicator_power_dbus_listener_class_init (IndicatorPowerDbusListenerClass *klass)
288+{
289+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
290+
291+ g_type_class_add_private (klass, sizeof (IndicatorPowerDbusListenerPrivate));
292+
293+ /* methods */
294+ object_class->dispose = indicator_power_dbus_listener_dispose;
295+ object_class->finalize = indicator_power_dbus_listener_finalize;
296+
297+ /**
298+ * IndicatorPowerDbusListener::devices-enumerated:
299+ *
300+ * @listener: the IndicatorPowerDbusListener
301+ * @devices: a GSList of #IndicatorPowerDevice objects. (transfer none)
302+ *
303+ * This is emitted each time a new set of devices is enumerated over the bus.
304+ */
305+ signals[SIGNAL_DEVICES] = g_signal_new (INDICATOR_POWER_DBUS_LISTENER_DEVICES_ENUMERATED,
306+ G_TYPE_FROM_CLASS(klass), 0,
307+ G_STRUCT_OFFSET (IndicatorPowerDbusListenerClass, devices_enumerated),
308+ NULL, NULL,
309+ g_cclosure_marshal_VOID__POINTER,
310+ G_TYPE_NONE, 1, G_TYPE_POINTER);
311+}
312+
313+/* Initialize an instance */
314+static void
315+indicator_power_dbus_listener_init (IndicatorPowerDbusListener *self)
316+{
317+ IndicatorPowerDbusListenerPrivate * priv;
318+
319+ priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
320+ INDICATOR_POWER_DBUS_LISTENER_TYPE,
321+ IndicatorPowerDbusListenerPrivate);
322+
323+ priv->cancellable = g_cancellable_new ();
324+
325+ priv->watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
326+ GSD_SERVICE,
327+ G_BUS_NAME_WATCHER_FLAGS_NONE,
328+ gsd_appeared_callback,
329+ NULL,
330+ self,
331+ NULL);
332+
333+ self->priv = priv;
334+}
335+
336+static void
337+indicator_power_dbus_listener_dispose (GObject *object)
338+{
339+ IndicatorPowerDbusListener * self = INDICATOR_POWER_DBUS_LISTENER(object);
340+ IndicatorPowerDbusListenerPrivate * priv = self->priv;
341+
342+ g_clear_object (&priv->proxy);
343+
344+ if (priv->cancellable != NULL)
345+ {
346+ g_cancellable_cancel (priv->cancellable);
347+ g_clear_object (&priv->cancellable);
348+ }
349+
350+ if (priv->watcher_id)
351+ {
352+ g_bus_unwatch_name (priv->watcher_id);
353+ priv->watcher_id = 0;
354+ }
355+
356+ G_OBJECT_CLASS (indicator_power_dbus_listener_parent_class)->dispose (object);
357+}
358+
359+static void
360+indicator_power_dbus_listener_finalize (GObject *object)
361+{
362+ G_OBJECT_CLASS (indicator_power_dbus_listener_parent_class)->finalize (object);
363+}
364+
365+/***
366+****
367+***/
368+
369+static void
370+get_devices_cb (GObject * source_object,
371+ GAsyncResult * res,
372+ gpointer user_data)
373+{
374+ GError *error;
375+ GSList * devices = NULL;
376+ GVariant * devices_container;
377+ IndicatorPowerDbusListener * self = INDICATOR_POWER_DBUS_LISTENER (user_data);
378+
379+ /* build an array of IndicatorPowerDevices from the DBus response */
380+ error = NULL;
381+ devices_container = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
382+ if (devices_container == NULL)
383+ {
384+ g_message ("Couldn't get devices: %s\n", error->message);
385+ g_error_free (error);
386+ }
387+ else
388+ {
389+ gsize i;
390+ GVariant * devices_variant = g_variant_get_child_value (devices_container, 0);
391+ const int device_count = devices_variant ? g_variant_n_children (devices_variant) : 0;
392+
393+ for (i=0; i<device_count; i++)
394+ {
395+ GVariant * v = g_variant_get_child_value (devices_variant, i);
396+ devices = g_slist_prepend (devices, indicator_power_device_new_from_variant (v));
397+ g_variant_unref (v);
398+ }
399+
400+ devices = g_slist_reverse (devices);
401+
402+ g_variant_unref (devices_variant);
403+ g_variant_unref (devices_container);
404+ }
405+
406+ g_signal_emit (self, signals[SIGNAL_DEVICES], (GQuark)0, devices);
407+ g_slist_free_full (devices, g_object_unref);
408+}
409+
410+static void
411+request_device_list (IndicatorPowerDbusListener * self)
412+{
413+ g_dbus_proxy_call (self->priv->proxy,
414+ "GetDevices",
415+ NULL,
416+ G_DBUS_CALL_FLAGS_NONE,
417+ -1,
418+ self->priv->cancellable,
419+ get_devices_cb,
420+ self);
421+}
422+
423+static void
424+receive_properties_changed (GDBusProxy *proxy G_GNUC_UNUSED,
425+ GVariant *changed_properties G_GNUC_UNUSED,
426+ GStrv invalidated_properties G_GNUC_UNUSED,
427+ gpointer user_data)
428+{
429+ request_device_list (INDICATOR_POWER_DBUS_LISTENER(user_data));
430+}
431+
432+
433+static void
434+service_proxy_cb (GObject *object,
435+ GAsyncResult *res,
436+ gpointer user_data)
437+{
438+ GError * error = NULL;
439+ IndicatorPowerDbusListener * self = INDICATOR_POWER_DBUS_LISTENER(user_data);
440+ IndicatorPowerDbusListenerPrivate * priv = self->priv;
441+
442+ priv->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
443+
444+ if (error != NULL)
445+ {
446+ g_error ("Error creating proxy: %s", error->message);
447+ g_error_free (error);
448+ return;
449+ }
450+
451+ /* we want to change the primary device changes */
452+ g_signal_connect (priv->proxy, "g-properties-changed",
453+ G_CALLBACK (receive_properties_changed), user_data);
454+
455+ /* get the initial state */
456+ request_device_list (self);
457+}
458+
459+static void
460+gsd_appeared_callback (GDBusConnection *connection,
461+ const gchar *name,
462+ const gchar *name_owner,
463+ gpointer user_data)
464+{
465+ IndicatorPowerDbusListener * self = INDICATOR_POWER_DBUS_LISTENER(user_data);
466+ IndicatorPowerDbusListenerPrivate * priv = self->priv;
467+
468+ g_dbus_proxy_new (connection,
469+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
470+ NULL,
471+ name,
472+ GSD_POWER_DBUS_PATH,
473+ GSD_POWER_DBUS_INTERFACE,
474+ priv->cancellable,
475+ service_proxy_cb,
476+ self);
477+}
478
479=== added file 'src/dbus-listener.h'
480--- src/dbus-listener.h 1970-01-01 00:00:00 +0000
481+++ src/dbus-listener.h 2012-07-11 17:08:19 +0000
482@@ -0,0 +1,82 @@
483+/*
484+
485+Listens for Power changes from org.gnome.SettingsDaemon.Power on Dbus
486+
487+Copyright 2012 Canonical Ltd.
488+
489+Authors:
490+ Javier Jardon <javier.jardon@codethink.co.uk>
491+ Charles Kerr <charles.kerr@canonical.com>
492+
493+This library is free software; you can redistribute it and/or
494+modify it under the terms of the GNU General Public License
495+version 3.0 as published by the Free Software Foundation.
496+
497+This library is distributed in the hope that it will be useful,
498+but WITHOUT ANY WARRANTY; without even the implied warranty of
499+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
500+GNU General Public License version 3.0 for more details.
501+
502+You should have received a copy of the GNU General Public
503+License along with this library. If not, see
504+<http://www.gnu.org/licenses/>.
505+*/
506+
507+#ifndef __INDICATOR_POWER_DBUS_LISTENER_H__
508+#define __INDICATOR_POWER_DBUS_LISTENER_H__
509+
510+#include <glib-object.h>
511+#include <libupower-glib/upower.h>
512+
513+G_BEGIN_DECLS
514+
515+#define INDICATOR_POWER_DBUS_LISTENER_TYPE (indicator_power_dbus_listener_get_type ())
516+#define INDICATOR_POWER_DBUS_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_POWER_DBUS_LISTENER_TYPE, IndicatorPowerDbusListener))
517+#define INDICATOR_POWER_DBUS_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_POWER_DBUS_LISTENER_TYPE, IndicatorPowerDbusListenerClass))
518+#define INDICATOR_IS_POWER_DBUS_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_POWER_DBUS_LISTENER_TYPE))
519+#define INDICATOR_IS_POWER_DBUS_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_POWER_DBUS_LISTENER_TYPE))
520+#define INDICATOR_POWER_DBUS_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_POWER_DBUS_LISTENER_TYPE, IndicatorPowerDbusListenerClass))
521+
522+typedef struct _IndicatorPowerDbusListener IndicatorPowerDbusListener;
523+typedef struct _IndicatorPowerDbusListenerClass IndicatorPowerDbusListenerClass;
524+typedef struct _IndicatorPowerDbusListenerPrivate IndicatorPowerDbusListenerPrivate;
525+
526+#define GSD_SERVICE "org.gnome.SettingsDaemon"
527+#define GSD_PATH "/org/gnome/SettingsDaemon"
528+#define GSD_POWER_DBUS_INTERFACE GSD_SERVICE ".Power"
529+#define GSD_POWER_DBUS_PATH GSD_PATH "/Power"
530+
531+/* signals */
532+#define INDICATOR_POWER_DBUS_LISTENER_DEVICES_ENUMERATED "devices-enumerated"
533+
534+/**
535+ * IndicatorPowerDbusListenerClass:
536+ * @parent_class: #GObjectClass
537+ */
538+struct _IndicatorPowerDbusListenerClass
539+{
540+ GObjectClass parent_class;
541+
542+ void (* devices_enumerated) (IndicatorPowerDbusListener*, GSList * devices);
543+};
544+
545+/**
546+ * IndicatorPowerDbusListener:
547+ * @parent: #GObject
548+ * @priv: A cached reference to the private data for the instance.
549+*/
550+struct _IndicatorPowerDbusListener
551+{
552+ GObject parent;
553+ IndicatorPowerDbusListenerPrivate * priv;
554+};
555+
556+/***
557+****
558+***/
559+
560+GType indicator_power_dbus_listener_get_type (void);
561+
562+G_END_DECLS
563+
564+#endif
565
566=== added file 'src/device.c'
567--- src/device.c 1970-01-01 00:00:00 +0000
568+++ src/device.c 2012-07-11 17:08:19 +0000
569@@ -0,0 +1,666 @@
570+/*
571+
572+A simple Device structure used internally by indicator-power
573+
574+Copyright 2012 Canonical Ltd.
575+
576+Authors:
577+ Charles Kerr <charles.kerr@canonical.com>
578+
579+This library is free software; you can redistribute it and/or
580+modify it under the terms of the GNU General Public License
581+version 3.0 as published by the Free Software Foundation.
582+
583+This library is distributed in the hope that it will be useful,
584+but WITHOUT ANY WARRANTY; without even the implied warranty of
585+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
586+GNU General Public License version 3.0 for more details.
587+
588+You should have received a copy of the GNU General Public
589+License along with this library. If not, see
590+<http://www.gnu.org/licenses/>.
591+*/
592+
593+#ifdef HAVE_CONFIG_H
594+ #include "config.h"
595+#endif
596+
597+#include <glib/gi18n.h>
598+
599+#include "device.h"
600+
601+struct _IndicatorPowerDevicePrivate
602+{
603+ UpDeviceKind kind;
604+ UpDeviceState state;
605+ gchar * object_path;
606+ gdouble percentage;
607+ time_t time;
608+};
609+
610+#define INDICATOR_POWER_DEVICE_GET_PRIVATE(o) (INDICATOR_POWER_DEVICE(o)->priv)
611+
612+/* Properties */
613+/* Enum for the properties so that they can be quickly found and looked up. */
614+enum {
615+ PROP_0,
616+ PROP_KIND,
617+ PROP_STATE,
618+ PROP_OBJECT_PATH,
619+ PROP_PERCENTAGE,
620+ PROP_TIME,
621+ N_PROPERTIES
622+};
623+
624+static GParamSpec * properties[N_PROPERTIES];
625+
626+/* GObject stuff */
627+static void indicator_power_device_class_init (IndicatorPowerDeviceClass *klass);
628+static void indicator_power_device_init (IndicatorPowerDevice *self);
629+static void indicator_power_device_dispose (GObject *object);
630+static void indicator_power_device_finalize (GObject *object);
631+static void set_property (GObject*, guint prop_id, const GValue*, GParamSpec* );
632+static void get_property (GObject*, guint prop_id, GValue*, GParamSpec* );
633+
634+/* LCOV_EXCL_START */
635+G_DEFINE_TYPE (IndicatorPowerDevice, indicator_power_device, G_TYPE_OBJECT);
636+/* LCOV_EXCL_STOP */
637+
638+static void
639+indicator_power_device_class_init (IndicatorPowerDeviceClass *klass)
640+{
641+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
642+
643+ g_type_class_add_private (klass, sizeof (IndicatorPowerDevicePrivate));
644+
645+ object_class->dispose = indicator_power_device_dispose;
646+ object_class->finalize = indicator_power_device_finalize;
647+ object_class->set_property = set_property;
648+ object_class->get_property = get_property;
649+
650+ properties[PROP_KIND] = g_param_spec_int (INDICATOR_POWER_DEVICE_KIND,
651+ "kind",
652+ "The device's UpDeviceKind",
653+ UP_DEVICE_KIND_UNKNOWN, UP_DEVICE_KIND_LAST,
654+ UP_DEVICE_KIND_UNKNOWN,
655+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
656+
657+ properties[PROP_STATE] = g_param_spec_int (INDICATOR_POWER_DEVICE_STATE,
658+ "state",
659+ "The device's UpDeviceState",
660+ UP_DEVICE_STATE_UNKNOWN, UP_DEVICE_STATE_LAST,
661+ UP_DEVICE_STATE_UNKNOWN,
662+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
663+
664+ properties[PROP_OBJECT_PATH] = g_param_spec_string (INDICATOR_POWER_DEVICE_OBJECT_PATH,
665+ "object path",
666+ "The device's DBus object path",
667+ NULL,
668+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
669+
670+ properties[PROP_PERCENTAGE] = g_param_spec_double (INDICATOR_POWER_DEVICE_PERCENTAGE,
671+ "percentage",
672+ "percent charged",
673+ 0.0, 100.0,
674+ 0.0,
675+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
676+
677+ properties[PROP_TIME] = g_param_spec_uint64 (INDICATOR_POWER_DEVICE_TIME,
678+ "time",
679+ "time left",
680+ 0, G_MAXUINT64,
681+ 0,
682+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
683+
684+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
685+}
686+
687+/* Initialize an instance */
688+static void
689+indicator_power_device_init (IndicatorPowerDevice *self)
690+{
691+ IndicatorPowerDevicePrivate * priv;
692+
693+ priv = G_TYPE_INSTANCE_GET_PRIVATE (self, INDICATOR_POWER_DEVICE_TYPE,
694+ IndicatorPowerDevicePrivate);
695+ priv->kind = UP_DEVICE_KIND_UNKNOWN;
696+ priv->state = UP_DEVICE_STATE_UNKNOWN;
697+ priv->object_path = NULL;
698+ priv->percentage = 0.0;
699+ priv->time = 0;
700+
701+ self->priv = priv;
702+}
703+
704+static void
705+indicator_power_device_dispose (GObject *object)
706+{
707+ G_OBJECT_CLASS (indicator_power_device_parent_class)->dispose (object);
708+}
709+
710+static void
711+indicator_power_device_finalize (GObject *object)
712+{
713+ IndicatorPowerDevice * self = INDICATOR_POWER_DEVICE(object);
714+ IndicatorPowerDevicePrivate * priv = self->priv;
715+
716+ g_clear_pointer (&priv->object_path, g_free);
717+
718+ G_OBJECT_CLASS (indicator_power_device_parent_class)->finalize (object);
719+}
720+
721+/***
722+****
723+***/
724+
725+static void
726+get_property (GObject * o, guint prop_id, GValue * value, GParamSpec * pspec)
727+{
728+ IndicatorPowerDevice * self = INDICATOR_POWER_DEVICE(o);
729+ IndicatorPowerDevicePrivate * priv = self->priv;
730+
731+ switch (prop_id)
732+ {
733+ case PROP_KIND:
734+ g_value_set_int (value, priv->kind);
735+ break;
736+
737+ case PROP_STATE:
738+ g_value_set_int (value, priv->state);
739+ break;
740+
741+ case PROP_OBJECT_PATH:
742+ g_value_set_string (value, priv->object_path);
743+ break;
744+
745+ case PROP_PERCENTAGE:
746+ g_value_set_double (value, priv->percentage);
747+ break;
748+
749+ case PROP_TIME:
750+ g_value_set_uint64 (value, priv->time);
751+ break;
752+
753+ default:
754+ G_OBJECT_WARN_INVALID_PROPERTY_ID(o, prop_id, pspec);
755+ break;
756+ }
757+}
758+
759+static void
760+set_property (GObject * o, guint prop_id, const GValue * value, GParamSpec * pspec)
761+{
762+ IndicatorPowerDevice * self = INDICATOR_POWER_DEVICE(o);
763+ IndicatorPowerDevicePrivate * priv = self->priv;
764+
765+ switch (prop_id)
766+ {
767+ case PROP_KIND:
768+ priv->kind = g_value_get_int (value);
769+ break;
770+
771+ case PROP_STATE:
772+ priv->state = g_value_get_int (value);
773+ break;
774+
775+ case PROP_OBJECT_PATH:
776+ g_free (priv->object_path);
777+ priv->object_path = g_value_dup_string (value);
778+ break;
779+
780+ case PROP_PERCENTAGE:
781+ priv->percentage = g_value_get_double (value);
782+ break;
783+
784+ case PROP_TIME:
785+ priv->time = g_value_get_uint64(value);
786+ break;
787+
788+ default:
789+ G_OBJECT_WARN_INVALID_PROPERTY_ID(o, prop_id, pspec);
790+ break;
791+ }
792+}
793+
794+/***
795+**** Accessors
796+***/
797+
798+UpDeviceKind
799+indicator_power_device_get_kind (const IndicatorPowerDevice * device)
800+{
801+ /* LCOV_EXCL_START */
802+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), UP_DEVICE_KIND_UNKNOWN);
803+ /* LCOV_EXCL_STOP */
804+
805+ return device->priv->kind;
806+}
807+
808+UpDeviceState
809+indicator_power_device_get_state (const IndicatorPowerDevice * device)
810+{
811+ /* LCOV_EXCL_START */
812+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), UP_DEVICE_STATE_UNKNOWN);
813+ /* LCOV_EXCL_STOP */
814+
815+ return device->priv->state;
816+}
817+
818+const gchar *
819+indicator_power_device_get_object_path (const IndicatorPowerDevice * device)
820+{
821+ /* LCOV_EXCL_START */
822+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), NULL);
823+ /* LCOV_EXCL_STOP */
824+
825+ return device->priv->object_path;
826+}
827+
828+gdouble
829+indicator_power_device_get_percentage (const IndicatorPowerDevice * device)
830+{
831+ /* LCOV_EXCL_START */
832+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), 0.0);
833+ /* LCOV_EXCL_STOP */
834+
835+ return device->priv->percentage;
836+}
837+
838+time_t
839+indicator_power_device_get_time (const IndicatorPowerDevice * device)
840+{
841+ /* LCOV_EXCL_START */
842+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), (time_t)0);
843+ /* LCOV_EXCL_STOP */
844+
845+ return device->priv->time;
846+}
847+
848+/***
849+****
850+****
851+***/
852+
853+static const gchar *
854+get_device_icon_suffix (gdouble percentage)
855+{
856+ if (percentage >= 60) return "full";
857+ if (percentage >= 30) return "good";
858+ if (percentage >= 10) return "low";
859+ return "caution";
860+}
861+
862+static const gchar *
863+get_device_icon_index (gdouble percentage)
864+{
865+ if (percentage >= 90) return "100";
866+ if (percentage >= 70) return "080";
867+ if (percentage >= 50) return "060";
868+ if (percentage >= 30) return "040";
869+ if (percentage >= 10) return "020";
870+ return "000";
871+}
872+
873+/**
874+ indicator_power_device_get_icon_names:
875+ @device: #IndicatorPowerDevice from which to generate the icon names
876+
877+ This function's logic differs from GSD's power plugin in some ways:
878+
879+ 1. All charging batteries use the same icon regardless of progress.
880+ <https://bugs.launchpad.net/indicator-power/+bug/824629/comments/7>
881+
882+ 2. For discharging batteries, we decide whether or not to use the 'caution'
883+ icon based on whether or not we have <= 30 minutes remaining, rather than
884+ looking at the battery's percentage left.
885+ <https://bugs.launchpad.net/indicator-power/+bug/743823>
886+
887+ See also indicator_power_device_get_gicon().
888+
889+ Return value: (array zero-terminated=1) (transfer full):
890+ A GStrv of icon names suitable for passing to g_themed_icon_new_from_names().
891+ Free with g_strfreev() when done.
892+*/
893+GStrv
894+indicator_power_device_get_icon_names (const IndicatorPowerDevice * device)
895+{
896+ const gchar *suffix_str;
897+ const gchar *index_str;
898+
899+ /* LCOV_EXCL_START */
900+ g_return_val_if_fail (INDICATOR_IS_POWER_DEVICE(device), NULL);
901+ /* LCOV_EXCL_STOP */
902+
903+ gdouble percentage = indicator_power_device_get_percentage (device);
904+ const UpDeviceKind kind = indicator_power_device_get_kind (device);
905+ const UpDeviceState state = indicator_power_device_get_state (device);
906+ const gchar * kind_str = kind_str = up_device_kind_to_string (kind);
907+
908+ GPtrArray * names = g_ptr_array_new ();
909+
910+ if (kind == UP_DEVICE_KIND_LINE_POWER)
911+ {
912+ g_ptr_array_add (names, g_strdup("ac-adapter-symbolic"));
913+ g_ptr_array_add (names, g_strdup("ac-adapter"));
914+ }
915+ else if (kind == UP_DEVICE_KIND_MONITOR)
916+ {
917+ g_ptr_array_add (names, g_strdup("gpm-monitor-symbolic"));
918+ g_ptr_array_add (names, g_strdup("gpm-monitor"));
919+ }
920+ else switch (state)
921+ {
922+ case UP_DEVICE_STATE_EMPTY:
923+ g_ptr_array_add (names, g_strdup("battery-empty-symbolic"));
924+ g_ptr_array_add (names, g_strdup_printf("gpm-%s-empty", kind_str));
925+ g_ptr_array_add (names, g_strdup_printf("gpm-%s-000", kind_str));
926+ g_ptr_array_add (names, g_strdup("battery-empty"));
927+ break;
928+
929+ case UP_DEVICE_STATE_FULLY_CHARGED:
930+ g_ptr_array_add (names, g_strdup("battery-full-charged-symbolic"));
931+ g_ptr_array_add (names, g_strdup("battery-full-charging-symbolic"));
932+ g_ptr_array_add (names, g_strdup_printf("gpm-%s-full", kind_str));
933+ g_ptr_array_add (names, g_strdup_printf("gpm-%s-100", kind_str));
934+ g_ptr_array_add (names, g_strdup("battery-full-charged"));
935+ g_ptr_array_add (names, g_strdup("battery-full-charging"));
936+ break;
937+
938+ case UP_DEVICE_STATE_CHARGING:
939+ case UP_DEVICE_STATE_PENDING_CHARGE:
940+ /* When charging, always use the same icon regardless of percentage.
941+ <http://bugs.launchpad.net/indicator-power/+bug/824629> */
942+ percentage = 0;
943+
944+ suffix_str = get_device_icon_suffix (percentage);
945+ index_str = get_device_icon_index (percentage);
946+ g_ptr_array_add (names, g_strdup_printf ("battery-%s-charging-symbolic", suffix_str));
947+ g_ptr_array_add (names, g_strdup_printf ("gpm-%s-%s-charging", kind_str, index_str));
948+ g_ptr_array_add (names, g_strdup_printf ("battery-%s-charging", suffix_str));
949+ break;
950+
951+ case UP_DEVICE_STATE_DISCHARGING:
952+ case UP_DEVICE_STATE_PENDING_DISCHARGE:
953+ /* Don't show the caution/red icons unless we have <=30 min left.
954+ <https://bugs.launchpad.net/indicator-power/+bug/743823>
955+ Themes use the caution color when the percentage is 0% or 20%,
956+ so if we have >30 min left, use 30% as the icon's percentage floor */
957+ if (indicator_power_device_get_time (device) > (30*60))
958+ percentage = MAX(percentage, 30);
959+
960+ suffix_str = get_device_icon_suffix (percentage);
961+ index_str = get_device_icon_index (percentage);
962+ g_ptr_array_add (names, g_strdup_printf ("battery-%s-symbolic", suffix_str));
963+ g_ptr_array_add (names, g_strdup_printf ("gpm-%s-%s", kind_str, index_str));
964+ g_ptr_array_add (names, g_strdup_printf ("battery-%s", suffix_str));
965+ break;
966+
967+ default:
968+ g_ptr_array_add (names, g_strdup("battery-missing-symbolic"));
969+ g_ptr_array_add (names, g_strdup("gpm-battery-missing"));
970+ g_ptr_array_add (names, g_strdup("battery-missing"));
971+ }
972+
973+ g_ptr_array_add (names, NULL); /* terminates the strv */
974+ return (GStrv) g_ptr_array_free (names, FALSE);
975+}
976+
977+/**
978+ indicator_power_device_get_gicon:
979+ @device: #IndicatorPowerDevice to generate the icon names from
980+
981+ A convenience function to call g_themed_icon_new_from_names()
982+ with the names returned by indicator_power_device_get_icon_names()
983+
984+ Return value: (transfer full): A themed GIcon
985+*/
986+GIcon *
987+indicator_power_device_get_gicon (const IndicatorPowerDevice * device)
988+{
989+ GStrv names = indicator_power_device_get_icon_names (device);
990+ GIcon * icon = g_themed_icon_new_from_names (names, -1);
991+ g_strfreev (names);
992+ return icon;
993+}
994+
995+/***
996+****
997+***/
998+
999+static void
1000+get_timestring (guint64 time_secs,
1001+ gchar **short_timestring,
1002+ gchar **detailed_timestring)
1003+{
1004+ gint hours;
1005+ gint minutes;
1006+
1007+ /* Add 0.5 to do rounding */
1008+ minutes = (int) ( ( time_secs / 60.0 ) + 0.5 );
1009+
1010+ if (minutes == 0)
1011+ {
1012+ *short_timestring = g_strdup (_("Unknown time"));
1013+ *detailed_timestring = g_strdup (_("Unknown time"));
1014+
1015+ return;
1016+ }
1017+
1018+ if (minutes < 60)
1019+ {
1020+ *short_timestring = g_strdup_printf ("0:%.2i", minutes);
1021+ *detailed_timestring = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%i minute",
1022+ "%i minutes",
1023+ minutes), minutes);
1024+ return;
1025+ }
1026+
1027+ hours = minutes / 60;
1028+ minutes = minutes % 60;
1029+
1030+ *short_timestring = g_strdup_printf ("%i:%.2i", hours, minutes);
1031+
1032+ if (minutes == 0)
1033+ {
1034+ *detailed_timestring = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
1035+ "%i hour",
1036+ "%i hours",
1037+ hours), hours);
1038+ }
1039+ else
1040+ {
1041+ /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes"
1042+ * Swap order with "%2$s %2$i %1$s %1$i if needed */
1043+ *detailed_timestring = g_strdup_printf (_("%i %s %i %s"),
1044+ hours, g_dngettext (GETTEXT_PACKAGE, "hour", "hours", hours),
1045+ minutes, g_dngettext (GETTEXT_PACKAGE, "minute", "minutes", minutes));
1046+ }
1047+}
1048+
1049+static const gchar *
1050+device_kind_to_localised_string (UpDeviceKind kind)
1051+{
1052+ const gchar *text = NULL;
1053+
1054+ switch (kind) {
1055+ case UP_DEVICE_KIND_LINE_POWER:
1056+ /* TRANSLATORS: system power cord */
1057+ text = _("AC Adapter");
1058+ break;
1059+ case UP_DEVICE_KIND_BATTERY:
1060+ /* TRANSLATORS: laptop primary battery */
1061+ text = _("Battery");
1062+ break;
1063+ case UP_DEVICE_KIND_UPS:
1064+ /* TRANSLATORS: battery-backed AC power source */
1065+ text = _("UPS");
1066+ break;
1067+ case UP_DEVICE_KIND_MONITOR:
1068+ /* TRANSLATORS: a monitor is a device to measure voltage and current */
1069+ text = _("Monitor");
1070+ break;
1071+ case UP_DEVICE_KIND_MOUSE:
1072+ /* TRANSLATORS: wireless mice with internal batteries */
1073+ text = _("Mouse");
1074+ break;
1075+ case UP_DEVICE_KIND_KEYBOARD:
1076+ /* TRANSLATORS: wireless keyboard with internal battery */
1077+ text = _("Keyboard");
1078+ break;
1079+ case UP_DEVICE_KIND_PDA:
1080+ /* TRANSLATORS: portable device */
1081+ text = _("PDA");
1082+ break;
1083+ case UP_DEVICE_KIND_PHONE:
1084+ /* TRANSLATORS: cell phone (mobile...) */
1085+ text = _("Cell phone");
1086+ break;
1087+ case UP_DEVICE_KIND_MEDIA_PLAYER:
1088+ /* TRANSLATORS: media player, mp3 etc */
1089+ text = _("Media player");
1090+ break;
1091+ case UP_DEVICE_KIND_TABLET:
1092+ /* TRANSLATORS: tablet device */
1093+ text = _("Tablet");
1094+ break;
1095+ case UP_DEVICE_KIND_COMPUTER:
1096+ /* TRANSLATORS: tablet device */
1097+ text = _("Computer");
1098+ break;
1099+ default:
1100+ g_warning ("enum unrecognised: %i", kind);
1101+ text = up_device_kind_to_string (kind);
1102+ }
1103+
1104+ return text;
1105+}
1106+
1107+void
1108+indicator_power_device_get_time_details (const IndicatorPowerDevice * device,
1109+ gchar ** short_details,
1110+ gchar ** details,
1111+ gchar ** accessible_name)
1112+{
1113+ if (!INDICATOR_IS_POWER_DEVICE(device))
1114+ {
1115+ *short_details = NULL;
1116+ *details = NULL;
1117+ *accessible_name = NULL;
1118+ g_warning ("%s: %p is not an IndicatorPowerDevice", G_STRFUNC, device);
1119+ return;
1120+ }
1121+
1122+ const time_t time = indicator_power_device_get_time (device);
1123+ const UpDeviceState state = indicator_power_device_get_state (device);
1124+ const gdouble percentage = indicator_power_device_get_percentage (device);
1125+ const UpDeviceKind kind = indicator_power_device_get_kind (device);
1126+ const gchar * device_name = device_kind_to_localised_string (kind);
1127+
1128+ if (time > 0)
1129+ {
1130+ gchar *short_timestring = NULL;
1131+ gchar *detailed_timestring = NULL;
1132+
1133+ get_timestring (time,
1134+ &short_timestring,
1135+ &detailed_timestring);
1136+
1137+ if (state == UP_DEVICE_STATE_CHARGING)
1138+ {
1139+ /* TRANSLATORS: %2 is a time string, e.g. "1 hour 5 minutes" */
1140+ *accessible_name = g_strdup_printf (_("%s (%s to charge (%.0lf%%))"), device_name, detailed_timestring, percentage);
1141+ *details = g_strdup_printf (_("%s (%s to charge)"), device_name, short_timestring);
1142+ *short_details = g_strdup_printf ("(%s)", short_timestring);
1143+ }
1144+ else if ((state == UP_DEVICE_STATE_DISCHARGING) && (time > (60*60*12)))
1145+ {
1146+ *accessible_name = g_strdup_printf (_("%s"), device_name);
1147+ *details = g_strdup_printf (_("%s"), device_name);
1148+ *short_details = g_strdup (short_timestring);
1149+ }
1150+ else
1151+ {
1152+ /* TRANSLATORS: %2 is a time string, e.g. "1 hour 5 minutes" */
1153+ *accessible_name = g_strdup_printf (_("%s (%s left (%.0lf%%))"), device_name, detailed_timestring, percentage);
1154+ *details = g_strdup_printf (_("%s (%s left)"), device_name, short_timestring);
1155+ *short_details = g_strdup (short_timestring);
1156+ }
1157+
1158+ g_free (short_timestring);
1159+ g_free (detailed_timestring);
1160+ }
1161+ else if (state == UP_DEVICE_STATE_FULLY_CHARGED)
1162+ {
1163+ *details = g_strdup_printf (_("%s (charged)"), device_name);
1164+ *accessible_name = g_strdup (*details);
1165+ *short_details = g_strdup ("");
1166+ }
1167+ else if (percentage > 0)
1168+ {
1169+ /* TRANSLATORS: %2 is a percentage value. Note: this string is only
1170+ * used when we don't have a time value */
1171+ *details = g_strdup_printf (_("%s (%.0lf%%)"), device_name, percentage);
1172+ *accessible_name = g_strdup (*details);
1173+ *short_details = g_strdup_printf (_("(%.0lf%%)"), percentage);
1174+ }
1175+ else if (kind == UP_DEVICE_KIND_LINE_POWER)
1176+ {
1177+ *details = g_strdup (device_name);
1178+ *accessible_name = g_strdup (device_name);
1179+ *short_details = g_strdup (device_name);
1180+ }
1181+ else
1182+ {
1183+ *details = g_strdup_printf (_("%s (not present)"), device_name);
1184+ *accessible_name = g_strdup (*details);
1185+ *short_details = g_strdup (_("(not present)"));
1186+ }
1187+}
1188+
1189+/***
1190+**** Instantiation
1191+***/
1192+
1193+IndicatorPowerDevice *
1194+indicator_power_device_new (const gchar * object_path,
1195+ UpDeviceKind kind,
1196+ gdouble percentage,
1197+ UpDeviceState state,
1198+ time_t timestamp)
1199+{
1200+ GObject * o = g_object_new (INDICATOR_POWER_DEVICE_TYPE,
1201+ INDICATOR_POWER_DEVICE_KIND, kind,
1202+ INDICATOR_POWER_DEVICE_STATE, state,
1203+ INDICATOR_POWER_DEVICE_OBJECT_PATH, object_path,
1204+ INDICATOR_POWER_DEVICE_PERCENTAGE, percentage,
1205+ INDICATOR_POWER_DEVICE_TIME, (guint64)timestamp,
1206+ NULL);
1207+ return INDICATOR_POWER_DEVICE(o);
1208+}
1209+
1210+IndicatorPowerDevice *
1211+indicator_power_device_new_from_variant (GVariant * v)
1212+{
1213+ g_return_val_if_fail (g_variant_is_of_type (v, G_VARIANT_TYPE("(susdut)")), NULL);
1214+
1215+ UpDeviceKind kind = UP_DEVICE_KIND_UNKNOWN;
1216+ UpDeviceState state = UP_DEVICE_STATE_UNKNOWN;
1217+ const gchar * icon = NULL;
1218+ const gchar * object_path = NULL;
1219+ gdouble percentage = 0;
1220+ guint64 time = 0;
1221+
1222+ g_variant_get (v, "(&su&sdut)",
1223+ &object_path,
1224+ &kind,
1225+ &icon,
1226+ &percentage,
1227+ &state,
1228+ &time);
1229+
1230+ return indicator_power_device_new (object_path,
1231+ kind,
1232+ percentage,
1233+ state,
1234+ time);
1235+}
1236
1237=== added file 'src/device.h'
1238--- src/device.h 1970-01-01 00:00:00 +0000
1239+++ src/device.h 2012-07-11 17:08:19 +0000
1240@@ -0,0 +1,107 @@
1241+/*
1242+
1243+A simple Device structure used internally by indicator-power
1244+
1245+Copyright 2012 Canonical Ltd.
1246+
1247+Authors:
1248+ Charles Kerr <charles.kerr@canonical.com>
1249+
1250+This library is free software; you can redistribute it and/or
1251+modify it under the terms of the GNU General Public License
1252+version 3.0 as published by the Free Software Foundation.
1253+
1254+This library is distributed in the hope that it will be useful,
1255+but WITHOUT ANY WARRANTY; without even the implied warranty of
1256+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1257+GNU General Public License version 3.0 for more details.
1258+
1259+You should have received a copy of the GNU General Public
1260+License along with this library. If not, see
1261+<http://www.gnu.org/licenses/>.
1262+*/
1263+
1264+#ifndef __INDICATOR_POWER_DEVICE_H__
1265+#define __INDICATOR_POWER_DEVICE_H__
1266+
1267+#include <glib-object.h>
1268+#include <libupower-glib/upower.h>
1269+
1270+G_BEGIN_DECLS
1271+
1272+#define INDICATOR_POWER_DEVICE_TYPE (indicator_power_device_get_type ())
1273+#define INDICATOR_POWER_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_POWER_DEVICE_TYPE, IndicatorPowerDevice))
1274+#define INDICATOR_POWER_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_POWER_DEVICE_TYPE, IndicatorPowerDeviceClass))
1275+#define INDICATOR_IS_POWER_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_POWER_DEVICE_TYPE))
1276+#define INDICATOR_IS_POWER_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_POWER_DEVICE_TYPE))
1277+#define INDICATOR_POWER_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_POWER_DEVICE_TYPE, IndicatorPowerDeviceClass))
1278+
1279+typedef struct _IndicatorPowerDevice IndicatorPowerDevice;
1280+typedef struct _IndicatorPowerDeviceClass IndicatorPowerDeviceClass;
1281+typedef struct _IndicatorPowerDevicePrivate IndicatorPowerDevicePrivate;
1282+
1283+#define INDICATOR_POWER_DEVICE_KIND "kind"
1284+#define INDICATOR_POWER_DEVICE_STATE "state"
1285+#define INDICATOR_POWER_DEVICE_OBJECT_PATH "object-path"
1286+#define INDICATOR_POWER_DEVICE_PERCENTAGE "percentage"
1287+#define INDICATOR_POWER_DEVICE_TIME "time"
1288+
1289+/**
1290+ * IndicatorPowerDeviceClass:
1291+ * @parent_class: #GObjectClass
1292+ */
1293+struct _IndicatorPowerDeviceClass
1294+{
1295+ GObjectClass parent_class;
1296+};
1297+
1298+/**
1299+ * IndicatorPowerDevice:
1300+ * @parent: #GObject
1301+ * @priv: A cached reference to the private data for the instance.
1302+*/
1303+struct _IndicatorPowerDevice
1304+{
1305+ GObject parent;
1306+ IndicatorPowerDevicePrivate * priv;
1307+};
1308+
1309+/***
1310+****
1311+***/
1312+
1313+GType indicator_power_device_get_type (void);
1314+
1315+IndicatorPowerDevice* indicator_power_device_new (const gchar * object_path,
1316+ UpDeviceKind kind,
1317+ gdouble percentage,
1318+ UpDeviceState state,
1319+ time_t time);
1320+
1321+/**
1322+ * Convenience wrapper around indicator_power_device_new()
1323+ * @variant holds the same args as indicator_power_device_new() in "(susdut)"
1324+ */
1325+IndicatorPowerDevice* indicator_power_device_new_from_variant (GVariant * variant);
1326+
1327+
1328+UpDeviceKind indicator_power_device_get_kind (const IndicatorPowerDevice * device);
1329+UpDeviceState indicator_power_device_get_state (const IndicatorPowerDevice * device);
1330+const gchar * indicator_power_device_get_object_path (const IndicatorPowerDevice * device);
1331+gdouble indicator_power_device_get_percentage (const IndicatorPowerDevice * device);
1332+time_t indicator_power_device_get_time (const IndicatorPowerDevice * device);
1333+
1334+GStrv indicator_power_device_get_icon_names (const IndicatorPowerDevice * device);
1335+GIcon * indicator_power_device_get_gicon (const IndicatorPowerDevice * device);
1336+
1337+void indicator_power_device_get_time_details (const IndicatorPowerDevice * device,
1338+ gchar ** short_details,
1339+ gchar ** details,
1340+ gchar ** accessible_name);
1341+
1342+
1343+
1344+
1345+G_END_DECLS
1346+
1347+#endif
1348
1349=== modified file 'src/indicator-power.c'
1350--- src/indicator-power.c 2012-04-15 14:23:24 +0000
1351+++ src/indicator-power.c 2012-07-11 17:08:19 +0000
1352@@ -20,7 +20,7 @@
1353 */
1354
1355 #ifdef HAVE_CONFIG_H
1356-#include "config.h"
1357+ #include "config.h"
1358 #endif
1359
1360 /* GStuff */
1361@@ -28,67 +28,41 @@
1362 #include <glib/gi18n-lib.h>
1363 #include <gio/gio.h>
1364
1365-/* upower */
1366-#include <libupower-glib/upower.h>
1367-
1368-/* Indicator Stuff */
1369-#include <libindicator/indicator.h>
1370-#include <libindicator/indicator-object.h>
1371+#include "dbus-listener.h"
1372+#include "device.h"
1373+#include "indicator-power.h"
1374
1375 #define ICON_POLICY_KEY "icon-policy"
1376
1377 #define DEFAULT_ICON "gpm-battery-missing"
1378
1379-#define DBUS_SERVICE "org.gnome.SettingsDaemon"
1380-#define DBUS_PATH "/org/gnome/SettingsDaemon"
1381-#define POWER_DBUS_PATH DBUS_PATH "/Power"
1382-#define POWER_DBUS_INTERFACE "org.gnome.SettingsDaemon.Power"
1383-
1384 enum {
1385 POWER_INDICATOR_ICON_POLICY_PRESENT,
1386 POWER_INDICATOR_ICON_POLICY_CHARGE,
1387 POWER_INDICATOR_ICON_POLICY_NEVER
1388 };
1389
1390-#define INDICATOR_POWER_TYPE (indicator_power_get_type ())
1391-#define INDICATOR_POWER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_POWER_TYPE, IndicatorPower))
1392-#define INDICATOR_POWER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_POWER_TYPE, IndicatorPowerClass))
1393-#define IS_INDICATOR_POWER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_POWER_TYPE))
1394-#define IS_INDICATOR_POWER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_POWER_TYPE))
1395-#define INDICATOR_POWER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_POWER_TYPE, IndicatorPowerClass))
1396-
1397-typedef struct _IndicatorPowerClass IndicatorPowerClass;
1398-typedef struct _IndicatorPower IndicatorPower;
1399-
1400-struct _IndicatorPowerClass
1401-{
1402- IndicatorObjectClass parent_class;
1403-};
1404-
1405-struct _IndicatorPower
1406-{
1407- IndicatorObject parent_instance;
1408-
1409+struct _IndicatorPowerPrivate
1410+{
1411 GtkMenu *menu;
1412
1413 GtkLabel *label;
1414 GtkImage *status_image;
1415 gchar *accessible_desc;
1416
1417- GCancellable *proxy_cancel;
1418- GDBusProxy *proxy;
1419- guint watcher_id;
1420+ IndicatorPowerDbusListener * dbus_listener;
1421
1422- GVariant *devices;
1423- GVariant *device;
1424+ GSList * devices;
1425+ IndicatorPowerDevice * device;
1426
1427 GSettings *settings;
1428 };
1429
1430-GType indicator_power_get_type (void) G_GNUC_CONST;
1431
1432+/* LCOV_EXCL_START */
1433 INDICATOR_SET_VERSION
1434 INDICATOR_SET_TYPE (INDICATOR_POWER_TYPE)
1435+/* LCOV_EXCL_STOP */
1436
1437 /* Prototypes */
1438 static void indicator_power_dispose (GObject *object);
1439@@ -105,9 +79,13 @@
1440
1441 static void on_entry_added (IndicatorObject * io, IndicatorObjectEntry * entry, gpointer user_data);
1442
1443+/*
1444 static void gsd_appeared_callback (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data);
1445+*/
1446
1447+/* LCOV_EXCL_START */
1448 G_DEFINE_TYPE (IndicatorPower, indicator_power, INDICATOR_OBJECT_TYPE);
1449+/* LCOV_EXCL_STOP */
1450
1451 static void
1452 indicator_power_class_init (IndicatorPowerClass *klass)
1453@@ -115,6 +93,8 @@
1454 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1455 IndicatorObjectClass *io_class = INDICATOR_OBJECT_CLASS (klass);
1456
1457+ g_type_class_add_private (klass, sizeof (IndicatorPowerPrivate));
1458+
1459 object_class->dispose = indicator_power_dispose;
1460 object_class->finalize = indicator_power_finalize;
1461
1462@@ -128,20 +108,20 @@
1463 static void
1464 indicator_power_init (IndicatorPower *self)
1465 {
1466- self->menu = GTK_MENU(gtk_menu_new());
1467-
1468- self->accessible_desc = NULL;
1469-
1470- self->watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
1471- DBUS_SERVICE,
1472- G_BUS_NAME_WATCHER_FLAGS_NONE,
1473- gsd_appeared_callback,
1474- NULL,
1475- self,
1476- NULL);
1477-
1478- self->settings = g_settings_new ("com.canonical.indicator.power");
1479- g_signal_connect_swapped (self->settings, "changed::" ICON_POLICY_KEY,
1480+ IndicatorPowerPrivate * priv;
1481+
1482+ priv = G_TYPE_INSTANCE_GET_PRIVATE (self, INDICATOR_POWER_TYPE, IndicatorPowerPrivate);
1483+
1484+ priv->menu = GTK_MENU(gtk_menu_new());
1485+
1486+ priv->accessible_desc = NULL;
1487+
1488+ priv->dbus_listener = g_object_new (INDICATOR_POWER_DBUS_LISTENER_TYPE, NULL);
1489+ g_signal_connect_swapped (priv->dbus_listener, INDICATOR_POWER_DBUS_LISTENER_DEVICES_ENUMERATED,
1490+ G_CALLBACK(indicator_power_set_devices), self);
1491+
1492+ priv->settings = g_settings_new ("com.canonical.indicator.power");
1493+ g_signal_connect_swapped (priv->settings, "changed::" ICON_POLICY_KEY,
1494 G_CALLBACK(update_visibility), self);
1495 g_object_set (G_OBJECT(self),
1496 INDICATOR_OBJECT_DEFAULT_VISIBILITY, FALSE,
1497@@ -149,27 +129,29 @@
1498
1499 g_signal_connect (INDICATOR_OBJECT(self), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
1500 G_CALLBACK(on_entry_added), NULL);
1501-}
1502-
1503+
1504+ self->priv = priv;
1505+}
1506+
1507+static void
1508+dispose_devices (IndicatorPower * self)
1509+{
1510+ IndicatorPowerPrivate * priv = self->priv;
1511+
1512+ g_clear_object (&priv->device);
1513+ g_slist_free_full (priv->devices, g_object_unref);
1514+ priv->devices = NULL;
1515+}
1516 static void
1517 indicator_power_dispose (GObject *object)
1518 {
1519 IndicatorPower *self = INDICATOR_POWER(object);
1520-
1521- if (self->devices != NULL) {
1522- g_variant_unref (self->devices);
1523- self->devices = NULL;
1524- }
1525-
1526- if (self->device != NULL) {
1527- g_variant_unref (self->device);
1528- self->device = NULL;
1529- }
1530-
1531- g_clear_object (&self->proxy);
1532- g_clear_object (&self->proxy_cancel);
1533-
1534- g_clear_object (&self->settings);
1535+ IndicatorPowerPrivate * priv = self->priv;
1536+
1537+ dispose_devices (self);
1538+
1539+ g_clear_object (&priv->dbus_listener);
1540+ g_clear_object (&priv->settings);
1541
1542 G_OBJECT_CLASS (indicator_power_parent_class)->dispose (object);
1543 }
1544@@ -178,8 +160,9 @@
1545 indicator_power_finalize (GObject *object)
1546 {
1547 IndicatorPower *self = INDICATOR_POWER(object);
1548+ IndicatorPowerPrivate * priv = self->priv;
1549
1550- g_free (self->accessible_desc);
1551+ g_free (priv->accessible_desc);
1552
1553 G_OBJECT_CLASS (indicator_power_parent_class)->finalize (object);
1554 }
1555@@ -198,216 +181,17 @@
1556 }
1557
1558 static void
1559-show_info_cb (GtkMenuItem *item,
1560- gpointer data)
1561-{
1562- /*TODO: show the statistics of the specific device*/
1563- spawn_command_line_async ("gnome-power-statistics");
1564-}
1565-
1566-static void
1567 option_toggled_cb (GtkCheckMenuItem *item, IndicatorPower * self)
1568 {
1569- gtk_widget_set_visible (GTK_WIDGET (self->label),
1570+ gtk_widget_set_visible (GTK_WIDGET (self->priv->label),
1571 gtk_check_menu_item_get_active(item));
1572 }
1573
1574-static void
1575-show_preferences_cb (GtkMenuItem *item,
1576- gpointer data)
1577-{
1578- spawn_command_line_async ("gnome-control-center power");
1579-}
1580-
1581-static void
1582-get_timestring (guint64 time_secs,
1583- gchar **short_timestring,
1584- gchar **detailed_timestring)
1585-{
1586- gint hours;
1587- gint minutes;
1588-
1589- /* Add 0.5 to do rounding */
1590- minutes = (int) ( ( time_secs / 60.0 ) + 0.5 );
1591-
1592- if (minutes == 0)
1593- {
1594- *short_timestring = g_strdup (_("Unknown time"));
1595- *detailed_timestring = g_strdup (_("Unknown time"));
1596-
1597- return;
1598- }
1599-
1600- if (minutes < 60)
1601- {
1602- *short_timestring = g_strdup_printf ("0:%.2i", minutes);
1603- *detailed_timestring = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE, "%i minute",
1604- "%i minutes",
1605- minutes), minutes);
1606- return;
1607- }
1608-
1609- hours = minutes / 60;
1610- minutes = minutes % 60;
1611-
1612- *short_timestring = g_strdup_printf ("%i:%.2i", hours, minutes);
1613-
1614- if (minutes == 0)
1615- {
1616- *detailed_timestring = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
1617- "%i hour",
1618- "%i hours",
1619- hours), hours);
1620- }
1621- else
1622- {
1623- /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes"
1624- * Swap order with "%2$s %2$i %1$s %1$i if needed */
1625- *detailed_timestring = g_strdup_printf (_("%i %s %i %s"),
1626- hours, g_dngettext (GETTEXT_PACKAGE, "hour", "hours", hours),
1627- minutes, g_dngettext (GETTEXT_PACKAGE, "minute", "minutes", minutes));
1628- }
1629-}
1630-
1631-static const gchar *
1632-device_kind_to_localised_string (UpDeviceKind kind)
1633-{
1634- const gchar *text = NULL;
1635-
1636- switch (kind) {
1637- case UP_DEVICE_KIND_LINE_POWER:
1638- /* TRANSLATORS: system power cord */
1639- text = _("AC adapter");
1640- break;
1641- case UP_DEVICE_KIND_BATTERY:
1642- /* TRANSLATORS: laptop primary battery */
1643- text = _("Battery");
1644- break;
1645- case UP_DEVICE_KIND_UPS:
1646- /* TRANSLATORS: battery-backed AC power source */
1647- text = _("UPS");
1648- break;
1649- case UP_DEVICE_KIND_MONITOR:
1650- /* TRANSLATORS: a monitor is a device to measure voltage and current */
1651- text = _("Monitor");
1652- break;
1653- case UP_DEVICE_KIND_MOUSE:
1654- /* TRANSLATORS: wireless mice with internal batteries */
1655- text = _("Mouse");
1656- break;
1657- case UP_DEVICE_KIND_KEYBOARD:
1658- /* TRANSLATORS: wireless keyboard with internal battery */
1659- text = _("Keyboard");
1660- break;
1661- case UP_DEVICE_KIND_PDA:
1662- /* TRANSLATORS: portable device */
1663- text = _("PDA");
1664- break;
1665- case UP_DEVICE_KIND_PHONE:
1666- /* TRANSLATORS: cell phone (mobile...) */
1667- text = _("Cell phone");
1668- break;
1669- case UP_DEVICE_KIND_MEDIA_PLAYER:
1670- /* TRANSLATORS: media player, mp3 etc */
1671- text = _("Media player");
1672- break;
1673- case UP_DEVICE_KIND_TABLET:
1674- /* TRANSLATORS: tablet device */
1675- text = _("Tablet");
1676- break;
1677- case UP_DEVICE_KIND_COMPUTER:
1678- /* TRANSLATORS: tablet device */
1679- text = _("Computer");
1680- break;
1681- default:
1682- g_warning ("enum unrecognised: %i", kind);
1683- text = up_device_kind_to_string (kind);
1684- }
1685-
1686- return text;
1687-}
1688-
1689-static void
1690-build_device_time_details (const gchar *device_name,
1691- guint64 time,
1692- UpDeviceState state,
1693- gdouble percentage,
1694- gchar **short_details,
1695- gchar **details,
1696- gchar **accessible_name)
1697-{
1698- gchar *short_timestring = NULL;
1699- gchar *detailed_timestring = NULL;
1700-
1701- if (time > 0)
1702- {
1703- get_timestring (time,
1704- &short_timestring,
1705- &detailed_timestring);
1706-
1707- if (state == UP_DEVICE_STATE_CHARGING)
1708- {
1709- /* TRANSLATORS: %2 is a time string, e.g. "1 hour 5 minutes" */
1710- *accessible_name = g_strdup_printf (_("%s (%s to charge (%.0lf%%))"),
1711- device_name, detailed_timestring, percentage);
1712- *details = g_strdup_printf (_("%s (%s to charge)"),
1713- device_name, short_timestring);
1714- *short_details = g_strdup_printf ("(%s)", short_timestring);
1715- }
1716- else if (state == UP_DEVICE_STATE_DISCHARGING)
1717- {
1718- *short_details = g_strdup_printf ("%s", short_timestring);
1719-
1720- if (time > 43200) /* 12 hours */
1721- {
1722- *accessible_name = g_strdup_printf (_("%s"), device_name);
1723- *details = g_strdup_printf (_("%s"), device_name);
1724- }
1725- else
1726- {
1727- /* TRANSLATORS: %2 is a time string, e.g. "1 hour 5 minutes" */
1728- *accessible_name = g_strdup_printf (_("%s (%s left (%.0lf%%))"),
1729- device_name, detailed_timestring, percentage);
1730- *details = g_strdup_printf (_("%s (%s left)"),
1731- device_name, short_timestring);
1732- }
1733- }
1734-
1735- g_free (short_timestring);
1736- g_free (detailed_timestring);
1737- }
1738- else
1739- {
1740- if (state == UP_DEVICE_STATE_FULLY_CHARGED)
1741- {
1742- *details = g_strdup_printf (_("%s (charged)"), device_name);
1743- *accessible_name = g_strdup (*details);
1744- *short_details = g_strdup ("");
1745- }
1746- else if (percentage > 0)
1747- {
1748- /* TRANSLATORS: %2 is a percentage value. Note: this string is only
1749- * used when we don't have a time value */
1750- *details = g_strdup_printf (_("%s (%.0lf%%)"),
1751- device_name, percentage);
1752- *accessible_name = g_strdup (*details);
1753- *short_details = g_strdup_printf (_("(%.0lf%%)"),
1754- percentage);
1755- }
1756- else
1757- {
1758- *details = g_strdup_printf (_("%s (not present)"), device_name);
1759- *accessible_name = g_strdup (*details);
1760- *short_details = g_strdup (_("(not present)"));
1761- }
1762- }
1763-}
1764-
1765 /* ensure that the entry is using self's accessible description */
1766 static void
1767 refresh_entry_accessible_desc (IndicatorPower * self, IndicatorObjectEntry * entry)
1768 {
1769- const char * newval = self->accessible_desc;
1770+ const char * newval = self->priv->accessible_desc;
1771
1772 if (entry->accessible_desc != newval)
1773 {
1774@@ -433,8 +217,8 @@
1775 if (desc && *desc)
1776 {
1777 /* update our copy of the string */
1778- char * oldval = self->accessible_desc;
1779- self->accessible_desc = g_strdup (desc);
1780+ char * oldval = self->priv->accessible_desc;
1781+ self->priv->accessible_desc = g_strdup (desc);
1782
1783 /* ensure that the entries are using self's accessible description */
1784 GList * l;
1785@@ -448,194 +232,70 @@
1786 }
1787 }
1788
1789-static const gchar *
1790-get_icon_percentage_for_status (const gchar *status)
1791-{
1792-
1793- if (g_strcmp0 (status, "caution") == 0)
1794- return "000";
1795- else if (g_strcmp0 (status, "low") == 0)
1796- return "040";
1797- else if (g_strcmp0 (status, "good") == 0)
1798- return "080";
1799- else
1800- return "100";
1801-}
1802-
1803-static GIcon*
1804-build_battery_icon (UpDeviceState state,
1805- gchar *suffix_str)
1806-{
1807- GIcon *gicon;
1808-
1809- GString *filename;
1810- gchar **iconnames;
1811-
1812- filename = g_string_new (NULL);
1813-
1814- if (state == UP_DEVICE_STATE_FULLY_CHARGED)
1815- {
1816- g_string_append (filename, "battery-charged;");
1817- g_string_append (filename, "battery-full-charged-symbolic;");
1818- g_string_append (filename, "battery-full-charged;");
1819- g_string_append (filename, "gpm-battery-charged;");
1820- g_string_append (filename, "gpm-battery-100-charging;");
1821- }
1822- else if (state == UP_DEVICE_STATE_CHARGING)
1823- {
1824- g_string_append (filename, "battery-000-charging;");
1825- g_string_append (filename, "battery-caution-charging-symbolic;");
1826- g_string_append (filename, "battery-caution-charging;");
1827- g_string_append (filename, "gpm-battery-000-charging;");
1828- }
1829- else if (state == UP_DEVICE_STATE_DISCHARGING)
1830- {
1831- const gchar *percentage = get_icon_percentage_for_status (suffix_str);
1832- g_string_append_printf (filename, "battery-%s;", suffix_str);
1833- g_string_append_printf (filename, "battery-%s-symbolic;", suffix_str);
1834- g_string_append_printf (filename, "battery-%s;", percentage);
1835- g_string_append_printf (filename, "gpm-battery-%s;", percentage);
1836- }
1837-
1838- iconnames = g_strsplit (filename->str, ";", -1);
1839- gicon = g_themed_icon_new_from_names (iconnames, -1);
1840-
1841- g_strfreev (iconnames);
1842- g_string_free (filename, TRUE);
1843-
1844- return gicon;
1845-}
1846-
1847-static GIcon*
1848-get_device_icon (UpDeviceKind kind,
1849- UpDeviceState state,
1850- guint64 time_sec,
1851- const gchar *device_icon)
1852-{
1853- GIcon *gicon = NULL;
1854-
1855- if (kind == UP_DEVICE_KIND_BATTERY &&
1856- (state == UP_DEVICE_STATE_FULLY_CHARGED ||
1857- state == UP_DEVICE_STATE_CHARGING ||
1858- state == UP_DEVICE_STATE_DISCHARGING))
1859- {
1860- if (state == UP_DEVICE_STATE_FULLY_CHARGED ||
1861- state == UP_DEVICE_STATE_CHARGING)
1862- {
1863- gicon = build_battery_icon (state, NULL);
1864- }
1865- else if (state == UP_DEVICE_STATE_DISCHARGING)
1866- {
1867- if ((time_sec > 60 * 30) && /* more than 30 minutes left */
1868- (g_strrstr (device_icon, "000") ||
1869- g_strrstr (device_icon, "020") ||
1870- g_strrstr (device_icon, "caution"))) /* the icon is red */
1871- {
1872- gicon = build_battery_icon (state, "low");
1873- }
1874- }
1875- }
1876-
1877- if (gicon == NULL)
1878- gicon = g_icon_new_for_string (device_icon, NULL);
1879-
1880- return gicon;
1881-}
1882-
1883-
1884-static void
1885-menu_add_device (GtkMenu *menu,
1886- GVariant *device)
1887-{
1888- UpDeviceKind kind;
1889- UpDeviceState state;
1890- GtkWidget *icon;
1891- GtkWidget *item;
1892- GtkWidget *details_label;
1893- GtkWidget *grid;
1894- GIcon *device_gicons;
1895- const gchar *device_icon = NULL;
1896- const gchar *object_path = NULL;
1897- gdouble percentage;
1898- guint64 time;
1899- const gchar *device_name;
1900- gchar *short_details = NULL;
1901- gchar *details = NULL;
1902- gchar *accessible_name = NULL;
1903- AtkObject *atk_object;
1904-
1905- if (device == NULL)
1906- return;
1907-
1908- g_variant_get (device,
1909- "(&su&sdut)",
1910- &object_path,
1911- &kind,
1912- &device_icon,
1913- &percentage,
1914- &state,
1915- &time);
1916-
1917- g_debug ("%s: got data from object %s", G_STRFUNC, object_path);
1918-
1919- if (kind == UP_DEVICE_KIND_LINE_POWER)
1920- return;
1921-
1922- /* Process the data */
1923- device_gicons = get_device_icon (kind, state, time, device_icon);
1924- icon = gtk_image_new_from_gicon (device_gicons,
1925- GTK_ICON_SIZE_SMALL_TOOLBAR);
1926- g_clear_object (&device_gicons);
1927-
1928- device_name = device_kind_to_localised_string (kind);
1929-
1930- build_device_time_details (device_name, time, state, percentage, &short_details, &details, &accessible_name);
1931-
1932- /* Create menu item */
1933- item = gtk_image_menu_item_new ();
1934- atk_object = gtk_widget_get_accessible(item);
1935- if (atk_object != NULL)
1936- atk_object_set_name (atk_object, accessible_name);
1937-
1938- grid = gtk_grid_new ();
1939- gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
1940- gtk_grid_attach (GTK_GRID (grid), icon, 0, 0, 1, 1);
1941- details_label = gtk_label_new (details);
1942- gtk_grid_attach_next_to (GTK_GRID (grid), details_label, icon, GTK_POS_RIGHT, 1, 1);
1943- gtk_container_add (GTK_CONTAINER (item), grid);
1944- gtk_widget_show (grid);
1945-
1946- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1947-
1948- g_signal_connect (G_OBJECT (item), "activate",
1949- G_CALLBACK (show_info_cb), NULL);
1950-
1951- g_free (short_details);
1952- g_free (details);
1953- g_free (accessible_name);
1954+static gboolean
1955+menu_add_device (GtkMenu * menu, const IndicatorPowerDevice * device)
1956+{
1957+ gboolean added = FALSE;
1958+ const UpDeviceKind kind = indicator_power_device_get_kind (device);
1959+
1960+ if (kind != UP_DEVICE_KIND_LINE_POWER)
1961+ {
1962+ GtkWidget *icon;
1963+ GtkWidget *item;
1964+ GtkWidget *details_label;
1965+ GtkWidget *grid;
1966+ GIcon *device_gicon;
1967+ gchar *short_details = NULL;
1968+ gchar *details = NULL;
1969+ gchar *accessible_name = NULL;
1970+ AtkObject *atk_object;
1971+
1972+ /* Process the data */
1973+ device_gicon = indicator_power_device_get_gicon (device);
1974+ icon = gtk_image_new_from_gicon (device_gicon, GTK_ICON_SIZE_SMALL_TOOLBAR);
1975+ g_clear_object (&device_gicon);
1976+
1977+ indicator_power_device_get_time_details (device, &short_details, &details, &accessible_name);
1978+
1979+ /* Create menu item */
1980+ item = gtk_image_menu_item_new ();
1981+ atk_object = gtk_widget_get_accessible(item);
1982+ if (atk_object != NULL)
1983+ atk_object_set_name (atk_object, accessible_name);
1984+
1985+ grid = gtk_grid_new ();
1986+ gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
1987+ gtk_grid_attach (GTK_GRID (grid), icon, 0, 0, 1, 1);
1988+ details_label = gtk_label_new (details);
1989+ gtk_grid_attach_next_to (GTK_GRID (grid), details_label, icon, GTK_POS_RIGHT, 1, 1);
1990+ gtk_container_add (GTK_CONTAINER (item), grid);
1991+ gtk_widget_show (grid);
1992+
1993+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1994+ added = TRUE;
1995+
1996+ g_signal_connect_swapped (G_OBJECT (item), "activate",
1997+ G_CALLBACK (spawn_command_line_async), "gnome-power-statistics");
1998+
1999+ g_free (short_details);
2000+ g_free (details);
2001+ g_free (accessible_name);
2002+ }
2003+
2004+ return added;
2005 }
2006
2007 static gsize
2008-menu_add_devices (GtkMenu *menu,
2009- GVariant *devices)
2010+menu_add_devices (GtkMenu * menu, GSList * devices)
2011 {
2012- gsize n_devices;
2013- guint i;
2014-
2015- if (devices == NULL)
2016- return 0;
2017-
2018- n_devices = g_variant_n_children (devices);
2019- g_debug ("Num devices: '%" G_GSIZE_FORMAT "'\n", n_devices);
2020-
2021- for (i = 0; i < n_devices; i++)
2022- {
2023- GVariant * device = g_variant_get_child_value (devices, i);
2024- menu_add_device (menu, device);
2025- g_variant_unref (device);
2026- }
2027-
2028- return n_devices;
2029+ GSList * l;
2030+ gsize n_added = 0;
2031+
2032+ for (l=devices; l!=NULL; l=l->next)
2033+ if (menu_add_device (menu, l->data))
2034+ ++n_added;
2035+
2036+ return n_added;
2037 }
2038
2039 static gboolean
2040@@ -653,75 +313,62 @@
2041 GtkWidget *image;
2042 GList *children;
2043 gsize n_devices = 0;
2044+ IndicatorPowerPrivate * priv = self->priv;
2045
2046 /* remove the existing menuitems */
2047- children = gtk_container_get_children (GTK_CONTAINER (self->menu));
2048+ children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
2049 g_list_foreach (children, (GFunc) gtk_widget_destroy, NULL);
2050 g_list_free (children);
2051
2052 /* devices */
2053- n_devices = menu_add_devices (self->menu, self->devices);
2054+ n_devices = menu_add_devices (priv->menu, priv->devices);
2055
2056 if (!get_greeter_mode ()) {
2057 /* only do the separator if we have at least one device */
2058 if (n_devices != 0)
2059 {
2060 item = gtk_separator_menu_item_new ();
2061- gtk_menu_shell_append (GTK_MENU_SHELL (self->menu), item);
2062+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), item);
2063 }
2064
2065 /* options */
2066 item = gtk_check_menu_item_new_with_label (_("Show Time in Menu Bar"));
2067 g_signal_connect (item, "toggled", G_CALLBACK(option_toggled_cb), self);
2068- g_settings_bind (self->settings, "show-time", item, "active", G_SETTINGS_BIND_DEFAULT);
2069- gtk_menu_shell_append (GTK_MENU_SHELL (self->menu), item);
2070+ g_settings_bind (priv->settings, "show-time", item, "active", G_SETTINGS_BIND_DEFAULT);
2071+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), item);
2072
2073 /* preferences */
2074- item = gtk_image_menu_item_new_with_label (_("Power Settings..."));
2075+ item = gtk_image_menu_item_new_with_label (_("Power Settings…"));
2076 image = gtk_image_new_from_icon_name (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU);
2077 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
2078- g_signal_connect (G_OBJECT (item), "activate",
2079- G_CALLBACK (show_preferences_cb), NULL);
2080- gtk_menu_shell_append (GTK_MENU_SHELL (self->menu), item);
2081+ g_signal_connect_swapped (G_OBJECT (item), "activate",
2082+ G_CALLBACK (spawn_command_line_async), "gnome-control-center power");
2083+ gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), item);
2084 }
2085
2086 /* show the menu */
2087- gtk_widget_show_all (GTK_WIDGET (self->menu));
2088+ gtk_widget_show_all (GTK_WIDGET (priv->menu));
2089 }
2090
2091-static GVariant *
2092-get_primary_device (GVariant *devices)
2093+static IndicatorPowerDevice*
2094+get_primary_device (GSList * devices)
2095 {
2096- gint primary_device_charging_index = -1;
2097- gint primary_device_discharging_index = -1;
2098- gint primary_device_index = -1;
2099+ IndicatorPowerDevice * primary_device = NULL;
2100+ IndicatorPowerDevice * primary_device_charging = NULL;
2101+ IndicatorPowerDevice * primary_device_discharging = NULL;
2102 gboolean charging = FALSE;
2103 gboolean discharging = FALSE;
2104 guint64 min_discharging_time = G_MAXUINT64;
2105 guint64 max_charging_time = 0;
2106- guint i;
2107-
2108- const gsize n_devices = devices ? g_variant_n_children (devices) : 0;
2109- g_debug ("Num devices: '%" G_GSIZE_FORMAT "'\n", n_devices);
2110-
2111- for (i = 0; i < n_devices; i++)
2112+ GSList * l;
2113+
2114+ for (l=devices; l!=NULL; l=l->next)
2115 {
2116- const gchar *object_path;
2117- UpDeviceKind kind;
2118- const gchar *device_icon;
2119- gdouble percentage;
2120- UpDeviceState state;
2121- guint64 time = 0;
2122-
2123- g_variant_get_child (devices, i, "(&su&sdut)",
2124- &object_path,
2125- &kind,
2126- &device_icon,
2127- &percentage,
2128- &state,
2129- &time);
2130-
2131- g_debug ("%s: got data from object %s", G_STRFUNC, object_path);
2132+ IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE(l->data);
2133+ const UpDeviceKind kind = indicator_power_device_get_kind (device);
2134+ const UpDeviceState state = indicator_power_device_get_state (device);
2135+ const gdouble percentage = indicator_power_device_get_percentage (device);
2136+ const time_t time = indicator_power_device_get_time (device);
2137
2138 /* Try to fix the case when we get a empty battery bay as a real battery */
2139 if (state == UP_DEVICE_STATE_UNKNOWN &&
2140@@ -738,7 +385,7 @@
2141 if (time < min_discharging_time)
2142 {
2143 min_discharging_time = time;
2144- primary_device_discharging_index = i;
2145+ primary_device_discharging = device;
2146 }
2147 }
2148 else if (state == UP_DEVICE_STATE_CHARGING)
2149@@ -746,126 +393,79 @@
2150 charging = TRUE;
2151 if (time == 0) /* Battery broken */
2152 {
2153- primary_device_charging_index = i;
2154+ primary_device_charging = device;
2155 }
2156 if (time > max_charging_time)
2157 {
2158 max_charging_time = time;
2159- primary_device_charging_index = i;
2160+ primary_device_charging = device;
2161 }
2162 }
2163 else
2164 {
2165- primary_device_index = i;
2166+ primary_device = device;
2167 }
2168 }
2169
2170 if (discharging)
2171 {
2172- primary_device_index = primary_device_discharging_index;
2173+ primary_device = primary_device_discharging;
2174 }
2175 else if (charging)
2176 {
2177- primary_device_index = primary_device_charging_index;
2178+ primary_device = primary_device_charging;
2179 }
2180
2181- if (primary_device_index >= 0)
2182- return g_variant_get_child_value (devices, primary_device_index);
2183+ if (primary_device != NULL)
2184+ g_object_ref (primary_device);
2185
2186- return NULL;
2187+ return primary_device;
2188 }
2189
2190 static void
2191-put_primary_device (IndicatorPower *self,
2192- GVariant *device)
2193+put_primary_device (IndicatorPower *self, IndicatorPowerDevice *device)
2194 {
2195- UpDeviceKind kind;
2196- UpDeviceState state;
2197- GIcon *device_gicons;
2198- gchar *short_details = NULL;
2199- gchar *details = NULL;
2200- gchar *accessible_name = NULL;
2201- const gchar *device_icon = NULL;
2202- const gchar *object_path = NULL;
2203- gdouble percentage;
2204- guint64 time;
2205- const gchar *device_name;
2206-
2207- /* set the icon and text */
2208- g_variant_get (device,
2209- "(&su&sdut)",
2210- &object_path,
2211- &kind,
2212- &device_icon,
2213- &percentage,
2214- &state,
2215- &time);
2216-
2217- g_debug ("%s: got data from object %s", G_STRFUNC, object_path);
2218+ IndicatorPowerPrivate * priv = self->priv;
2219
2220 /* set icon */
2221- device_gicons = get_device_icon (kind, state, time, device_icon);
2222- gtk_image_set_from_gicon (self->status_image,
2223- device_gicons,
2224- GTK_ICON_SIZE_LARGE_TOOLBAR);
2225- g_clear_object (&device_gicons);
2226- gtk_widget_show (GTK_WIDGET (self->status_image));
2227-
2228-
2229- /* get the device name */
2230- device_name = device_kind_to_localised_string (kind);
2231+ GIcon * device_gicon = indicator_power_device_get_gicon (device);
2232+ gtk_image_set_from_gicon (priv->status_image, device_gicon, GTK_ICON_SIZE_LARGE_TOOLBAR);
2233+ g_clear_object (&device_gicon);
2234+ gtk_widget_show (GTK_WIDGET (priv->status_image));
2235
2236 /* get the description */
2237- build_device_time_details (device_name, time, state, percentage, &short_details, &details, &accessible_name);
2238-
2239- gtk_label_set_label (GTK_LABEL (self->label),
2240- short_details);
2241+ gchar * short_details;
2242+ gchar * details;
2243+ gchar * accessible_name;
2244+ indicator_power_device_get_time_details (device, &short_details, &details, &accessible_name);
2245+ gtk_label_set_label (GTK_LABEL (priv->label), short_details);
2246 set_accessible_desc (self, accessible_name);
2247-
2248+ g_free (accessible_name);
2249+ g_free (details);
2250 g_free (short_details);
2251- g_free (details);
2252- g_free (accessible_name);
2253 }
2254
2255-static void
2256-get_devices_cb (GObject *source_object,
2257- GAsyncResult *res,
2258- gpointer user_data)
2259+void
2260+indicator_power_set_devices (IndicatorPower * self, GSList * devices)
2261 {
2262- IndicatorPower *self = INDICATOR_POWER (user_data);
2263- GVariant *devices_container;
2264- GError *error = NULL;
2265-
2266- devices_container = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
2267- if (devices_container == NULL)
2268- {
2269- g_message ("Couldn't get devices: %s\n", error->message);
2270- g_error_free (error);
2271- }
2272- else /* update 'devices' */
2273- {
2274- if (self->devices != NULL)
2275- g_variant_unref (self->devices);
2276- self->devices = g_variant_get_child_value (devices_container, 0);
2277-
2278- g_variant_unref (devices_container);
2279-
2280- if (self->device != NULL)
2281- g_variant_unref (self->device);
2282- self->device = get_primary_device (self->devices);
2283-
2284- if (self->device == NULL)
2285- {
2286- g_message ("Couldn't find primary device");
2287- }
2288- else
2289- {
2290- put_primary_device (self, self->device);
2291- }
2292- }
2293-
2294+ /* LCOV_EXCL_START */
2295+ g_return_if_fail (IS_INDICATOR_POWER(self));
2296+ /* LCOV_EXCL_STOP */
2297+
2298+ IndicatorPowerPrivate * priv = self->priv;
2299+
2300+ /* update our devices & primary device */
2301+ g_slist_foreach (devices, (GFunc)g_object_ref, NULL);
2302+ dispose_devices (self);
2303+ priv->devices = g_slist_copy (devices);
2304+ priv->device = get_primary_device (priv->devices);
2305+
2306+ /* and our menus/visibility from the new device list */
2307+ if (priv->device != NULL)
2308+ put_primary_device (self, priv->device);
2309+ else
2310+ g_message ("Couldn't find primary device");
2311 build_menu (self);
2312-
2313 update_visibility (self);
2314 }
2315
2316@@ -876,85 +476,6 @@
2317 should_be_visible (self));
2318 }
2319
2320-static void
2321-receive_properties_changed (GDBusProxy *proxy G_GNUC_UNUSED,
2322- GVariant *changed_properties G_GNUC_UNUSED,
2323- GStrv invalidated_properties G_GNUC_UNUSED,
2324- gpointer user_data)
2325-{
2326- IndicatorPower *self = INDICATOR_POWER (user_data);
2327-
2328- /* it's time to refresh our device list */
2329- g_dbus_proxy_call (self->proxy,
2330- "GetDevices",
2331- NULL,
2332- G_DBUS_CALL_FLAGS_NONE,
2333- -1,
2334- self->proxy_cancel,
2335- get_devices_cb,
2336- user_data);
2337-}
2338-
2339-static void
2340-service_proxy_cb (GObject *object,
2341- GAsyncResult *res,
2342- gpointer user_data)
2343-{
2344- IndicatorPower *self = INDICATOR_POWER (user_data);
2345- GError *error = NULL;
2346-
2347- self->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
2348-
2349- g_clear_object (&self->proxy_cancel);
2350-
2351- if (error != NULL)
2352- {
2353- g_error ("Error creating proxy: %s", error->message);
2354- g_error_free (error);
2355-
2356- return;
2357- }
2358-
2359- /* we want to change the primary device changes */
2360- g_signal_connect (self->proxy,
2361- "g-properties-changed",
2362- G_CALLBACK (receive_properties_changed),
2363- user_data);
2364-
2365- /* get the initial state */
2366- g_dbus_proxy_call (self->proxy,
2367- "GetDevices",
2368- NULL,
2369- G_DBUS_CALL_FLAGS_NONE,
2370- -1,
2371- self->proxy_cancel,
2372- get_devices_cb,
2373- user_data);
2374-}
2375-
2376-static void
2377-gsd_appeared_callback (GDBusConnection *connection,
2378- const gchar *name,
2379- const gchar *name_owner,
2380- gpointer user_data)
2381-{
2382- IndicatorPower *self = INDICATOR_POWER (user_data);
2383-
2384- self->proxy_cancel = g_cancellable_new ();
2385-
2386- g_dbus_proxy_new (connection,
2387- G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
2388- NULL,
2389- name,
2390- POWER_DBUS_PATH,
2391- POWER_DBUS_INTERFACE,
2392- self->proxy_cancel,
2393- service_proxy_cb,
2394- self);
2395-}
2396-
2397-
2398-
2399
2400 /* Grabs the label. Creates it if it doesn't
2401 exist already */
2402@@ -962,32 +483,34 @@
2403 get_label (IndicatorObject *io)
2404 {
2405 IndicatorPower *self = INDICATOR_POWER (io);
2406+ IndicatorPowerPrivate * priv = self->priv;
2407
2408- if (self->label == NULL)
2409+ if (priv->label == NULL)
2410 {
2411 /* Create the label if it doesn't exist already */
2412- self->label = GTK_LABEL (gtk_label_new (""));
2413- gtk_widget_set_visible (GTK_WIDGET (self->label), FALSE);
2414+ priv->label = GTK_LABEL (gtk_label_new (""));
2415+ gtk_widget_set_visible (GTK_WIDGET (priv->label), FALSE);
2416 }
2417
2418- return self->label;
2419+ return priv->label;
2420 }
2421
2422 static GtkImage *
2423 get_image (IndicatorObject *io)
2424 {
2425+ GIcon *gicon;
2426 IndicatorPower *self = INDICATOR_POWER (io);
2427- GIcon *gicon;
2428+ IndicatorPowerPrivate * priv = self->priv;
2429
2430- if (self->status_image == NULL)
2431+ if (priv->status_image == NULL)
2432 {
2433 /* Will create the status icon if it doesn't exist already */
2434 gicon = g_themed_icon_new (DEFAULT_ICON);
2435- self->status_image = GTK_IMAGE (gtk_image_new_from_gicon (gicon,
2436+ priv->status_image = GTK_IMAGE (gtk_image_new_from_gicon (gicon,
2437 GTK_ICON_SIZE_LARGE_TOOLBAR));
2438 }
2439
2440- return self->status_image;
2441+ return priv->status_image;
2442 }
2443
2444 static GtkMenu *
2445@@ -997,7 +520,7 @@
2446
2447 build_menu (self);
2448
2449- return GTK_MENU (self->menu);
2450+ return GTK_MENU (self->priv->menu);
2451 }
2452
2453 static const gchar *
2454@@ -1005,7 +528,7 @@
2455 {
2456 IndicatorPower *self = INDICATOR_POWER (io);
2457
2458- return self->accessible_desc;
2459+ return self->priv->accessible_desc;
2460 }
2461
2462 static const gchar *
2463@@ -1019,28 +542,22 @@
2464 ***/
2465
2466 static void
2467-count_batteries(GVariant *devices, int *total, int *inuse)
2468+count_batteries (GSList * devices, int *total, int *inuse)
2469 {
2470- const int n_devices = devices ? g_variant_n_children (devices) : 0;
2471+ GSList * l;
2472
2473- int i;
2474- for (i=0; i<n_devices; i++)
2475+ for (l=devices; l!=NULL; l=l->next)
2476 {
2477- GVariant * device = g_variant_get_child_value (devices, i);
2478+ const IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE(l->data);
2479
2480- UpDeviceKind kind;
2481- g_variant_get_child (device, 1, "u", &kind);
2482- if (kind == UP_DEVICE_KIND_BATTERY)
2483+ if (indicator_power_device_get_kind(device) == UP_DEVICE_KIND_BATTERY)
2484 {
2485 ++*total;
2486
2487- UpDeviceState state;
2488- g_variant_get_child (device, 4, "u", &state);
2489+ const UpDeviceState state = indicator_power_device_get_state (device);
2490 if ((state == UP_DEVICE_STATE_CHARGING) || (state == UP_DEVICE_STATE_DISCHARGING))
2491 ++*inuse;
2492 }
2493-
2494- g_variant_unref (device);
2495 }
2496
2497 g_debug("count_batteries found %d batteries (%d are charging/discharging)", *total, *inuse);
2498@@ -1050,8 +567,9 @@
2499 should_be_visible (IndicatorPower * self)
2500 {
2501 gboolean visible = TRUE;
2502+ IndicatorPowerPrivate * priv = self->priv;
2503
2504- const int icon_policy = g_settings_get_enum (self->settings, ICON_POLICY_KEY);
2505+ const int icon_policy = g_settings_get_enum (priv->settings, ICON_POLICY_KEY);
2506
2507 g_debug ("icon_policy is: %d (present==0, charge==1, never==2)", icon_policy);
2508
2509@@ -1062,7 +580,7 @@
2510 else
2511 {
2512 int batteries=0, inuse=0;
2513- count_batteries (self->devices, &batteries, &inuse);
2514+ count_batteries (priv->devices, &batteries, &inuse);
2515
2516 if (icon_policy == POWER_INDICATOR_ICON_POLICY_PRESENT)
2517 {
2518
2519=== added file 'src/indicator-power.h'
2520--- src/indicator-power.h 1970-01-01 00:00:00 +0000
2521+++ src/indicator-power.h 2012-07-11 17:08:19 +0000
2522@@ -0,0 +1,58 @@
2523+/*
2524+An indicator to power related information in the menubar.
2525+
2526+Copyright 2011 Canonical Ltd.
2527+
2528+Authors:
2529+ Javier Jardon <javier.jardon@codethink.co.uk>
2530+
2531+This program is free software: you can redistribute it and/or modify it
2532+under the terms of the GNU General Public License version 3, as published
2533+by the Free Software Foundation.
2534+
2535+This program is distributed in the hope that it will be useful, but
2536+WITHOUT ANY WARRANTY; without even the implied warranties of
2537+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2538+PURPOSE. See the GNU General Public License for more details.
2539+
2540+You should have received a copy of the GNU General Public License along
2541+with this program. If not, see <http://www.gnu.org/licenses/>.
2542+*/
2543+
2544+/* Gtk required */
2545+#include <gtk/gtk.h>
2546+
2547+/* parent class */
2548+#include <libindicator/indicator.h>
2549+#include <libindicator/indicator-object.h>
2550+
2551+G_BEGIN_DECLS
2552+
2553+#define INDICATOR_POWER_TYPE (indicator_power_get_type ())
2554+#define INDICATOR_POWER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_POWER_TYPE, IndicatorPower))
2555+#define INDICATOR_POWER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_POWER_TYPE, IndicatorPowerClass))
2556+#define IS_INDICATOR_POWER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_POWER_TYPE))
2557+#define IS_INDICATOR_POWER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_POWER_TYPE))
2558+#define INDICATOR_POWER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_POWER_TYPE, IndicatorPowerClass))
2559+
2560+typedef struct _IndicatorPower IndicatorPower;
2561+typedef struct _IndicatorPowerClass IndicatorPowerClass;
2562+typedef struct _IndicatorPowerPrivate IndicatorPowerPrivate;
2563+
2564+struct _IndicatorPowerClass
2565+{
2566+ IndicatorObjectClass parent_class;
2567+};
2568+
2569+struct _IndicatorPower
2570+{
2571+ IndicatorObject parent_instance;
2572+ IndicatorPowerPrivate * priv;
2573+};
2574+
2575+GType indicator_power_get_type (void) G_GNUC_CONST;
2576+
2577+void indicator_power_set_devices (IndicatorPower * power,
2578+ GSList * devices);
2579+
2580+G_END_DECLS
2581
2582=== added directory 'tests'
2583=== added file 'tests/Makefile.am'
2584--- tests/Makefile.am 1970-01-01 00:00:00 +0000
2585+++ tests/Makefile.am 2012-07-11 17:08:19 +0000
2586@@ -0,0 +1,62 @@
2587+TESTS =
2588+CLEANFILES =
2589+BUILT_SOURCES =
2590+check_PROGRAMS =
2591+
2592+###
2593+###
2594+###
2595+
2596+# stock UMB tests on user-visible strings
2597+include $(srcdir)/Makefile.am.strings
2598+
2599+check_LIBRARIES = libgtest.a
2600+nodist_libgtest_a_SOURCES = \
2601+ $(GTEST_SOURCE)/src/gtest-all.cc \
2602+ $(GTEST_SOURCE)/src/gtest_main.cc
2603+
2604+AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I${top_srcdir}/src -Wall -Werror
2605+AM_CXXFLAGS = $(GTEST_CXXFLAGS)
2606+
2607+###
2608+###
2609+###
2610+
2611+TEST_LIBS = \
2612+ $(top_builddir)/src/.libs/libpower.a \
2613+ $(INDICATOR_LIBS) \
2614+ $(UPOWER_LIBS) \
2615+ $(COVERAGE_LDFLAGS) \
2616+ libgtest.a
2617+
2618+TEST_CPPFLAGS = \
2619+ $(AM_CPPFLAGS) \
2620+ $(UPOWER_CFLAGS) \
2621+ $(INDICATOR_CFLAGS)
2622+
2623+BUILT_SOURCES += gschemas.compiled
2624+CLEANFILES += gschemas.compiled
2625+gschemas.compiled: Makefile
2626+ @glib-compile-schemas --targetdir=$(abs_builddir) $(top_builddir)/data
2627+
2628+TESTS += test-device
2629+check_PROGRAMS += test-device
2630+test_device_SOURCES = test-device.cc
2631+test_device_LDADD = $(TEST_LIBS)
2632+test_device_CPPFLAGS = $(TEST_CPPFLAGS)
2633+
2634+#TESTS += test-dbus-listener
2635+#check_PROGRAMS += test-dbus-listener
2636+#test_dbus_listener_SOURCES = test-dbus-listener.cc
2637+#test_dbus_listener_LDADD = $(TEST_LIBS)
2638+#test_dbus_listener_CPPFLAGS = $(TEST_CPPFLAGS)
2639+
2640+TESTS += test-indicator
2641+check_PROGRAMS += test-indicator
2642+test_indicator_SOURCES = test-indicator.cc
2643+test_indicator_LDADD = $(TEST_LIBS)
2644+test_indicator_CPPFLAGS = $(TEST_CPPFLAGS) -DSCHEMA_DIR="\"$(top_builddir)/tests/\""
2645+
2646+###
2647+###
2648+###
2649
2650=== added file 'tests/Makefile.am.strings'
2651--- tests/Makefile.am.strings 1970-01-01 00:00:00 +0000
2652+++ tests/Makefile.am.strings 2012-07-11 17:08:19 +0000
2653@@ -0,0 +1,38 @@
2654+TESTS += \
2655+ test-ellipsis \
2656+ test-space-ellipsis \
2657+ test-ascii-quotes
2658+
2659+#####
2660+# Tests for there being proper ellipsis instead of three periods in a row
2661+#####
2662+test-ellipsis: $(top_srcdir)/po
2663+ @echo "#!/bin/bash" > $@
2664+ @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
2665+ @echo "grep -c -e \"^msgid.*\.\.\.\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"Ellipsis found in user visible strings\" >&2 && exit 1" >> $@
2666+ @echo "exit 0" >> $@
2667+ @chmod +x $@
2668+
2669+#####
2670+# Tests for there being a space before an ellipsis
2671+#####
2672+test-space-ellipsis: $(top_srcdir)/po
2673+ @echo "#!/bin/bash" > $@
2674+ @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
2675+ @echo "grep -c -e \"^msgid.* …\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"Space before ellipsis found in user visible strings\" >&2 && exit 1" >> $@
2676+ @echo "exit 0" >> $@
2677+ @chmod +x $@
2678+
2679+#####
2680+# Tests for ASCII quote types
2681+#####
2682+test-ascii-quotes: $(top_srcdir)/po
2683+ @echo "#!/bin/bash" > $@
2684+ @echo "(cd $(top_srcdir)/po && make $(GETTEXT_PACKAGE).pot)" >> $@
2685+ @echo "grep -c -e \"^msgid \\\".*'.*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII apostrophy found in user visible strings\" >&2 && exit 1" >> $@
2686+ @echo "grep -c -e \"^msgid \\\".*\\\".*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII quote found in user visible strings\" >&2 && exit 1" >> $@
2687+ @echo "grep -c -e \"^msgid \\\".*\\\`.*\\\"\" $(top_srcdir)/po/$(GETTEXT_PACKAGE).pot > /dev/null && echo \"ASCII backtick found in user visible strings\" >&2 && exit 1" >> $@
2688+ @echo "exit 0" >> $@
2689+ @chmod +x $@
2690+
2691+CLEANFILES += $(TESTS)
2692
2693=== added file 'tests/test-dbus-listener.cc'
2694--- tests/test-dbus-listener.cc 1970-01-01 00:00:00 +0000
2695+++ tests/test-dbus-listener.cc 2012-07-11 17:08:19 +0000
2696@@ -0,0 +1,370 @@
2697+/*
2698+Copyright 2012 Canonical Ltd.
2699+
2700+Authors:
2701+ Charles Kerr <charles.kerr@canonical.com>
2702+
2703+This program is free software: you can redistribute it and/or modify it
2704+under the terms of the GNU General Public License version 3, as published
2705+by the Free Software Foundation.
2706+
2707+This program is distributed in the hope that it will be useful, but
2708+WITHOUT ANY WARRANTY; without even the implied warranties of
2709+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2710+PURPOSE. See the GNU General Public License for more details.
2711+
2712+You should have received a copy of the GNU General Public License along
2713+with this program. If not, see <http://www.gnu.org/licenses/>.
2714+*/
2715+
2716+#include <gtest/gtest.h>
2717+
2718+#include "dbus-listener.h"
2719+#include "device.h"
2720+
2721+/***
2722+****
2723+***/
2724+
2725+namespace
2726+{
2727+ void ensure_glib_initialized ()
2728+ {
2729+ static bool initialized = false;
2730+
2731+ if (G_UNLIKELY(!initialized))
2732+ {
2733+ initialized = true;
2734+ g_type_init();
2735+ }
2736+ }
2737+}
2738+
2739+/***
2740+****
2741+***/
2742+
2743+class DbusListenerTest : public ::testing::Test
2744+{
2745+ protected:
2746+ GSList * devices;
2747+ GDBusConnection * connection;
2748+ GMainLoop * mainloop;
2749+ GTestDBus * bus;
2750+ GDBusNodeInfo * gsd_power_introspection_data;
2751+ GVariant * get_devices_retval;
2752+ bool bus_acquired;
2753+ bool name_acquired;
2754+ int gsd_name_ownership_id;
2755+ int gsd_power_registration_id;
2756+ char * gsd_power_error_string;
2757+
2758+ protected:
2759+
2760+ static void
2761+ on_bus_acquired (GDBusConnection *conn, const gchar * name, gpointer gself)
2762+ {
2763+ g_debug ("bus acquired: %s, connection is %p", name, conn);
2764+
2765+ DbusListenerTest * test = static_cast<DbusListenerTest*> (gself);
2766+ test->connection = conn;
2767+ test->bus_acquired = true;
2768+ }
2769+
2770+ static void
2771+ on_name_acquired (GDBusConnection * conn, const gchar * name, gpointer gself)
2772+ {
2773+ g_debug ("name acquired: %s, connection is %p", name, conn);
2774+
2775+ DbusListenerTest * test = static_cast<DbusListenerTest*> (gself);
2776+ test->name_acquired = true;
2777+ g_main_loop_quit (test->mainloop);
2778+ }
2779+
2780+ static void
2781+ on_name_lost (GDBusConnection * conn, const gchar * name, gpointer gself)
2782+ {
2783+ g_debug ("name lost: %s, connection is %p", name, conn);
2784+
2785+ DbusListenerTest * test = static_cast<DbusListenerTest*> (gself);
2786+ test->name_acquired = false;
2787+ g_main_loop_quit (test->mainloop);
2788+ }
2789+
2790+ protected:
2791+
2792+ static void
2793+ on_devices_enumerated (IndicatorPowerDbusListener * l, GSList * devices, gpointer gself)
2794+ {
2795+ g_debug ("on_devices_enumerated");
2796+
2797+ DbusListenerTest * test = static_cast<DbusListenerTest*> (gself);
2798+ test->name_acquired = false;
2799+ g_slist_foreach (devices, (GFunc)g_object_ref, NULL);
2800+ test->devices = g_slist_copy (devices);
2801+ g_main_loop_quit (test->mainloop);
2802+ }
2803+
2804+ static void
2805+ gsd_power_handle_method_call (GDBusConnection * connection,
2806+ const gchar * sender,
2807+ const gchar * object_path,
2808+ const gchar * interface_name,
2809+ const gchar * method_name,
2810+ GVariant * parameters,
2811+ GDBusMethodInvocation * invocation,
2812+ gpointer gself)
2813+ {
2814+ DbusListenerTest * test = static_cast<DbusListenerTest*> (gself);
2815+ g_assert (!g_strcmp0 (method_name, "GetDevices"));
2816+ if (test->gsd_power_error_string != NULL) {
2817+ const GQuark domain = g_quark_from_static_string ("mock-gsd-power");
2818+ g_message ("returning an error");
2819+ g_dbus_method_invocation_return_error_literal (invocation, domain, 0, test->gsd_power_error_string);
2820+ } else {
2821+ g_dbus_method_invocation_return_value (invocation, test->get_devices_retval);
2822+ }
2823+ }
2824+
2825+ protected:
2826+
2827+ virtual void SetUp()
2828+ {
2829+ bus_acquired = false;
2830+ name_acquired = false;
2831+ connection = NULL;
2832+ devices = NULL;
2833+ get_devices_retval = NULL;
2834+ gsd_power_error_string = NULL;
2835+
2836+ // bring up the test bus
2837+ ensure_glib_initialized ();
2838+ mainloop = g_main_loop_new (NULL, FALSE);
2839+ bus = g_test_dbus_new (G_TEST_DBUS_NONE);
2840+ g_test_dbus_up (bus);
2841+
2842+ // own org.gnome.SettingsDameon on this test bus
2843+ gsd_name_ownership_id = g_bus_own_name (
2844+ G_BUS_TYPE_SESSION,
2845+ GSD_SERVICE,
2846+ G_BUS_NAME_OWNER_FLAGS_NONE,
2847+ on_bus_acquired,
2848+ on_name_acquired,
2849+ on_name_lost,
2850+ this, NULL);
2851+ ASSERT_FALSE (bus_acquired);
2852+ ASSERT_FALSE (name_acquired);
2853+ ASSERT_TRUE (connection == NULL);
2854+ g_main_loop_run (mainloop);
2855+ ASSERT_TRUE (bus_acquired);
2856+ ASSERT_TRUE (name_acquired);
2857+ ASSERT_TRUE (G_IS_DBUS_CONNECTION(connection));
2858+
2859+ // parse the org.gnome.SettingsDaemon.Power interface
2860+ const gchar introspection_xml[] =
2861+ "<node>"
2862+ " <interface name='org.gnome.SettingsDaemon.Power'>"
2863+ " <property name='Icon' type='s' access='read'>"
2864+ " </property>"
2865+ " <property name='Tooltip' type='s' access='read'>"
2866+ " </property>"
2867+ " <method name='GetDevices'>"
2868+ " <arg name='devices' type='a(susdut)' direction='out' />"
2869+ " </method>"
2870+ " </interface>"
2871+ "</node>";
2872+ gsd_power_introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
2873+ ASSERT_TRUE (gsd_power_introspection_data != NULL);
2874+
2875+ // Set up a mock GSD.
2876+ // All it really does is wait for calls to GetDevice and
2877+ // returns the get_devices_retval variant
2878+ const GDBusInterfaceVTable gsd_power_interface_vtable = {
2879+ gsd_power_handle_method_call,
2880+ NULL, /* GetProperty */
2881+ NULL, /* SetProperty */
2882+ };
2883+ gsd_power_registration_id = g_dbus_connection_register_object (connection,
2884+ GSD_POWER_DBUS_PATH,
2885+ gsd_power_introspection_data->interfaces[0],
2886+ &gsd_power_interface_vtable,
2887+ this, NULL, NULL);
2888+ }
2889+
2890+ virtual void TearDown()
2891+ {
2892+ g_free (gsd_power_error_string);
2893+
2894+ g_dbus_connection_unregister_object (connection, gsd_power_registration_id);
2895+
2896+ g_dbus_node_info_unref (gsd_power_introspection_data);
2897+ g_bus_unown_name (gsd_name_ownership_id);
2898+
2899+ g_slist_free_full (devices, g_object_unref);
2900+ g_test_dbus_down (bus);
2901+ g_main_loop_unref (mainloop);
2902+ }
2903+};
2904+
2905+/***
2906+****
2907+***/
2908+
2909+
2910+TEST_F(DbusListenerTest, GSDHasPowerAndBattery)
2911+{
2912+ // build a GetDevices retval that shows an AC line and a discharging battery
2913+ GVariantBuilder * builder = g_variant_builder_new (G_VARIANT_TYPE("a(susdut)"));
2914+ g_variant_builder_add (builder, "(susdut)",
2915+ "/org/freedesktop/UPower/devices/line_power_AC",
2916+ UP_DEVICE_KIND_LINE_POWER,
2917+ ". GThemedIcon ac-adapter-symbolic ac-adapter ",
2918+ 0.0,
2919+ UP_DEVICE_STATE_UNKNOWN,
2920+ 0);
2921+ g_variant_builder_add (builder, "(susdut)",
2922+ "/org/freedesktop/UPower/devices/battery_BAT0",
2923+ UP_DEVICE_KIND_BATTERY,
2924+ ". GThemedIcon battery-good-symbolic gpm-battery-060 battery-good ",
2925+ 52.871712,
2926+ UP_DEVICE_STATE_DISCHARGING,
2927+ 8834);
2928+ GVariant * value = g_variant_builder_end (builder);
2929+ get_devices_retval = g_variant_new_tuple (&value, 1);
2930+ g_variant_builder_unref (builder);
2931+
2932+ // create an i-power dbus listener to watch for GSD
2933+ ASSERT_EQ (g_slist_length(devices), 0);
2934+ GObject * o = G_OBJECT (g_object_new (INDICATOR_POWER_DBUS_LISTENER_TYPE, NULL));
2935+ ASSERT_TRUE (o != NULL);
2936+ ASSERT_TRUE (INDICATOR_IS_POWER_DBUS_LISTENER(o));
2937+ g_signal_connect(o, INDICATOR_POWER_DBUS_LISTENER_DEVICES_ENUMERATED,
2938+ G_CALLBACK(on_devices_enumerated), this);
2939+ g_main_loop_run (mainloop);
2940+
2941+ // test the devices should have gotten
2942+ ASSERT_EQ (g_slist_length(devices), 2);
2943+ IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE (g_slist_nth_data (devices, 0));
2944+ ASSERT_EQ (indicator_power_device_get_kind(device), UP_DEVICE_KIND_LINE_POWER);
2945+ ASSERT_STREQ ("/org/freedesktop/UPower/devices/line_power_AC", indicator_power_device_get_object_path(device));
2946+ device = INDICATOR_POWER_DEVICE (g_slist_nth_data (devices, 1));
2947+ ASSERT_EQ (UP_DEVICE_KIND_BATTERY, indicator_power_device_get_kind(device));
2948+ ASSERT_STREQ ("/org/freedesktop/UPower/devices/battery_BAT0", indicator_power_device_get_object_path(device));
2949+
2950+ // cleanup
2951+ g_object_run_dispose (o); // used to get coverage of both branches in the object's dispose func's g_clear_*() calls
2952+ g_object_unref (o);
2953+}
2954+
2955+TEST_F(DbusListenerTest, GSDHasNoDevices)
2956+{
2957+ GVariantBuilder * builder = g_variant_builder_new (G_VARIANT_TYPE("a(susdut)"));
2958+ GVariant * value = g_variant_builder_end (builder);
2959+ get_devices_retval = g_variant_new_tuple (&value, 1);
2960+ g_variant_builder_unref (builder);
2961+
2962+ // create an i-power dbus listener to watch for GSD
2963+ ASSERT_EQ (g_slist_length(devices), 0);
2964+ GObject * o = G_OBJECT (g_object_new (INDICATOR_POWER_DBUS_LISTENER_TYPE, NULL));
2965+ ASSERT_TRUE (o != NULL);
2966+ ASSERT_TRUE (INDICATOR_IS_POWER_DBUS_LISTENER(o));
2967+ g_signal_connect(o, INDICATOR_POWER_DBUS_LISTENER_DEVICES_ENUMERATED,
2968+ G_CALLBACK(on_devices_enumerated), this);
2969+ g_main_loop_run (mainloop);
2970+
2971+ // test the devices should have gotten
2972+ ASSERT_EQ (g_slist_length(devices), 0);
2973+
2974+ // FIXME: this test improves coverage and confirms that the code
2975+ // doesn't crash, but more meaningful tests would be better too.
2976+
2977+ // cleanup
2978+ g_object_run_dispose (o); // used to get coverage of both branches in the object's dispose func's g_clear_*() calls
2979+ g_object_unref (o);
2980+}
2981+
2982+TEST_F(DbusListenerTest, GSDReturnsError)
2983+{
2984+ gsd_power_error_string = g_strdup ("no devices for you lol");
2985+
2986+ // create an i-power dbus listener to watch for GSD
2987+ ASSERT_EQ (g_slist_length(devices), 0);
2988+ GObject * o = G_OBJECT (g_object_new (INDICATOR_POWER_DBUS_LISTENER_TYPE, NULL));
2989+ ASSERT_TRUE (o != NULL);
2990+ ASSERT_TRUE (INDICATOR_IS_POWER_DBUS_LISTENER(o));
2991+ g_signal_connect(o, INDICATOR_POWER_DBUS_LISTENER_DEVICES_ENUMERATED,
2992+ G_CALLBACK(on_devices_enumerated), this);
2993+ g_main_loop_run (mainloop);
2994+
2995+ // test the devices should have gotten
2996+ ASSERT_EQ (g_slist_length(devices), 0);
2997+
2998+ // FIXME: this test improves coverage and confirms that the code
2999+ // doesn't crash, but more meaningful tests would be better too.
3000+
3001+ // cleanup
3002+ g_object_run_dispose (o); // used to get coverage of both branches in the object's dispose func's g_clear_*() calls
3003+ g_object_unref (o);
3004+}
3005+
3006+/* This test emits a PropertiesChanged signal and confirms that
3007+ the dbus listener asks for a fresh set of devices as a result. */
3008+TEST_F(DbusListenerTest, GSDPropChanged)
3009+{
3010+ gsd_power_error_string = g_strdup ("no devices for you lol");
3011+
3012+ // create an i-power dbus listener to watch for GSD
3013+ ASSERT_EQ (g_slist_length(devices), 0);
3014+ GObject * o = G_OBJECT (g_object_new (INDICATOR_POWER_DBUS_LISTENER_TYPE, NULL));
3015+ ASSERT_TRUE (INDICATOR_IS_POWER_DBUS_LISTENER(o));
3016+ g_signal_connect(o, INDICATOR_POWER_DBUS_LISTENER_DEVICES_ENUMERATED,
3017+ G_CALLBACK(on_devices_enumerated), this);
3018+ g_main_loop_run (mainloop);
3019+ // test the devices should have gotten
3020+ ASSERT_EQ (g_slist_length(devices), 0);
3021+
3022+ // build a GetDevices retval that shows an AC line and a discharging battery
3023+ g_clear_pointer (&gsd_power_error_string, g_free);
3024+ GVariantBuilder * builder = g_variant_builder_new (G_VARIANT_TYPE("a(susdut)"));
3025+ g_variant_builder_add (builder, "(susdut)",
3026+ "/org/freedesktop/UPower/devices/line_power_AC",
3027+ UP_DEVICE_KIND_LINE_POWER,
3028+ ". GThemedIcon ac-adapter-symbolic ac-adapter ",
3029+ 0.0,
3030+ UP_DEVICE_STATE_UNKNOWN,
3031+ 0);
3032+ g_variant_builder_add (builder, "(susdut)",
3033+ "/org/freedesktop/UPower/devices/battery_BAT0",
3034+ UP_DEVICE_KIND_BATTERY,
3035+ ". GThemedIcon battery-good-symbolic gpm-battery-060 battery-good ",
3036+ 52.871712,
3037+ UP_DEVICE_STATE_DISCHARGING,
3038+ 8834);
3039+ GVariant * value = g_variant_builder_end (builder);
3040+ get_devices_retval = g_variant_new_tuple (&value, 1);
3041+ g_variant_builder_unref (builder);
3042+
3043+ // tell the listener that some property changed
3044+ GVariantBuilder props_builder;
3045+ g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}"));
3046+ GVariant * props_changed = g_variant_new ("(s@a{sv}@as)", GSD_POWER_DBUS_INTERFACE,
3047+ g_variant_builder_end (&props_builder),
3048+ g_variant_new_strv (NULL, 0));
3049+ g_variant_ref_sink (props_changed);
3050+ GError * error = NULL;
3051+ g_dbus_connection_emit_signal (connection,
3052+ NULL,
3053+ GSD_POWER_DBUS_PATH,
3054+ "org.freedesktop.DBus.Properties",
3055+ "PropertiesChanged",
3056+ props_changed,
3057+ &error);
3058+ ASSERT_TRUE(error == NULL);
3059+
3060+ // give i-power's dbus listener a chance to ask for a fresh device list
3061+ g_main_loop_run (mainloop);
3062+ ASSERT_EQ (g_slist_length(devices), 2);
3063+
3064+ // cleanup
3065+ g_object_unref (o);
3066+}
3067
3068=== added file 'tests/test-device.cc'
3069--- tests/test-device.cc 1970-01-01 00:00:00 +0000
3070+++ tests/test-device.cc 2012-07-11 17:08:19 +0000
3071@@ -0,0 +1,470 @@
3072+/*
3073+Copyright 2012 Canonical Ltd.
3074+
3075+Authors:
3076+ Charles Kerr <charles.kerr@canonical.com>
3077+
3078+This program is free software: you can redistribute it and/or modify it
3079+under the terms of the GNU General Public License version 3, as published
3080+by the Free Software Foundation.
3081+
3082+This program is distributed in the hope that it will be useful, but
3083+WITHOUT ANY WARRANTY; without even the implied warranties of
3084+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3085+PURPOSE. See the GNU General Public License for more details.
3086+
3087+You should have received a copy of the GNU General Public License along
3088+with this program. If not, see <http://www.gnu.org/licenses/>.
3089+*/
3090+
3091+#include <gtest/gtest.h>
3092+#include "device.h"
3093+
3094+namespace
3095+{
3096+ void ensure_glib_initialized ()
3097+ {
3098+ static bool initialized = false;
3099+
3100+ if (G_UNLIKELY(!initialized))
3101+ {
3102+ initialized = true;
3103+ g_type_init();
3104+ }
3105+ }
3106+}
3107+
3108+class DeviceTest : public ::testing::Test
3109+{
3110+ protected:
3111+
3112+ virtual void SetUp()
3113+ {
3114+ ensure_glib_initialized ();
3115+ }
3116+
3117+ virtual void TearDown()
3118+ {
3119+ }
3120+
3121+ protected:
3122+
3123+ void check_icon_names (const IndicatorPowerDevice * device, const char * expected)
3124+ {
3125+ char ** names = indicator_power_device_get_icon_names (device);
3126+ char * str = g_strjoinv (";", names);
3127+ ASSERT_STREQ (expected, str);
3128+ g_free (str);
3129+ g_strfreev (names);
3130+ }
3131+
3132+ void check_strings (const IndicatorPowerDevice * device,
3133+ const char * expected_timestring,
3134+ const char * expected_details,
3135+ const char * expected_accessible)
3136+ {
3137+ char * timestring = NULL;
3138+ char * details = NULL;
3139+ char * accessible = NULL;
3140+
3141+ indicator_power_device_get_time_details (device, &timestring, &details, &accessible);
3142+ EXPECT_STREQ (expected_timestring, timestring);
3143+ EXPECT_STREQ (expected_details, details);
3144+ EXPECT_STREQ (expected_accessible, accessible);
3145+
3146+ g_free (accessible);
3147+ g_free (details);
3148+ g_free (timestring);
3149+ }
3150+};
3151+
3152+
3153+/***
3154+****
3155+***/
3156+
3157+TEST_F(DeviceTest, GObjectNew)
3158+{
3159+ ensure_glib_initialized ();
3160+
3161+ GObject * o = G_OBJECT (g_object_new (INDICATOR_POWER_DEVICE_TYPE, NULL));
3162+ ASSERT_TRUE (o != NULL);
3163+ ASSERT_TRUE (INDICATOR_IS_POWER_DEVICE(o));
3164+ g_object_run_dispose (o); // used to get coverage of both branches in the object's dispose func's g_clear_*() calls
3165+ g_object_unref (o);
3166+}
3167+
3168+TEST_F(DeviceTest, Properties)
3169+{
3170+ int i;
3171+ gdouble d;
3172+ GObject * o;
3173+ gchar * str;
3174+ guint64 u64;
3175+ const gchar * key;
3176+
3177+ ensure_glib_initialized ();
3178+
3179+ o = G_OBJECT (g_object_new (INDICATOR_POWER_DEVICE_TYPE, NULL));
3180+ ASSERT_TRUE (o != NULL);
3181+ ASSERT_TRUE (INDICATOR_IS_POWER_DEVICE(o));
3182+
3183+ // Test getting & setting a Device's properties.
3184+
3185+ // KIND
3186+ key = INDICATOR_POWER_DEVICE_KIND;
3187+ g_object_set (o, key, UP_DEVICE_KIND_BATTERY, NULL);
3188+ g_object_get (o, key, &i, NULL);
3189+ ASSERT_EQ (i, UP_DEVICE_KIND_BATTERY);
3190+
3191+ // STATE
3192+ key = INDICATOR_POWER_DEVICE_STATE;
3193+ g_object_set (o, key, UP_DEVICE_STATE_CHARGING, NULL);
3194+ g_object_get (o, key, &i, NULL);
3195+ ASSERT_EQ (i, UP_DEVICE_STATE_CHARGING);
3196+
3197+ // OBJECT_PATH
3198+ key = INDICATOR_POWER_DEVICE_OBJECT_PATH;
3199+ g_object_set (o, key, "/object/path", NULL);
3200+ g_object_get (o, key, &str, NULL);
3201+ ASSERT_STREQ (str, "/object/path");
3202+ g_free (str);
3203+
3204+ // PERCENTAGE
3205+ key = INDICATOR_POWER_DEVICE_PERCENTAGE;
3206+ g_object_set (o, key, 50.0, NULL);
3207+ g_object_get (o, key, &d, NULL);
3208+ ASSERT_EQ((int)d, 50);
3209+
3210+ // TIME
3211+ key = INDICATOR_POWER_DEVICE_TIME;
3212+ g_object_set (o, key, (guint64)30, NULL);
3213+ g_object_get (o, key, &u64, NULL);
3214+ ASSERT_EQ(u64, 30);
3215+
3216+ // cleanup
3217+ g_object_unref (o);
3218+}
3219+
3220+TEST_F(DeviceTest, New)
3221+{
3222+ ensure_glib_initialized ();
3223+
3224+ IndicatorPowerDevice * device = indicator_power_device_new ("/object/path",
3225+ UP_DEVICE_KIND_BATTERY,
3226+ 50.0,
3227+ UP_DEVICE_STATE_CHARGING,
3228+ 30);
3229+ ASSERT_TRUE (device != NULL);
3230+ ASSERT_TRUE (INDICATOR_IS_POWER_DEVICE(device));
3231+ ASSERT_EQ (indicator_power_device_get_kind(device), UP_DEVICE_KIND_BATTERY);
3232+ ASSERT_EQ (indicator_power_device_get_state(device), UP_DEVICE_STATE_CHARGING);
3233+ ASSERT_STREQ (indicator_power_device_get_object_path(device), "/object/path");
3234+ ASSERT_EQ ((int)indicator_power_device_get_percentage(device), 50);
3235+ ASSERT_EQ (indicator_power_device_get_time(device), 30);
3236+
3237+ // cleanup
3238+ g_object_unref (device);
3239+}
3240+
3241+TEST_F(DeviceTest, NewFromVariant)
3242+{
3243+ ensure_glib_initialized ();
3244+
3245+ GVariant * variant = g_variant_new ("(susdut)",
3246+ "/object/path",
3247+ UP_DEVICE_KIND_BATTERY,
3248+ "icon",
3249+ 50.0,
3250+ UP_DEVICE_STATE_CHARGING,
3251+ 30);
3252+ IndicatorPowerDevice * device = indicator_power_device_new_from_variant (variant);
3253+ ASSERT_TRUE (variant != NULL);
3254+ ASSERT_TRUE (device != NULL);
3255+ ASSERT_TRUE (INDICATOR_IS_POWER_DEVICE(device));
3256+ ASSERT_EQ (indicator_power_device_get_kind(device), UP_DEVICE_KIND_BATTERY);
3257+ ASSERT_EQ (indicator_power_device_get_state(device), UP_DEVICE_STATE_CHARGING);
3258+ ASSERT_STREQ (indicator_power_device_get_object_path(device), "/object/path");
3259+ ASSERT_EQ ((int)indicator_power_device_get_percentage(device), 50);
3260+ ASSERT_EQ (indicator_power_device_get_time(device), 30);
3261+
3262+ // cleanup
3263+ g_object_unref (device);
3264+ g_variant_unref (variant);
3265+}
3266+
3267+TEST_F(DeviceTest, BadAccessors)
3268+{
3269+ ensure_glib_initialized ();
3270+
3271+ // test that these functions can handle being passed NULL pointers
3272+ IndicatorPowerDevice * device = NULL;
3273+ indicator_power_device_get_kind (device);
3274+ indicator_power_device_get_time (device);
3275+ indicator_power_device_get_state (device);
3276+ indicator_power_device_get_percentage (device);
3277+ indicator_power_device_get_object_path (device);
3278+
3279+ // test that these functions can handle being passed non-device GObjects
3280+ device = reinterpret_cast<IndicatorPowerDevice*>(g_cancellable_new ());
3281+ indicator_power_device_get_kind (device);
3282+ indicator_power_device_get_time (device);
3283+ indicator_power_device_get_state (device);
3284+ indicator_power_device_get_percentage (device);
3285+ indicator_power_device_get_object_path (device);
3286+ g_object_unref (device);
3287+}
3288+
3289+/***
3290+****
3291+***/
3292+
3293+TEST_F(DeviceTest, IconNames)
3294+{
3295+ IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE (g_object_new (INDICATOR_POWER_DEVICE_TYPE, NULL));
3296+ GObject * o = G_OBJECT(device);
3297+
3298+ // bad arguments
3299+ ASSERT_TRUE (indicator_power_device_get_icon_names (NULL) == NULL);
3300+
3301+ // power
3302+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_LINE_POWER,
3303+ NULL);
3304+ check_icon_names (device, "ac-adapter-symbolic;"
3305+ "ac-adapter");
3306+
3307+ // monitor
3308+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_MONITOR,
3309+ NULL);
3310+ check_icon_names (device, "gpm-monitor-symbolic;"
3311+ "gpm-monitor");
3312+
3313+ // empty battery
3314+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3315+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_EMPTY,
3316+ NULL);
3317+ check_icon_names (device, "battery-empty-symbolic;"
3318+ "gpm-battery-empty;"
3319+ "gpm-battery-000;"
3320+ "battery-empty");
3321+
3322+ // charged battery
3323+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3324+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_FULLY_CHARGED,
3325+ NULL);
3326+ check_icon_names (device, "battery-full-charged-symbolic;battery-full-charging-symbolic;"
3327+ "gpm-battery-full;gpm-battery-100;"
3328+ "battery-full-charged;battery-full-charging");
3329+
3330+ // charging battery, 95%
3331+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3332+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING,
3333+ INDICATOR_POWER_DEVICE_PERCENTAGE, 95.0,
3334+ NULL);
3335+ check_icon_names (device, "battery-caution-charging-symbolic;"
3336+ "gpm-battery-000-charging;"
3337+ "battery-caution-charging");
3338+
3339+ // charging battery, 85%
3340+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3341+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING,
3342+ INDICATOR_POWER_DEVICE_PERCENTAGE, 85.0,
3343+ NULL);
3344+ check_icon_names (device, "battery-caution-charging-symbolic;"
3345+ "gpm-battery-000-charging;"
3346+ "battery-caution-charging");
3347+
3348+ // charging battery, 50%
3349+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3350+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING,
3351+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3352+ NULL);
3353+ check_icon_names (device, "battery-caution-charging-symbolic;"
3354+ "gpm-battery-000-charging;"
3355+ "battery-caution-charging");
3356+
3357+ // charging battery, 25%
3358+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3359+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING,
3360+ INDICATOR_POWER_DEVICE_PERCENTAGE, 25.0,
3361+ NULL);
3362+ check_icon_names (device, "battery-caution-charging-symbolic;"
3363+ "gpm-battery-000-charging;"
3364+ "battery-caution-charging");
3365+
3366+ // charging battery, 5%
3367+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3368+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING,
3369+ INDICATOR_POWER_DEVICE_PERCENTAGE, 5.0,
3370+ NULL);
3371+ check_icon_names (device, "battery-caution-charging-symbolic;"
3372+ "gpm-battery-000-charging;"
3373+ "battery-caution-charging");
3374+
3375+
3376+ // discharging battery, 95%
3377+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3378+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3379+ INDICATOR_POWER_DEVICE_PERCENTAGE, 95.0,
3380+ NULL);
3381+ check_icon_names (device, "battery-full-symbolic;"
3382+ "gpm-battery-100;"
3383+ "battery-full");
3384+
3385+ // discharging battery, 85%
3386+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3387+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3388+ INDICATOR_POWER_DEVICE_PERCENTAGE, 85.0,
3389+ NULL);
3390+ check_icon_names (device, "battery-full-symbolic;"
3391+ "gpm-battery-080;"
3392+ "battery-full");
3393+
3394+ // discharging battery, 50% -- 1 hour left
3395+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3396+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3397+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3398+ INDICATOR_POWER_DEVICE_TIME, (guint64)(60*60),
3399+ NULL);
3400+ check_icon_names (device, "battery-good-symbolic;"
3401+ "gpm-battery-060;"
3402+ "battery-good");
3403+
3404+ // discharging battery, 25% -- 1 hour left
3405+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3406+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3407+ INDICATOR_POWER_DEVICE_PERCENTAGE, 25.0,
3408+ INDICATOR_POWER_DEVICE_TIME, (guint64)(60*60),
3409+ NULL);
3410+ check_icon_names (device, "battery-good-symbolic;"
3411+ "gpm-battery-040;"
3412+ "battery-good");
3413+
3414+ // discharging battery, 25% -- 15 minutes left
3415+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3416+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3417+ INDICATOR_POWER_DEVICE_PERCENTAGE, 25.0,
3418+ INDICATOR_POWER_DEVICE_TIME, (guint64)(60*15),
3419+ NULL);
3420+ check_icon_names (device, "battery-low-symbolic;"
3421+ "gpm-battery-020;"
3422+ "battery-low");
3423+
3424+ // discharging battery, 5% -- 1 hour left
3425+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3426+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3427+ INDICATOR_POWER_DEVICE_PERCENTAGE, 5.0,
3428+ INDICATOR_POWER_DEVICE_TIME, (guint64)(60*60),
3429+ NULL);
3430+ check_icon_names (device, "battery-good-symbolic;"
3431+ "gpm-battery-040;"
3432+ "battery-good");
3433+
3434+ // discharging battery, 5% -- 15 minutes left
3435+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3436+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3437+ INDICATOR_POWER_DEVICE_PERCENTAGE, 5.0,
3438+ INDICATOR_POWER_DEVICE_TIME, (guint64)(60*15),
3439+ NULL);
3440+ check_icon_names (device, "battery-caution-symbolic;"
3441+ "gpm-battery-000;"
3442+ "battery-caution");
3443+ // state unknown
3444+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3445+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_UNKNOWN,
3446+ NULL);
3447+ check_icon_names (device, "battery-missing-symbolic;"
3448+ "gpm-battery-missing;"
3449+ "battery-missing");
3450+
3451+ // cleanup
3452+ g_object_unref(o);
3453+}
3454+
3455+
3456+TEST_F(DeviceTest, Labels)
3457+{
3458+ // set our language so that i18n won't break these tests
3459+ char * real_lang = g_strdup(g_getenv ("LANG"));
3460+ g_setenv ("LANG", "en_US.UTF-8", TRUE);
3461+
3462+ // bad args: NULL device
3463+ check_strings (NULL, NULL, NULL, NULL);
3464+
3465+ // bad args: a GObject that isn't a device
3466+ GObject * o = G_OBJECT(g_cancellable_new());
3467+ check_strings ((IndicatorPowerDevice*)o, NULL, NULL, NULL);
3468+ g_object_unref (o);
3469+
3470+ /**
3471+ ***
3472+ **/
3473+
3474+ IndicatorPowerDevice * device = INDICATOR_POWER_DEVICE (g_object_new (INDICATOR_POWER_DEVICE_TYPE, NULL));
3475+ o = G_OBJECT(device);
3476+
3477+ // charging
3478+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3479+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING,
3480+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3481+ INDICATOR_POWER_DEVICE_TIME, guint64(60*61),
3482+ NULL);
3483+ check_strings (device, "(1:01)",
3484+ "Battery (1:01 to charge)",
3485+ "Battery (1 hour 1 minute to charge (50%))");
3486+
3487+ // discharging, < 12 hours left
3488+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3489+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3490+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3491+ INDICATOR_POWER_DEVICE_TIME, guint64(60*61),
3492+ NULL);
3493+ check_strings (device, "1:01",
3494+ "Battery (1:01 left)",
3495+ "Battery (1 hour 1 minute left (50%))");
3496+
3497+ // discharging, > 12 hours left
3498+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3499+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3500+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3501+ INDICATOR_POWER_DEVICE_TIME, guint64(60*60*13),
3502+ NULL);
3503+ check_strings (device, "13:00", "Battery", "Battery");
3504+
3505+ // fully charged
3506+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3507+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_FULLY_CHARGED,
3508+ INDICATOR_POWER_DEVICE_PERCENTAGE, 100.0,
3509+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
3510+ NULL);
3511+ check_strings (device, "", "Battery (charged)", "Battery (charged)");
3512+
3513+ // percentage but no time estimate
3514+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3515+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3516+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3517+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
3518+ NULL);
3519+ check_strings (device, "(50%)", "Battery (50%)", "Battery (50%)");
3520+
3521+ // no percentage, no time estimate
3522+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_BATTERY,
3523+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3524+ INDICATOR_POWER_DEVICE_PERCENTAGE, 0.0,
3525+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
3526+ NULL);
3527+ check_strings (device, "(not present)", "Battery (not present)", "Battery (not present)");
3528+
3529+ // power line
3530+ g_object_set (o, INDICATOR_POWER_DEVICE_KIND, UP_DEVICE_KIND_LINE_POWER,
3531+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_UNKNOWN,
3532+ INDICATOR_POWER_DEVICE_PERCENTAGE, 0.0,
3533+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
3534+ NULL);
3535+ check_strings (device, "AC Adapter", "AC Adapter", "AC Adapter");
3536+
3537+ // cleanup
3538+ g_object_unref(o);
3539+ g_setenv ("LANG", real_lang, TRUE);
3540+ g_free (real_lang);
3541+}
3542
3543=== added file 'tests/test-indicator.cc'
3544--- tests/test-indicator.cc 1970-01-01 00:00:00 +0000
3545+++ tests/test-indicator.cc 2012-07-11 17:08:19 +0000
3546@@ -0,0 +1,312 @@
3547+/*
3548+Copyright 2012 Canonical Ltd.
3549+
3550+Authors:
3551+ Charles Kerr <charles.kerr@canonical.com>
3552+
3553+This program is free software: you can redistribute it and/or modify it
3554+under the terms of the GNU General Public License version 3, as published
3555+by the Free Software Foundation.
3556+
3557+This program is distributed in the hope that it will be useful, but
3558+WITHOUT ANY WARRANTY; without even the implied warranties of
3559+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3560+PURPOSE. See the GNU General Public License for more details.
3561+
3562+You should have received a copy of the GNU General Public License along
3563+with this program. If not, see <http://www.gnu.org/licenses/>.
3564+*/
3565+
3566+#include <gtest/gtest.h>
3567+
3568+#include "dbus-listener.h"
3569+#include "device.h"
3570+#include "indicator-power.h"
3571+
3572+/***
3573+****
3574+***/
3575+
3576+namespace
3577+{
3578+ void ensure_glib_initialized ()
3579+ {
3580+ static bool initialized = false;
3581+
3582+ if (G_UNLIKELY(!initialized))
3583+ {
3584+ initialized = true;
3585+ g_type_init();
3586+ }
3587+ }
3588+}
3589+
3590+/***
3591+****
3592+***/
3593+
3594+class IndicatorTest : public ::testing::Test
3595+{
3596+ protected:
3597+
3598+ IndicatorPowerDevice * ac_device;
3599+ IndicatorPowerDevice * battery_device;
3600+
3601+ virtual void SetUp()
3602+ {
3603+ ensure_glib_initialized ();
3604+
3605+ g_setenv( "GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
3606+
3607+ ac_device = indicator_power_device_new (
3608+ "/org/freedesktop/UPower/devices/line_power_AC",
3609+ UP_DEVICE_KIND_LINE_POWER,
3610+ 0.0, UP_DEVICE_STATE_UNKNOWN, 0);
3611+
3612+ battery_device = indicator_power_device_new (
3613+ "/org/freedesktop/UPower/devices/battery_BAT0",
3614+ UP_DEVICE_KIND_BATTERY,
3615+ 52.871712, UP_DEVICE_STATE_DISCHARGING, 8834);
3616+ }
3617+
3618+ virtual void TearDown()
3619+ {
3620+ g_object_unref (battery_device);
3621+ g_object_unref (ac_device);
3622+ }
3623+
3624+ const char* GetAccessibleDesc (IndicatorPower * power) const
3625+ {
3626+ GList * entries = indicator_object_get_entries (INDICATOR_OBJECT(power));
3627+ g_assert (g_list_length(entries) == 1);
3628+ IndicatorObjectEntry * entry = static_cast<IndicatorObjectEntry*>(entries->data);
3629+ const char * ret = entry->accessible_desc;
3630+ g_list_free (entries);
3631+ return ret;
3632+ }
3633+};
3634+
3635+/***
3636+****
3637+***/
3638+
3639+TEST_F(IndicatorTest, GObjectNew)
3640+{
3641+ GObject * o = G_OBJECT (g_object_new (INDICATOR_POWER_TYPE, NULL));
3642+ ASSERT_TRUE (o != NULL);
3643+ ASSERT_TRUE (IS_INDICATOR_POWER(o));
3644+ g_object_run_dispose (o); // used to get coverage of both branches in the object's dispose func's g_clear_*() calls
3645+ g_object_unref (o);
3646+}
3647+
3648+TEST_F(IndicatorTest, SetDevices)
3649+{
3650+ GSList * devices;
3651+ IndicatorPower * power = INDICATOR_POWER(g_object_new (INDICATOR_POWER_TYPE, NULL));
3652+
3653+ devices = NULL;
3654+ devices = g_slist_append (devices, ac_device);
3655+ devices = g_slist_append (devices, battery_device);
3656+ indicator_power_set_devices (power, devices);
3657+ g_slist_free (devices);
3658+
3659+ g_object_unref (power);
3660+}
3661+
3662+TEST_F(IndicatorTest, DischargingStrings)
3663+{
3664+ IndicatorPower * power = INDICATOR_POWER(g_object_new (INDICATOR_POWER_TYPE, NULL));
3665+ GSList * devices = g_slist_append (NULL, battery_device);
3666+
3667+ // give the indicator a discharging battery with 30 minutes of life left
3668+ g_object_set (battery_device,
3669+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3670+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3671+ INDICATOR_POWER_DEVICE_TIME, guint64(60*30),
3672+ NULL);
3673+ indicator_power_set_devices (power, devices);
3674+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (30 minutes left (50%))");
3675+
3676+ // give the indicator a discharging battery with 1 hour of life left
3677+ g_object_set (battery_device,
3678+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_DISCHARGING,
3679+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3680+ INDICATOR_POWER_DEVICE_TIME, guint64(60*60),
3681+ NULL);
3682+ indicator_power_set_devices (power, devices);
3683+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (1 hour left (50%))");
3684+
3685+ // give the indicator a discharging battery with 2 hours of life left
3686+ g_object_set (battery_device,
3687+ INDICATOR_POWER_DEVICE_PERCENTAGE, 100.0,
3688+ INDICATOR_POWER_DEVICE_TIME, guint64(60*60*2),
3689+ NULL);
3690+ indicator_power_set_devices (power, devices);
3691+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (2 hours left (100%))");
3692+
3693+ // give the indicator a discharging battery with over 12 hours of life left
3694+ g_object_set (battery_device,
3695+ INDICATOR_POWER_DEVICE_TIME, guint64(60*60*12 + 1),
3696+ NULL);
3697+ indicator_power_set_devices (power, devices);
3698+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery");
3699+
3700+ // give the indicator a discharging battery with 29 seconds left
3701+ g_object_set (battery_device,
3702+ INDICATOR_POWER_DEVICE_TIME, guint64(29),
3703+ NULL);
3704+ indicator_power_set_devices (power, devices);
3705+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (Unknown time left (100%))");
3706+
3707+ // what happens if the time estimate isn't available
3708+ g_object_set (battery_device,
3709+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
3710+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3711+ NULL);
3712+ indicator_power_set_devices (power, devices);
3713+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (50%)");
3714+
3715+ // what happens if the time estimate AND percentage isn't available
3716+ g_object_set (battery_device,
3717+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
3718+ INDICATOR_POWER_DEVICE_PERCENTAGE, 0.0,
3719+ NULL);
3720+ indicator_power_set_devices (power, devices);
3721+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (not present)");
3722+
3723+ // cleanup
3724+ g_slist_free (devices);
3725+ g_object_unref (power);
3726+}
3727+
3728+TEST_F(IndicatorTest, ChargingStrings)
3729+{
3730+ IndicatorPower * power = INDICATOR_POWER(g_object_new (INDICATOR_POWER_TYPE, NULL));
3731+ GSList * devices = g_slist_prepend (NULL, battery_device);
3732+
3733+ // give the indicator a discharging battery with 1 hour of life left
3734+ g_object_set (battery_device,
3735+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_CHARGING,
3736+ INDICATOR_POWER_DEVICE_PERCENTAGE, 50.0,
3737+ INDICATOR_POWER_DEVICE_TIME, guint64(60*60),
3738+ NULL);
3739+ indicator_power_set_devices (power, devices);
3740+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (1 hour to charge (50%))");
3741+
3742+ // give the indicator a discharging battery with 2 hours of life left
3743+ g_object_set (battery_device,
3744+ INDICATOR_POWER_DEVICE_TIME, guint64(60*60*2),
3745+ NULL);
3746+ indicator_power_set_devices (power, devices);
3747+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (2 hours to charge (50%))");
3748+
3749+ // cleanup
3750+ g_slist_free (devices);
3751+ g_object_unref (power);
3752+}
3753+
3754+TEST_F(IndicatorTest, ChargedStrings)
3755+{
3756+ IndicatorPower * power = INDICATOR_POWER(g_object_new (INDICATOR_POWER_TYPE, NULL));
3757+ GSList * devices = g_slist_append (NULL, battery_device);
3758+
3759+ // give the indicator a discharging battery with 1 hour of life left
3760+ g_object_set (battery_device,
3761+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_FULLY_CHARGED,
3762+ INDICATOR_POWER_DEVICE_PERCENTAGE, 100.0,
3763+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
3764+ NULL);
3765+ indicator_power_set_devices (power, devices);
3766+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (charged)");
3767+
3768+ // cleanup
3769+ g_slist_free (devices);
3770+ g_object_unref (power);
3771+}
3772+
3773+TEST_F(IndicatorTest, AvoidChargingBatteriesWithZeroSecondsLeft)
3774+{
3775+ IndicatorPower * power = INDICATOR_POWER(g_object_new (INDICATOR_POWER_TYPE, NULL));
3776+
3777+ g_object_set (battery_device,
3778+ INDICATOR_POWER_DEVICE_STATE, UP_DEVICE_STATE_FULLY_CHARGED,
3779+ INDICATOR_POWER_DEVICE_PERCENTAGE, 100.0,
3780+ INDICATOR_POWER_DEVICE_TIME, guint64(0),
3781+ NULL);
3782+ IndicatorPowerDevice * bad_battery_device = indicator_power_device_new (
3783+ "/org/freedesktop/UPower/devices/battery_BAT0",
3784+ UP_DEVICE_KIND_BATTERY,
3785+ 53, UP_DEVICE_STATE_CHARGING, 0);
3786+
3787+ GSList * devices = NULL;
3788+ devices = g_slist_append (devices, battery_device);
3789+ devices = g_slist_append (devices, bad_battery_device);
3790+ indicator_power_set_devices (power, devices);
3791+ ASSERT_STREQ (GetAccessibleDesc(power), "Battery (53%)");
3792+
3793+ // cleanup
3794+ g_slist_free (devices);
3795+ g_object_unref (power);
3796+ g_object_unref (bad_battery_device);
3797+}
3798+
3799+TEST_F(IndicatorTest, OtherDevices)
3800+{
3801+ IndicatorPower * power = INDICATOR_POWER(g_object_new (INDICATOR_POWER_TYPE, NULL));
3802+
3803+ g_object_ref (battery_device);
3804+ GSList * devices = g_slist_append (NULL, battery_device);
3805+
3806+ devices = g_slist_append (devices, indicator_power_device_new (
3807+ "/org/freedesktop/UPower/devices/mouse", UP_DEVICE_KIND_MOUSE,
3808+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3809+ devices = g_slist_append (devices, indicator_power_device_new (
3810+ "/org/freedesktop/UPower/devices/ups", UP_DEVICE_KIND_UPS,
3811+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3812+ devices = g_slist_append (devices, indicator_power_device_new (
3813+ "/org/freedesktop/UPower/devices/keyboard", UP_DEVICE_KIND_KEYBOARD,
3814+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3815+ devices = g_slist_append (devices, indicator_power_device_new (
3816+ "/org/freedesktop/UPower/devices/pda", UP_DEVICE_KIND_PDA,
3817+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3818+ devices = g_slist_append (devices, indicator_power_device_new (
3819+ "/org/freedesktop/UPower/devices/phone", UP_DEVICE_KIND_PHONE,
3820+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3821+ devices = g_slist_append (devices, indicator_power_device_new (
3822+ "/org/freedesktop/UPower/devices/monitor", UP_DEVICE_KIND_MONITOR,
3823+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3824+ devices = g_slist_append (devices, indicator_power_device_new (
3825+ "/org/freedesktop/UPower/devices/media_player", UP_DEVICE_KIND_MEDIA_PLAYER,
3826+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3827+ devices = g_slist_append (devices, indicator_power_device_new (
3828+ "/org/freedesktop/UPower/devices/tablet", UP_DEVICE_KIND_TABLET,
3829+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3830+ devices = g_slist_append (devices, indicator_power_device_new (
3831+ "/org/freedesktop/UPower/devices/computer", UP_DEVICE_KIND_COMPUTER,
3832+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3833+ devices = g_slist_append (devices, indicator_power_device_new (
3834+ "/org/freedesktop/UPower/devices/unknown", UP_DEVICE_KIND_UNKNOWN,
3835+ 0, UP_DEVICE_STATE_UNKNOWN, 0));
3836+
3837+ indicator_power_set_devices (power, devices);
3838+
3839+ // FIXME: this tests to confirm the code doesn't crash,
3840+ // but further tests would be helpful
3841+
3842+ // cleanup
3843+ g_slist_free_full (devices, g_object_unref);
3844+ g_object_unref (power);
3845+}
3846+
3847+TEST_F(IndicatorTest, NoDevices)
3848+{
3849+ IndicatorPower * power = INDICATOR_POWER(g_object_new (INDICATOR_POWER_TYPE, NULL));
3850+
3851+ indicator_power_set_devices (power, NULL);
3852+
3853+ // FIXME: this tests to confirm the code doesn't crash,
3854+ // but further tests would be helpful
3855+
3856+ // cleanup
3857+ g_object_unref (power);
3858+}

Subscribers

People subscribed via source and target branches