Merge lp:~larsu/unity-control-center/bluez5-gnome-bluetooth into lp:unity-control-center

Proposed by Sebastien Bacher
Status: Merged
Approved by: Sebastien Bacher
Approved revision: 12808
Merged at revision: 12820
Proposed branch: lp:~larsu/unity-control-center/bluez5-gnome-bluetooth
Merge into: lp:unity-control-center
Diff against target: 11178 lines (+10736/-93)
46 files modified
configure.ac (+4/-10)
panels/Makefile.am (+2/-5)
panels/bluetooth/Makefile.am (+16/-4)
panels/bluetooth/bluetooth-killswitch.c (+387/-0)
panels/bluetooth/bluetooth-killswitch.h (+78/-0)
panels/bluetooth/cc-bluetooth-panel.c (+3/-74)
panels/bluetooth/gnome-bluetooth/Makefile.am (+1/-0)
panels/bluetooth/gnome-bluetooth/lib/Makefile.am (+99/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.c (+681/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.h (+127/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.c (+419/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.h (+55/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.c (+365/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.h (+69/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-private.h (+39/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.c (+1173/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.h (+86/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-client-private.h (+61/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.c (+1757/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.h (+87/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.xml (+59/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-enums.h (+177/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-fdo.xml (+33/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-filter-widget.c (+477/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-filter-widget.h (+67/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-utils.c (+342/-0)
panels/bluetooth/gnome-bluetooth/lib/bluetooth-utils.h (+72/-0)
panels/bluetooth/gnome-bluetooth/lib/pin-code-database.xml (+155/-0)
panels/bluetooth/gnome-bluetooth/lib/test-agent.c (+86/-0)
panels/bluetooth/gnome-bluetooth/lib/test-class.c (+66/-0)
panels/bluetooth/gnome-bluetooth/lib/test-client.c (+326/-0)
panels/bluetooth/gnome-bluetooth/lib/test-deviceselection.c (+421/-0)
panels/bluetooth/gnome-bluetooth/wizard/Makefile.am (+38/-0)
panels/bluetooth/gnome-bluetooth/wizard/TEST-PROCEDURE.txt (+33/-0)
panels/bluetooth/gnome-bluetooth/wizard/bluetooth-input.c (+239/-0)
panels/bluetooth/gnome-bluetooth/wizard/bluetooth-input.h (+65/-0)
panels/bluetooth/gnome-bluetooth/wizard/bluetooth-wizard.1 (+29/-0)
panels/bluetooth/gnome-bluetooth/wizard/main.c (+1115/-0)
panels/bluetooth/gnome-bluetooth/wizard/pin-code-database.xml (+155/-0)
panels/bluetooth/gnome-bluetooth/wizard/pin.c (+174/-0)
panels/bluetooth/gnome-bluetooth/wizard/pin.h (+33/-0)
panels/bluetooth/gnome-bluetooth/wizard/test-input.c (+54/-0)
panels/bluetooth/gnome-bluetooth/wizard/wizard.ui (+540/-0)
panels/bluetooth/rfkill-glib.c (+299/-0)
panels/bluetooth/rfkill-glib.h (+65/-0)
panels/bluetooth/rfkill.h (+107/-0)
To merge this branch: bzr merge lp:~larsu/unity-control-center/bluez5-gnome-bluetooth
Reviewer Review Type Date Requested Status
Sebastien Bacher Approve
Review via email: mp+267835@code.launchpad.net

Commit message

bluetooth: make compatible with bluez5

Since we don't want to update to gnome bluetooth's new UI, import
gnome-bluetooth until commit ef7d546, which has bluez5 support but no UI
changes.

Description of the change

bluetooth: make compatible with bluez5

Since we don't want to update to gnome bluetooth's new UI, import
gnome-bluetooth until commit ef7d546, which has bluez5 support but no UI
changes.

To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote :

Lars is not around, merge proposing for him, I stack a branch with some addition tweaks/fixes on top of that one. The changes could be nicer but that should do the job to unblock the bluez5 migration, we can iterate more later

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2015-02-12 14:09:23 +0000
3+++ configure.ac 2015-08-12 15:47:27 +0000
4@@ -171,6 +171,7 @@
5 gdk-pixbuf-2.0 >= $GDKPIXBUF_REQUIRED_VERSION
6 pwquality
7 accountsservice >= $ACCOUNTSSERVICE_REQUIRED_VERSION)
8+PKG_CHECK_MODULES(BLUETOOTH_PANEL, $COMMON_MODULES)
9
10 AM_PROG_VALAC([0.20.0])
11
12@@ -188,11 +189,6 @@
13 fi
14 AM_CONDITIONAL(BUILD_NETWORK, [test x$have_networkmanager = xyes])
15
16-# Check for gnome-bluetooth
17-PKG_CHECK_MODULES(BLUETOOTH, $COMMON_MODULES gnome-bluetooth-1.0 >= 3.5.5,
18- [have_bluetooth=yes], have_bluetooth=no)
19-AM_CONDITIONAL(BUILD_BLUETOOTH, [test x$have_bluetooth = xyes])
20-
21 # Check for CUPS 1.4 or newer
22 AC_ARG_ENABLE([cups],
23 AS_HELP_STRING([--disable-cups], [disable CUPS support (default: enabled)]),,
24@@ -419,6 +415,9 @@
25 panels/appearance/Makefile
26 panels/appearance/unity-appearance-panel.desktop.in
27 panels/bluetooth/Makefile
28+panels/bluetooth/gnome-bluetooth/Makefile
29+panels/bluetooth/gnome-bluetooth/lib/Makefile
30+panels/bluetooth/gnome-bluetooth/wizard/Makefile
31 panels/bluetooth/unity-bluetooth-panel.desktop.in
32 panels/datetime/Makefile
33 panels/datetime/unity-datetime-panel.desktop.in
34@@ -502,11 +501,6 @@
35 else
36 AC_MSG_NOTICE([ Network panel disabled])
37 fi
38-if test "x$have_bluetooth" = "xyes"; then
39- AC_MSG_NOTICE([** gnome-bluetooth (Bluetooth panel)])
40-else
41- AC_MSG_NOTICE([ Bluetooth panel disabled])
42-fi
43 if test "x$enable_cups" = "xyes"; then
44 AC_MSG_NOTICE([** CUPS (Printers panel)])
45 else
46
47=== modified file 'panels/Makefile.am'
48--- panels/Makefile.am 2014-02-10 22:19:33 +0000
49+++ panels/Makefile.am 2015-08-12 15:47:27 +0000
50@@ -12,7 +12,8 @@
51 sound \
52 keyboard \
53 universal-access \
54- user-accounts
55+ user-accounts \
56+ bluetooth
57
58 if BUILD_WACOM
59 SUBDIRS += wacom
60@@ -26,8 +27,4 @@
61 SUBDIRS += network
62 endif
63
64-if BUILD_BLUETOOTH
65-SUBDIRS += bluetooth
66-endif
67-
68 -include $(top_srcdir)/git.mk
69
70=== modified file 'panels/bluetooth/Makefile.am'
71--- panels/bluetooth/Makefile.am 2014-02-19 23:36:18 +0000
72+++ panels/bluetooth/Makefile.am 2015-08-12 15:47:27 +0000
73@@ -1,3 +1,5 @@
74+SUBDIRS = gnome-bluetooth
75+
76 # This is used in PANEL_CFLAGS
77 cappletname = bluetooth
78
79@@ -6,7 +8,8 @@
80
81 INCLUDES = \
82 $(PANEL_CFLAGS) \
83- $(BLUETOOTH_CFLAGS) \
84+ $(BLUETOOTH_PANEL_CFLAGS) \
85+ -I$(srcdir)/gnome-bluetooth/lib \
86 -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
87 $(NULL)
88
89@@ -17,9 +20,18 @@
90 libbluetooth_la_SOURCES = \
91 $(BUILT_SOURCES) \
92 cc-bluetooth-panel.c \
93- cc-bluetooth-panel.h
94-
95-libbluetooth_la_LIBADD = $(PANEL_LIBS) $(BLUETOOTH_LIBS)
96+ cc-bluetooth-panel.h \
97+ bluetooth-killswitch.c \
98+ bluetooth-killswitch.h \
99+ rfkill.h \
100+ rfkill-glib.c \
101+ rfkill-glib.h
102+
103+libbluetooth_la_LIBADD = \
104+ $(PANEL_LIBS) \
105+ $(BLUETOOTH_PANEL_LIBS) \
106+ $(builddir)/gnome-bluetooth/lib/libgnome-bluetooth.la
107+
108 libbluetooth_la_LDFLAGS = $(PANEL_LDFLAGS)
109
110 resource_files = $(shell glib-compile-resources --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/bluetooth.gresource.xml)
111
112=== added file 'panels/bluetooth/bluetooth-killswitch.c'
113--- panels/bluetooth/bluetooth-killswitch.c 1970-01-01 00:00:00 +0000
114+++ panels/bluetooth/bluetooth-killswitch.c 2015-08-12 15:47:27 +0000
115@@ -0,0 +1,387 @@
116+/*
117+ *
118+ * BlueZ - Bluetooth protocol stack for Linux
119+ *
120+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
121+ * Copyright (C) 2006-2009 Bastien Nocera <hadess@hadess.net>
122+ *
123+ *
124+ * This program is free software; you can redistribute it and/or modify
125+ * it under the terms of the GNU General Public License as published by
126+ * the Free Software Foundation; either version 2 of the License, or
127+ * (at your option) any later version.
128+ *
129+ * This program is distributed in the hope that it will be useful,
130+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
131+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
132+ * GNU General Public License for more details.
133+ *
134+ * You should have received a copy of the GNU General Public License
135+ * along with this program; if not, write to the Free Software
136+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
137+ *
138+ */
139+
140+/**
141+ * SECTION:bluetooth-killswitch
142+ * @short_description: a Bluetooth killswitch object
143+ * @stability: Stable
144+ * @include: bluetooth-killswitch.h
145+ *
146+ * An object to manipulate Bluetooth killswitches.
147+ **/
148+
149+#ifdef HAVE_CONFIG_H
150+#include <config.h>
151+#endif
152+
153+#include <errno.h>
154+#include <sys/types.h>
155+#include <string.h>
156+#include <glib.h>
157+
158+#include "bluetooth-killswitch.h"
159+#include "rfkill-glib.h"
160+
161+enum {
162+ STATE_CHANGED,
163+ LAST_SIGNAL
164+};
165+
166+static int signals[LAST_SIGNAL] = { 0 };
167+
168+#define BLUETOOTH_KILLSWITCH_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
169+ BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitchPrivate))
170+
171+typedef struct _BluetoothIndKillswitch BluetoothIndKillswitch;
172+struct _BluetoothIndKillswitch {
173+ guint index;
174+ BluetoothKillswitchState state;
175+};
176+
177+struct _BluetoothKillswitchPrivate {
178+ RfkillGlib *rfkill;
179+ gboolean in_init;
180+ GList *killswitches; /* a GList of BluetoothIndKillswitch */
181+ BluetoothKillswitchPrivate *priv;
182+};
183+
184+G_DEFINE_TYPE(BluetoothKillswitch, bluetooth_killswitch, G_TYPE_OBJECT)
185+
186+static BluetoothKillswitchState
187+event_to_state (guint soft, guint hard)
188+{
189+ if (hard)
190+ return BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED;
191+ else if (soft)
192+ return BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED;
193+ else
194+ return BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED;
195+}
196+
197+static const char *
198+state_to_string (BluetoothKillswitchState state)
199+{
200+ switch (state) {
201+ case BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER:
202+ return "no-adapter";
203+ case BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED:
204+ return "soft-blocked";
205+ case BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED:
206+ return "unblocked";
207+ case BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED:
208+ return "hard-blocked";
209+ default:
210+ g_assert_not_reached ();
211+ }
212+}
213+
214+const char *
215+bluetooth_killswitch_state_to_string (BluetoothKillswitchState state)
216+{
217+ g_return_val_if_fail (state >= BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER, NULL);
218+ g_return_val_if_fail (state <= BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED, NULL);
219+
220+ return state_to_string (state);
221+}
222+
223+static void
224+update_killswitch (BluetoothKillswitch *killswitch,
225+ guint index, guint soft, guint hard)
226+{
227+ BluetoothKillswitchPrivate *priv;
228+ gboolean changed;
229+ GList *l;
230+
231+ priv = killswitch->priv;
232+ changed = FALSE;
233+
234+ for (l = priv->killswitches; l != NULL; l = l->next) {
235+ BluetoothIndKillswitch *ind = l->data;
236+
237+ if (ind->index == index) {
238+ BluetoothKillswitchState state = event_to_state (soft, hard);
239+ if (state != ind->state) {
240+ ind->state = state;
241+ changed = TRUE;
242+ }
243+ break;
244+ }
245+ }
246+
247+ if (changed != FALSE) {
248+ g_debug ("updating killswitch status %d to %s",
249+ index, state_to_string (bluetooth_killswitch_get_state (killswitch)));
250+ g_signal_emit (G_OBJECT (killswitch),
251+ signals[STATE_CHANGED],
252+ 0, bluetooth_killswitch_get_state (killswitch));
253+ }
254+}
255+
256+void
257+bluetooth_killswitch_set_state (BluetoothKillswitch *killswitch,
258+ BluetoothKillswitchState state)
259+{
260+ BluetoothKillswitchPrivate *priv;
261+ struct rfkill_event event;
262+ ssize_t len;
263+
264+ g_return_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch));
265+ g_return_if_fail (state != BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED);
266+
267+ priv = killswitch->priv;
268+
269+ memset (&event, 0, sizeof(event));
270+ event.op = RFKILL_OP_CHANGE_ALL;
271+ event.type = RFKILL_TYPE_BLUETOOTH;
272+ if (state == BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED)
273+ event.soft = 1;
274+ else if (state == BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED)
275+ event.soft = 0;
276+ else
277+ g_assert_not_reached ();
278+
279+ len = rfkill_glib_send_event (priv->rfkill, &event);
280+ if (len < 0)
281+ g_warning ("Failed to change RFKILL state: %s",
282+ g_strerror (errno));
283+}
284+
285+BluetoothKillswitchState
286+bluetooth_killswitch_get_state (BluetoothKillswitch *killswitch)
287+{
288+ BluetoothKillswitchPrivate *priv;
289+ int state = BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED;
290+ GList *l;
291+
292+ g_return_val_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch), state);
293+
294+ priv = killswitch->priv;
295+
296+ if (priv->killswitches == NULL)
297+ return BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER;
298+
299+ for (l = priv->killswitches ; l ; l = l->next) {
300+ BluetoothIndKillswitch *ind = l->data;
301+
302+ g_debug ("killswitch %d is %s",
303+ ind->index, state_to_string (ind->state));
304+
305+ if (ind->state == BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) {
306+ state = BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED;
307+ break;
308+ }
309+
310+ if (ind->state == BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED) {
311+ state = BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED;
312+ continue;
313+ }
314+
315+ state = ind->state;
316+ }
317+
318+ g_debug ("killswitches state %s", state_to_string (state));
319+
320+ return state;
321+}
322+
323+gboolean
324+bluetooth_killswitch_has_killswitches (BluetoothKillswitch *killswitch)
325+{
326+ BluetoothKillswitchPrivate *priv = killswitch->priv;
327+
328+ g_return_val_if_fail (BLUETOOTH_IS_KILLSWITCH (killswitch), FALSE);
329+
330+ return (priv->killswitches != NULL);
331+}
332+
333+static void
334+remove_killswitch (BluetoothKillswitch *killswitch,
335+ guint index)
336+{
337+ BluetoothKillswitchPrivate *priv;
338+ GList *l;
339+
340+ priv = killswitch->priv;
341+
342+ for (l = priv->killswitches; l != NULL; l = l->next) {
343+ BluetoothIndKillswitch *ind = l->data;
344+ if (ind->index == index) {
345+ priv->killswitches = g_list_remove (priv->killswitches, ind);
346+ g_debug ("removing killswitch idx %d", index);
347+ g_free (ind);
348+ g_signal_emit (G_OBJECT (killswitch),
349+ signals[STATE_CHANGED],
350+ 0, bluetooth_killswitch_get_state (killswitch));
351+ return;
352+ }
353+ }
354+}
355+
356+static void
357+add_killswitch (BluetoothKillswitch *killswitch,
358+ guint index,
359+ BluetoothKillswitchState state)
360+
361+{
362+ BluetoothKillswitchPrivate *priv;
363+ BluetoothIndKillswitch *ind;
364+
365+ priv = killswitch->priv;
366+
367+ g_debug ("adding killswitch idx %d state %s", index, state_to_string (state));
368+ ind = g_new0 (BluetoothIndKillswitch, 1);
369+ ind->index = index;
370+ ind->state = state;
371+ priv->killswitches = g_list_append (priv->killswitches, ind);
372+}
373+
374+static void
375+killswitch_changed (RfkillGlib *rfkill,
376+ GList *events,
377+ BluetoothKillswitch *killswitch)
378+{
379+ BluetoothKillswitchState state;
380+ gboolean changed;
381+ GList *l;
382+
383+ if (killswitch->priv->in_init) {
384+ for (l = events; l != NULL; l = l->next) {
385+ struct rfkill_event *event = l->data;
386+
387+ if (event->op != RFKILL_OP_ADD)
388+ continue;
389+ if (event->type != RFKILL_TYPE_BLUETOOTH)
390+ continue;
391+
392+ state = event_to_state (event->soft, event->hard);
393+
394+ g_debug ("Read killswitch (idx=%d): %s",
395+ event->idx, bluetooth_killswitch_state_to_string (state));
396+
397+ add_killswitch (killswitch, event->idx, state);
398+ }
399+
400+ g_signal_emit (G_OBJECT (killswitch),
401+ signals[STATE_CHANGED],
402+ 0, bluetooth_killswitch_get_state (killswitch));
403+ return;
404+ }
405+
406+ changed = FALSE;
407+
408+ /* Gather the previous killswitch so we can
409+ * see what really changed */
410+ state = bluetooth_killswitch_get_state (killswitch);
411+
412+ for (l = events; l != NULL; l = l->next) {
413+ struct rfkill_event *event = l->data;
414+
415+ if (event->type != RFKILL_TYPE_BLUETOOTH &&
416+ event->type != RFKILL_TYPE_ALL)
417+ continue;
418+
419+ if (event->op == RFKILL_OP_CHANGE) {
420+ update_killswitch (killswitch, event->idx, event->soft, event->hard);
421+ /* No changed here because update_killswitch
422+ * handles sending the state-changed signal */
423+ } else if (event->op == RFKILL_OP_DEL) {
424+ remove_killswitch (killswitch, event->idx);
425+ changed = TRUE;
426+ } else if (event->op == RFKILL_OP_ADD) {
427+ BluetoothKillswitchState state;
428+ state = event_to_state (event->soft, event->hard);
429+ add_killswitch (killswitch, event->idx, state);
430+ changed = TRUE;
431+ }
432+ }
433+
434+ if (changed) {
435+ BluetoothKillswitchState new_state;
436+
437+ new_state = bluetooth_killswitch_get_state (killswitch);
438+ if (new_state != state) {
439+ g_signal_emit (G_OBJECT (killswitch),
440+ signals[STATE_CHANGED],
441+ 0, bluetooth_killswitch_get_state (killswitch));
442+ }
443+ }
444+}
445+
446+static void
447+bluetooth_killswitch_init (BluetoothKillswitch *killswitch)
448+{
449+ BluetoothKillswitchPrivate *priv;
450+
451+ priv = BLUETOOTH_KILLSWITCH_GET_PRIVATE (killswitch);
452+ killswitch->priv = priv;
453+
454+ priv->rfkill = rfkill_glib_new ();
455+ g_signal_connect (priv->rfkill, "changed",
456+ G_CALLBACK (killswitch_changed), killswitch);
457+
458+ priv->in_init = TRUE;
459+ if (rfkill_glib_open (priv->rfkill) < 0)
460+ return;
461+ priv->in_init = FALSE;
462+}
463+
464+static void
465+bluetooth_killswitch_finalize (GObject *object)
466+{
467+ BluetoothKillswitch *killswitch;
468+
469+ killswitch = BLUETOOTH_KILLSWITCH (object);
470+
471+ g_clear_object (&killswitch->priv->rfkill);
472+
473+ g_list_free_full (killswitch->priv->killswitches, g_free);
474+ killswitch->priv->killswitches = NULL;
475+
476+ G_OBJECT_CLASS(bluetooth_killswitch_parent_class)->finalize(object);
477+}
478+
479+static void
480+bluetooth_killswitch_class_init(BluetoothKillswitchClass *klass)
481+{
482+ GObjectClass *object_class = (GObjectClass *) klass;
483+
484+ g_type_class_add_private(klass, sizeof(BluetoothKillswitchPrivate));
485+ object_class->finalize = bluetooth_killswitch_finalize;
486+
487+ signals[STATE_CHANGED] =
488+ g_signal_new ("state-changed",
489+ G_TYPE_FROM_CLASS (klass),
490+ G_SIGNAL_RUN_LAST,
491+ G_STRUCT_OFFSET (BluetoothKillswitchClass, state_changed),
492+ NULL, NULL,
493+ g_cclosure_marshal_VOID__INT,
494+ G_TYPE_NONE, 1, G_TYPE_INT);
495+
496+}
497+
498+BluetoothKillswitch *
499+bluetooth_killswitch_new (void)
500+{
501+ return BLUETOOTH_KILLSWITCH (g_object_new (BLUETOOTH_TYPE_KILLSWITCH, NULL));
502+}
503
504=== added file 'panels/bluetooth/bluetooth-killswitch.h'
505--- panels/bluetooth/bluetooth-killswitch.h 1970-01-01 00:00:00 +0000
506+++ panels/bluetooth/bluetooth-killswitch.h 2015-08-12 15:47:27 +0000
507@@ -0,0 +1,78 @@
508+/*
509+ *
510+ * BlueZ - Bluetooth protocol stack for Linux
511+ *
512+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
513+ * Copyright (C) 2006-2009 Bastien Nocera <hadess@hadess.net>
514+ *
515+ *
516+ * This program is free software; you can redistribute it and/or modify
517+ * it under the terms of the GNU General Public License as published by
518+ * the Free Software Foundation; either version 2 of the License, or
519+ * (at your option) any later version.
520+ *
521+ * This program is distributed in the hope that it will be useful,
522+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
523+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
524+ * GNU General Public License for more details.
525+ *
526+ * You should have received a copy of the GNU General Public License
527+ * along with this program; if not, write to the Free Software
528+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
529+ *
530+ */
531+
532+#ifndef __BLUETOOTH_KILLSWITCH_H
533+#define __BLUETOOTH_KILLSWITCH_H
534+
535+#include <glib-object.h>
536+
537+G_BEGIN_DECLS
538+
539+typedef enum {
540+ BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER = -1,
541+ BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED = 0,
542+ BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED,
543+ BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED
544+} BluetoothKillswitchState;
545+
546+#define BLUETOOTH_TYPE_KILLSWITCH (bluetooth_killswitch_get_type())
547+#define BLUETOOTH_KILLSWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
548+ BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitch))
549+#define BLUETOOTH_KILLSWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
550+ BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitchClass))
551+#define BLUETOOTH_IS_KILLSWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
552+ BLUETOOTH_TYPE_KILLSWITCH))
553+#define BLUETOOTH_IS_KILLSWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
554+ BLUETOOTH_TYPE_KILLSWITCH))
555+#define BLUETOOTH_GET_KILLSWITCH_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
556+ BLUETOOTH_TYPE_KILLSWITCH, BluetoothKillswitchClass))
557+
558+typedef struct _BluetoothKillswitch BluetoothKillswitch;
559+typedef struct _BluetoothKillswitchClass BluetoothKillswitchClass;
560+typedef struct _BluetoothKillswitchPrivate BluetoothKillswitchPrivate;
561+
562+struct _BluetoothKillswitch {
563+ GObject parent;
564+ BluetoothKillswitchPrivate *priv;
565+};
566+
567+struct _BluetoothKillswitchClass {
568+ GObjectClass parent_class;
569+
570+ void (*state_changed) (BluetoothKillswitch *killswitch, BluetoothKillswitchState state);
571+};
572+
573+GType bluetooth_killswitch_get_type(void);
574+
575+BluetoothKillswitch * bluetooth_killswitch_new (void);
576+
577+gboolean bluetooth_killswitch_has_killswitches (BluetoothKillswitch *killswitch);
578+void bluetooth_killswitch_set_state (BluetoothKillswitch *killswitch,
579+ BluetoothKillswitchState state);
580+BluetoothKillswitchState bluetooth_killswitch_get_state (BluetoothKillswitch *killswitch);
581+const char *bluetooth_killswitch_state_to_string (BluetoothKillswitchState state);
582+
583+G_END_DECLS
584+
585+#endif /* __BLUETOOTH_KILLSWITCH_H */
586
587=== modified file 'panels/bluetooth/cc-bluetooth-panel.c'
588--- panels/bluetooth/cc-bluetooth-panel.c 2015-04-02 04:53:12 +0000
589+++ panels/bluetooth/cc-bluetooth-panel.c 2015-08-12 15:47:27 +0000
590@@ -35,7 +35,6 @@
591 #include <bluetooth-utils.h>
592 #include <bluetooth-killswitch.h>
593 #include <bluetooth-chooser.h>
594-#include <bluetooth-plugin-manager.h>
595
596 CC_PANEL_REGISTER (CcBluetoothPanel, cc_bluetooth_panel)
597
598@@ -102,8 +101,6 @@
599 {
600 CcBluetoothPanel *self;
601
602- bluetooth_plugin_manager_cleanup ();
603-
604 self = CC_BLUETOOTH_PANEL (object);
605 g_cancellable_cancel (self->priv->cancellable);
606 g_clear_object (&self->priv->cancellable);
607@@ -260,37 +257,6 @@
608 }
609
610 static void
611-add_extra_setup_widgets (CcBluetoothPanel *self,
612- const char *bdaddr)
613-{
614- GValue value = { 0 };
615- char **uuids;
616- GList *list, *l;
617- GtkWidget *container;
618-
619- if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
620- "uuids", &value) == FALSE)
621- return;
622-
623- uuids = (char **) g_value_get_boxed (&value);
624- list = bluetooth_plugin_manager_get_widgets (bdaddr, (const char **) uuids);
625- if (list == NULL) {
626- g_value_unset (&value);
627- return;
628- }
629-
630- container = WID ("additional_setup_box");
631- for (l = list; l != NULL; l = l->next) {
632- GtkWidget *widget = l->data;
633- gtk_box_pack_start (GTK_BOX (container), widget,
634- FALSE, FALSE, 0);
635- gtk_widget_show_all (widget);
636- }
637- gtk_widget_show (container);
638- g_value_unset (&value);
639-}
640-
641-static void
642 remove_extra_setup_widgets (CcBluetoothPanel *self)
643 {
644 GtkWidget *box;
645@@ -397,10 +363,6 @@
646 ;
647 }
648
649- /* Extra widgets */
650- if (g_strcmp0 (self->priv->selected_bdaddr, bdaddr) != 0)
651- add_extra_setup_widgets (self, bdaddr);
652-
653 gtk_label_set_text (GTK_LABEL (WID ("address_label")), bdaddr);
654
655 gtk_widget_set_sensitive (WID ("button_delete"), TRUE);
656@@ -544,34 +506,6 @@
657 g_free (alias);
658 }
659
660-static void
661-mount_finish_cb (GObject *source_object,
662- GAsyncResult *res,
663- gpointer user_data)
664-{
665- GError *error = NULL;
666-
667- if (bluetooth_browse_address_finish (source_object, res, &error) == FALSE) {
668- g_printerr ("Failed to mount OBEX volume: %s", error->message);
669- g_error_free (error);
670- return;
671- }
672-}
673-
674-static void
675-browse_callback (GtkButton *button,
676- CcBluetoothPanel *self)
677-{
678- char *bdaddr;
679-
680- bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
681-
682- bluetooth_browse_address (G_OBJECT (self), bdaddr,
683- GDK_CURRENT_TIME, mount_finish_cb, NULL);
684-
685- g_free (bdaddr);
686-}
687-
688 /* Visibility/Discoverable */
689 static void discoverable_changed (BluetoothClient *client,
690 GParamSpec *spec,
691@@ -693,7 +627,7 @@
692 NULL,
693 "org.bluez",
694 adapter,
695- "org.bluez.Adapter",
696+ "org.bluez.Adapter1",
697 NULL,
698 &error);
699 g_free (adapter);
700@@ -736,10 +670,8 @@
701
702 name = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (self->priv->chooser));
703
704- if (show_confirm_dialog (self, name) != FALSE) {
705- if (remove_selected_device (self))
706- bluetooth_plugin_manager_device_deleted (address);
707- }
708+ if (show_confirm_dialog (self, name) != FALSE)
709+ remove_selected_device (self);
710
711 g_free (address);
712 g_free (name);
713@@ -828,7 +760,6 @@
714 self->priv = BLUETOOTH_PANEL_PRIVATE (self);
715 g_resources_register (cc_bluetooth_get_resource ());
716
717- bluetooth_plugin_manager_init ();
718 self->priv->cancellable = g_cancellable_new ();
719 self->priv->killswitch = bluetooth_killswitch_new ();
720 self->priv->client = bluetooth_client_new ();
721@@ -914,8 +845,6 @@
722 G_CALLBACK (keyboard_callback), self);
723 g_signal_connect (G_OBJECT (WID ("sound_link")), "activate-link",
724 G_CALLBACK (sound_callback), self);
725- g_signal_connect (G_OBJECT (WID ("browse_button")), "clicked",
726- G_CALLBACK (browse_callback), self);
727 g_signal_connect (G_OBJECT (WID ("send_button")), "clicked",
728 G_CALLBACK (send_callback), self);
729 g_signal_connect (G_OBJECT (WID ("switch_connection")), "notify::active",
730
731=== added directory 'panels/bluetooth/gnome-bluetooth'
732=== added file 'panels/bluetooth/gnome-bluetooth/Makefile.am'
733--- panels/bluetooth/gnome-bluetooth/Makefile.am 1970-01-01 00:00:00 +0000
734+++ panels/bluetooth/gnome-bluetooth/Makefile.am 2015-08-12 15:47:27 +0000
735@@ -0,0 +1,1 @@
736+SUBDIRS = lib wizard
737
738=== added directory 'panels/bluetooth/gnome-bluetooth/lib'
739=== added file 'panels/bluetooth/gnome-bluetooth/lib/Makefile.am'
740--- panels/bluetooth/gnome-bluetooth/lib/Makefile.am 1970-01-01 00:00:00 +0000
741+++ panels/bluetooth/gnome-bluetooth/lib/Makefile.am 2015-08-12 15:47:27 +0000
742@@ -0,0 +1,99 @@
743+EXTRA_DIST =
744+CLEANFILES =
745+
746+lib_LTLIBRARIES = libgnome-bluetooth.la
747+
748+# will be scanned for introspection annotation, but won't be installed
749+libgnome_bluetooth_c_sources = \
750+ bluetooth-client.c \
751+ bluetooth-utils.c \
752+ bluetooth-agent.c \
753+ gnome-bluetooth-enum-types.c \
754+ bluetooth-chooser.c \
755+ bluetooth-filter-widget.c \
756+ bluetooth-chooser-button.c \
757+ bluetooth-chooser-combo.c \
758+ bluetooth-client-glue.c \
759+ bluetooth-fdo-glue.c
760+
761+libgnome_bluetooth_private_headers = \
762+ bluetooth-client-private.h \
763+ bluetooth-agent.h \
764+ gnome-bluetooth-enum-types.h \
765+ bluetooth-chooser-private.h \
766+ bluetooth-client-glue.h \
767+ bluetooth-fdo-glue.h
768+
769+# public headers don't need to be listed, are handled by _HEADERS
770+libgnome_bluetooth_la_SOURCES = \
771+ $(libgnome_bluetooth_private_headers) \
772+ $(libgnome_bluetooth_c_sources)
773+
774+libgnome_bluetooth_la_LIBADD = $(BLUETOOTH_PANEL_LIBS)
775+
776+libgnome_bluetooth_introspect_headers = \
777+ bluetooth-client.h \
778+ bluetooth-chooser.h \
779+ bluetooth-chooser-button.h \
780+ bluetooth-chooser-combo.h \
781+ bluetooth-filter-widget.h \
782+ bluetooth-enums.h \
783+ bluetooth-utils.h
784+
785+gnomebluetoothdir = $(pkgincludedir)
786+gnomebluetooth_HEADERS = $(libgnome_bluetooth_introspect_headers)
787+
788+AM_CFLAGS = \
789+ -I$(srcdir) \
790+ $(BLUETOOTH_PANEL_CFLAGS) \
791+ $(WARN_CFLAGS) \
792+ $(DISABLE_DEPRECATED) \
793+ -DG_LOG_DOMAIN=\"Bluetooth\"
794+
795+BUILT_SOURCES = bluetooth-client-glue.h \
796+ bluetooth-client-glue.c \
797+ bluetooth-fdo-glue.h \
798+ bluetooth-fdo-glue.c \
799+ gnome-bluetooth-enum-types.h \
800+ gnome-bluetooth-enum-types.c
801+
802+CLEANFILES += $(BUILT_SOURCES)
803+
804+EXTRA_DIST += bluetooth-client.xml bluetooth-fdo.xml
805+
806+MAINTAINERCLEANFILES = Makefile.in
807+
808+bluetooth-client-glue.c: bluetooth-client-glue.h
809+
810+bluetooth-client-glue.c bluetooth-client-glue.h: bluetooth-client.xml
811+ $(AM_V_GEN) gdbus-codegen --c-namespace= --generate-c-code=bluetooth-client-glue --interface-prefix=org.bluez $<
812+
813+bluetooth-fdo-glue.c: bluetooth-fdo-glue.h
814+
815+bluetooth-fdo-glue.c bluetooth-fdo-glue.h: bluetooth-fdo.xml
816+ $(AM_V_GEN) gdbus-codegen --c-namespace= --generate-c-code=bluetooth-fdo-glue --interface-prefix=org.freedesktop.DBus $<
817+
818+gnome_bluetooth_headers_to_scan_for_enums = bluetooth-enums.h
819+# Generate the enums source code, with glib-mkenums:
820+# This is based on the same Makefile.am stuff in pango:
821+gnome_bluetooth_built_headers = gnome-bluetooth-enum-types.h
822+gnome_bluetooth_built_cfiles = gnome-bluetooth-enum-types.c
823+
824+gnome-bluetooth-enum-types.h: $(gnome_bluetooth_headers_to_scan_for_enums) Makefile
825+ $(AM_V_GEN) (cd $(srcdir) && glib-mkenums \
826+ --fhead "#ifndef __GNOME_BLUETOOTH_ENUM_TYPES_H__\n#define __GNOME_BLUETOOTH_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
827+ --fprod "/* enumerations from \"@filename@\" */\n" \
828+ --vhead "GType @enum_name@_get_type (void);\n#define BLUETOOTH_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
829+ --ftail "G_END_DECLS\n\n#endif /* __GNOME_BLUETOOTH_ENUM_TYPES_H__ */" \
830+ $(gnome_bluetooth_headers_to_scan_for_enums)) > $@
831+
832+gnome-bluetooth-enum-types.c: $(gnome_bluetooth_headers_to_scan_for_enums) Makefile gnome-bluetooth-enum-types.h
833+ $(AM_V_GEN) (cd $(srcdir) && glib-mkenums \
834+ --fhead "#include <bluetooth-enums.h>\n" \
835+ --fhead "#include \"gnome-bluetooth-enum-types.h\"\n" \
836+ --fhead "#include <glib-object.h>" \
837+ --fprod "\n/* enumerations from \"@filename@\" */" \
838+ --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \
839+ --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
840+ --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \
841+ $(gnome_bluetooth_headers_to_scan_for_enums)) > $@
842
843=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.c'
844--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.c 1970-01-01 00:00:00 +0000
845+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.c 2015-08-12 15:47:27 +0000
846@@ -0,0 +1,681 @@
847+/*
848+ *
849+ * BlueZ - Bluetooth protocol stack for Linux
850+ *
851+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
852+ *
853+ *
854+ * This library is free software; you can redistribute it and/or
855+ * modify it under the terms of the GNU Lesser General Public
856+ * License as published by the Free Software Foundation; either
857+ * version 2.1 of the License, or (at your option) any later version.
858+ *
859+ * This library is distributed in the hope that it will be useful,
860+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
861+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
862+ * Lesser General Public License for more details.
863+ *
864+ * You should have received a copy of the GNU Lesser General Public
865+ * License along with this library; if not, write to the Free Software
866+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
867+ *
868+ */
869+
870+#ifdef HAVE_CONFIG_H
871+#include <config.h>
872+#endif
873+
874+#include <stdio.h>
875+#include <gio/gio.h>
876+
877+#include "bluetooth-client-glue.h"
878+#include "bluetooth-fdo-glue.h"
879+#include "bluetooth-agent.h"
880+
881+#define BLUEZ_SERVICE "org.bluez"
882+#define BLUEZ_AGENT_PATH "/org/bluez/agent/gnome"
883+#define BLUEZ_MANAGER_PATH "/"
884+
885+static const gchar introspection_xml[] =
886+"<node name='/'>"
887+" <interface name='org.bluez.Agent1'>"
888+" <method name='Release'/>"
889+" <method name='RequestPinCode'>"
890+" <arg type='o' name='device' direction='in'/>"
891+" <arg type='s' name='pincode' direction='out'/>"
892+" </method>"
893+" <method name='RequestPasskey'>"
894+" <arg type='o' name='device' direction='in'/>"
895+" <arg type='u' name='passkey' direction='out'/>"
896+" </method>"
897+" <method name='DisplayPasskey'>"
898+" <arg type='o' name='device' direction='in'/>"
899+" <arg type='u' name='passkey' direction='in'/>"
900+" <arg type='y' name='entered' direction='in'/>"
901+" </method>"
902+" <method name='DisplayPinCode'>"
903+" <arg type='o' name='device' direction='in'/>"
904+" <arg type='s' name='pincode' direction='in'/>"
905+" </method>"
906+" <method name='RequestConfirmation'>"
907+" <arg type='o' name='device' direction='in'/>"
908+" <arg type='u' name='passkey' direction='in'/>"
909+" </method>"
910+" <method name='RequestAuthorization'>"
911+" <arg type='o' name='device' direction='in'/>"
912+" </method>"
913+" <method name='AuthorizeService'>"
914+" <arg type='o' name='device' direction='in'/>"
915+" <arg type='s' name='uuid' direction='in'/>"
916+" </method>"
917+" <method name='Cancel'/>"
918+" </interface>"
919+"</node>";
920+
921+#define BLUETOOTH_AGENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
922+ BLUETOOTH_TYPE_AGENT, BluetoothAgentPrivate))
923+
924+typedef struct _BluetoothAgentPrivate BluetoothAgentPrivate;
925+
926+struct _BluetoothAgentPrivate {
927+ GDBusConnection *conn;
928+ gchar *busname;
929+ gchar *path;
930+ AgentManager1 *agent_manager;
931+ GDBusNodeInfo *introspection_data;
932+ guint reg_id;
933+ guint watch_id;
934+
935+ BluetoothAgentPasskeyFunc pincode_func;
936+ gpointer pincode_data;
937+
938+ BluetoothAgentDisplayFunc display_func;
939+ gpointer display_data;
940+
941+ BluetoothAgentDisplayPinCodeFunc display_pincode_func;
942+ gpointer display_pincode_data;
943+
944+ BluetoothAgentPasskeyFunc passkey_func;
945+ gpointer passkey_data;
946+
947+ BluetoothAgentConfirmFunc confirm_func;
948+ gpointer confirm_data;
949+
950+ BluetoothAgentAuthorizeFunc authorize_func;
951+ gpointer authorize_data;
952+
953+ BluetoothAgentAuthorizeServiceFunc authorize_service_func;
954+ gpointer authorize_service_data;
955+
956+ BluetoothAgentCancelFunc cancel_func;
957+ gpointer cancel_data;
958+};
959+
960+static GDBusProxy *get_device_from_path (const char *path)
961+{
962+ Device1 *device;
963+ device = device1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
964+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
965+ BLUEZ_SERVICE,
966+ path,
967+ NULL,
968+ NULL);
969+
970+ return G_DBUS_PROXY(device);
971+}
972+
973+G_DEFINE_TYPE(BluetoothAgent, bluetooth_agent, G_TYPE_OBJECT)
974+
975+static gboolean bluetooth_agent_request_pincode(BluetoothAgent *agent,
976+ const char *path, GDBusMethodInvocation *invocation)
977+{
978+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
979+ GDBusProxy *device;
980+
981+ if (priv->pincode_func == NULL)
982+ return FALSE;
983+
984+ device = get_device_from_path(path);
985+ if (device == NULL)
986+ return FALSE;
987+
988+ priv->pincode_func(invocation, device, priv->pincode_data);
989+
990+ g_object_unref(device);
991+
992+ return TRUE;
993+}
994+
995+static gboolean bluetooth_agent_request_passkey(BluetoothAgent *agent,
996+ const char *path, GDBusMethodInvocation *invocation)
997+{
998+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
999+ GDBusProxy *device;
1000+
1001+ if (priv->passkey_func == NULL)
1002+ return FALSE;
1003+
1004+ device = get_device_from_path(path);
1005+ if (device == NULL)
1006+ return FALSE;
1007+
1008+ priv->passkey_func(invocation, device, priv->passkey_data);
1009+
1010+ g_object_unref(device);
1011+
1012+ return TRUE;
1013+}
1014+
1015+static gboolean bluetooth_agent_display_passkey(BluetoothAgent *agent,
1016+ const char *path, guint passkey, guint8 entered,
1017+ GDBusMethodInvocation *invocation)
1018+{
1019+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1020+ GDBusProxy *device;
1021+
1022+ if (priv->display_func == NULL)
1023+ return FALSE;
1024+
1025+ device = get_device_from_path(path);
1026+ if (device == NULL)
1027+ return FALSE;
1028+
1029+ priv->display_func(invocation, device, passkey, entered,
1030+ priv->display_data);
1031+
1032+ g_object_unref(device);
1033+
1034+ return TRUE;
1035+}
1036+
1037+static gboolean bluetooth_agent_display_pincode(BluetoothAgent *agent,
1038+ const char *path, const char *pincode,
1039+ GDBusMethodInvocation *invocation)
1040+{
1041+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1042+ GDBusProxy *device;
1043+
1044+ if (priv->display_pincode_func == NULL)
1045+ return FALSE;
1046+
1047+ device = get_device_from_path(path);
1048+ if (device == NULL)
1049+ return FALSE;
1050+
1051+ priv->display_pincode_func(invocation, device, pincode,
1052+ priv->display_data);
1053+
1054+ g_object_unref(device);
1055+
1056+ return TRUE;
1057+}
1058+
1059+static gboolean bluetooth_agent_request_confirmation(BluetoothAgent *agent,
1060+ const char *path, guint passkey,
1061+ GDBusMethodInvocation *invocation)
1062+{
1063+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1064+ GDBusProxy *device;
1065+
1066+ if (priv->confirm_func == NULL)
1067+ return FALSE;
1068+
1069+ device = get_device_from_path(path);
1070+ if (device == NULL)
1071+ return FALSE;
1072+
1073+ priv->confirm_func(invocation, device, passkey, priv->confirm_data);
1074+
1075+ g_object_unref(device);
1076+
1077+ return TRUE;
1078+}
1079+
1080+static gboolean bluetooth_agent_request_authorization(BluetoothAgent *agent,
1081+ const char *path, GDBusMethodInvocation *invocation)
1082+{
1083+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1084+ GDBusProxy *device;
1085+
1086+ if (priv->authorize_func == NULL)
1087+ return FALSE;
1088+
1089+ device = get_device_from_path(path);
1090+ if (device == NULL)
1091+ return FALSE;
1092+
1093+ priv->authorize_func(invocation, device, priv->authorize_data);
1094+
1095+ g_object_unref(device);
1096+
1097+ return TRUE;
1098+}
1099+
1100+static gboolean bluetooth_agent_authorize_service(BluetoothAgent *agent,
1101+ const char *path, const char *uuid,
1102+ GDBusMethodInvocation *invocation)
1103+{
1104+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1105+ GDBusProxy *device;
1106+
1107+ if (priv->authorize_service_func == NULL)
1108+ return FALSE;
1109+
1110+ device = get_device_from_path(path);
1111+ if (device == NULL)
1112+ return FALSE;
1113+
1114+ priv->authorize_service_func(invocation, device, uuid,
1115+ priv->authorize_service_data);
1116+
1117+ g_object_unref(device);
1118+
1119+ return TRUE;
1120+}
1121+
1122+static gboolean bluetooth_agent_cancel(BluetoothAgent *agent,
1123+ GDBusMethodInvocation *invocation)
1124+{
1125+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1126+
1127+ if (priv->cancel_func == NULL)
1128+ return FALSE;
1129+
1130+ return priv->cancel_func(invocation, priv->cancel_data);
1131+}
1132+
1133+static void
1134+name_appeared_cb (GDBusConnection *connection,
1135+ const gchar *name,
1136+ const gchar *name_owner,
1137+ BluetoothAgent *agent)
1138+{
1139+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1140+
1141+ g_free (priv->busname);
1142+ priv->busname = g_strdup (name_owner);
1143+}
1144+
1145+static void
1146+name_vanished_cb (GDBusConnection *connection,
1147+ const gchar *name,
1148+ BluetoothAgent *agent)
1149+{
1150+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1151+
1152+ g_free (priv->busname);
1153+ priv->busname = NULL;
1154+}
1155+
1156+static void bluetooth_agent_init(BluetoothAgent *agent)
1157+{
1158+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1159+
1160+ priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
1161+ g_assert (priv->introspection_data);
1162+ priv->conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
1163+ priv->watch_id = g_bus_watch_name_on_connection (priv->conn,
1164+ BLUEZ_SERVICE,
1165+ G_BUS_NAME_WATCHER_FLAGS_NONE,
1166+ (GBusNameAppearedCallback) name_appeared_cb,
1167+ (GBusNameVanishedCallback) name_vanished_cb,
1168+ agent,
1169+ NULL);
1170+}
1171+
1172+static void bluetooth_agent_finalize(GObject *agent)
1173+{
1174+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1175+
1176+ bluetooth_agent_unregister (BLUETOOTH_AGENT (agent));
1177+
1178+ g_bus_unwatch_name (priv->watch_id);
1179+ g_free (priv->busname);
1180+ g_dbus_node_info_unref (priv->introspection_data);
1181+ g_object_unref (priv->conn);
1182+
1183+ G_OBJECT_CLASS(bluetooth_agent_parent_class)->finalize(agent);
1184+}
1185+
1186+static void bluetooth_agent_class_init(BluetoothAgentClass *klass)
1187+{
1188+ GObjectClass *object_class = (GObjectClass *) klass;
1189+
1190+ g_type_class_add_private(klass, sizeof(BluetoothAgentPrivate));
1191+
1192+ object_class->finalize = bluetooth_agent_finalize;
1193+}
1194+
1195+BluetoothAgent *
1196+bluetooth_agent_new (void)
1197+{
1198+ return BLUETOOTH_AGENT (g_object_new (BLUETOOTH_TYPE_AGENT, NULL));
1199+}
1200+
1201+static void
1202+handle_method_call (GDBusConnection *connection,
1203+ const gchar *sender,
1204+ const gchar *object_path,
1205+ const gchar *interface_name,
1206+ const gchar *method_name,
1207+ GVariant *parameters,
1208+ GDBusMethodInvocation *invocation,
1209+ gpointer user_data)
1210+{
1211+ BluetoothAgent *agent = (BluetoothAgent *) user_data;
1212+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1213+
1214+ if (g_str_equal (sender, priv->busname) == FALSE) {
1215+ GError *error = NULL;
1216+ error = g_error_new (AGENT_ERROR, AGENT_ERROR_REJECT,
1217+ "Permission Denied");
1218+ g_dbus_method_invocation_take_error(invocation, error);
1219+ return;
1220+ }
1221+
1222+ if (g_strcmp0 (method_name, "Release") == 0) {
1223+ g_dbus_method_invocation_return_value (invocation, NULL);
1224+ } else if (g_strcmp0 (method_name, "RequestPinCode") == 0) {
1225+ char *path;
1226+ g_variant_get (parameters, "(o)", &path);
1227+ bluetooth_agent_request_pincode (agent, path, invocation);
1228+ g_free (path);
1229+ } else if (g_strcmp0 (method_name, "RequestPasskey") == 0) {
1230+ char *path;
1231+ g_variant_get (parameters, "(o)", &path);
1232+ bluetooth_agent_request_passkey (agent, path, invocation);
1233+ g_free (path);
1234+ } else if (g_strcmp0 (method_name, "DisplayPasskey") == 0) {
1235+ char *path;
1236+ guint32 passkey;
1237+ guint8 entered;
1238+
1239+ g_variant_get (parameters, "(ouy)", &path, &passkey, &entered);
1240+ bluetooth_agent_display_passkey (agent, path, passkey, entered, invocation);
1241+ g_free (path);
1242+ } else if (g_strcmp0 (method_name, "DisplayPinCode") == 0) {
1243+ char *path;
1244+ char *pincode;
1245+
1246+ g_variant_get (parameters, "(os)", &path, &pincode);
1247+ bluetooth_agent_display_pincode (agent, path, pincode, invocation);
1248+ g_free (path);
1249+ } else if (g_strcmp0 (method_name, "RequestConfirmation") == 0) {
1250+ char *path;
1251+ guint32 passkey;
1252+
1253+ g_variant_get (parameters, "(ou)", &path, &passkey);
1254+ bluetooth_agent_request_confirmation (agent, path, passkey, invocation);
1255+ g_free (path);
1256+ } else if (g_strcmp0 (method_name, "RequestAuthorization") == 0) {
1257+ char *path;
1258+
1259+ g_variant_get (parameters, "(o)", &path);
1260+ bluetooth_agent_request_authorization (agent, path, invocation);
1261+ g_free (path);
1262+ } else if (g_strcmp0 (method_name, "AuthorizeService") == 0) {
1263+ char *path, *uuid;
1264+ g_variant_get (parameters, "(os)", &path, &uuid);
1265+ bluetooth_agent_authorize_service (agent, path, uuid, invocation);
1266+ g_free (path);
1267+ g_free (uuid);
1268+ } else if (g_strcmp0 (method_name, "Cancel") == 0) {
1269+ bluetooth_agent_cancel (agent, invocation);
1270+ }
1271+}
1272+
1273+static const GDBusInterfaceVTable interface_vtable =
1274+{
1275+ handle_method_call,
1276+ NULL, /* GetProperty */
1277+ NULL, /* SetProperty */
1278+};
1279+
1280+gboolean bluetooth_agent_setup(BluetoothAgent *agent, const char *path)
1281+{
1282+ BluetoothAgentPrivate *priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1283+ GError *error = NULL;
1284+
1285+ if (priv->path != NULL) {
1286+ g_warning ("Agent already setup on '%s'", priv->path);
1287+ return FALSE;
1288+ }
1289+
1290+ priv->path = g_strdup(path);
1291+
1292+ priv->reg_id = g_dbus_connection_register_object (priv->conn,
1293+ priv->path,
1294+ priv->introspection_data->interfaces[0],
1295+ &interface_vtable,
1296+ agent,
1297+ NULL,
1298+ &error);
1299+ if (priv->reg_id == 0) {
1300+ g_warning ("Failed to register object: %s", error->message);
1301+ g_error_free (error);
1302+ }
1303+
1304+ return TRUE;
1305+}
1306+
1307+gboolean bluetooth_agent_register(BluetoothAgent *agent)
1308+{
1309+ BluetoothAgentPrivate *priv;
1310+ GError *error = NULL;
1311+ gboolean ret;
1312+
1313+ g_return_val_if_fail (BLUETOOTH_IS_AGENT (agent), FALSE);
1314+
1315+ priv = BLUETOOTH_AGENT_GET_PRIVATE (agent);
1316+
1317+ priv->agent_manager = agent_manager1_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
1318+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1319+ BLUEZ_SERVICE, "/org/bluez", NULL, NULL);
1320+
1321+ priv->reg_id = g_dbus_connection_register_object (priv->conn,
1322+ BLUEZ_AGENT_PATH,
1323+ priv->introspection_data->interfaces[0],
1324+ &interface_vtable,
1325+ agent,
1326+ NULL,
1327+ &error);
1328+ if (priv->reg_id == 0) {
1329+ g_warning ("Failed to register object: %s", error->message);
1330+ g_error_free (error);
1331+ error = NULL;
1332+ return FALSE;
1333+ }
1334+
1335+ ret = agent_manager1_call_register_agent_sync (priv->agent_manager,
1336+ BLUEZ_AGENT_PATH,
1337+ "DisplayYesNo",
1338+ NULL, &error);
1339+ if (ret == FALSE) {
1340+ g_printerr ("Agent registration failed: %s\n", error->message);
1341+ g_error_free (error);
1342+ return FALSE;
1343+ }
1344+
1345+ ret = agent_manager1_call_request_default_agent_sync (priv->agent_manager,
1346+ BLUEZ_AGENT_PATH,
1347+ NULL, &error);
1348+ if (ret == FALSE) {
1349+ g_printerr ("Agent registration failed: %s\n", error->message);
1350+ g_error_free (error);
1351+ return FALSE;
1352+ }
1353+
1354+ return TRUE;
1355+}
1356+
1357+gboolean bluetooth_agent_unregister(BluetoothAgent *agent)
1358+{
1359+ BluetoothAgentPrivate *priv;
1360+ GError *error = NULL;
1361+
1362+ g_return_val_if_fail (BLUETOOTH_IS_AGENT (agent), FALSE);
1363+
1364+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1365+
1366+ if (priv->agent_manager == NULL)
1367+ return FALSE;
1368+
1369+ if (agent_manager1_call_unregister_agent_sync (priv->agent_manager,
1370+ BLUEZ_AGENT_PATH,
1371+ NULL, &error) == FALSE) {
1372+ /* Ignore errors if the adapter is gone */
1373+ if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD) == FALSE) {
1374+ g_printerr ("Agent unregistration failed: %s '%s'\n",
1375+ error->message,
1376+ g_quark_to_string (error->domain));
1377+ }
1378+ g_error_free(error);
1379+ }
1380+
1381+ g_object_unref(priv->agent_manager);
1382+ priv->agent_manager = NULL;
1383+
1384+ g_free(priv->path);
1385+ priv->path = NULL;
1386+
1387+ g_free(priv->busname);
1388+ priv->busname = NULL;
1389+
1390+ if (priv->reg_id > 0) {
1391+ g_dbus_connection_unregister_object (priv->conn, priv->reg_id);
1392+ priv->reg_id = 0;
1393+ }
1394+
1395+ return TRUE;
1396+}
1397+
1398+void bluetooth_agent_set_pincode_func(BluetoothAgent *agent,
1399+ BluetoothAgentPasskeyFunc func, gpointer data)
1400+{
1401+ BluetoothAgentPrivate *priv;
1402+
1403+ g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
1404+
1405+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1406+
1407+ priv->pincode_func = func;
1408+ priv->pincode_data = data;
1409+}
1410+
1411+void bluetooth_agent_set_passkey_func(BluetoothAgent *agent,
1412+ BluetoothAgentPasskeyFunc func, gpointer data)
1413+{
1414+ BluetoothAgentPrivate *priv;
1415+
1416+ g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
1417+
1418+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1419+
1420+ priv->passkey_func = func;
1421+ priv->passkey_data = data;
1422+}
1423+
1424+void bluetooth_agent_set_display_func(BluetoothAgent *agent,
1425+ BluetoothAgentDisplayFunc func, gpointer data)
1426+{
1427+ BluetoothAgentPrivate *priv;
1428+
1429+ g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
1430+
1431+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1432+
1433+ priv->display_func = func;
1434+ priv->display_data = data;
1435+}
1436+
1437+void bluetooth_agent_set_display_pincode_func(BluetoothAgent *agent,
1438+ BluetoothAgentDisplayPinCodeFunc func, gpointer data)
1439+{
1440+ BluetoothAgentPrivate *priv;
1441+
1442+ g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
1443+
1444+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1445+
1446+ priv->display_pincode_func = func;
1447+ priv->display_pincode_data = data;
1448+}
1449+
1450+void bluetooth_agent_set_confirm_func(BluetoothAgent *agent,
1451+ BluetoothAgentConfirmFunc func, gpointer data)
1452+{
1453+ BluetoothAgentPrivate *priv;
1454+
1455+ g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
1456+
1457+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1458+
1459+ priv->confirm_func = func;
1460+ priv->confirm_data = data;
1461+}
1462+
1463+void bluetooth_agent_set_authorize_func(BluetoothAgent *agent,
1464+ BluetoothAgentAuthorizeFunc func, gpointer data)
1465+{
1466+ BluetoothAgentPrivate *priv;
1467+
1468+ g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
1469+
1470+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1471+
1472+ priv->authorize_func = func;
1473+ priv->authorize_data = data;
1474+}
1475+
1476+void bluetooth_agent_set_authorize_service_func(BluetoothAgent *agent,
1477+ BluetoothAgentAuthorizeServiceFunc func, gpointer data)
1478+{
1479+ BluetoothAgentPrivate *priv;
1480+
1481+ g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
1482+
1483+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1484+
1485+ priv->authorize_service_func = func;
1486+ priv->authorize_service_data = data;
1487+}
1488+
1489+void bluetooth_agent_set_cancel_func(BluetoothAgent *agent,
1490+ BluetoothAgentCancelFunc func, gpointer data)
1491+{
1492+ BluetoothAgentPrivate *priv;
1493+
1494+ g_return_if_fail (BLUETOOTH_IS_AGENT (agent));
1495+
1496+ priv = BLUETOOTH_AGENT_GET_PRIVATE(agent);
1497+
1498+ priv->cancel_func = func;
1499+ priv->cancel_data = data;
1500+}
1501+
1502+GQuark bluetooth_agent_error_quark(void)
1503+{
1504+ static GQuark quark = 0;
1505+ if (!quark)
1506+ quark = g_quark_from_static_string("agent");
1507+
1508+ return quark;
1509+}
1510+
1511+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
1512+
1513+GType bluetooth_agent_error_get_type(void)
1514+{
1515+ static GType etype = 0;
1516+ if (etype == 0) {
1517+ static const GEnumValue values[] = {
1518+ ENUM_ENTRY(AGENT_ERROR_REJECT, "Rejected"),
1519+ { 0, 0, 0 }
1520+ };
1521+
1522+ etype = g_enum_register_static("agent", values);
1523+ }
1524+
1525+ return etype;
1526+}
1527+
1528
1529=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.h'
1530--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.h 1970-01-01 00:00:00 +0000
1531+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-agent.h 2015-08-12 15:47:27 +0000
1532@@ -0,0 +1,127 @@
1533+/*
1534+ *
1535+ * BlueZ - Bluetooth protocol stack for Linux
1536+ *
1537+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
1538+ *
1539+ *
1540+ * This library is free software; you can redistribute it and/or
1541+ * modify it under the terms of the GNU Lesser General Public
1542+ * License as published by the Free Software Foundation; either
1543+ * version 2.1 of the License, or (at your option) any later version.
1544+ *
1545+ * This library is distributed in the hope that it will be useful,
1546+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1547+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1548+ * Lesser General Public License for more details.
1549+ *
1550+ * You should have received a copy of the GNU Lesser General Public
1551+ * License along with this library; if not, write to the Free Software
1552+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1553+ *
1554+ */
1555+
1556+#ifndef __BLUETOOTH_AGENT_H
1557+#define __BLUETOOTH_AGENT_H
1558+
1559+#include <glib-object.h>
1560+#include <gio/gio.h>
1561+
1562+G_BEGIN_DECLS
1563+
1564+#define BLUETOOTH_TYPE_AGENT (bluetooth_agent_get_type())
1565+#define BLUETOOTH_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
1566+ BLUETOOTH_TYPE_AGENT, BluetoothAgent))
1567+#define BLUETOOTH_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
1568+ BLUETOOTH_TYPE_AGENT, BluetoothAgentClass))
1569+#define BLUETOOTH_IS_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
1570+ BLUETOOTH_TYPE_AGENT))
1571+#define BLUETOOTH_IS_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
1572+ BLUETOOTH_TYPE_AGENT))
1573+#define BLUETOOTH_GET_AGENT_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
1574+ BLUETOOTH_TYPE_AGENT, BluetoothAgentClass))
1575+
1576+typedef struct _BluetoothAgent BluetoothAgent;
1577+typedef struct _BluetoothAgentClass BluetoothAgentClass;
1578+
1579+struct _BluetoothAgent {
1580+ GObject parent;
1581+};
1582+
1583+struct _BluetoothAgentClass {
1584+ GObjectClass parent_class;
1585+};
1586+
1587+GType bluetooth_agent_get_type(void);
1588+
1589+BluetoothAgent *bluetooth_agent_new(void);
1590+
1591+gboolean bluetooth_agent_setup(BluetoothAgent *agent, const char *path);
1592+
1593+gboolean bluetooth_agent_register(BluetoothAgent *agent);
1594+gboolean bluetooth_agent_unregister(BluetoothAgent *agent);
1595+
1596+typedef void (*BluetoothAgentPasskeyFunc) (GDBusMethodInvocation *invocation,
1597+ GDBusProxy *device,
1598+ gpointer data);
1599+typedef void (*BluetoothAgentDisplayFunc) (GDBusMethodInvocation *invocation,
1600+ GDBusProxy *device,
1601+ guint passkey,
1602+ guint entered,
1603+ gpointer data);
1604+typedef void (*BluetoothAgentDisplayPinCodeFunc) (GDBusMethodInvocation *invocation,
1605+ GDBusProxy *device,
1606+ const char *pincode,
1607+ gpointer data);
1608+typedef void (*BluetoothAgentConfirmFunc) (GDBusMethodInvocation *invocation,
1609+ GDBusProxy *device,
1610+ guint passkey,
1611+ gpointer data);
1612+typedef void (*BluetoothAgentAuthorizeFunc) (GDBusMethodInvocation *invocation,
1613+ GDBusProxy *device,
1614+ gpointer data);
1615+typedef void (*BluetoothAgentAuthorizeServiceFunc) (GDBusMethodInvocation *invocation,
1616+ GDBusProxy *device,
1617+ const char *uuid,
1618+ gpointer data);
1619+typedef gboolean (*BluetoothAgentCancelFunc) (GDBusMethodInvocation *invocation,
1620+ gpointer data);
1621+
1622+void bluetooth_agent_set_pincode_func (BluetoothAgent *agent,
1623+ BluetoothAgentPasskeyFunc func,
1624+ gpointer data);
1625+void bluetooth_agent_set_passkey_func (BluetoothAgent *agent,
1626+ BluetoothAgentPasskeyFunc func,
1627+ gpointer data);
1628+void bluetooth_agent_set_display_func (BluetoothAgent *agent,
1629+ BluetoothAgentDisplayFunc func,
1630+ gpointer data);
1631+void bluetooth_agent_set_display_pincode_func (BluetoothAgent *agent,
1632+ BluetoothAgentDisplayPinCodeFunc func,
1633+ gpointer data);
1634+void bluetooth_agent_set_confirm_func (BluetoothAgent *agent,
1635+ BluetoothAgentConfirmFunc func,
1636+ gpointer data);
1637+void bluetooth_agent_set_authorize_func (BluetoothAgent *agent,
1638+ BluetoothAgentAuthorizeFunc func,
1639+ gpointer data);
1640+void bluetooth_agent_set_authorize_service_func (BluetoothAgent *agent,
1641+ BluetoothAgentAuthorizeServiceFunc func,
1642+ gpointer data);
1643+void bluetooth_agent_set_cancel_func (BluetoothAgent *agent,
1644+ BluetoothAgentCancelFunc func,
1645+ gpointer data);
1646+
1647+#define AGENT_ERROR (bluetooth_agent_error_quark())
1648+#define AGENT_ERROR_TYPE (bluetooth_agent_error_get_type())
1649+
1650+typedef enum {
1651+ AGENT_ERROR_REJECT
1652+} AgentError;
1653+
1654+GType bluetooth_agent_error_get_type (void);
1655+GQuark bluetooth_agent_error_quark (void);
1656+
1657+G_END_DECLS
1658+
1659+#endif /* __BLUETOOTH_AGENT_H */
1660
1661=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.c'
1662--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.c 1970-01-01 00:00:00 +0000
1663+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.c 2015-08-12 15:47:27 +0000
1664@@ -0,0 +1,419 @@
1665+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
1666+/*
1667+ * (C) Copyright 2007-2009 Bastien Nocera <hadess@hadess.net>
1668+ *
1669+ * This library is free software; you can redistribute it and/or
1670+ * modify it under the terms of the GNU Library General Public
1671+ * License as published by the Free Software Foundation; either
1672+ * version 2 of the License, or (at your option) any later version.
1673+ *
1674+ * This library is distributed in the hope that it will be useful,
1675+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1676+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1677+ * Library General Public License for more details.
1678+ *
1679+ * You should have received a copy of the GNU Library General Public
1680+ * License along with this library; if not, write to the
1681+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1682+ * Boston, MA 02111-1307, USA.
1683+ */
1684+
1685+/**
1686+ * SECTION:bluetooth-chooser-button
1687+ * @short_description: a Bluetooth chooser button
1688+ * @stability: Stable
1689+ * @include: bluetooth-chooser-button.h
1690+ *
1691+ * A button used to select Bluetooth devices which will pop-up a
1692+ * #BluetoothChooser widget inside a dialogue when clicked.
1693+ **/
1694+
1695+#ifdef HAVE_CONFIG_H
1696+#include "config.h"
1697+#endif
1698+
1699+#include <glib/gi18n.h>
1700+#include <gtk/gtk.h>
1701+
1702+#include "bluetooth-chooser-button.h"
1703+#include "bluetooth-client.h"
1704+#include "bluetooth-chooser.h"
1705+#include "bluetooth-utils.h"
1706+
1707+struct _BluetoothChooserButton {
1708+ GtkButton parent;
1709+
1710+ BluetoothClient *client;
1711+ GtkWidget *image;
1712+ GtkWidget *dialog;
1713+ GtkWidget *chooser;
1714+ char *bdaddr;
1715+ guint is_available : 1;
1716+ guint has_selection : 1;
1717+};
1718+
1719+enum {
1720+ PROP_0,
1721+ PROP_DEVICE,
1722+ PROP_IS_AVAILABLE,
1723+};
1724+
1725+enum {
1726+ CHOOSER_CREATED,
1727+ LAST_SIGNAL
1728+};
1729+
1730+static int signals[LAST_SIGNAL] = { 0 };
1731+
1732+static void bluetooth_chooser_button_class_init (BluetoothChooserButtonClass * klass);
1733+static void bluetooth_chooser_button_init (BluetoothChooserButton * button);
1734+
1735+static GtkButtonClass *parent_class;
1736+
1737+G_DEFINE_TYPE(BluetoothChooserButton, bluetooth_chooser_button, GTK_TYPE_BUTTON);
1738+
1739+#define DEFAULT_STR N_("Click to select device...")
1740+
1741+static void
1742+set_btdevname (BluetoothChooserButton *button, const char *bdaddr, const char *name, const char *icon)
1743+{
1744+ char *found_name, *found_icon;
1745+
1746+ found_name = NULL;
1747+ found_icon = NULL;
1748+
1749+ if (bdaddr != NULL && (name == NULL || icon == NULL)) {
1750+ GtkTreeModel *model;
1751+ GtkTreeIter iter;
1752+ gboolean cont = FALSE;
1753+
1754+ model = bluetooth_client_get_device_model (button->client);
1755+ if (model != NULL) {
1756+ cont = gtk_tree_model_iter_children (GTK_TREE_MODEL(model),
1757+ &iter, NULL);
1758+ }
1759+
1760+ while (cont == TRUE) {
1761+ char *value;
1762+
1763+ gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1764+ BLUETOOTH_COLUMN_ADDRESS, &value, -1);
1765+ if (g_ascii_strcasecmp(bdaddr, value) == 0) {
1766+ gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
1767+ BLUETOOTH_COLUMN_ALIAS, &found_name,
1768+ BLUETOOTH_COLUMN_ICON, &found_icon,
1769+ -1);
1770+ g_free (value);
1771+ break;
1772+ }
1773+ g_free (value);
1774+ cont = gtk_tree_model_iter_next (GTK_TREE_MODEL(model), &iter);
1775+ }
1776+
1777+ if (model != NULL)
1778+ g_object_unref (model);
1779+
1780+ if (found_name == NULL) {
1781+ found_name = g_strdup (bdaddr);
1782+ g_strdelimit (found_name, ":", '-');
1783+ }
1784+ if (found_icon == NULL)
1785+ found_icon = g_strdup ("bluetooth");
1786+ }
1787+
1788+ if (bdaddr != NULL) {
1789+ /* Update the name */
1790+ if (name == NULL)
1791+ gtk_button_set_label (GTK_BUTTON (button), found_name);
1792+ else
1793+ gtk_button_set_label (GTK_BUTTON (button), name);
1794+ /* And the icon */
1795+ if (icon == NULL)
1796+ gtk_image_set_from_icon_name (GTK_IMAGE (button->image), found_icon, GTK_ICON_SIZE_MENU);
1797+ else
1798+ gtk_image_set_from_icon_name (GTK_IMAGE (button->image), icon, GTK_ICON_SIZE_MENU);
1799+
1800+ /* And our copy of the address, and notify if it's actually changed */
1801+ if (button->bdaddr == NULL || strcmp (bdaddr, button->bdaddr) != 0) {
1802+ g_free (button->bdaddr);
1803+ button->bdaddr = g_strdup (bdaddr);
1804+ g_object_notify (G_OBJECT (button), "device");
1805+ }
1806+ } else {
1807+ gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR));
1808+ if (button->bdaddr != NULL) {
1809+ g_free (button->bdaddr);
1810+ button->bdaddr = NULL;
1811+ gtk_image_clear (GTK_IMAGE (button->image));
1812+ g_object_notify (G_OBJECT (button), "device");
1813+ }
1814+ }
1815+
1816+ g_free (found_name);
1817+ g_free (found_icon);
1818+}
1819+
1820+static void select_device_changed(BluetoothChooser *self, gchar *address, gpointer data)
1821+{
1822+ BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
1823+
1824+ button->has_selection = (address != NULL);
1825+ gtk_dialog_set_response_sensitive(GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT,
1826+ button->has_selection && button->is_available);
1827+}
1828+
1829+static void
1830+dialog_response_cb (GtkDialog *dialog, int response_id, gpointer data)
1831+{
1832+ BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
1833+ char *bdaddr, *icon, *name;
1834+
1835+ if (response_id == GTK_RESPONSE_ACCEPT) {
1836+ BluetoothChooser *chooser = BLUETOOTH_CHOOSER (button->chooser);
1837+ bdaddr = bluetooth_chooser_get_selected_device (chooser);
1838+ name = bluetooth_chooser_get_selected_device_name (chooser);
1839+ icon = bluetooth_chooser_get_selected_device_icon (chooser);
1840+ }
1841+
1842+ gtk_widget_destroy (GTK_WIDGET (dialog));
1843+ button->dialog = NULL;
1844+
1845+ if (response_id != GTK_RESPONSE_ACCEPT)
1846+ return;
1847+
1848+ set_btdevname (button, bdaddr, name, icon);
1849+ g_free (bdaddr);
1850+ g_free (name);
1851+ g_free (icon);
1852+}
1853+
1854+static void
1855+bluetooth_chooser_button_clicked (GtkButton *widget)
1856+{
1857+ BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (widget);
1858+ GtkWidget *parent;
1859+
1860+ if (button->dialog != NULL) {
1861+ gtk_window_present (GTK_WINDOW (button->dialog));
1862+ return;
1863+ }
1864+
1865+ parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
1866+ //FIXME title
1867+ button->dialog = gtk_dialog_new_with_buttons("", GTK_WINDOW (parent),
1868+ GTK_DIALOG_MODAL,
1869+ "_Cancel", GTK_RESPONSE_REJECT,
1870+ "_OK", GTK_RESPONSE_ACCEPT, NULL);
1871+ g_signal_connect (button->dialog, "response",
1872+ G_CALLBACK (dialog_response_cb), button);
1873+ gtk_dialog_set_response_sensitive (GTK_DIALOG(button->dialog),
1874+ GTK_RESPONSE_ACCEPT, FALSE);
1875+ gtk_window_set_default_size (GTK_WINDOW(button->dialog), 480, 400);
1876+
1877+ gtk_container_set_border_width (GTK_CONTAINER (button->dialog), 5);
1878+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (button->dialog))), 2);
1879+
1880+ /* Create the button->chooser */
1881+ button->chooser = bluetooth_chooser_new ();
1882+ g_signal_connect(button->chooser, "selected-device-changed",
1883+ G_CALLBACK(select_device_changed), button);
1884+ g_signal_emit (G_OBJECT (button),
1885+ signals[CHOOSER_CREATED],
1886+ 0, button->chooser);
1887+ g_object_set (G_OBJECT (button->chooser), "device-selected", button->bdaddr, NULL);
1888+ gtk_container_set_border_width (GTK_CONTAINER(button->chooser), 5);
1889+ gtk_widget_show (button->chooser);
1890+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (button->dialog))), button->chooser,
1891+ TRUE, TRUE, 0);
1892+
1893+ gtk_widget_show (button->dialog);
1894+}
1895+
1896+static void
1897+default_adapter_changed (GObject *object, GParamSpec *pspec, gpointer data)
1898+{
1899+ BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
1900+ char *adapter;
1901+ gboolean powered;
1902+
1903+ g_object_get (G_OBJECT (button->client),
1904+ "default-adapter", &adapter,
1905+ "default-adapter-powered", &powered,
1906+ NULL);
1907+ if (adapter != NULL)
1908+ button->is_available = powered;
1909+ else
1910+ button->is_available = FALSE;
1911+
1912+ if (adapter != NULL && button->bdaddr != NULL)
1913+ set_btdevname (button, button->bdaddr, NULL, NULL);
1914+ g_free (adapter);
1915+
1916+ if (button->dialog != NULL)
1917+ gtk_dialog_set_response_sensitive (GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT,
1918+ button->has_selection && button->is_available);
1919+
1920+ g_object_notify (G_OBJECT (button), "is-available");
1921+}
1922+
1923+static void
1924+bluetooth_chooser_button_finalize (GObject *object)
1925+{
1926+ BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (object);
1927+
1928+ if (button->client != NULL) {
1929+ g_object_unref (button->client);
1930+ button->client = NULL;
1931+ }
1932+ if (button->dialog != NULL) {
1933+ gtk_widget_destroy (button->dialog);
1934+ button->dialog = NULL;
1935+ button->chooser = NULL;
1936+ }
1937+
1938+ G_OBJECT_CLASS (parent_class)->finalize (object);
1939+}
1940+
1941+static void
1942+bluetooth_chooser_button_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
1943+{
1944+ BluetoothChooserButton *button;
1945+
1946+ g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object));
1947+ button = BLUETOOTH_CHOOSER_BUTTON (object);
1948+
1949+ switch (property_id) {
1950+ case PROP_DEVICE: {
1951+ const char *str = g_value_get_string (value);
1952+ g_return_if_fail (str == NULL || bluetooth_verify_address (str));
1953+ set_btdevname (button, str, NULL, NULL);
1954+ break;
1955+ }
1956+ default:
1957+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1958+ }
1959+}
1960+
1961+static void
1962+bluetooth_chooser_button_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
1963+{
1964+ BluetoothChooserButton *button;
1965+
1966+ g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object));
1967+ button = BLUETOOTH_CHOOSER_BUTTON (object);
1968+
1969+ switch (property_id) {
1970+ case PROP_DEVICE:
1971+ g_value_set_string (value, button->bdaddr);
1972+ break;
1973+ case PROP_IS_AVAILABLE:
1974+ g_value_set_boolean (value, button->is_available);
1975+ break;
1976+ default:
1977+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1978+ }
1979+}
1980+
1981+static void
1982+bluetooth_chooser_button_class_init (BluetoothChooserButtonClass *klass)
1983+{
1984+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
1985+ GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
1986+
1987+ parent_class = g_type_class_peek_parent (klass);
1988+
1989+ object_class->finalize = bluetooth_chooser_button_finalize;
1990+ object_class->set_property = bluetooth_chooser_button_set_property;
1991+ object_class->get_property = bluetooth_chooser_button_get_property;
1992+
1993+ button_class->clicked = bluetooth_chooser_button_clicked;
1994+
1995+ /**
1996+ * BluetoothChooserButton::chooser-created:
1997+ * @self: a #BluetoothChooserButton widget
1998+ * @chooser: a #BluetoothChooser widget
1999+ *
2000+ * The signal is sent when a popup dialogue is created for the user to select
2001+ * a device. This signal allows you to change the configuration and filtering
2002+ * of the tree from its defaults.
2003+ **/
2004+ signals[CHOOSER_CREATED] =
2005+ g_signal_new ("chooser-created",
2006+ G_TYPE_FROM_CLASS (klass),
2007+ G_SIGNAL_RUN_LAST,
2008+ G_STRUCT_OFFSET (BluetoothChooserButtonClass, chooser_created),
2009+ NULL, NULL,
2010+ g_cclosure_marshal_VOID__OBJECT,
2011+ G_TYPE_NONE, 1, G_TYPE_OBJECT);
2012+
2013+ /**
2014+ * BluetoothChooserButton:device:
2015+ *
2016+ * The Bluetooth address of the selected device or %NULL.
2017+ **/
2018+ g_object_class_install_property (object_class, PROP_DEVICE,
2019+ g_param_spec_string ("device", "Device", "The Bluetooth address of the selected device.",
2020+ NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
2021+ /**
2022+ * BluetoothChooserButton:is-available:
2023+ *
2024+ * %TRUE if there is a powered Bluetooth adapter available.
2025+ *
2026+ * See also: bluetooth_chooser_button_available()
2027+ **/
2028+ g_object_class_install_property (object_class, PROP_IS_AVAILABLE,
2029+ g_param_spec_boolean ("is-available", "Bluetooth is available", "Whether Bluetooth is available.",
2030+ TRUE, G_PARAM_READABLE));
2031+}
2032+
2033+static void
2034+bluetooth_chooser_button_init (BluetoothChooserButton *button)
2035+{
2036+ gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR));
2037+
2038+ button->image = gtk_image_new ();
2039+ gtk_button_set_image (GTK_BUTTON (button), button->image);
2040+
2041+ button->bdaddr = NULL;
2042+ button->dialog = NULL;
2043+
2044+ button->client = bluetooth_client_new ();
2045+ g_signal_connect (G_OBJECT (button->client), "notify::default-adapter",
2046+ G_CALLBACK (default_adapter_changed), button);
2047+ g_signal_connect (G_OBJECT (button->client), "notify::default-adapter-powered",
2048+ G_CALLBACK (default_adapter_changed), button);
2049+
2050+ /* And set the default value already */
2051+ default_adapter_changed (NULL, NULL, button);
2052+}
2053+
2054+/**
2055+ * bluetooth_chooser_button_new:
2056+ *
2057+ * Returns a new #BluetoothChooserButton widget.
2058+ *
2059+ * Return value: a #BluetoothChooserButton widget.
2060+ **/
2061+GtkWidget *
2062+bluetooth_chooser_button_new (void)
2063+{
2064+ return g_object_new (BLUETOOTH_TYPE_CHOOSER_BUTTON,
2065+ NULL);
2066+}
2067+
2068+/**
2069+ * bluetooth_chooser_button_available:
2070+ * @button: a #BluetoothChooserButton
2071+ *
2072+ * Returns whether there is a powered Bluetooth adapter.
2073+ *
2074+ * Return value: %TRUE if there is a powered Bluetooth adapter available, and the button should be sensitive.
2075+ **/
2076+gboolean
2077+bluetooth_chooser_button_available (BluetoothChooserButton *button)
2078+{
2079+ g_return_val_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (button), FALSE);
2080+
2081+ return button->is_available;
2082+}
2083+
2084
2085=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.h'
2086--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.h 1970-01-01 00:00:00 +0000
2087+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-button.h 2015-08-12 15:47:27 +0000
2088@@ -0,0 +1,55 @@
2089+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2090+/*
2091+ * (C) Copyright 2007 Bastien Nocera <hadess@hadess.net>
2092+ *
2093+ * This library is free software; you can redistribute it and/or
2094+ * modify it under the terms of the GNU Library General Public
2095+ * License as published by the Free Software Foundation; either
2096+ * version 2 of the License, or (at your option) any later version.
2097+ *
2098+ * This library is distributed in the hope that it will be useful,
2099+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2100+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2101+ * Library General Public License for more details.
2102+ *
2103+ * You should have received a copy of the GNU Library General Public
2104+ * License along with this library; if not, write to the
2105+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2106+ * Boston, MA 02111-1307, USA.
2107+ */
2108+
2109+#ifndef __BLUETOOTH_CHOOSER_BUTTON_H__
2110+#define __BLUETOOTH_CHOOSER_BUTTON_H__
2111+
2112+#include <gtk/gtk.h>
2113+
2114+G_BEGIN_DECLS
2115+
2116+#define BLUETOOTH_TYPE_CHOOSER_BUTTON (bluetooth_chooser_button_get_type ())
2117+#define BLUETOOTH_CHOOSER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BLUETOOTH_TYPE_CHOOSER_BUTTON, BluetoothChooserButton))
2118+#define BLUETOOTH_IS_CHOOSER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BLUETOOTH_TYPE_CHOOSER_BUTTON))
2119+
2120+/**
2121+ * BluetoothChooserButton:
2122+ *
2123+ * The <structname>BluetoothChooserButton</structname> struct contains
2124+ * only private fields and should not be directly accessed.
2125+ */
2126+typedef struct _BluetoothChooserButton BluetoothChooserButton;
2127+
2128+typedef struct _BluetoothChooserButtonClass BluetoothChooserButtonClass;
2129+
2130+struct _BluetoothChooserButtonClass {
2131+ GtkButtonClass parent_class;
2132+
2133+ void (*chooser_created) (BluetoothChooserButton *self, GtkWidget *chooser);
2134+};
2135+
2136+GType bluetooth_chooser_button_get_type (void);
2137+
2138+GtkWidget * bluetooth_chooser_button_new (void);
2139+gboolean bluetooth_chooser_button_available (BluetoothChooserButton *button);
2140+
2141+G_END_DECLS
2142+
2143+#endif /* __BLUETOOTH_CHOOSER_BUTTON_H__ */
2144
2145=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.c'
2146--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.c 1970-01-01 00:00:00 +0000
2147+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.c 2015-08-12 15:47:27 +0000
2148@@ -0,0 +1,365 @@
2149+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2150+/*
2151+ * (C) Copyright 2007-2009 Bastien Nocera <hadess@hadess.net>
2152+ *
2153+ * This library is free software; you can redistribute it and/or
2154+ * modify it under the terms of the GNU Library General Public
2155+ * License as published by the Free Software Foundation; either
2156+ * version 2 of the License, or (at your option) any later version.
2157+ *
2158+ * This library is distributed in the hope that it will be useful,
2159+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2160+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2161+ * Library General Public License for more details.
2162+ *
2163+ * You should have received a copy of the GNU Library General Public
2164+ * License along with this library; if not, write to the
2165+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2166+ * Boston, MA 02111-1307, USA.
2167+ */
2168+
2169+/**
2170+ * SECTION:bluetooth-chooser-combo
2171+ * @short_description: a Bluetooth chooser combo button
2172+ * @stability: Stable
2173+ * @include: bluetooth-chooser-combo.h
2174+ *
2175+ * A combo box used to select Bluetooth devices.
2176+ **/
2177+
2178+#ifdef HAVE_CONFIG_H
2179+#include "config.h"
2180+#endif
2181+
2182+#include <glib/gi18n.h>
2183+#include <gtk/gtk.h>
2184+
2185+#include "bluetooth-chooser-combo.h"
2186+#include "bluetooth-client.h"
2187+#include "bluetooth-chooser.h"
2188+#include "bluetooth-chooser-private.h"
2189+#include "bluetooth-utils.h"
2190+
2191+struct _BluetoothChooserComboPrivate {
2192+ GtkWidget *chooser;
2193+ GtkWidget *drop_box;
2194+ GtkWidget *drop;
2195+ GtkTreeModel *model;
2196+ guint model_notify_id;
2197+ GtkTreeSelection *selection;
2198+
2199+ char *bdaddr;
2200+};
2201+
2202+enum {
2203+ PROP_0,
2204+ PROP_CHOOSER,
2205+ PROP_DEVICE,
2206+};
2207+
2208+enum {
2209+ CHOOSER_CREATED,
2210+ LAST_SIGNAL
2211+};
2212+
2213+static int signals[LAST_SIGNAL] = { 0 };
2214+
2215+static void bluetooth_chooser_combo_class_init (BluetoothChooserComboClass * klass);
2216+static void bluetooth_chooser_combo_init (BluetoothChooserCombo * combo);
2217+
2218+static GtkBoxClass *parent_class;
2219+
2220+G_DEFINE_TYPE(BluetoothChooserCombo, bluetooth_chooser_combo, GTK_TYPE_BOX);
2221+
2222+#define BLUETOOTH_CHOOSER_COMBO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
2223+ BLUETOOTH_TYPE_CHOOSER_COMBO, BluetoothChooserComboPrivate))
2224+
2225+static void
2226+bluetooth_chooser_combo_set_device (BluetoothChooserCombo *combo,
2227+ const char *bdaddr)
2228+{
2229+ if (bdaddr == NULL || combo->priv->model == NULL) {
2230+ g_free (combo->priv->bdaddr);
2231+ gtk_widget_set_sensitive (combo->priv->drop_box, FALSE);
2232+ } else {
2233+ GtkTreeIter iter;
2234+ gboolean cont = FALSE;
2235+
2236+ gtk_widget_set_sensitive (combo->priv->drop_box, TRUE);
2237+
2238+ g_free (combo->priv->bdaddr);
2239+ if (g_strcmp0 (BLUETOOTH_CHOOSER_COMBO_FIRST_DEVICE, bdaddr) != 0)
2240+ combo->priv->bdaddr = g_strdup (bdaddr);
2241+ else
2242+ combo->priv->bdaddr = NULL;
2243+
2244+ cont = gtk_tree_model_iter_children (combo->priv->model, &iter, NULL);
2245+ while (cont == TRUE) {
2246+ char *value;
2247+
2248+ gtk_tree_model_get (GTK_TREE_MODEL (combo->priv->model), &iter,
2249+ BLUETOOTH_COLUMN_ADDRESS, &value, -1);
2250+
2251+ if (combo->priv->bdaddr == NULL) {
2252+ gtk_tree_selection_select_iter (combo->priv->selection, &iter);
2253+ combo->priv->bdaddr = value;
2254+ break;
2255+ }
2256+
2257+ if (g_ascii_strcasecmp(bdaddr, value) == 0) {
2258+ gtk_tree_selection_select_iter (combo->priv->selection, &iter);
2259+ g_free (value);
2260+ break;
2261+ }
2262+ g_free (value);
2263+ cont = gtk_tree_model_iter_next (GTK_TREE_MODEL (combo->priv->model), &iter);
2264+ }
2265+ }
2266+ g_object_notify (G_OBJECT (combo), "device");
2267+}
2268+
2269+static void
2270+bluetooth_chooser_combo_dispose (GObject *object)
2271+{
2272+ BluetoothChooserCombo *combo = BLUETOOTH_CHOOSER_COMBO (object);
2273+
2274+ if (combo->priv->model_notify_id != 0) {
2275+ GtkWidget *treeview;
2276+
2277+ treeview = bluetooth_chooser_get_treeview (BLUETOOTH_CHOOSER (combo->priv->chooser));
2278+ g_signal_handler_disconnect (treeview, combo->priv->model_notify_id);
2279+ combo->priv->model_notify_id = 0;
2280+ }
2281+ if (combo->priv->model != NULL) {
2282+ g_object_unref (combo->priv->model);
2283+ combo->priv->model = NULL;
2284+ }
2285+ if (combo->priv->chooser != NULL) {
2286+ g_object_unref (combo->priv->chooser);
2287+ combo->priv->chooser = NULL;
2288+ }
2289+
2290+ G_OBJECT_CLASS (parent_class)->dispose (object);
2291+}
2292+
2293+static void
2294+bluetooth_chooser_combo_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
2295+{
2296+ BluetoothChooserCombo *combo;
2297+
2298+ g_return_if_fail (BLUETOOTH_IS_CHOOSER_COMBO (object));
2299+ combo = BLUETOOTH_CHOOSER_COMBO (object);
2300+
2301+ switch (property_id) {
2302+ case PROP_DEVICE:
2303+ g_return_if_fail (bluetooth_verify_address (g_value_get_string (value)) || g_value_get_string (value) == NULL);
2304+ bluetooth_chooser_combo_set_device (combo, g_value_get_string (value));
2305+ break;
2306+ default:
2307+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2308+ }
2309+}
2310+
2311+static void
2312+bluetooth_chooser_combo_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
2313+{
2314+ BluetoothChooserCombo *combo;
2315+
2316+ g_return_if_fail (BLUETOOTH_IS_CHOOSER_COMBO (object));
2317+ combo = BLUETOOTH_CHOOSER_COMBO (object);
2318+
2319+ switch (property_id) {
2320+ case PROP_CHOOSER:
2321+ g_value_set_object (value, combo->priv->chooser);
2322+ break;
2323+ case PROP_DEVICE:
2324+ g_value_set_string (value, combo->priv->bdaddr);
2325+ break;
2326+ default:
2327+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2328+ }
2329+}
2330+
2331+static void
2332+bluetooth_chooser_combo_class_init (BluetoothChooserComboClass *klass)
2333+{
2334+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
2335+
2336+ parent_class = g_type_class_peek_parent (klass);
2337+
2338+ object_class->dispose = bluetooth_chooser_combo_dispose;
2339+ object_class->set_property = bluetooth_chooser_combo_set_property;
2340+ object_class->get_property = bluetooth_chooser_combo_get_property;
2341+
2342+ g_type_class_add_private(klass, sizeof(BluetoothChooserComboPrivate));
2343+
2344+ /**
2345+ * BluetoothChooserCombo::chooser-created:
2346+ * @self: a #BluetoothChooserCombo widget
2347+ * @chooser: a #BluetoothChooser widget
2348+ *
2349+ * The signal is sent when a popup dialogue is created for the user to select
2350+ * a device. This signal allows you to change the configuration and filtering
2351+ * of the tree from its defaults.
2352+ **/
2353+ signals[CHOOSER_CREATED] =
2354+ g_signal_new ("chooser-created",
2355+ G_TYPE_FROM_CLASS (klass),
2356+ G_SIGNAL_RUN_LAST,
2357+ G_STRUCT_OFFSET (BluetoothChooserComboClass, chooser_created),
2358+ NULL, NULL,
2359+ g_cclosure_marshal_VOID__OBJECT,
2360+ G_TYPE_NONE, 1, G_TYPE_OBJECT);
2361+
2362+ /**
2363+ * BluetoothChooserCombo:chooser:
2364+ *
2365+ * The #BluetoothChooser used in the widget
2366+ **/
2367+ g_object_class_install_property (object_class, PROP_CHOOSER,
2368+ g_param_spec_object ("chooser", "Chooser", "The #BluetoothChooser used in the widget",
2369+ BLUETOOTH_TYPE_CHOOSER, G_PARAM_READABLE));
2370+ /**
2371+ * BluetoothChooserCombo:device:
2372+ *
2373+ * The Bluetooth address of the selected device or %NULL
2374+ **/
2375+ g_object_class_install_property (object_class, PROP_DEVICE,
2376+ g_param_spec_string ("device", "Device", "The Bluetooth address of the selected device.",
2377+ NULL, G_PARAM_READWRITE));
2378+}
2379+
2380+static void
2381+treeview_model_notify_cb (GObject *gobject,
2382+ GParamSpec *pspec,
2383+ gpointer user_data)
2384+{
2385+ BluetoothChooserCombo *combo = BLUETOOTH_CHOOSER_COMBO (user_data);
2386+ GtkTreeModel *model;
2387+
2388+ g_object_get (gobject, "model", &model, NULL);
2389+ gtk_combo_box_set_model (GTK_COMBO_BOX (combo->priv->drop), model);
2390+ if (combo->priv->model != NULL) {
2391+ g_object_unref (combo->priv->model);
2392+ combo->priv->model = NULL;
2393+ }
2394+ combo->priv->model = model;
2395+}
2396+
2397+static void
2398+treeview_selection_changed_cb (GtkTreeSelection *treeselection,
2399+ gpointer user_data)
2400+{
2401+ BluetoothChooserCombo *combo = BLUETOOTH_CHOOSER_COMBO (user_data);
2402+ GtkTreeIter iter;
2403+ char *value = NULL;
2404+
2405+ if (gtk_tree_selection_get_selected (combo->priv->selection, NULL, &iter)) {
2406+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo->priv->drop), &iter);
2407+ if (combo->priv->model != NULL)
2408+ gtk_tree_model_get (GTK_TREE_MODEL (combo->priv->model), &iter,
2409+ BLUETOOTH_COLUMN_ADDRESS, &value, -1);
2410+ } else {
2411+ if (combo->priv->model != NULL)
2412+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo->priv->drop), -1);
2413+ }
2414+
2415+ if (g_strcmp0 (combo->priv->bdaddr, value) != 0) {
2416+ g_free (combo->priv->bdaddr);
2417+ combo->priv->bdaddr = value;
2418+ g_object_notify (G_OBJECT (combo), "device");
2419+ } else {
2420+ g_free (value);
2421+ }
2422+}
2423+
2424+static void
2425+drop_changed_cb (GtkComboBox *widget,
2426+ gpointer user_data)
2427+{
2428+ BluetoothChooserCombo *combo = BLUETOOTH_CHOOSER_COMBO (user_data);
2429+ GtkTreeIter iter;
2430+ char *value = NULL;
2431+
2432+ if (gtk_combo_box_get_active_iter (widget, &iter)) {
2433+ gtk_tree_selection_select_iter (combo->priv->selection, &iter);
2434+ if (combo->priv->model != NULL)
2435+ gtk_tree_model_get (GTK_TREE_MODEL (combo->priv->model), &iter,
2436+ BLUETOOTH_COLUMN_ADDRESS, &value, -1);
2437+ } else {
2438+ if (combo->priv->model != NULL)
2439+ gtk_tree_selection_unselect_all (combo->priv->selection);
2440+ }
2441+
2442+ if (g_strcmp0 (combo->priv->bdaddr, value) != 0) {
2443+ g_free (combo->priv->bdaddr);
2444+ combo->priv->bdaddr = value;
2445+ g_object_notify (G_OBJECT (combo), "device");
2446+ } else {
2447+ g_free (value);
2448+ }
2449+}
2450+
2451+static void
2452+bluetooth_chooser_combo_init (BluetoothChooserCombo *combo)
2453+{
2454+ GtkWidget *treeview;
2455+ GtkCellRenderer *renderer;
2456+
2457+ combo->priv = BLUETOOTH_CHOOSER_COMBO_GET_PRIVATE (combo);
2458+
2459+ combo->priv->drop_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2460+ gtk_box_set_homogeneous (GTK_BOX (combo->priv->drop_box), TRUE);
2461+ gtk_box_pack_start (GTK_BOX (combo), combo->priv->drop_box,
2462+ TRUE, FALSE, 0);
2463+ /* Setup the combo itself */
2464+ combo->priv->drop = gtk_combo_box_new ();
2465+ gtk_box_pack_start (GTK_BOX (combo->priv->drop_box), combo->priv->drop,
2466+ TRUE, TRUE, 0);
2467+ renderer = gtk_cell_renderer_pixbuf_new ();
2468+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo->priv->drop),
2469+ renderer,
2470+ FALSE);
2471+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo->priv->drop),
2472+ renderer,
2473+ "icon-name", BLUETOOTH_COLUMN_ICON,
2474+ NULL);
2475+ renderer = gtk_cell_renderer_text_new ();
2476+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo->priv->drop),
2477+ renderer,
2478+ TRUE);
2479+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo->priv->drop),
2480+ renderer,
2481+ "text", BLUETOOTH_COLUMN_ALIAS,
2482+ NULL);
2483+
2484+ combo->priv->chooser = bluetooth_chooser_new ();
2485+
2486+ treeview = bluetooth_chooser_get_treeview (BLUETOOTH_CHOOSER (combo->priv->chooser));
2487+ combo->priv->model_notify_id = g_signal_connect (G_OBJECT (treeview), "notify::model",
2488+ G_CALLBACK (treeview_model_notify_cb), combo);
2489+ treeview_model_notify_cb (G_OBJECT (treeview), NULL, combo);
2490+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo->priv->drop), 0);
2491+
2492+ combo->priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
2493+ g_signal_connect (G_OBJECT (combo->priv->selection), "changed",
2494+ G_CALLBACK (treeview_selection_changed_cb), combo);
2495+ g_signal_connect (G_OBJECT (combo->priv->drop), "changed",
2496+ G_CALLBACK (drop_changed_cb), combo);
2497+
2498+ gtk_widget_show_all (GTK_WIDGET (combo));
2499+}
2500+
2501+/**
2502+ * bluetooth_chooser_combo_new:
2503+ *
2504+ * Returns a new #BluetoothChooserCombo widget.
2505+ *
2506+ * Return value: a #BluetoothChooserCombo widget.
2507+ **/
2508+GtkWidget *
2509+bluetooth_chooser_combo_new (void)
2510+{
2511+ return g_object_new (BLUETOOTH_TYPE_CHOOSER_COMBO, NULL);
2512+}
2513+
2514
2515=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.h'
2516--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.h 1970-01-01 00:00:00 +0000
2517+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-combo.h 2015-08-12 15:47:27 +0000
2518@@ -0,0 +1,69 @@
2519+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2520+/*
2521+ * (C) Copyright 2007 Bastien Nocera <hadess@hadess.net>
2522+ *
2523+ * This library is free software; you can redistribute it and/or
2524+ * modify it under the terms of the GNU Library General Public
2525+ * License as published by the Free Software Foundation; either
2526+ * version 2 of the License, or (at your option) any later version.
2527+ *
2528+ * This library is distributed in the hope that it will be useful,
2529+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2530+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2531+ * Library General Public License for more details.
2532+ *
2533+ * You should have received a copy of the GNU Library General Public
2534+ * License along with this library; if not, write to the
2535+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2536+ * Boston, MA 02111-1307, USA.
2537+ */
2538+
2539+#ifndef __BLUETOOTH_CHOOSER_COMBO_H__
2540+#define __BLUETOOTH_CHOOSER_COMBO_H__
2541+
2542+#include <gtk/gtk.h>
2543+
2544+G_BEGIN_DECLS
2545+
2546+#define BLUETOOTH_TYPE_CHOOSER_COMBO (bluetooth_chooser_combo_get_type ())
2547+#define BLUETOOTH_CHOOSER_COMBO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BLUETOOTH_TYPE_CHOOSER_COMBO, BluetoothChooserCombo))
2548+#define BLUETOOTH_IS_CHOOSER_COMBO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BLUETOOTH_TYPE_CHOOSER_COMBO))
2549+#define BLUETOOTH_IS_CHOOSER_COMBO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
2550+ BLUETOOTH_TYPE_CHOOSER_COMBO))
2551+#define BLUETOOTH_GET_CHOOSER_COMBO_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
2552+ BLUETOOTH_TYPE_CHOOSER_COMBO, BluetoothChooserComboClass))
2553+
2554+/**
2555+* BLUETOOTH_CHOOSER_COMBO_FIRST_DEVICE:
2556+*
2557+* A convenience value used to select the first device regardless of its address.
2558+**/
2559+#define BLUETOOTH_CHOOSER_COMBO_FIRST_DEVICE "00:00:00:00:00:00"
2560+
2561+typedef struct _BluetoothChooserComboPrivate BluetoothChooserComboPrivate;
2562+typedef struct _BluetoothChooserComboClass BluetoothChooserComboClass;
2563+
2564+/**
2565+ * BluetoothChooserCombo:
2566+ *
2567+ * The <structname>BluetoothChooserCombo</structname> struct contains
2568+ * only private fields and should not be directly accessed.
2569+ */
2570+typedef struct _BluetoothChooserCombo {
2571+ GtkBox parent;
2572+ BluetoothChooserComboPrivate *priv;
2573+} BluetoothChooserCombo;
2574+
2575+struct _BluetoothChooserComboClass {
2576+ GtkBoxClass parent_class;
2577+
2578+ void (*chooser_created) (BluetoothChooserCombo *self, GtkWidget *chooser);
2579+};
2580+
2581+GType bluetooth_chooser_combo_get_type (void);
2582+
2583+GtkWidget * bluetooth_chooser_combo_new (void);
2584+
2585+G_END_DECLS
2586+
2587+#endif /* __BLUETOOTH_CHOOSER_COMBO_H__ */
2588
2589=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-private.h'
2590--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-private.h 1970-01-01 00:00:00 +0000
2591+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser-private.h 2015-08-12 15:47:27 +0000
2592@@ -0,0 +1,39 @@
2593+/*
2594+ *
2595+ * BlueZ - Bluetooth protocol stack for Linux
2596+ *
2597+ * Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
2598+ *
2599+ *
2600+ * This library is free software; you can redistribute it and/or
2601+ * modify it under the terms of the GNU Lesser General Public
2602+ * License as published by the Free Software Foundation; either
2603+ * version 2.1 of the License, or (at your option) any later version.
2604+ *
2605+ * This library is distributed in the hope that it will be useful,
2606+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2607+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2608+ * Lesser General Public License for more details.
2609+ *
2610+ * You should have received a copy of the GNU Lesser General Public
2611+ * License along with this library; if not, write to the Free Software
2612+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2613+ *
2614+ */
2615+
2616+#ifndef __BLUETOOTH_CHOOSER_PRIVATE_H
2617+#define __BLUETOOTH_CHOOSER_PRIVATE_H
2618+
2619+#include <glib-object.h>
2620+#include <gtk/gtk.h>
2621+#include <bluetooth-enums.h>
2622+
2623+G_BEGIN_DECLS
2624+
2625+GtkTreeModel *bluetooth_chooser_get_model (BluetoothChooser *self);
2626+GtkWidget *bluetooth_chooser_get_treeview (BluetoothChooser *self);
2627+gboolean bluetooth_chooser_remove_selected_device (BluetoothChooser *self);
2628+
2629+G_END_DECLS
2630+
2631+#endif /* __BLUETOOTH_CHOOSER_PRIVATE_H */
2632
2633=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.c'
2634--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.c 1970-01-01 00:00:00 +0000
2635+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.c 2015-08-12 15:47:27 +0000
2636@@ -0,0 +1,1173 @@
2637+/*
2638+ *
2639+ * BlueZ - Bluetooth protocol stack for Linux
2640+ *
2641+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
2642+ * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net>
2643+ *
2644+ *
2645+ * This library is free software; you can redistribute it and/or
2646+ * modify it under the terms of the GNU Lesser General Public
2647+ * License as published by the Free Software Foundation; either
2648+ * version 2.1 of the License, or (at your option) any later version.
2649+ *
2650+ * This library is distributed in the hope that it will be useful,
2651+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2652+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2653+ * Lesser General Public License for more details.
2654+ *
2655+ * You should have received a copy of the GNU Lesser General Public
2656+ * License along with this library; if not, write to the Free Software
2657+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2658+ *
2659+ */
2660+
2661+/**
2662+ * SECTION:bluetooth-chooser
2663+ * @short_description: a Bluetooth chooser widget
2664+ * @stability: Stable
2665+ * @include: bluetooth-chooser.h
2666+ *
2667+ * A tree-like widget used to select Bluetooth devices.
2668+ **/
2669+
2670+#ifdef HAVE_CONFIG_H
2671+#include <config.h>
2672+#endif
2673+
2674+#include <gtk/gtk.h>
2675+
2676+#include <glib/gi18n-lib.h>
2677+
2678+#include "bluetooth-client.h"
2679+#include "bluetooth-client-private.h"
2680+#include "bluetooth-utils.h"
2681+#include "bluetooth-chooser.h"
2682+#include "bluetooth-chooser-private.h"
2683+#include "gnome-bluetooth-enum-types.h"
2684+#include "bluetooth-filter-widget.h"
2685+
2686+enum {
2687+ SELECTED_DEVICE_CHANGED,
2688+ SELECTED_DEVICE_ACTIVATED,
2689+ LAST_SIGNAL
2690+};
2691+
2692+static int selection_table_signals[LAST_SIGNAL] = { 0 };
2693+
2694+#define BLUETOOTH_CHOOSER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
2695+ BLUETOOTH_TYPE_CHOOSER, BluetoothChooserPrivate))
2696+
2697+typedef struct _BluetoothChooserPrivate BluetoothChooserPrivate;
2698+
2699+struct _BluetoothChooserPrivate {
2700+ BluetoothClient *client;
2701+ GtkTreeSelection *selection;
2702+ GtkTreeModel *model, *filter, *adapter_model;
2703+
2704+ gulong default_adapter_changed_id;
2705+
2706+ /* Widgets/UI bits that can be shown or hidden */
2707+ GtkCellRenderer *bonded_cell;
2708+ GtkCellRenderer *connected_cell;
2709+ GtkWidget *treeview, *scrolled_window;
2710+ GtkWidget *search_hbox, *search_label, *spinner;
2711+ GtkWidget *filters_vbox;
2712+
2713+ /* Current filter */
2714+ int device_type_filter;
2715+ GtkTreeModel *device_type_filter_model;
2716+ int device_category_filter;
2717+ char *device_service_filter;
2718+
2719+ guint show_paired : 1;
2720+ guint show_connected : 1;
2721+ guint show_searching : 1;
2722+ guint show_device_type : 1;
2723+ guint show_device_category : 1;
2724+ guint disco_rq : 1;
2725+ guint internal_filter : 1;
2726+};
2727+
2728+G_DEFINE_TYPE(BluetoothChooser, bluetooth_chooser, GTK_TYPE_BOX)
2729+
2730+enum {
2731+ DEVICE_TYPE_FILTER_COL_NAME = 0,
2732+ DEVICE_TYPE_FILTER_COL_MASK,
2733+ DEVICE_TYPE_FILTER_NUM_COLS
2734+};
2735+
2736+enum {
2737+ TREEVIEW_COLUMN_DEVICE = 0,
2738+ TREEVIEW_COLUMN_TYPE = 1
2739+};
2740+
2741+static void
2742+bonded_to_icon (GtkTreeViewColumn *column, GtkCellRenderer *cell,
2743+ GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
2744+{
2745+ gboolean bonded;
2746+
2747+ gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_PAIRED, &bonded, -1);
2748+
2749+ g_object_set (cell, "icon-name", bonded ? "bluetooth-paired" : NULL, NULL);
2750+}
2751+
2752+static void
2753+connected_to_icon (GtkTreeViewColumn *column, GtkCellRenderer *cell,
2754+ GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
2755+{
2756+ gboolean connected;
2757+
2758+ gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_CONNECTED, &connected, -1);
2759+
2760+ g_object_set (cell, "icon-name", connected ? "gtk-connected" : NULL, NULL);
2761+}
2762+
2763+static void
2764+type_to_text (GtkTreeViewColumn *column, GtkCellRenderer *cell,
2765+ GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
2766+{
2767+ guint type;
2768+
2769+ gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_TYPE, &type, -1);
2770+
2771+ g_object_set (cell, "text", (type == 0) ? _("Unknown") : bluetooth_type_to_string (type), NULL);
2772+}
2773+
2774+static void
2775+alias_to_label (GtkTreeViewColumn *column, GtkCellRenderer *cell,
2776+ GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
2777+{
2778+ char *alias, *escaped, *label;
2779+ gboolean connected;
2780+
2781+ gtk_tree_model_get (model, iter,
2782+ BLUETOOTH_COLUMN_ALIAS, &alias,
2783+ BLUETOOTH_COLUMN_CONNECTED, &connected,
2784+ -1);
2785+
2786+ if (connected == FALSE) {
2787+ g_object_set (cell, "text", alias, NULL);
2788+ } else {
2789+ escaped = g_markup_escape_text (alias, -1);
2790+ label = g_strdup_printf ("<b>%s</b>", escaped);
2791+ g_free (escaped);
2792+
2793+ g_object_set (cell, "markup", label, NULL);
2794+ g_free (label);
2795+ }
2796+ g_free (alias);
2797+}
2798+
2799+static void
2800+set_search_label (BluetoothChooser *self, gboolean state)
2801+{
2802+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
2803+
2804+ if (priv->show_searching == FALSE) {
2805+ /* Just making sure */
2806+ gtk_spinner_stop (GTK_SPINNER (priv->spinner));
2807+ return;
2808+ }
2809+ if (state == FALSE) {
2810+ gtk_spinner_stop (GTK_SPINNER (priv->spinner));
2811+ gtk_widget_hide (priv->spinner);
2812+ gtk_label_set_text (GTK_LABEL (priv->search_label), _("No adapters available"));
2813+ } else {
2814+ gtk_widget_show (priv->spinner);
2815+ gtk_spinner_start (GTK_SPINNER (priv->spinner));
2816+ gtk_label_set_text (GTK_LABEL (priv->search_label), _("Searching for devices..."));
2817+ }
2818+}
2819+
2820+/**
2821+ * bluetooth_chooser_start_discovery:
2822+ * @self: a #BluetoothChooser widget.
2823+ *
2824+ * Starts a discovery on the default Bluetooth adapter. Note that this will
2825+ * only work if the Search label is visible, as otherwise the user has no
2826+ * visual feedback that the process is on-going.
2827+ *
2828+ * See also: #BluetoothChooser:show-searching
2829+ **/
2830+void
2831+bluetooth_chooser_start_discovery (BluetoothChooser *self)
2832+{
2833+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
2834+
2835+ g_return_if_fail (priv->show_searching);
2836+
2837+ g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", TRUE, NULL);
2838+ set_search_label (self, TRUE);
2839+ priv->disco_rq = TRUE;
2840+}
2841+
2842+/**
2843+ * bluetooth_chooser_stop_discovery:
2844+ * @self: a #BluetoothChooser widget.
2845+ *
2846+ * Stops a discovery started with #bluetooth_chooser_start_discovery.
2847+ **/
2848+void
2849+bluetooth_chooser_stop_discovery (BluetoothChooser *self)
2850+{
2851+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
2852+
2853+ g_return_if_fail (priv->show_searching);
2854+
2855+ priv->disco_rq = FALSE;
2856+ g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", FALSE, NULL);
2857+}
2858+
2859+static char *
2860+bluetooth_chooser_get_selected_device_data (BluetoothChooser *self, guint column)
2861+{
2862+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
2863+ GtkTreeIter iter;
2864+ gchar *str;
2865+ gboolean selected;
2866+
2867+ selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter);
2868+ if (selected == FALSE)
2869+ return NULL;
2870+
2871+ gtk_tree_model_get (priv->filter, &iter, column, &str, -1);
2872+ return str;
2873+}
2874+
2875+/**
2876+ * bluetooth_chooser_get_selected_device:
2877+ * @self: a #BluetoothChooser widget.
2878+ *
2879+ * Returns the Bluetooth address for the currently selected device.
2880+ *
2881+ * Return value: the Bluetooth address for the currently selected device, or %NULL.
2882+ **/
2883+gchar *
2884+bluetooth_chooser_get_selected_device (BluetoothChooser *self)
2885+{
2886+ return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_ADDRESS);
2887+}
2888+
2889+/**
2890+ * bluetooth_chooser_get_selected_device_name:
2891+ * @self: a #BluetoothChooser widget.
2892+ *
2893+ * Returns the name for the currently selected device.
2894+ *
2895+ * Return value: the name for the currently selected device, or %NULL.
2896+ **/
2897+gchar *
2898+bluetooth_chooser_get_selected_device_name (BluetoothChooser *self)
2899+{
2900+ return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_NAME);
2901+}
2902+
2903+/**
2904+ * bluetooth_chooser_get_selected_device_icon:
2905+ * @self: a #BluetoothChooser widget.
2906+ *
2907+ * Returns the icon name to use to represent the currently selected device.
2908+ *
2909+ * Return value: the icon name to use to represent the currently selected device, or %NULL.
2910+ **/
2911+gchar *
2912+bluetooth_chooser_get_selected_device_icon (BluetoothChooser *self)
2913+{
2914+ return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_ICON);
2915+}
2916+
2917+/**
2918+ * bluetooth_chooser_get_selected_device_type:
2919+ * @self: a #BluetoothChooser widget.
2920+ *
2921+ * Returns the #BluetoothType of the device selected.
2922+ *
2923+ * Return value: the #BluetoothType of the device selected, or '0' if unknown.
2924+ **/
2925+BluetoothType
2926+bluetooth_chooser_get_selected_device_type (BluetoothChooser *self)
2927+{
2928+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
2929+ GtkTreeIter iter;
2930+ guint type;
2931+ gboolean selected;
2932+
2933+ selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter);
2934+ if (selected == FALSE)
2935+ return 0;
2936+
2937+ gtk_tree_model_get (priv->filter, &iter, BLUETOOTH_COLUMN_TYPE, &type, -1);
2938+ return type;
2939+}
2940+
2941+/**
2942+ * bluetooth_chooser_get_selected_device_is_connected:
2943+ * @self: a #BluetoothChooser widget.
2944+ *
2945+ * Returns whether the selected device is connected to this computer.
2946+ *
2947+ * Return value: whether the selected device is connected to this computer,
2948+ * will always be %FALSE if no devices are selected.
2949+ **/
2950+gboolean
2951+bluetooth_chooser_get_selected_device_is_connected (BluetoothChooser *self)
2952+{
2953+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
2954+ GtkTreeIter iter;
2955+ gboolean selected, connected;
2956+
2957+ selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter);
2958+ if (selected == FALSE)
2959+ return 0;
2960+
2961+ gtk_tree_model_get (priv->filter, &iter, BLUETOOTH_COLUMN_CONNECTED, &connected, -1);
2962+ return connected;
2963+}
2964+
2965+/**
2966+ * bluetooth_chooser_get_selected_device_info:
2967+ * @self: A #BluetoothChooser widget.
2968+ * @field: The identifier for the field to get data for.
2969+ * @value: An empty #GValue to set.
2970+ *
2971+ * Returns whether the @value has been set.
2972+ *
2973+ * Return value: %TRUE if the @value has been set.
2974+ **/
2975+gboolean
2976+bluetooth_chooser_get_selected_device_info (BluetoothChooser *self,
2977+ const char *field,
2978+ GValue *value)
2979+{
2980+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
2981+ GEnumClass *eclass;
2982+ GEnumValue *ev;
2983+ GtkTreeIter iter;
2984+
2985+ g_return_val_if_fail (field != NULL, FALSE);
2986+
2987+ if (gtk_tree_selection_get_selected (priv->selection, NULL, &iter) == FALSE)
2988+ return FALSE;
2989+
2990+ eclass = g_type_class_ref (BLUETOOTH_TYPE_COLUMN);
2991+ ev = g_enum_get_value_by_nick (eclass, field);
2992+ if (ev == NULL) {
2993+ g_warning ("Unknown field '%s'", field);
2994+ g_type_class_unref (eclass);
2995+ return FALSE;
2996+ }
2997+
2998+ gtk_tree_model_get_value (priv->filter, &iter, ev->value, value);
2999+
3000+ g_type_class_unref (eclass);
3001+
3002+ return TRUE;
3003+}
3004+
3005+/**
3006+ * bluetooth_chooser_dump_selected_device:
3007+ * @self: A #BluetoothChooser widget.
3008+ *
3009+ * Prints all the known attributes for the currently selected device
3010+ * on the standard output. Useful for debugging.
3011+ **/
3012+void
3013+bluetooth_chooser_dump_selected_device (BluetoothChooser *self)
3014+{
3015+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3016+ GtkTreeIter iter;
3017+ GtkTreeModel *model;
3018+
3019+ gtk_tree_selection_get_selected (priv->selection, &model, &iter);
3020+
3021+ bluetooth_client_dump_device (model, &iter);
3022+}
3023+
3024+/**
3025+ * bluetooth_chooser_get_model:
3026+ * @self: A #BluetoothChooser widget.
3027+ *
3028+ * Returns the #BluetoothChooser's #GtkTreeModel.
3029+ *
3030+ * Return value: a #GtkTreeModel object.
3031+ **/
3032+GtkTreeModel *
3033+bluetooth_chooser_get_model (BluetoothChooser *self)
3034+{
3035+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3036+
3037+ return priv->model;
3038+}
3039+
3040+/**
3041+ * bluetooth_chooser_get_treeview:
3042+ * @self: A #BluetoothChooser widget.
3043+ *
3044+ * Returns the #GtkTreeView object for the #BluetoothChooser.
3045+ *
3046+ * Return value: a #GtkTreeView object.
3047+ **/
3048+GtkWidget *
3049+bluetooth_chooser_get_treeview (BluetoothChooser *self)
3050+{
3051+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3052+
3053+ return priv->treeview;
3054+}
3055+
3056+/**
3057+ * bluetooth_chooser_get_scrolled_window:
3058+ * @self: A #BluetoothChooser widget.
3059+ *
3060+ * Returns the #GtkScrolledWindow object for the #BluetoothChooser.
3061+ * This is useful to set a minimum height to the chooser using
3062+ * gtk_scrolled_window_set_min_content_height() or to join the
3063+ * chooser with a toolbar.
3064+ *
3065+ * Return value: (transfer none): a #GtkScrolledWindow object.
3066+ **/
3067+GtkWidget *
3068+bluetooth_chooser_get_scrolled_window (BluetoothChooser *self)
3069+{
3070+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3071+
3072+ return priv->scrolled_window;
3073+}
3074+
3075+static void
3076+device_model_row_changed (GtkTreeModel *model,
3077+ GtkTreePath *path,
3078+ GtkTreeIter *iter,
3079+ gpointer data)
3080+{
3081+ BluetoothChooser *self = BLUETOOTH_CHOOSER (data);
3082+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3083+ char *address;
3084+
3085+ /* Not the selection changing? */
3086+ if (gtk_tree_selection_path_is_selected (priv->selection, path) == FALSE)
3087+ return;
3088+
3089+ g_object_notify (G_OBJECT (self), "device-selected");
3090+ address = bluetooth_chooser_get_selected_device (self);
3091+ g_signal_emit (G_OBJECT (self),
3092+ selection_table_signals[SELECTED_DEVICE_CHANGED],
3093+ 0, address);
3094+ g_free (address);
3095+}
3096+
3097+static void
3098+select_browse_device_callback (GtkTreeSelection *selection, gpointer user_data)
3099+{
3100+ BluetoothChooser *self = user_data;
3101+ char *address;
3102+
3103+ g_object_notify (G_OBJECT(self), "device-selected");
3104+ address = bluetooth_chooser_get_selected_device (self);
3105+ g_signal_emit (G_OBJECT (self),
3106+ selection_table_signals[SELECTED_DEVICE_CHANGED],
3107+ 0, address);
3108+ g_free (address);
3109+}
3110+
3111+static void
3112+row_activated_cb (GtkTreeView *tree_view,
3113+ GtkTreePath *path,
3114+ GtkTreeViewColumn *column,
3115+ BluetoothChooser *self)
3116+{
3117+ char *address;
3118+
3119+ address = bluetooth_chooser_get_selected_device (self);
3120+ g_signal_emit (G_OBJECT (self),
3121+ selection_table_signals[SELECTED_DEVICE_ACTIVATED],
3122+ 0, address);
3123+ g_free (address);
3124+}
3125+
3126+static gboolean
3127+filter_type_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv)
3128+{
3129+ int type;
3130+
3131+ if (priv->device_type_filter == BLUETOOTH_TYPE_ANY)
3132+ return TRUE;
3133+
3134+ gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_TYPE, &type, -1);
3135+ return (type & priv->device_type_filter);
3136+}
3137+
3138+static gboolean
3139+filter_category_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv)
3140+{
3141+ gboolean bonded, trusted;
3142+
3143+ if (priv->device_category_filter == BLUETOOTH_CATEGORY_ALL)
3144+ return TRUE;
3145+
3146+ gtk_tree_model_get (model, iter,
3147+ BLUETOOTH_COLUMN_PAIRED, &bonded,
3148+ BLUETOOTH_COLUMN_TRUSTED, &trusted,
3149+ -1);
3150+
3151+ if (priv->device_category_filter == BLUETOOTH_CATEGORY_PAIRED)
3152+ return bonded;
3153+ if (priv->device_category_filter == BLUETOOTH_CATEGORY_TRUSTED)
3154+ return trusted;
3155+ if (priv->device_category_filter == BLUETOOTH_CATEGORY_NOT_PAIRED_OR_TRUSTED)
3156+ return (!bonded && !trusted);
3157+ if (priv->device_category_filter == BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED)
3158+ return (bonded || trusted);
3159+
3160+ g_assert_not_reached ();
3161+
3162+ return FALSE;
3163+}
3164+
3165+static gboolean
3166+filter_service_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv)
3167+{
3168+ char **services;
3169+ gboolean ret = FALSE;
3170+ guint i;
3171+
3172+ if (priv->device_service_filter == NULL)
3173+ return TRUE;
3174+
3175+ gtk_tree_model_get (model, iter,
3176+ BLUETOOTH_COLUMN_UUIDS, &services,
3177+ -1);
3178+ if (services == NULL) {
3179+ /* FIXME we need a way to discover the services here */
3180+ return FALSE;
3181+ }
3182+
3183+ for (i = 0; services[i] != NULL; i++) {
3184+ if (g_str_equal (priv->device_service_filter, services[i]) != FALSE) {
3185+ ret = TRUE;
3186+ break;
3187+ }
3188+ }
3189+
3190+ g_strfreev (services);
3191+
3192+ return ret;
3193+}
3194+
3195+static gboolean
3196+filter_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
3197+{
3198+ BluetoothChooser *self = BLUETOOTH_CHOOSER (data);
3199+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3200+
3201+ return filter_type_func (model, iter, priv)
3202+ && filter_category_func (model, iter, priv)
3203+ && filter_service_func (model, iter, priv);
3204+}
3205+
3206+static void
3207+filter_type_changed_cb (GObject *object, GParamSpec *spec, gpointer user_data)
3208+{
3209+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(object);
3210+
3211+ if (priv->filter)
3212+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
3213+}
3214+
3215+static void
3216+filter_category_changed_cb (GObject *object, GParamSpec *spec, gpointer user_data)
3217+{
3218+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(object);
3219+
3220+ if (priv->filter)
3221+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
3222+}
3223+
3224+static void
3225+adapter_model_row_changed (GtkTreeModel *model,
3226+ GtkTreePath *path,
3227+ GtkTreeIter *iter,
3228+ gpointer data)
3229+{
3230+ BluetoothChooser *self = BLUETOOTH_CHOOSER (data);
3231+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3232+ gboolean discovering, is_default, powered;
3233+
3234+ /* Not an adapter changing? */
3235+ if (gtk_tree_path_get_depth (path) != 1)
3236+ return;
3237+
3238+ gtk_tree_model_get (model, iter,
3239+ BLUETOOTH_COLUMN_DEFAULT, &is_default,
3240+ BLUETOOTH_COLUMN_DISCOVERING, &discovering,
3241+ BLUETOOTH_COLUMN_POWERED, &powered,
3242+ -1);
3243+
3244+ if (is_default == FALSE)
3245+ return;
3246+ if (powered != FALSE && discovering == FALSE && priv->disco_rq != FALSE) {
3247+ g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", TRUE, NULL);
3248+ set_search_label (self, TRUE);
3249+ return;
3250+ }
3251+ gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), powered);
3252+ set_search_label (self, discovering);
3253+}
3254+
3255+static void default_adapter_changed (GObject *gobject,
3256+ GParamSpec *arg1,
3257+ gpointer data)
3258+{
3259+ BluetoothChooser *self = BLUETOOTH_CHOOSER (data);
3260+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3261+ char *adapter;
3262+
3263+ g_object_get (gobject, "default-adapter", &adapter, NULL);
3264+
3265+ if (adapter == NULL) {
3266+ gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), FALSE);
3267+ set_search_label (self, FALSE);
3268+ gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), NULL);
3269+ }
3270+
3271+ if (priv->model) {
3272+ g_object_unref (priv->model);
3273+ priv->model = NULL;
3274+ }
3275+
3276+ if (adapter == NULL)
3277+ return;
3278+
3279+ g_free (adapter);
3280+
3281+ priv->model = bluetooth_client_get_device_model (priv->client);
3282+ if (priv->model) {
3283+ priv->filter = gtk_tree_model_filter_new (priv->model, NULL);
3284+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter),
3285+ filter_func, self, NULL);
3286+ gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), priv->filter);
3287+ g_signal_connect (priv->filter, "row-changed",
3288+ G_CALLBACK (device_model_row_changed), self);
3289+ g_object_unref (priv->filter);
3290+ gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), TRUE);
3291+
3292+ /* Start a discovery if it was requested before we
3293+ * had an adapter available */
3294+ if (priv->disco_rq != FALSE) {
3295+ bluetooth_chooser_start_discovery (self);
3296+ set_search_label (self, TRUE);
3297+ }
3298+ }
3299+}
3300+
3301+static GtkWidget *
3302+create_treeview (BluetoothChooser *self)
3303+{
3304+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3305+ GtkWidget *scrolled, *tree;
3306+ GtkCellRenderer *renderer;
3307+ GtkTreeViewColumn *column;
3308+
3309+ /* Create the scrolled window */
3310+ scrolled = gtk_scrolled_window_new (NULL, NULL);
3311+
3312+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolled),
3313+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3314+
3315+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolled),
3316+ GTK_SHADOW_OUT);
3317+
3318+ /* Create the tree view */
3319+ tree = gtk_tree_view_new ();
3320+
3321+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(tree), TRUE);
3322+
3323+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(tree), TRUE);
3324+
3325+ g_object_set (tree, "show-expanders", FALSE, NULL);
3326+
3327+ g_signal_connect (G_OBJECT (tree), "row-activated",
3328+ G_CALLBACK (row_activated_cb), self);
3329+
3330+ column = gtk_tree_view_column_new ();
3331+
3332+ gtk_tree_view_column_set_title (column, _("Device"));
3333+ gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN(column), TRUE);
3334+
3335+ /* The type icon */
3336+ renderer = gtk_cell_renderer_pixbuf_new ();
3337+ gtk_tree_view_column_set_spacing (column, 4);
3338+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
3339+ gtk_tree_view_column_set_attributes (column, renderer,
3340+ "icon-name", BLUETOOTH_COLUMN_ICON, NULL);
3341+
3342+ /* The device name */
3343+ renderer = gtk_cell_renderer_text_new ();
3344+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
3345+ g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
3346+ gtk_tree_view_column_set_cell_data_func (column, renderer,
3347+ alias_to_label, NULL, NULL);
3348+
3349+ /* The connected icon */
3350+ priv->connected_cell = gtk_cell_renderer_pixbuf_new ();
3351+ gtk_tree_view_column_pack_start (column, priv->connected_cell, FALSE);
3352+
3353+ gtk_tree_view_column_set_cell_data_func (column, priv->connected_cell,
3354+ connected_to_icon, NULL, NULL);
3355+ g_object_set (G_OBJECT (priv->connected_cell), "visible", priv->show_connected, NULL);
3356+
3357+ /* The bonded icon */
3358+ priv->bonded_cell = gtk_cell_renderer_pixbuf_new ();
3359+ gtk_tree_view_column_pack_end (column, priv->bonded_cell, FALSE);
3360+
3361+ gtk_tree_view_column_set_cell_data_func (column, priv->bonded_cell,
3362+ bonded_to_icon, NULL, NULL);
3363+ g_object_set (G_OBJECT (priv->bonded_cell), "visible", priv->show_paired, NULL);
3364+
3365+ gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
3366+
3367+ gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW(tree), -1,
3368+ _("Type"), gtk_cell_renderer_text_new(),
3369+ type_to_text, NULL, NULL);
3370+
3371+ priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree));
3372+
3373+ gtk_tree_selection_set_mode (priv->selection, GTK_SELECTION_SINGLE);
3374+
3375+ g_signal_connect (G_OBJECT(priv->selection), "changed",
3376+ G_CALLBACK(select_browse_device_callback), self);
3377+
3378+ /* Set the model, and filter */
3379+ priv->model = bluetooth_client_get_device_model (priv->client);
3380+ if (priv->model) {
3381+ priv->filter = gtk_tree_model_filter_new (priv->model, NULL);
3382+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter),
3383+ filter_func, self, NULL);
3384+ gtk_tree_view_set_model (GTK_TREE_VIEW(tree), priv->filter);
3385+ g_signal_connect (priv->filter, "row-changed",
3386+ G_CALLBACK (device_model_row_changed), self);
3387+ g_object_unref (priv->filter);
3388+ } else {
3389+ gtk_widget_set_sensitive (GTK_WIDGET (tree), FALSE);
3390+ set_search_label (self, FALSE);
3391+ }
3392+
3393+ gtk_container_add (GTK_CONTAINER(scrolled), tree);
3394+ priv->treeview = tree;
3395+
3396+ return scrolled;
3397+}
3398+
3399+static void
3400+bluetooth_chooser_init(BluetoothChooser *self)
3401+{
3402+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3403+
3404+ GtkWidget *vbox;
3405+ GtkWidget *hbox;
3406+
3407+ gtk_widget_push_composite_child ();
3408+
3409+ g_object_set (G_OBJECT (self), "orientation", GTK_ORIENTATION_VERTICAL, NULL);
3410+
3411+ priv->client = bluetooth_client_new ();
3412+
3413+ /* Setup the widget itself */
3414+ gtk_box_set_spacing (GTK_BOX(self), 18);
3415+ gtk_container_set_border_width (GTK_CONTAINER(self), 0);
3416+
3417+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
3418+ gtk_widget_show (vbox);
3419+ gtk_box_pack_start (GTK_BOX (self), vbox, TRUE, TRUE, 0);
3420+
3421+ /* The treeview label */
3422+ priv->search_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 24);
3423+ gtk_widget_set_name (priv->search_hbox, "search_hbox");
3424+ if (priv->show_searching)
3425+ gtk_widget_show (priv->search_hbox);
3426+ gtk_box_pack_end (GTK_BOX (vbox), priv->search_hbox, FALSE, TRUE, 0);
3427+ gtk_widget_set_no_show_all (priv->search_hbox, TRUE);
3428+
3429+ /* Setup the adapter disco mode callback for the search button */
3430+ priv->adapter_model = bluetooth_client_get_adapter_model (priv->client);
3431+ g_signal_connect (priv->adapter_model, "row-changed",
3432+ G_CALLBACK (adapter_model_row_changed), self);
3433+
3434+ /* The searching label */
3435+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
3436+ gtk_widget_set_name (hbox, "searching label hbox");
3437+ priv->spinner = gtk_spinner_new ();
3438+ gtk_container_add (GTK_CONTAINER (hbox), priv->spinner);
3439+ gtk_widget_show (priv->spinner);
3440+ priv->search_label = gtk_label_new (_("Searching for devices..."));
3441+ gtk_container_add (GTK_CONTAINER (hbox), priv->search_label);
3442+ gtk_widget_show (priv->search_label);
3443+ gtk_widget_show (hbox);
3444+
3445+ if (priv->show_searching) {
3446+ gboolean discovering;
3447+
3448+ g_object_get (G_OBJECT (priv->client), "default-adapter-discovering", &discovering, NULL);
3449+ set_search_label (self, discovering);
3450+ }
3451+
3452+ gtk_box_pack_start (GTK_BOX (priv->search_hbox), hbox, FALSE, TRUE, 0);
3453+
3454+ /* The treeview */
3455+ priv->scrolled_window = create_treeview (self);
3456+ gtk_widget_show_all (priv->scrolled_window);
3457+ gtk_box_pack_start (GTK_BOX (vbox), priv->scrolled_window, TRUE, TRUE, 0);
3458+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3459+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window), GTK_SHADOW_IN);
3460+
3461+ /* The filters */
3462+ priv->device_type_filter_model = GTK_TREE_MODEL (gtk_list_store_new (DEVICE_TYPE_FILTER_NUM_COLS,
3463+ G_TYPE_STRING, G_TYPE_INT));
3464+ priv->filters_vbox = bluetooth_filter_widget_new ();
3465+ gtk_widget_show (priv->filters_vbox);
3466+ gtk_box_pack_start (GTK_BOX (self), priv->filters_vbox, FALSE, TRUE, 0);
3467+ gtk_widget_set_no_show_all (priv->filters_vbox, TRUE);
3468+
3469+ /* if filters are not visible hide the vbox */
3470+ if (!priv->show_device_type && !priv->show_device_category)
3471+ gtk_widget_hide (priv->filters_vbox);
3472+
3473+ priv->default_adapter_changed_id = g_signal_connect (priv->client, "notify::default-adapter",
3474+ G_CALLBACK (default_adapter_changed), self);
3475+
3476+ g_signal_connect(self, "notify::device-type-filter",
3477+ G_CALLBACK(filter_type_changed_cb), NULL);
3478+ g_signal_connect(self, "notify::device-category-filter",
3479+ G_CALLBACK(filter_category_changed_cb), NULL);
3480+
3481+ gtk_widget_pop_composite_child ();
3482+}
3483+
3484+static GObject *
3485+bluetooth_chooser_constructor (GType type,
3486+ guint n_construct_params,
3487+ GObjectConstructParam *construct_params)
3488+{
3489+ BluetoothChooser *self;
3490+ BluetoothChooserPrivate *priv;
3491+ GObject *object;
3492+
3493+ object = G_OBJECT_CLASS (bluetooth_chooser_parent_class)->constructor (type,
3494+ n_construct_params,
3495+ construct_params);
3496+ self = BLUETOOTH_CHOOSER (object);
3497+ priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
3498+
3499+ if (priv->internal_filter) {
3500+ bluetooth_filter_widget_bind_filter (BLUETOOTH_FILTER_WIDGET (priv->filters_vbox), self);
3501+ }
3502+ return object;
3503+}
3504+
3505+static void
3506+bluetooth_chooser_finalize (GObject *object)
3507+{
3508+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(object);
3509+
3510+ if (priv->client) {
3511+ g_signal_handler_disconnect (G_OBJECT(priv->client), priv->default_adapter_changed_id);
3512+ priv->default_adapter_changed_id = 0;
3513+
3514+ g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", FALSE, NULL);
3515+ g_object_unref (priv->client);
3516+ priv->client = NULL;
3517+ }
3518+ if (priv->adapter_model) {
3519+ g_object_unref (priv->adapter_model);
3520+ priv->adapter_model = NULL;
3521+ }
3522+ if (priv->model != NULL) {
3523+ g_object_unref (priv->model);
3524+ priv->model = NULL;
3525+ }
3526+ g_free (priv->device_service_filter);
3527+
3528+ G_OBJECT_CLASS(bluetooth_chooser_parent_class)->finalize(object);
3529+}
3530+
3531+enum {
3532+ PROP_0,
3533+ PROP_DEVICE_SELECTED,
3534+ PROP_SHOW_PAIRING,
3535+ PROP_SHOW_CONNECTED,
3536+ PROP_SHOW_SEARCHING,
3537+ PROP_SHOW_DEVICE_TYPE,
3538+ PROP_SHOW_DEVICE_TYPE_COLUMN,
3539+ PROP_SHOW_DEVICE_CATEGORY,
3540+ PROP_DEVICE_TYPE_FILTER,
3541+ PROP_DEVICE_CATEGORY_FILTER,
3542+ PROP_DEVICE_SERVICE_FILTER,
3543+ PROP_INTERNAL_FILTER
3544+};
3545+
3546+static void
3547+bluetooth_chooser_set_property (GObject *object, guint prop_id,
3548+ const GValue *value, GParamSpec *pspec)
3549+{
3550+ BluetoothChooser *self = BLUETOOTH_CHOOSER (object);
3551+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE (object);
3552+
3553+ switch (prop_id) {
3554+ case PROP_DEVICE_SELECTED: {
3555+ const char *address;
3556+ char *selected;
3557+ GtkTreeIter iter;
3558+ gboolean cont;
3559+
3560+ address = g_value_get_string (value);
3561+ if (address == NULL) {
3562+ gtk_tree_selection_unselect_all (priv->selection);
3563+ return;
3564+ }
3565+
3566+ selected = bluetooth_chooser_get_selected_device (self);
3567+ if (g_strcmp0 (selected, address) == 0) {
3568+ g_free (selected);
3569+ return;
3570+ }
3571+ g_free (selected);
3572+
3573+ cont = gtk_tree_model_get_iter_first (priv->filter, &iter);
3574+ while (cont == TRUE) {
3575+ char *iaddress;
3576+ gtk_tree_model_get (priv->filter, &iter,
3577+ BLUETOOTH_COLUMN_ADDRESS, &iaddress, -1);
3578+ if (g_strcmp0 (iaddress, address) == 0) {
3579+ gtk_tree_selection_select_iter (priv->selection, &iter);
3580+ g_free (iaddress);
3581+ return;
3582+ }
3583+ g_free (iaddress);
3584+
3585+ cont = gtk_tree_model_iter_next (priv->filter, &iter);
3586+ }
3587+ break;
3588+ }
3589+ case PROP_SHOW_PAIRING:
3590+ priv->show_paired = g_value_get_boolean (value);
3591+ if (priv->bonded_cell != NULL)
3592+ g_object_set (G_OBJECT (priv->bonded_cell), "visible", priv->show_paired, NULL);
3593+ break;
3594+ case PROP_SHOW_CONNECTED:
3595+ priv->show_connected = g_value_get_boolean (value);
3596+ if (priv->connected_cell != NULL)
3597+ g_object_set (G_OBJECT (priv->connected_cell), "visible", priv->show_connected, NULL);
3598+ break;
3599+ case PROP_SHOW_SEARCHING:
3600+ priv->show_searching = g_value_get_boolean (value);
3601+ g_object_set (G_OBJECT (priv->search_hbox), "visible", priv->show_searching, NULL);
3602+ break;
3603+ case PROP_SHOW_DEVICE_TYPE:
3604+ priv->show_device_type = g_value_get_boolean (value);
3605+ if (priv->internal_filter) {
3606+ if (priv->show_device_type || priv->show_device_category)
3607+ g_object_set (G_OBJECT (priv->filters_vbox), "visible", TRUE, NULL);
3608+ else
3609+ g_object_set (G_OBJECT (priv->filters_vbox), "visible", FALSE, NULL);
3610+ }
3611+ break;
3612+ case PROP_SHOW_DEVICE_TYPE_COLUMN: {
3613+ GtkTreeViewColumn *column;
3614+
3615+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_TYPE);
3616+ gtk_tree_view_column_set_visible (column,
3617+ g_value_get_boolean (value));
3618+
3619+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_DEVICE);
3620+ if (g_value_get_boolean (value))
3621+ gtk_tree_view_column_set_title (column, _("Device"));
3622+ else
3623+ gtk_tree_view_column_set_title (column, _("Devices"));
3624+ break;
3625+ }
3626+ case PROP_SHOW_DEVICE_CATEGORY:
3627+ priv->show_device_category = g_value_get_boolean (value);
3628+ if (priv->internal_filter) {
3629+ if (priv->show_device_type || priv->show_device_category)
3630+ g_object_set (G_OBJECT (priv->filters_vbox), "visible", TRUE, NULL);
3631+ else
3632+ g_object_set (G_OBJECT (priv->filters_vbox), "visible", FALSE, NULL);
3633+ }
3634+ break;
3635+ case PROP_DEVICE_TYPE_FILTER:
3636+ priv->device_type_filter = g_value_get_int (value);
3637+ g_object_notify (object, "device-type-filter");
3638+ break;
3639+ case PROP_DEVICE_CATEGORY_FILTER:
3640+ priv->device_category_filter = g_value_get_enum (value);
3641+ g_object_notify (object, "device-category-filter");
3642+ break;
3643+ case PROP_DEVICE_SERVICE_FILTER:
3644+ g_free (priv->device_service_filter);
3645+ priv->device_service_filter = g_value_dup_string (value);
3646+ if (priv->filter)
3647+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
3648+ break;
3649+ case PROP_INTERNAL_FILTER:
3650+ priv->internal_filter = g_value_get_boolean (value);
3651+ g_object_set (G_OBJECT (priv->filters_vbox), "visible", priv->internal_filter, NULL);
3652+ break;
3653+ default:
3654+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
3655+ break;
3656+ }
3657+}
3658+
3659+static void
3660+bluetooth_chooser_get_property (GObject *object, guint prop_id,
3661+ GValue *value, GParamSpec *pspec)
3662+{
3663+ BluetoothChooser *self = BLUETOOTH_CHOOSER(object);
3664+ BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(object);
3665+
3666+ switch (prop_id) {
3667+ case PROP_DEVICE_SELECTED:
3668+ g_value_take_string (value, bluetooth_chooser_get_selected_device (self));
3669+ break;
3670+ case PROP_SHOW_PAIRING:
3671+ g_value_set_boolean (value, priv->show_paired);
3672+ break;
3673+ case PROP_SHOW_CONNECTED:
3674+ g_value_set_boolean (value, priv->show_connected);
3675+ break;
3676+ case PROP_SHOW_SEARCHING:
3677+ g_value_set_boolean (value, priv->show_searching);
3678+ break;
3679+ case PROP_SHOW_DEVICE_TYPE:
3680+ g_value_set_boolean (value, priv->show_device_type);
3681+ break;
3682+ case PROP_SHOW_DEVICE_TYPE_COLUMN:
3683+ g_value_set_boolean (value,
3684+ gtk_tree_view_column_get_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_TYPE)));
3685+ break;
3686+ case PROP_SHOW_DEVICE_CATEGORY:
3687+ g_value_set_boolean (value, priv->show_device_category);
3688+ break;
3689+ case PROP_DEVICE_TYPE_FILTER:
3690+ g_value_set_int (value, priv->device_type_filter);
3691+ break;
3692+ case PROP_DEVICE_CATEGORY_FILTER:
3693+ g_value_set_enum (value, priv->device_category_filter);
3694+ break;
3695+ case PROP_DEVICE_SERVICE_FILTER:
3696+ g_value_set_string (value, priv->device_service_filter);
3697+ break;
3698+ case PROP_INTERNAL_FILTER:
3699+ g_value_set_boolean (value, priv->internal_filter);
3700+ break;
3701+ default:
3702+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
3703+ break;
3704+ }
3705+}
3706+
3707+static void
3708+bluetooth_chooser_class_init (BluetoothChooserClass *klass)
3709+{
3710+ /* Use to calculate the maximum value for the
3711+ * device-type-filter value */
3712+ guint i;
3713+ int max_filter_val;
3714+
3715+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
3716+
3717+ g_type_class_add_private(klass, sizeof(BluetoothChooserPrivate));
3718+
3719+ G_OBJECT_CLASS(klass)->constructor = bluetooth_chooser_constructor;
3720+ G_OBJECT_CLASS(klass)->finalize = bluetooth_chooser_finalize;
3721+
3722+ G_OBJECT_CLASS(klass)->set_property = bluetooth_chooser_set_property;
3723+ G_OBJECT_CLASS(klass)->get_property = bluetooth_chooser_get_property;
3724+
3725+ /**
3726+ * BluetoothChooser::selected-device-changed:
3727+ * @chooser: a #BluetoothChooser widget which received the signal
3728+ * @address: the Bluetooth address for the currently selected device, or %NULL
3729+ *
3730+ * The #BluetoothChooser::selected-device-changed signal is launched when the
3731+ * selected device is changed, it will be %NULL if a device was unselected.
3732+ **/
3733+ selection_table_signals[SELECTED_DEVICE_CHANGED] =
3734+ g_signal_new ("selected-device-changed",
3735+ G_TYPE_FROM_CLASS (klass),
3736+ G_SIGNAL_RUN_LAST,
3737+ G_STRUCT_OFFSET (BluetoothChooserClass, selected_device_changed),
3738+ NULL, NULL,
3739+ g_cclosure_marshal_VOID__STRING,
3740+ G_TYPE_NONE, 1, G_TYPE_STRING);
3741+ /**
3742+ * BluetoothChooser::selected-device-activated:
3743+ * @chooser: a #BluetoothChooser widget which received the signal
3744+ * @address: the Bluetooth address for the currently selected device, or %NULL
3745+ *
3746+ * The #BluetoothChooser::selected-device-activated signal is launched when a
3747+ * device is double-clicked in the chooser.
3748+ **/
3749+ selection_table_signals[SELECTED_DEVICE_ACTIVATED] =
3750+ g_signal_new ("selected-device-activated",
3751+ G_TYPE_FROM_CLASS (klass),
3752+ G_SIGNAL_RUN_LAST,
3753+ G_STRUCT_OFFSET (BluetoothChooserClass, selected_device_activated),
3754+ NULL, NULL,
3755+ g_cclosure_marshal_VOID__STRING,
3756+ G_TYPE_NONE, 1, G_TYPE_STRING);
3757+
3758+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3759+ PROP_DEVICE_SELECTED, g_param_spec_string ("device-selected",
3760+ "device-selected", "The Bluetooth address for the currently selected device, or %NULL", NULL, G_PARAM_READABLE | G_PARAM_WRITABLE));
3761+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3762+ PROP_SHOW_PAIRING, g_param_spec_boolean ("show-pairing",
3763+ "show-pairing", "Whether to show the pairing column in the tree.", FALSE, G_PARAM_READWRITE));
3764+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3765+ PROP_SHOW_CONNECTED, g_param_spec_boolean ("show-connected",
3766+ "show-connected", "Whether to show the connected column in the tree.", FALSE, G_PARAM_READWRITE));
3767+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3768+ PROP_SHOW_SEARCHING, g_param_spec_boolean ("show-searching",
3769+ "show-searching",
3770+ "Whether to show the Searching label , this is necessary if you want to programmatically start a discovery, using bluetooth_chooser_start_discovery()",
3771+ FALSE, G_PARAM_READWRITE));
3772+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3773+ PROP_SHOW_DEVICE_TYPE, g_param_spec_boolean ("show-device-type",
3774+ "show-device-type", "Whether to show the device type filter", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3775+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3776+ PROP_SHOW_DEVICE_TYPE_COLUMN, g_param_spec_boolean ("show-device-type-column",
3777+ "show-device-type-column", "Whether to show the device type column", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3778+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3779+ PROP_SHOW_DEVICE_CATEGORY, g_param_spec_boolean ("show-device-category",
3780+ "show-device-category", "Whether to show the device category filter", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3781+ for (i = 0, max_filter_val = 0 ; i < _BLUETOOTH_TYPE_NUM_TYPES; i++)
3782+ max_filter_val += 1 << i;
3783+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3784+ PROP_DEVICE_TYPE_FILTER, g_param_spec_int ("device-type-filter",
3785+ "device-type-filter", "A bitmask of #BluetoothType to show", BLUETOOTH_TYPE_ANY, max_filter_val, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3786+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3787+ PROP_DEVICE_CATEGORY_FILTER, g_param_spec_enum ("device-category-filter",
3788+ "device-category-filter", "The #BluetoothCategory to show", BLUETOOTH_TYPE_CATEGORY, BLUETOOTH_CATEGORY_ALL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3789+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3790+ PROP_DEVICE_SERVICE_FILTER, g_param_spec_string ("device-service-filter",
3791+ "device-service-filter", "A string representing the service to filter for", NULL, G_PARAM_WRITABLE));
3792+ g_object_class_install_property (G_OBJECT_CLASS(klass),
3793+ PROP_INTERNAL_FILTER, g_param_spec_boolean ("has-internal-device-filter",
3794+ "has-internal-device-filter", "Whether the #BluetoothChooser should be constructed with a visible #BluetoothFilterWidget", TRUE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
3795+}
3796+
3797+/**
3798+ * bluetooth_chooser_new:
3799+ *
3800+ * Returns a new #BluetoothChooser widget.
3801+ *
3802+ * Return value: A #BluetoothChooser widget
3803+ **/
3804+GtkWidget *
3805+bluetooth_chooser_new (void)
3806+{
3807+ return g_object_new(BLUETOOTH_TYPE_CHOOSER, NULL);
3808+}
3809+
3810
3811=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.h'
3812--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.h 1970-01-01 00:00:00 +0000
3813+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-chooser.h 2015-08-12 15:47:27 +0000
3814@@ -0,0 +1,86 @@
3815+/*
3816+ *
3817+ * BlueZ - Bluetooth protocol stack for Linux
3818+ *
3819+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
3820+ * Copyright (C) 2006-2007 Bastien Nocera <hadess@hadess.net>
3821+ *
3822+ *
3823+ * This library is free software; you can redistribute it and/or
3824+ * modify it under the terms of the GNU Lesser General Public
3825+ * License as published by the Free Software Foundation; either
3826+ * version 2.1 of the License, or (at your option) any later version.
3827+ *
3828+ * This library is distributed in the hope that it will be useful,
3829+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3830+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3831+ * Lesser General Public License for more details.
3832+ *
3833+ * You should have received a copy of the GNU Lesser General Public
3834+ * License along with this library; if not, write to the Free Software
3835+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3836+ *
3837+ */
3838+
3839+#ifndef __BLUETOOTH_CHOOSER_H
3840+#define __BLUETOOTH_CHOOSER_H
3841+
3842+#include <gtk/gtk.h>
3843+#include <bluetooth-enums.h>
3844+
3845+G_BEGIN_DECLS
3846+
3847+#define BLUETOOTH_TYPE_CHOOSER (bluetooth_chooser_get_type())
3848+#define BLUETOOTH_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
3849+ BLUETOOTH_TYPE_CHOOSER, BluetoothChooser))
3850+#define BLUETOOTH_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
3851+ BLUETOOTH_TYPE_CHOOSER, BluetoothChooserClass))
3852+#define BLUETOOTH_IS_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
3853+ BLUETOOTH_TYPE_CHOOSER))
3854+#define BLUETOOTH_IS_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \
3855+ BLUETOOTH_TYPE_CHOOSER))
3856+#define BLUETOOTH_GET_CHOOSER_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \
3857+ BLUETOOTH_TYPE_CHOOSER, BluetoothChooserClass))
3858+
3859+/**
3860+ * BluetoothChooser:
3861+ *
3862+ * The <structname>BluetoothChooser</structname> struct contains
3863+ * only private fields and should not be directly accessed.
3864+ */
3865+typedef struct _BluetoothChooser BluetoothChooser;
3866+typedef struct _BluetoothChooserClass BluetoothChooserClass;
3867+
3868+struct _BluetoothChooser {
3869+ GtkBox parent;
3870+};
3871+
3872+struct _BluetoothChooserClass {
3873+ GtkBoxClass parent_class;
3874+
3875+ void (*selected_device_changed) (BluetoothChooser *chooser, const char *address);
3876+ void (*selected_device_activated) (BluetoothChooser *chooser, const char *address);
3877+};
3878+
3879+GType bluetooth_chooser_get_type (void);
3880+
3881+GtkWidget *bluetooth_chooser_new (void);
3882+
3883+char *bluetooth_chooser_get_selected_device (BluetoothChooser *self);
3884+gboolean bluetooth_chooser_get_selected_device_info (BluetoothChooser *self,
3885+ const char *field,
3886+ GValue *value);
3887+char *bluetooth_chooser_get_selected_device_name (BluetoothChooser *self);
3888+char * bluetooth_chooser_get_selected_device_icon (BluetoothChooser *self);
3889+BluetoothType bluetooth_chooser_get_selected_device_type (BluetoothChooser *self);
3890+gboolean bluetooth_chooser_get_selected_device_is_connected (BluetoothChooser *self);
3891+void bluetooth_chooser_dump_selected_device (BluetoothChooser *self);
3892+
3893+GtkWidget *bluetooth_chooser_get_scrolled_window (BluetoothChooser *self);
3894+
3895+void bluetooth_chooser_start_discovery (BluetoothChooser *self);
3896+void bluetooth_chooser_stop_discovery (BluetoothChooser *self);
3897+
3898+G_END_DECLS
3899+
3900+#endif /* __BLUETOOTH_CHOOSER_H */
3901
3902=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-client-private.h'
3903--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-client-private.h 1970-01-01 00:00:00 +0000
3904+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-client-private.h 2015-08-12 15:47:27 +0000
3905@@ -0,0 +1,61 @@
3906+/*
3907+ *
3908+ * BlueZ - Bluetooth protocol stack for Linux
3909+ *
3910+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
3911+ *
3912+ *
3913+ * This library is free software; you can redistribute it and/or
3914+ * modify it under the terms of the GNU Lesser General Public
3915+ * License as published by the Free Software Foundation; either
3916+ * version 2.1 of the License, or (at your option) any later version.
3917+ *
3918+ * This library is distributed in the hope that it will be useful,
3919+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3920+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3921+ * Lesser General Public License for more details.
3922+ *
3923+ * You should have received a copy of the GNU Lesser General Public
3924+ * License along with this library; if not, write to the Free Software
3925+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3926+ *
3927+ */
3928+
3929+#ifndef __BLUETOOTH_CLIENT_PRIVATE_H
3930+#define __BLUETOOTH_CLIENT_PRIVATE_H
3931+
3932+#include <glib-object.h>
3933+#include <gtk/gtk.h>
3934+#include <bluetooth-enums.h>
3935+
3936+G_BEGIN_DECLS
3937+
3938+typedef void (*BluetoothClientSetupFunc) (BluetoothClient *client,
3939+ const GError *error,
3940+ const char *device_path);
3941+
3942+void bluetooth_client_setup_device (BluetoothClient *client,
3943+ const char *path,
3944+ gboolean pair,
3945+ GCancellable *cancellable,
3946+ GAsyncReadyCallback callback,
3947+ gpointer user_data);
3948+gboolean bluetooth_client_setup_device_finish (BluetoothClient *client,
3949+ GAsyncResult *res,
3950+ char **path,
3951+ GError **error);
3952+
3953+gboolean bluetooth_client_set_trusted(BluetoothClient *client,
3954+ const char *device, gboolean trusted);
3955+
3956+GDBusProxy *bluetooth_client_get_device (BluetoothClient *client,
3957+ const char *path);
3958+
3959+void bluetooth_client_dump_device (GtkTreeModel *model,
3960+ GtkTreeIter *iter);
3961+
3962+gboolean bluetooth_client_get_connectable(const char **uuids);
3963+
3964+G_END_DECLS
3965+
3966+#endif /* __BLUETOOTH_CLIENT_PRIVATE_H */
3967
3968=== added file 'panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.c'
3969--- panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.c 1970-01-01 00:00:00 +0000
3970+++ panels/bluetooth/gnome-bluetooth/lib/bluetooth-client.c 2015-08-12 15:47:27 +0000
3971@@ -0,0 +1,1757 @@
3972+/*
3973+ *
3974+ * BlueZ - Bluetooth protocol stack for Linux
3975+ *
3976+ * Copyright (C) 2005-2008 Marcel Holtmann <marcel@holtmann.org>
3977+ * Copyright (C) 2010 Giovanni Campagna <scampa.giovanni@gmail.com>
3978+ * Copyright (C) 2013 Intel Corporation.
3979+ *
3980+ *
3981+ * This library is free software; you can redistribute it and/or
3982+ * modify it under the terms of the GNU Lesser General Public
3983+ * License as published by the Free Software Foundation; either
3984+ * version 2.1 of the License, or (at your option) any later version.
3985+ *
3986+ * This library is distributed in the hope that it will be useful,
3987+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3988+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3989+ * Lesser General Public License for more details.
3990+ *
3991+ * You should have received a copy of the GNU Lesser General Public
3992+ * License along with this library; if not, write to the Free Software
3993+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3994+ *
3995+ */
3996+
3997+/**
3998+ * SECTION:bluetooth-client
3999+ * @short_description: Bluetooth client object
4000+ * @stability: Stable
4001+ * @include: bluetooth-client.h
4002+ *
4003+ * The #BluetoothClient object is used to query the state of Bluetooth
4004+ * devices and adapters.
4005+ **/
4006+
4007+#ifdef HAVE_CONFIG_H
4008+#include <config.h>
4009+#endif
4010+
4011+#include <string.h>
4012+#include <glib/gi18n-lib.h>
4013+#include <gtk/gtk.h>
4014+
4015+#include "bluetooth-client.h"
4016+#include "bluetooth-client-private.h"
4017+#include "bluetooth-client-glue.h"
4018+#include "bluetooth-fdo-glue.h"
4019+#include "bluetooth-utils.h"
4020+#include "gnome-bluetooth-enum-types.h"
4021+
4022+#define BLUEZ_SERVICE "org.bluez"
4023+#define BLUEZ_MANAGER_PATH "/"
4024+#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
4025+#define BLUEZ_DEVICE_INTERFACE "org.bluez.Device1"
4026+#define FDO_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
4027+
4028+#define BLUETOOTH_CLIENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
4029+ BLUETOOTH_TYPE_CLIENT, BluetoothClientPrivate))
4030+
4031+typedef struct _BluetoothClientPrivate BluetoothClientPrivate;
4032+
4033+struct _BluetoothClientPrivate {
4034+ guint owner_change_id;
4035+ ObjectManager *manager;
4036+ GtkTreeStore *store;
4037+ GtkTreeRowReference *default_adapter;
4038+};
4039+
4040+enum {
4041+ PROP_0,
4042+ PROP_DEFAULT_ADAPTER,
4043+ PROP_DEFAULT_ADAPTER_POWERED,
4044+ PROP_DEFAULT_ADAPTER_DISCOVERABLE,
4045+ PROP_DEFAULT_ADAPTER_NAME,
4046+ PROP_DEFAULT_ADAPTER_DISCOVERING
4047+};
4048+
4049+enum {
4050+ DEVICE_REMOVED,
4051+ LAST_SIGNAL
4052+};
4053+
4054+static guint signals[LAST_SIGNAL] = { 0 };
4055+
4056+static const char *connectable_uuids[] = {
4057+ "HSP",
4058+ "AudioSource",
4059+ "AudioSink",
4060+ "A/V_RemoteControlTarget",
4061+ "A/V_RemoteControl",
4062+ "Headset_-_AG",
4063+ "Handsfree",
4064+ "HandsfreeAudioGateway",
4065+ "HumanInterfaceDeviceService",
4066+};
4067+
4068+G_DEFINE_TYPE(BluetoothClient, bluetooth_client, G_TYPE_OBJECT)
4069+
4070+typedef gboolean (*IterSearchFunc) (GtkTreeStore *store,
4071+ GtkTreeIter *iter, gpointer user_data);
4072+
4073+static gboolean iter_search(GtkTreeStore *store,
4074+ GtkTreeIter *iter, GtkTreeIter *parent,
4075+ IterSearchFunc func, gpointer user_data)
4076+{
4077+ gboolean cont, found = FALSE;
4078+
4079+ if (parent == NULL)
4080+ cont = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store),
4081+ iter);
4082+ else
4083+ cont = gtk_tree_model_iter_children(GTK_TREE_MODEL(store),
4084+ iter, parent);
4085+
4086+ while (cont == TRUE) {
4087+ GtkTreeIter child;
4088+
4089+ found = func(store, iter, user_data);
4090+ if (found == TRUE)
4091+ break;
4092+
4093+ found = iter_search(store, &child, iter, func, user_data);
4094+ if (found == TRUE) {
4095+ *iter = child;
4096+ break;
4097+ }
4098+
4099+ cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter);
4100+ }
4101+
4102+ return found;
4103+}
4104+
4105+static gboolean compare_path(GtkTreeStore *store,
4106+ GtkTreeIter *iter, gpointer user_data)
4107+{
4108+ const gchar *path = user_data;
4109+ GDBusProxy *object;
4110+ gboolean found = FALSE;
4111+
4112+ gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
4113+ BLUETOOTH_COLUMN_PROXY, &object, -1);
4114+
4115+ if (object != NULL) {
4116+ found = g_str_equal(path, g_dbus_proxy_get_object_path(object));
4117+ g_object_unref(object);
4118+ }
4119+
4120+ return found;
4121+}
4122+
4123+static gboolean
4124+compare_address (GtkTreeStore *store,
4125+ GtkTreeIter *iter,
4126+ gpointer user_data)
4127+{
4128+ const char *address = user_data;
4129+ char *tmp_address;
4130+ gboolean found = FALSE;
4131+
4132+ gtk_tree_model_get (GTK_TREE_MODEL(store), iter,
4133+ BLUETOOTH_COLUMN_ADDRESS, &tmp_address, -1);
4134+ found = g_str_equal (address, tmp_address);
4135+ g_free (tmp_address);
4136+
4137+ return found;
4138+}
4139+
4140+static gboolean
4141+get_iter_from_path (GtkTreeStore *store,
4142+ GtkTreeIter *iter,
4143+ const char *path)
4144+{
4145+ return iter_search(store, iter, NULL, compare_path, (gpointer) path);
4146+}
4147+
4148+static gboolean
4149+get_iter_from_proxy(GtkTreeStore *store,
4150+ GtkTreeIter *iter,
4151+ GDBusProxy *proxy)
4152+{
4153+ return iter_search(store, iter, NULL, compare_path,
4154+ (gpointer) g_dbus_proxy_get_object_path (proxy));
4155+}
4156+
4157+static gboolean
4158+get_iter_from_address (GtkTreeStore *store,
4159+ GtkTreeIter *iter,
4160+ const char *address,
4161+ GDBusProxy *adapter)
4162+{
4163+ GtkTreeIter parent_iter;
4164+
4165+ if (get_iter_from_proxy (store, &parent_iter, adapter) == FALSE)
4166+ return FALSE;
4167+
4168+ return iter_search (store, iter, &parent_iter, compare_address, (gpointer) address);
4169+}
4170+
4171+static char **
4172+device_list_uuids (GVariant *variant)
4173+{
4174+ GPtrArray *ret;
4175+ const char **uuids;
4176+ guint i;
4177+
4178+ if (variant == NULL)
4179+ return NULL;
4180+
4181+ uuids = g_variant_get_strv (variant, NULL);
4182+ if (uuids == NULL)
4183+ return NULL;
4184+
4185+ ret = g_ptr_array_new ();
4186+
4187+ for (i = 0; uuids[i] != NULL; i++) {
4188+ const char *uuid;
4189+
4190+ uuid = bluetooth_uuid_to_string (uuids[i]);
4191+ if (uuid == NULL)
4192+ continue;
4193+ g_ptr_array_add (ret, g_strdup (uuid));
4194+ }
4195+ g_free (uuids);
4196+
4197+ if (ret->len == 0) {
4198+ g_ptr_array_free (ret, TRUE);
4199+ return NULL;
4200+ }
4201+
4202+ g_ptr_array_add (ret, NULL);
4203+
4204+ return (char **) g_ptr_array_free (ret, FALSE);
4205+}
4206+
4207+gboolean
4208+bluetooth_client_get_connectable(const char **uuids)
4209+{
4210+ int i, j;
4211+
4212+ for (i = 0; uuids && uuids[i] != NULL; i++) {
4213+ for (j = 0; j < G_N_ELEMENTS (connectable_uuids); j++) {
4214+ if (g_str_equal (connectable_uuids[j], uuids[i]))
4215+ return TRUE;
4216+ }
4217+ }
4218+
4219+ return FALSE;
4220+}
4221+
4222+static void
4223+device_g_properties_changed (GDBusProxy *device,
4224+ GVariant *changed_p,
4225+ GStrv invalidated_p,
4226+ BluetoothClient *client)
4227+{
4228+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4229+ GVariantIter i;
4230+ const char *property;
4231+ GtkTreeIter iter;
4232+ GVariant *v;
4233+
4234+ if (get_iter_from_proxy (priv->store, &iter, device) == FALSE)
4235+ return;
4236+
4237+ g_variant_iter_init (&i, changed_p);
4238+ while (g_variant_iter_next (&i, "{&sv}", &property, &v)) {
4239+
4240+ if (g_str_equal (property, "Name") == TRUE) {
4241+ const gchar *name = g_variant_get_string (v, NULL);
4242+
4243+ gtk_tree_store_set (priv->store, &iter,
4244+ BLUETOOTH_COLUMN_NAME, name, -1);
4245+ } else if (g_str_equal (property, "Alias") == TRUE) {
4246+ const gchar *alias = g_variant_get_string (v, NULL);
4247+
4248+ gtk_tree_store_set (priv->store, &iter,
4249+ BLUETOOTH_COLUMN_ALIAS, alias, -1);
4250+ } else if (g_str_equal (property, "Icon") == TRUE) {
4251+ const gchar *icon = g_variant_get_string (v, NULL);
4252+
4253+ gtk_tree_store_set (priv->store, &iter,
4254+ BLUETOOTH_COLUMN_ICON, icon, -1);
4255+ } else if (g_str_equal (property, "Paired") == TRUE) {
4256+ gboolean paired = g_variant_get_boolean (v);
4257+
4258+ gtk_tree_store_set (priv->store, &iter,
4259+ BLUETOOTH_COLUMN_PAIRED, paired, -1);
4260+ } else if (g_str_equal (property, "Trusted") == TRUE) {
4261+ gboolean trusted = g_variant_get_boolean (v);
4262+
4263+ gtk_tree_store_set (priv->store, &iter,
4264+ BLUETOOTH_COLUMN_TRUSTED, trusted, -1);
4265+ } else if (g_str_equal (property, "Connected") == TRUE) {
4266+ gboolean connected = g_variant_get_boolean (v);
4267+
4268+ gtk_tree_store_set (priv->store, &iter,
4269+ BLUETOOTH_COLUMN_CONNECTED, connected, -1);
4270+ } else if (g_str_equal (property, "UUIDs") == TRUE) {
4271+ char **uuids;
4272+
4273+ uuids = device_list_uuids (v);
4274+ gtk_tree_store_set (priv->store, &iter,
4275+ BLUETOOTH_COLUMN_UUIDS, uuids, -1);
4276+ g_strfreev (uuids);
4277+ } else if (g_str_equal (property, "LegacyPairing") == TRUE) {
4278+ gboolean legacypairing;
4279+
4280+ legacypairing = g_variant_get_boolean (v);
4281+ gtk_tree_store_set (priv->store, &iter,
4282+ BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
4283+ -1);
4284+ } else if (g_str_equal (property, "Class") == TRUE) {
4285+ BluetoothType type;
4286+
4287+ type = v ? bluetooth_class_to_type (g_variant_get_uint32 (v)) : BLUETOOTH_TYPE_ANY;
4288+ gtk_tree_store_set (priv->store, &iter,
4289+ BLUETOOTH_COLUMN_TYPE, type,
4290+ -1);
4291+ } else {
4292+ g_debug ("Unhandled property: %s", property);
4293+ }
4294+
4295+ g_variant_unref (v);
4296+ }
4297+}
4298+
4299+static void
4300+device_added (ObjectManager *manager,
4301+ BluetoothClient *client,
4302+ const char *path,
4303+ GVariant *variant)
4304+{
4305+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4306+ GDBusProxy *adapter;
4307+ Device1 *device;
4308+ Properties *properties;
4309+ GVariant *v, *dict;
4310+ const char *adapter_path, *address, *alias, *name, *icon;
4311+ char **uuids;
4312+ gboolean paired, trusted, connected;
4313+ int legacypairing;
4314+ BluetoothType type;
4315+ GtkTreeIter iter, parent;
4316+
4317+ device = device1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
4318+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
4319+ BLUEZ_SERVICE,
4320+ path,
4321+ NULL,
4322+ NULL);
4323+ if (device == NULL)
4324+ return;
4325+
4326+ properties = properties_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
4327+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
4328+ BLUEZ_SERVICE,
4329+ path,
4330+ NULL,
4331+ NULL);
4332+
4333+ dict = g_variant_lookup_value (variant, BLUEZ_DEVICE_INTERFACE,
4334+ G_VARIANT_TYPE_DICTIONARY);
4335+
4336+ v = g_variant_lookup_value (dict, "Adapter", G_VARIANT_TYPE_OBJECT_PATH);
4337+ adapter_path = v ? g_variant_get_string (v, NULL) : NULL;
4338+
4339+ v = g_variant_lookup_value (dict, "Address", G_VARIANT_TYPE_STRING);
4340+ address = v ? g_variant_get_string (v, NULL) : NULL;
4341+
4342+ v = g_variant_lookup_value (dict, "Alias", G_VARIANT_TYPE_STRING);
4343+ alias = v ? g_variant_get_string (v, NULL) : NULL;
4344+
4345+ v = g_variant_lookup_value (dict, "Name", G_VARIANT_TYPE_STRING);
4346+ name = v ? g_variant_get_string (v, NULL) : NULL;
4347+
4348+ v = g_variant_lookup_value (dict, "Class", G_VARIANT_TYPE_UINT32);
4349+ type = v ? bluetooth_class_to_type (g_variant_get_uint32 (v)) : BLUETOOTH_TYPE_ANY;
4350+
4351+ v = g_variant_lookup_value (dict, "Icon", G_VARIANT_TYPE_STRING);
4352+ icon = v ? g_variant_get_string (v, NULL) : "bluetooth";
4353+
4354+ v = g_variant_lookup_value (dict, "Paired", G_VARIANT_TYPE_BOOLEAN);
4355+ paired = v ? g_variant_get_boolean (v) : FALSE;
4356+
4357+ v = g_variant_lookup_value (dict, "Trusted", G_VARIANT_TYPE_BOOLEAN);
4358+ trusted = v ? g_variant_get_boolean (v) : FALSE;
4359+
4360+ v = g_variant_lookup_value (dict, "Connected", G_VARIANT_TYPE_BOOLEAN);
4361+ connected = v ? g_variant_get_boolean (v) : FALSE;
4362+
4363+ v = g_variant_lookup_value (dict, "UUIDs", G_VARIANT_TYPE_STRING_ARRAY);
4364+ uuids = device_list_uuids (v);
4365+
4366+ v = g_variant_lookup_value (dict, "LegacyPairing", G_VARIANT_TYPE_BOOLEAN);
4367+ legacypairing = v ? g_variant_get_boolean (v) : -1;
4368+
4369+ if (get_iter_from_path (priv->store, &parent, adapter_path) == FALSE) {
4370+ g_object_unref (device);
4371+ return;
4372+ }
4373+
4374+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &parent,
4375+ BLUETOOTH_COLUMN_PROXY, &adapter, -1);
4376+
4377+ if (get_iter_from_address (priv->store, &iter, address, adapter) == FALSE) {
4378+ gtk_tree_store_insert_with_values (priv->store, &iter, &parent, -1,
4379+ BLUETOOTH_COLUMN_ADDRESS, address,
4380+ BLUETOOTH_COLUMN_ALIAS, alias,
4381+ BLUETOOTH_COLUMN_NAME, name,
4382+ BLUETOOTH_COLUMN_TYPE, type,
4383+ BLUETOOTH_COLUMN_ICON, icon,
4384+ BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
4385+ BLUETOOTH_COLUMN_UUIDS, uuids,
4386+ BLUETOOTH_COLUMN_PAIRED, paired,
4387+ BLUETOOTH_COLUMN_CONNECTED, connected,
4388+ BLUETOOTH_COLUMN_TRUSTED, trusted,
4389+ BLUETOOTH_COLUMN_PROXY, device,
4390+ BLUETOOTH_COLUMN_PROPERTIES, properties,
4391+ -1);
4392+ } else {
4393+ gtk_tree_store_set(priv->store, &iter,
4394+ BLUETOOTH_COLUMN_ADDRESS, address,
4395+ BLUETOOTH_COLUMN_ALIAS, alias,
4396+ BLUETOOTH_COLUMN_NAME, name,
4397+ BLUETOOTH_COLUMN_TYPE, type,
4398+ BLUETOOTH_COLUMN_ICON, icon,
4399+ BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
4400+ BLUETOOTH_COLUMN_UUIDS, uuids,
4401+ BLUETOOTH_COLUMN_PAIRED, paired,
4402+ BLUETOOTH_COLUMN_CONNECTED, connected,
4403+ BLUETOOTH_COLUMN_TRUSTED, trusted,
4404+ BLUETOOTH_COLUMN_PROXY, device,
4405+ BLUETOOTH_COLUMN_PROPERTIES, properties,
4406+ -1);
4407+ }
4408+ g_strfreev (uuids);
4409+
4410+ g_signal_connect (G_OBJECT (device), "g-properties-changed",
4411+ G_CALLBACK (device_g_properties_changed), client);
4412+
4413+ g_object_unref (properties);
4414+ g_object_unref (device);
4415+ g_object_unref (adapter);
4416+}
4417+
4418+static void
4419+device_removed (const char *path,
4420+ BluetoothClient *client)
4421+{
4422+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4423+ GtkTreeIter iter;
4424+
4425+ if (get_iter_from_path(priv->store, &iter, path) == TRUE) {
4426+ g_signal_emit (G_OBJECT (client), signals[DEVICE_REMOVED], 0, path);
4427+ gtk_tree_store_remove(priv->store, &iter);
4428+ }
4429+}
4430+
4431+static void
4432+powered_callback (GDBusProxy *proxy,
4433+ GAsyncResult *res,
4434+ gpointer data)
4435+{
4436+ GError *error = NULL;
4437+
4438+ if (!properties_call_set_finish (PROPERTIES(proxy), res, &error)) {
4439+ g_debug ("Call to Set Powered failed %s: %s",
4440+ g_dbus_proxy_get_object_path (proxy), error->message);
4441+ g_error_free (error);
4442+ }
4443+
4444+ g_object_unref (proxy);
4445+}
4446+
4447+static gboolean
4448+adapter_set_powered (BluetoothClient *client,
4449+ const char *path,
4450+ gboolean powered)
4451+{
4452+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4453+ Properties *properties;
4454+ GtkTreeIter iter;
4455+
4456+ g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE);
4457+
4458+ if (get_iter_from_path (priv->store, &iter, path) == FALSE)
4459+ return FALSE;
4460+
4461+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
4462+ BLUETOOTH_COLUMN_PROPERTIES, &properties, -1);
4463+
4464+ if (properties == NULL)
4465+ return FALSE;
4466+
4467+
4468+ properties_call_set (properties,
4469+ BLUEZ_ADAPTER_INTERFACE,
4470+ "Powered",
4471+ g_variant_new_variant (g_variant_new_boolean (powered)),
4472+ NULL,
4473+ (GAsyncReadyCallback) powered_callback,
4474+ NULL);
4475+
4476+ return TRUE;
4477+}
4478+
4479+static void
4480+default_adapter_changed (ObjectManager *manager,
4481+ const char *path,
4482+ BluetoothClient *client)
4483+{
4484+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4485+ GtkTreeIter iter;
4486+ GtkTreePath *tree_path;
4487+ gboolean powered;
4488+
4489+ g_assert (!priv->default_adapter);
4490+
4491+ if (get_iter_from_path (priv->store, &iter, path) == FALSE)
4492+ return;
4493+
4494+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
4495+ priv->default_adapter = gtk_tree_row_reference_new (GTK_TREE_MODEL (priv->store), tree_path);
4496+ gtk_tree_path_free (tree_path);
4497+
4498+ gtk_tree_store_set (priv->store, &iter,
4499+ BLUETOOTH_COLUMN_DEFAULT, TRUE, -1);
4500+
4501+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
4502+ BLUETOOTH_COLUMN_POWERED, &powered, -1);
4503+
4504+ if (powered) {
4505+ g_object_notify (G_OBJECT (client), "default-adapter");
4506+ g_object_notify (G_OBJECT (client), "default-adapter-powered");
4507+ g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
4508+ g_object_notify (G_OBJECT (client), "default-adapter-discovering");
4509+ g_object_notify (G_OBJECT (client), "default-adapter-name");
4510+ return;
4511+ }
4512+
4513+ /*
4514+ * If the adapter is turn off (Powered = False in bluetooth) object
4515+ * notifications will be sent only when a Powered = True signal arrives
4516+ * from bluetoothd
4517+ */
4518+ adapter_set_powered (client, path, TRUE);
4519+}
4520+
4521+static void
4522+adapter_g_properties_changed (GDBusProxy *adapter,
4523+ GVariant *changed_p,
4524+ GStrv invalidated_p,
4525+ BluetoothClient *client)
4526+{
4527+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4528+ GVariantIter i;
4529+ const char *property;
4530+ GtkTreeIter iter;
4531+ GVariant *v;
4532+ gboolean notify = FALSE;
4533+
4534+ if (get_iter_from_proxy (priv->store, &iter, adapter) == FALSE)
4535+ return;
4536+
4537+ g_variant_iter_init (&i, changed_p);
4538+ while (g_variant_iter_next (&i, "{&sv}", &property, &v)) {
4539+ if (g_str_equal (property, "Name") == TRUE) {
4540+ const gchar *name = g_variant_get_string (v, NULL);
4541+ gboolean is_default;
4542+
4543+ gtk_tree_store_set (priv->store, &iter,
4544+ BLUETOOTH_COLUMN_NAME, name, -1);
4545+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
4546+ BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
4547+ if (is_default != FALSE) {
4548+ g_object_notify (G_OBJECT (client), "default-adapter-powered");
4549+ g_object_notify (G_OBJECT (client), "default-adapter-name");
4550+ }
4551+ notify = TRUE;
4552+ } else if (g_str_equal (property, "Discovering") == TRUE) {
4553+ gboolean discovering = g_variant_get_boolean (v);
4554+ gboolean is_default;
4555+
4556+ gtk_tree_store_set (priv->store, &iter,
4557+ BLUETOOTH_COLUMN_DISCOVERING, discovering, -1);
4558+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
4559+ BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
4560+ if (is_default != FALSE)
4561+ g_object_notify (G_OBJECT (client), "default-adapter-discovering");
4562+ notify = TRUE;
4563+ } else if (g_str_equal (property, "Powered") == TRUE) {
4564+ gboolean powered = g_variant_get_boolean (v);
4565+ gboolean is_default;
4566+
4567+ gtk_tree_store_set (priv->store, &iter,
4568+ BLUETOOTH_COLUMN_POWERED, powered, -1);
4569+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
4570+ BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
4571+ if (is_default != FALSE && powered) {
4572+ g_object_notify (G_OBJECT (client), "default-adapter");
4573+ g_object_notify (G_OBJECT (client), "default-adapter-powered");
4574+ g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
4575+ g_object_notify (G_OBJECT (client), "default-adapter-discovering");
4576+ g_object_notify (G_OBJECT (client), "default-adapter-name");
4577+ }
4578+ notify = TRUE;
4579+ } else if (g_str_equal (property, "Discoverable") == TRUE) {
4580+ gboolean discoverable = g_variant_get_boolean (v);
4581+ gboolean is_default;
4582+
4583+ gtk_tree_store_set (priv->store, &iter,
4584+ BLUETOOTH_COLUMN_DISCOVERABLE, discoverable, -1);
4585+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
4586+ BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
4587+ if (is_default != FALSE)
4588+ g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
4589+ notify = TRUE;
4590+ }
4591+
4592+ if (notify != FALSE) {
4593+ GtkTreePath *path;
4594+
4595+ /* Tell the world */
4596+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
4597+ gtk_tree_model_row_changed (GTK_TREE_MODEL (priv->store), path, &iter);
4598+ gtk_tree_path_free (path);
4599+ }
4600+ g_variant_unref (v);
4601+ }
4602+}
4603+
4604+static void
4605+adapter_added (ObjectManager *manager,
4606+ const char *path,
4607+ GVariant *variant,
4608+ BluetoothClient *client)
4609+{
4610+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4611+ GtkTreeIter iter;
4612+ Adapter1 *adapter;
4613+ Properties *properties;
4614+ const gchar *address, *name;
4615+ GVariant *v, *dict;
4616+ gboolean discovering, discoverable, powered;
4617+
4618+ adapter = adapter1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
4619+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
4620+ BLUEZ_SERVICE,
4621+ path,
4622+ NULL,
4623+ NULL);
4624+
4625+ properties = properties_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
4626+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
4627+ BLUEZ_SERVICE,
4628+ path,
4629+ NULL,
4630+ NULL);
4631+
4632+ dict = g_variant_lookup_value (variant, BLUEZ_ADAPTER_INTERFACE,
4633+ G_VARIANT_TYPE_DICTIONARY);
4634+
4635+ v = g_variant_lookup_value (dict, "Address", G_VARIANT_TYPE_STRING);
4636+ address = v ? g_variant_get_string (v, NULL) : NULL;
4637+
4638+ v = g_variant_lookup_value (dict, "Name", G_VARIANT_TYPE_STRING);
4639+ name = v ? g_variant_get_string (v, NULL) : NULL;
4640+
4641+ v = g_variant_lookup_value (dict, "Discovering", G_VARIANT_TYPE_BOOLEAN);
4642+ discovering = v ? g_variant_get_boolean (v) : FALSE;
4643+
4644+ v = g_variant_lookup_value (dict, "Powered", G_VARIANT_TYPE_BOOLEAN);
4645+ powered = v ? g_variant_get_boolean (v) : FALSE;
4646+
4647+ v = g_variant_lookup_value (dict, "Discoverable", G_VARIANT_TYPE_BOOLEAN);
4648+ discoverable = v ? g_variant_get_boolean (v) : FALSE;
4649+
4650+ gtk_tree_store_insert_with_values(priv->store, &iter, NULL, -1,
4651+ BLUETOOTH_COLUMN_PROXY, adapter,
4652+ BLUETOOTH_COLUMN_PROPERTIES, properties,
4653+ BLUETOOTH_COLUMN_ADDRESS, address,
4654+ BLUETOOTH_COLUMN_NAME, name,
4655+ BLUETOOTH_COLUMN_DISCOVERING, discovering,
4656+ BLUETOOTH_COLUMN_DISCOVERABLE, discoverable,
4657+ BLUETOOTH_COLUMN_POWERED, powered,
4658+ -1);
4659+
4660+ g_signal_connect (G_OBJECT (adapter), "g-properties-changed",
4661+ G_CALLBACK (adapter_g_properties_changed), client);
4662+
4663+ if (!priv->default_adapter)
4664+ default_adapter_changed (manager, path, client);
4665+
4666+ g_object_unref (properties);
4667+ g_object_unref (adapter);
4668+}
4669+
4670+static void
4671+adapter_removed (ObjectManager *manager,
4672+ const char *path,
4673+ BluetoothClient *client)
4674+{
4675+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4676+ GtkTreeIter iter;
4677+ gboolean was_default;
4678+
4679+ if (get_iter_from_path (priv->store, &iter, path) == FALSE)
4680+ return;
4681+
4682+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
4683+ BLUETOOTH_COLUMN_DEFAULT, &was_default, -1);
4684+
4685+ if (!was_default)
4686+ return;
4687+
4688+ g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free);
4689+ gtk_tree_store_remove (priv->store, &iter);
4690+
4691+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(priv->store),
4692+ &iter)) {
4693+ GDBusProxy *adapter;
4694+ const char *adapter_path;
4695+
4696+ gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
4697+ BLUETOOTH_COLUMN_PROXY, &adapter, -1);
4698+
4699+ adapter_path = g_dbus_proxy_get_object_path (adapter);
4700+ default_adapter_changed (manager, adapter_path, client);
4701+
4702+ g_object_unref(adapter);
4703+ } else {
4704+ g_object_notify (G_OBJECT (client), "default-adapter");
4705+ g_object_notify (G_OBJECT (client), "default-adapter-powered");
4706+ g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
4707+ g_object_notify (G_OBJECT (client), "default-adapter-discovering");
4708+ }
4709+}
4710+
4711+static void
4712+interface_added (BluetoothClient *client,
4713+ const char *path,
4714+ GVariant *variant)
4715+{
4716+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4717+
4718+ if (g_variant_lookup_value (variant, BLUEZ_ADAPTER_INTERFACE,
4719+ G_VARIANT_TYPE_DICTIONARY)) {
4720+ g_debug ("New Adapter interface added.");
4721+ adapter_added (priv->manager, path, variant, client);
4722+ return;
4723+ }
4724+
4725+ if (g_variant_lookup_value (variant, BLUEZ_DEVICE_INTERFACE,
4726+ G_VARIANT_TYPE_DICTIONARY)) {
4727+ g_debug ("New Device interface added.");
4728+ device_added (priv->manager, client, path, variant);
4729+ return;
4730+ }
4731+}
4732+
4733+static void
4734+interface_removed (BluetoothClient *client,
4735+ const char *path,
4736+ GVariant *variant)
4737+{
4738+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4739+ const char **ifaces;
4740+ int i;
4741+
4742+ ifaces = g_variant_get_strv (variant, NULL);
4743+
4744+ for (i = 0 ; ifaces[i] != NULL ; i++) {
4745+ if (g_strcmp0(ifaces[i], BLUEZ_ADAPTER_INTERFACE) == 0) {
4746+ adapter_removed(priv->manager, path, client);
4747+ return;
4748+ }
4749+
4750+ if (g_strcmp0(ifaces[i], BLUEZ_DEVICE_INTERFACE) == 0) {
4751+ device_removed (path, client);
4752+ return;
4753+ }
4754+ }
4755+}
4756+
4757+static void
4758+object_manager_g_signal (GDBusProxy *proxy,
4759+ gchar *sender_name,
4760+ gchar *signal_name,
4761+ GVariant *parameters,
4762+ BluetoothClient *client)
4763+{
4764+ char *object_path;
4765+ GVariant *variant;
4766+
4767+ g_variant_get (parameters, "(o*)", &object_path, &variant);
4768+
4769+ if (g_strcmp0 (signal_name, "InterfacesAdded") == 0) {
4770+ interface_added (client, object_path, variant);
4771+ } else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0) {
4772+ interface_removed (client, object_path, variant);
4773+ } else {
4774+ g_assert_not_reached ();
4775+ }
4776+
4777+ g_free (object_path);
4778+}
4779+
4780+static void
4781+bluez_appeared_cb (GDBusConnection *connection,
4782+ const gchar *name,
4783+ const gchar *name_owner,
4784+ BluetoothClient *client)
4785+{
4786+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4787+ GVariantIter iter;
4788+ GVariant *variant, *v, *ifaces;
4789+ char *key;
4790+
4791+ priv->manager = object_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
4792+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
4793+ BLUEZ_SERVICE,
4794+ BLUEZ_MANAGER_PATH,
4795+ NULL,
4796+ NULL);
4797+
4798+ g_signal_connect (G_OBJECT (priv->manager), "g-signal",
4799+ G_CALLBACK (object_manager_g_signal), client);
4800+
4801+ variant = NULL;
4802+ object_manager_call_get_managed_objects_sync (OBJECT_MANAGER (priv->manager),
4803+ &variant, NULL, NULL);
4804+ if (variant == NULL)
4805+ return;
4806+
4807+ g_variant_iter_init (&iter, variant);
4808+ while ((v = g_variant_iter_next_value (&iter))) {
4809+ g_variant_get (v, "{o*}", &key, &ifaces);
4810+ interface_added (client, key, ifaces);
4811+ }
4812+
4813+ g_variant_unref (variant);
4814+}
4815+
4816+static void
4817+bluez_vanished_cb (GDBusConnection *connection,
4818+ const gchar *name,
4819+ BluetoothClient *client)
4820+{
4821+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4822+
4823+ g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free);
4824+
4825+ gtk_tree_store_clear (priv->store);
4826+
4827+ g_clear_object (&priv->manager);
4828+}
4829+
4830+static void bluetooth_client_init(BluetoothClient *client)
4831+{
4832+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4833+
4834+ priv->store = gtk_tree_store_new(_BLUETOOTH_NUM_COLUMNS, G_TYPE_OBJECT,
4835+ G_TYPE_OBJECT, G_TYPE_STRING,
4836+ G_TYPE_STRING, G_TYPE_STRING,
4837+ G_TYPE_UINT, G_TYPE_STRING,
4838+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
4839+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_INT,
4840+ G_TYPE_BOOLEAN, G_TYPE_HASH_TABLE, G_TYPE_STRV);
4841+
4842+ priv->owner_change_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
4843+ BLUEZ_SERVICE,
4844+ G_BUS_NAME_WATCHER_FLAGS_NONE,
4845+ (GBusNameAppearedCallback) bluez_appeared_cb,
4846+ (GBusNameVanishedCallback) bluez_vanished_cb,
4847+ client, NULL);
4848+}
4849+
4850+static GDBusProxy *
4851+_bluetooth_client_get_default_adapter(BluetoothClient *client)
4852+{
4853+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
4854+ GtkTreePath *path;
4855+ GtkTreeIter iter;
4856+ GDBusProxy *adapter;
4857+
4858+ g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), NULL);
4859+
4860+ if (priv->default_adapter == NULL)
4861+ return NULL;
4862+
4863+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
4864+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
4865+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
4866+ BLUETOOTH_COLUMN_PROXY, &adapter, -1);
4867+ gtk_tree_path_free (path);
4868+
4869+ return adapter;
4870+}
4871+
4872+static const char*
4873+_bluetooth_client_get_default_adapter_path (BluetoothClient *self)
4874+{
4875+ GDBusProxy *adapter = _bluetooth_client_get_default_adapter (self);
4876+
4877+ if (adapter != NULL) {
4878+ const char *ret = g_dbus_proxy_get_object_path (adapter);
4879+ g_object_unref (adapter);
4880+ return ret;
4881+ }
4882+ return NULL;
4883+}
4884+
4885+static gboolean
4886+_bluetooth_client_get_default_adapter_powered (BluetoothClient *self)
4887+{
4888+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (self);
4889+ GtkTreePath *path;
4890+ GtkTreeIter iter;
4891+ gboolean ret;
4892+
4893+ if (priv->default_adapter == NULL)
4894+ return FALSE;
4895+
4896+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
4897+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
4898+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, BLUETOOTH_COLUMN_POWERED, &ret, -1);
4899+ gtk_tree_path_free (path);
4900+
4901+ return ret;
4902+}
4903+
4904+static char *
4905+_bluetooth_client_get_default_adapter_name (BluetoothClient *self)
4906+{
4907+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (self);
4908+ GtkTreePath *path;
4909+ GtkTreeIter iter;
4910+ char *ret;
4911+
4912+ if (priv->default_adapter == NULL)
4913+ return NULL;
4914+
4915+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
4916+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
4917+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, BLUETOOTH_COLUMN_NAME, &ret, -1);
4918+ gtk_tree_path_free (path);
4919+
4920+ return ret;
4921+}
4922+
4923+/**
4924+ * _bluetooth_client_get_discoverable:
4925+ * @client: a #BluetoothClient
4926+ *
4927+ * Gets the default adapter's discoverable status, cached in the adapter model.
4928+ *
4929+ * Returns: the discoverable status, or FALSE if no default adapter exists
4930+ */
4931+static gboolean
4932+_bluetooth_client_get_discoverable (BluetoothClient *client)
4933+{
4934+ BluetoothClientPrivate *priv;
4935+ GtkTreePath *path;
4936+ GtkTreeIter iter;
4937+ gboolean ret;
4938+
4939+ g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE);
4940+
4941+ priv = BLUETOOTH_CLIENT_GET_PRIVATE (client);
4942+ if (priv->default_adapter == NULL)
4943+ return FALSE;
4944+
4945+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
4946+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
4947+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
4948+ BLUETOOTH_COLUMN_DISCOVERABLE, &ret, -1);
4949+
4950+ return ret;
4951+}
4952+
4953+/**
4954+ * _bluetooth_client_set_discoverable:
4955+ * @client: a #BluetoothClient object
4956+ * @discoverable: whether the device should be discoverable
4957+ * @timeout: timeout in seconds for making undiscoverable, or 0 for never
4958+ *
4959+ * Sets the default adapter's discoverable status.
4960+ *
4961+ * Return value: Whether setting the state on the default adapter was successful.
4962+ **/
4963+static gboolean
4964+_bluetooth_client_set_discoverable (BluetoothClient *client,
4965+ gboolean discoverable,
4966+ guint timeout)
4967+{
4968+ BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (client);
4969+ GError *error = NULL;
4970+ GtkTreePath *path;
4971+ Properties *properties;
4972+ gboolean ret;
4973+ GtkTreeIter iter;
4974+
4975+ g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE);
4976+
4977+ if (priv->default_adapter == NULL)
4978+ return FALSE;
4979+
4980+ path = gtk_tree_row_reference_get_path (priv->default_adapter);
4981+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
4982+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
4983+ BLUETOOTH_COLUMN_PROPERTIES, &properties, -1);
4984+ gtk_tree_path_free (path);
4985+
4986+ if (properties == NULL)
4987+ return FALSE;
4988+
4989+ ret = properties_call_set_sync (properties,
4990+ BLUEZ_ADAPTER_INTERFACE,
4991+ "Discoverable",
4992+ g_variant_new_variant (g_variant_new_boolean (discoverable)),
4993+ NULL, &error);
4994+ if (ret == FALSE) {
4995+ g_warning ("Failed to set Discoverable to %d: %s", discoverable, error->message);
4996+ g_error_free (error);
4997+ } else {
4998+ ret = properties_call_set_sync (properties,
4999+ BLUEZ_ADAPTER_INTERFACE,
5000+ "DiscoverableTimeout",
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches