~elementary-os/elementaryos/os-patch-gnome-bluetooth-bionic

« back to all changes in this revision

Viewing changes to lib/bluetooth-client.c

  • Committer: RabbitBot
  • Date: 2018-02-05 12:57:34 UTC
  • Revision ID: rabbitbot@elementary.io-20180205125734-a49s78k7asb5pokc
Initial import, version 3.26.1-3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *  BlueZ - Bluetooth protocol stack for Linux
 
4
 *
 
5
 *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
 
6
 *  Copyright (C) 2010       Giovanni Campagna <scampa.giovanni@gmail.com>
 
7
 *  Copyright (C) 2013       Intel Corporation.
 
8
 *
 
9
 *
 
10
 *  This library is free software; you can redistribute it and/or
 
11
 *  modify it under the terms of the GNU Lesser General Public
 
12
 *  License as published by the Free Software Foundation; either
 
13
 *  version 2.1 of the License, or (at your option) any later version.
 
14
 *
 
15
 *  This library is distributed in the hope that it will be useful,
 
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
 *  Lesser General Public License for more details.
 
19
 *
 
20
 *  You should have received a copy of the GNU Lesser General Public
 
21
 *  License along with this library; if not, write to the Free Software
 
22
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
23
 *
 
24
 */
 
25
 
 
26
/**
 
27
 * SECTION:bluetooth-client
 
28
 * @short_description: Bluetooth client object
 
29
 * @stability: Stable
 
30
 * @include: bluetooth-client.h
 
31
 *
 
32
 * The #BluetoothClient object is used to query the state of Bluetooth
 
33
 * devices and adapters.
 
34
 **/
 
35
 
 
36
#ifdef HAVE_CONFIG_H
 
37
#include <config.h>
 
38
#endif
 
39
 
 
40
#include <string.h>
 
41
#include <glib/gi18n-lib.h>
 
42
#include <gtk/gtk.h>
 
43
 
 
44
#include "bluetooth-client.h"
 
45
#include "bluetooth-client-private.h"
 
46
#include "bluetooth-client-glue.h"
 
47
#include "bluetooth-fdo-glue.h"
 
48
#include "bluetooth-utils.h"
 
49
#include "gnome-bluetooth-enum-types.h"
 
50
#include "pin.h"
 
51
 
 
52
#define BLUEZ_SERVICE                   "org.bluez"
 
53
#define BLUEZ_MANAGER_PATH              "/"
 
54
#define BLUEZ_ADAPTER_INTERFACE         "org.bluez.Adapter1"
 
55
#define BLUEZ_DEVICE_INTERFACE          "org.bluez.Device1"
 
56
#define FDO_PROPERTIES_INTERFACE        "org.freedesktop.DBus.Properties"
 
57
 
 
58
#define BLUETOOTH_CLIENT_GET_PRIVATE(obj) bluetooth_client_get_instance_private (obj)
 
59
 
 
60
typedef struct _BluetoothClientPrivate BluetoothClientPrivate;
 
61
 
 
62
struct _BluetoothClientPrivate {
 
63
        guint owner_change_id;
 
64
        ObjectManager *manager;
 
65
        GtkTreeStore *store;
 
66
        GtkTreeRowReference *default_adapter;
 
67
};
 
68
 
 
69
enum {
 
70
        PROP_0,
 
71
        PROP_DEFAULT_ADAPTER,
 
72
        PROP_DEFAULT_ADAPTER_POWERED,
 
73
        PROP_DEFAULT_ADAPTER_DISCOVERABLE,
 
74
        PROP_DEFAULT_ADAPTER_NAME,
 
75
        PROP_DEFAULT_ADAPTER_DISCOVERING
 
76
};
 
77
 
 
78
enum {
 
79
        DEVICE_REMOVED,
 
80
        LAST_SIGNAL
 
81
};
 
82
 
 
83
static guint signals[LAST_SIGNAL] = { 0 };
 
84
 
 
85
static const char *connectable_uuids[] = {
 
86
        "HSP",
 
87
        "AudioSource",
 
88
        "AudioSink",
 
89
        "A/V_RemoteControlTarget",
 
90
        "A/V_RemoteControl",
 
91
        "Headset_-_AG",
 
92
        "Handsfree",
 
93
        "HandsfreeAudioGateway",
 
94
        "HumanInterfaceDeviceService",
 
95
};
 
96
 
 
97
G_DEFINE_TYPE_WITH_PRIVATE(BluetoothClient, bluetooth_client, G_TYPE_OBJECT)
 
98
 
 
99
typedef gboolean (*IterSearchFunc) (GtkTreeStore *store,
 
100
                                GtkTreeIter *iter, gpointer user_data);
 
101
 
 
102
static gboolean iter_search(GtkTreeStore *store,
 
103
                                GtkTreeIter *iter, GtkTreeIter *parent,
 
104
                                IterSearchFunc func, gpointer user_data)
 
105
{
 
106
        gboolean cont, found = FALSE;
 
107
 
 
108
        if (parent == NULL)
 
109
                cont = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store),
 
110
                                                                        iter);
 
111
        else
 
112
                cont = gtk_tree_model_iter_children(GTK_TREE_MODEL(store),
 
113
                                                                iter, parent);
 
114
 
 
115
        while (cont == TRUE) {
 
116
                GtkTreeIter child;
 
117
 
 
118
                found = func(store, iter, user_data);
 
119
                if (found == TRUE)
 
120
                        break;
 
121
 
 
122
                found = iter_search(store, &child, iter, func, user_data);
 
123
                if (found == TRUE) {
 
124
                        *iter = child;
 
125
                        break;
 
126
                }
 
127
 
 
128
                cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter);
 
129
        }
 
130
 
 
131
        return found;
 
132
}
 
133
 
 
134
static gboolean compare_path(GtkTreeStore *store,
 
135
                                        GtkTreeIter *iter, gpointer user_data)
 
136
{
 
137
        const gchar *path = user_data;
 
138
        GDBusProxy *object;
 
139
        gboolean found = FALSE;
 
140
 
 
141
        gtk_tree_model_get(GTK_TREE_MODEL(store), iter,
 
142
                                        BLUETOOTH_COLUMN_PROXY, &object, -1);
 
143
 
 
144
        if (object != NULL) {
 
145
                found = g_str_equal(path, g_dbus_proxy_get_object_path(object));
 
146
                g_object_unref(object);
 
147
        }
 
148
 
 
149
        return found;
 
150
}
 
151
 
 
152
static gboolean
 
153
compare_address (GtkTreeStore *store,
 
154
                 GtkTreeIter *iter,
 
155
                 gpointer user_data)
 
156
{
 
157
        const char *address = user_data;
 
158
        char *tmp_address;
 
159
        gboolean found = FALSE;
 
160
 
 
161
        gtk_tree_model_get (GTK_TREE_MODEL(store), iter,
 
162
                            BLUETOOTH_COLUMN_ADDRESS, &tmp_address, -1);
 
163
        found = g_str_equal (address, tmp_address);
 
164
        g_free (tmp_address);
 
165
 
 
166
        return found;
 
167
}
 
168
 
 
169
static gboolean
 
170
get_iter_from_path (GtkTreeStore *store,
 
171
                    GtkTreeIter *iter,
 
172
                    const char *path)
 
173
{
 
174
        return iter_search(store, iter, NULL, compare_path, (gpointer) path);
 
175
}
 
176
 
 
177
static gboolean
 
178
get_iter_from_proxy(GtkTreeStore *store,
 
179
                    GtkTreeIter *iter,
 
180
                    GDBusProxy *proxy)
 
181
{
 
182
        return iter_search(store, iter, NULL, compare_path,
 
183
                           (gpointer) g_dbus_proxy_get_object_path (proxy));
 
184
}
 
185
 
 
186
static gboolean
 
187
get_iter_from_address (GtkTreeStore *store,
 
188
                       GtkTreeIter  *iter,
 
189
                       const char   *address,
 
190
                       GDBusProxy   *adapter)
 
191
{
 
192
        GtkTreeIter parent_iter;
 
193
 
 
194
        if (get_iter_from_proxy (store, &parent_iter, adapter) == FALSE)
 
195
                return FALSE;
 
196
 
 
197
        return iter_search (store, iter, &parent_iter, compare_address, (gpointer) address);
 
198
}
 
199
 
 
200
static char **
 
201
device_list_uuids (GVariant *variant)
 
202
{
 
203
        GPtrArray *ret;
 
204
        const char **uuids;
 
205
        guint i;
 
206
 
 
207
        if (variant == NULL)
 
208
                return NULL;
 
209
 
 
210
        uuids = g_variant_get_strv (variant, NULL);
 
211
        if (uuids == NULL)
 
212
                return NULL;
 
213
 
 
214
        ret = g_ptr_array_new ();
 
215
 
 
216
        for (i = 0; uuids[i] != NULL; i++) {
 
217
                const char *uuid;
 
218
 
 
219
                uuid = bluetooth_uuid_to_string (uuids[i]);
 
220
                if (uuid == NULL)
 
221
                        continue;
 
222
                g_ptr_array_add (ret, g_strdup (uuid));
 
223
        }
 
224
        g_free (uuids);
 
225
 
 
226
        if (ret->len == 0) {
 
227
                g_ptr_array_free (ret, TRUE);
 
228
                return NULL;
 
229
        }
 
230
 
 
231
        g_ptr_array_add (ret, NULL);
 
232
 
 
233
        return (char **) g_ptr_array_free (ret, FALSE);
 
234
}
 
235
 
 
236
gboolean
 
237
bluetooth_client_get_connectable(const char **uuids)
 
238
{
 
239
        int i, j;
 
240
 
 
241
        for (i = 0; uuids && uuids[i] != NULL; i++) {
 
242
                for (j = 0; j < G_N_ELEMENTS (connectable_uuids); j++) {
 
243
                        if (g_str_equal (connectable_uuids[j], uuids[i]))
 
244
                                return TRUE;
 
245
                }
 
246
        }
 
247
 
 
248
        return FALSE;
 
249
}
 
250
 
 
251
static const char *
 
252
phone_oui_to_icon_name (const char *bdaddr)
 
253
{
 
254
        char *vendor;
 
255
        const char *ret = NULL;
 
256
 
 
257
        vendor = oui_to_vendor (bdaddr);
 
258
        if (vendor == NULL)
 
259
                return NULL;
 
260
 
 
261
        if (strstr (vendor, "Apple") != NULL)
 
262
                ret = "phone-apple-iphone";
 
263
        else if (strstr (vendor, "Samsung") != NULL)
 
264
                ret = "phone-samsung-galaxy-s";
 
265
        else if (strstr (vendor, "Google") != NULL)
 
266
                ret = "phone-google-nexus-one";
 
267
        g_free (vendor);
 
268
 
 
269
        return ret;
 
270
}
 
271
 
 
272
static const char *
 
273
icon_override (const char    *bdaddr,
 
274
               BluetoothType  type)
 
275
{
 
276
        /* audio-card, you're ugly */
 
277
        switch (type) {
 
278
        case BLUETOOTH_TYPE_HEADSET:
 
279
                return "audio-headset";
 
280
        case BLUETOOTH_TYPE_HEADPHONES:
 
281
                return "audio-headphones";
 
282
        case BLUETOOTH_TYPE_OTHER_AUDIO:
 
283
                return "audio-speakers";
 
284
        case BLUETOOTH_TYPE_PHONE:
 
285
                return phone_oui_to_icon_name (bdaddr);
 
286
        case BLUETOOTH_TYPE_DISPLAY:
 
287
                return "video-display";
 
288
        case BLUETOOTH_TYPE_SCANNER:
 
289
                return "scanner";
 
290
        case BLUETOOTH_TYPE_REMOTE_CONTROL:
 
291
        case BLUETOOTH_TYPE_WEARABLE:
 
292
        case BLUETOOTH_TYPE_TOY:
 
293
                /* FIXME */
 
294
        default:
 
295
                return NULL;
 
296
        }
 
297
}
 
298
 
 
299
static void
 
300
device_g_properties_changed (GDBusProxy      *device,
 
301
                             GVariant        *changed_p,
 
302
                             GStrv            invalidated_p,
 
303
                             BluetoothClient *client)
 
304
{
 
305
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
306
        GVariantIter i;
 
307
        const char *property;
 
308
        GtkTreeIter iter;
 
309
        GVariant *v;
 
310
 
 
311
        if (get_iter_from_proxy (priv->store, &iter, device) == FALSE)
 
312
                return;
 
313
 
 
314
        g_variant_iter_init (&i, changed_p);
 
315
        while (g_variant_iter_next (&i, "{&sv}", &property, &v)) {
 
316
 
 
317
                if (g_str_equal (property, "Name") == TRUE) {
 
318
                        const gchar *name = g_variant_get_string (v, NULL);
 
319
 
 
320
                        gtk_tree_store_set (priv->store, &iter,
 
321
                                            BLUETOOTH_COLUMN_NAME, name, -1);
 
322
                } else if (g_str_equal (property, "Alias") == TRUE) {
 
323
                        const gchar *alias = g_variant_get_string (v, NULL);
 
324
 
 
325
                        gtk_tree_store_set (priv->store, &iter,
 
326
                                            BLUETOOTH_COLUMN_ALIAS, alias, -1);
 
327
                } else if (g_str_equal (property, "Icon") == TRUE) {
 
328
                        const gchar *icon = g_variant_get_string (v, NULL);
 
329
 
 
330
                        /* See "Class" handling below */
 
331
                        if (g_strcmp0 (icon, "audio-card") != 0) {
 
332
                                gtk_tree_store_set (priv->store, &iter,
 
333
                                                    BLUETOOTH_COLUMN_ICON, icon, -1);
 
334
                        }
 
335
                } else if (g_str_equal (property, "Paired") == TRUE) {
 
336
                        gboolean paired = g_variant_get_boolean (v);
 
337
 
 
338
                        gtk_tree_store_set (priv->store, &iter,
 
339
                                            BLUETOOTH_COLUMN_PAIRED, paired, -1);
 
340
                } else if (g_str_equal (property, "Trusted") == TRUE) {
 
341
                        gboolean trusted = g_variant_get_boolean (v);
 
342
 
 
343
                        gtk_tree_store_set (priv->store, &iter,
 
344
                                            BLUETOOTH_COLUMN_TRUSTED, trusted, -1);
 
345
                } else if (g_str_equal (property, "Connected") == TRUE) {
 
346
                        gboolean connected = g_variant_get_boolean (v);
 
347
 
 
348
                        gtk_tree_store_set (priv->store, &iter,
 
349
                                            BLUETOOTH_COLUMN_CONNECTED, connected, -1);
 
350
                } else if (g_str_equal (property, "UUIDs") == TRUE) {
 
351
                        char **uuids;
 
352
 
 
353
                        uuids = device_list_uuids (v);
 
354
                        gtk_tree_store_set (priv->store, &iter,
 
355
                                            BLUETOOTH_COLUMN_UUIDS, uuids, -1);
 
356
                        g_strfreev (uuids);
 
357
                } else if (g_str_equal (property, "LegacyPairing") == TRUE) {
 
358
                        gboolean legacypairing;
 
359
 
 
360
                        legacypairing = g_variant_get_boolean (v);
 
361
                        gtk_tree_store_set (priv->store, &iter,
 
362
                                            BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
 
363
                                            -1);
 
364
                } else if (g_str_equal (property, "Class") == TRUE) {
 
365
                        BluetoothType type;
 
366
                        const char *icon = NULL;
 
367
                        char *bdaddr;
 
368
 
 
369
                        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
 
370
                                            BLUETOOTH_COLUMN_ADDRESS, &bdaddr,
 
371
                                            -1);
 
372
 
 
373
                        type = v ? bluetooth_class_to_type (g_variant_get_uint32 (v)) : BLUETOOTH_TYPE_ANY;
 
374
                        icon = icon_override (bdaddr, type);
 
375
 
 
376
                        g_free (bdaddr);
 
377
 
 
378
                        if (icon) {
 
379
                                gtk_tree_store_set (priv->store, &iter,
 
380
                                                    BLUETOOTH_COLUMN_TYPE, type,
 
381
                                                    BLUETOOTH_COLUMN_ICON, icon,
 
382
                                                    -1);
 
383
                        } else {
 
384
                                gtk_tree_store_set (priv->store, &iter,
 
385
                                                    BLUETOOTH_COLUMN_TYPE, type,
 
386
                                                    -1);
 
387
                        }
 
388
                } else {
 
389
                        g_debug ("Unhandled property: %s", property);
 
390
                }
 
391
 
 
392
                g_variant_unref (v);
 
393
        }
 
394
}
 
395
 
 
396
static void
 
397
device_added (ObjectManager   *manager,
 
398
              BluetoothClient *client,
 
399
              const char      *path,
 
400
              GVariant        *variant)
 
401
{
 
402
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
403
        GDBusProxy *adapter;
 
404
        Device1 *device;
 
405
        Properties *properties;
 
406
        GVariant *v, *dict;
 
407
        const char *adapter_path, *address, *alias, *name, *icon;
 
408
        char **uuids;
 
409
        gboolean paired, trusted, connected;
 
410
        int legacypairing;
 
411
        BluetoothType type;
 
412
        GtkTreeIter iter, parent;
 
413
 
 
414
        device = device1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 
415
                                                 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 
416
                                                 BLUEZ_SERVICE,
 
417
                                                 path,
 
418
                                                 NULL,
 
419
                                                 NULL);
 
420
        if (device == NULL)
 
421
                return;
 
422
 
 
423
        properties = properties_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 
424
                                                        G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 
425
                                                        BLUEZ_SERVICE,
 
426
                                                        path,
 
427
                                                        NULL,
 
428
                                                        NULL);
 
429
 
 
430
        dict = g_variant_lookup_value (variant, BLUEZ_DEVICE_INTERFACE,
 
431
                                       G_VARIANT_TYPE_DICTIONARY);
 
432
 
 
433
        v = g_variant_lookup_value (dict, "Adapter", G_VARIANT_TYPE_OBJECT_PATH);
 
434
        adapter_path = v ? g_variant_get_string (v, NULL) : NULL;
 
435
 
 
436
        v = g_variant_lookup_value (dict, "Address", G_VARIANT_TYPE_STRING);
 
437
        address = v ? g_variant_get_string (v, NULL) : NULL;
 
438
 
 
439
        v = g_variant_lookup_value (dict, "Alias", G_VARIANT_TYPE_STRING);
 
440
        alias = v ? g_variant_get_string (v, NULL) : NULL;
 
441
 
 
442
        v = g_variant_lookup_value (dict, "Name", G_VARIANT_TYPE_STRING);
 
443
        name = v ? g_variant_get_string (v, NULL) : NULL;
 
444
 
 
445
        v = g_variant_lookup_value (dict, "Class", G_VARIANT_TYPE_UINT32);
 
446
        type = v ? bluetooth_class_to_type (g_variant_get_uint32 (v)) : BLUETOOTH_TYPE_ANY;
 
447
        icon = icon_override (address, type);
 
448
 
 
449
        if (icon == NULL) {
 
450
                v = g_variant_lookup_value (dict, "Icon", G_VARIANT_TYPE_STRING);
 
451
                icon = v ? g_variant_get_string (v, NULL) : "bluetooth";
 
452
        }
 
453
 
 
454
        v = g_variant_lookup_value (dict, "Paired", G_VARIANT_TYPE_BOOLEAN);
 
455
        paired = v ? g_variant_get_boolean (v) : FALSE;
 
456
 
 
457
        v = g_variant_lookup_value (dict, "Trusted", G_VARIANT_TYPE_BOOLEAN);
 
458
        trusted = v ? g_variant_get_boolean (v) : FALSE;
 
459
 
 
460
        v = g_variant_lookup_value (dict, "Connected", G_VARIANT_TYPE_BOOLEAN);
 
461
        connected = v ? g_variant_get_boolean (v) : FALSE;
 
462
 
 
463
        v = g_variant_lookup_value (dict, "UUIDs", G_VARIANT_TYPE_STRING_ARRAY);
 
464
        uuids = device_list_uuids (v);
 
465
 
 
466
        v = g_variant_lookup_value (dict, "LegacyPairing", G_VARIANT_TYPE_BOOLEAN);
 
467
        legacypairing = v ? g_variant_get_boolean (v) : -1;
 
468
 
 
469
        if (get_iter_from_path (priv->store, &parent, adapter_path) == FALSE) {
 
470
                g_object_unref (device);
 
471
                return;
 
472
        }
 
473
 
 
474
        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &parent,
 
475
                            BLUETOOTH_COLUMN_PROXY, &adapter, -1);
 
476
 
 
477
        if (get_iter_from_address (priv->store, &iter, address, adapter) == FALSE) {
 
478
                gtk_tree_store_insert_with_values (priv->store, &iter, &parent, -1,
 
479
                                                   BLUETOOTH_COLUMN_ADDRESS, address,
 
480
                                                   BLUETOOTH_COLUMN_ALIAS, alias,
 
481
                                                   BLUETOOTH_COLUMN_NAME, name,
 
482
                                                   BLUETOOTH_COLUMN_TYPE, type,
 
483
                                                   BLUETOOTH_COLUMN_ICON, icon,
 
484
                                                   BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
 
485
                                                   BLUETOOTH_COLUMN_UUIDS, uuids,
 
486
                                                   BLUETOOTH_COLUMN_PAIRED, paired,
 
487
                                                   BLUETOOTH_COLUMN_CONNECTED, connected,
 
488
                                                   BLUETOOTH_COLUMN_TRUSTED, trusted,
 
489
                                                   BLUETOOTH_COLUMN_PROXY, device,
 
490
                                                   BLUETOOTH_COLUMN_PROPERTIES, properties,
 
491
                                                   -1);
 
492
        } else {
 
493
                gtk_tree_store_set(priv->store, &iter,
 
494
                                   BLUETOOTH_COLUMN_ADDRESS, address,
 
495
                                   BLUETOOTH_COLUMN_ALIAS, alias,
 
496
                                   BLUETOOTH_COLUMN_NAME, name,
 
497
                                   BLUETOOTH_COLUMN_TYPE, type,
 
498
                                   BLUETOOTH_COLUMN_ICON, icon,
 
499
                                   BLUETOOTH_COLUMN_LEGACYPAIRING, legacypairing,
 
500
                                   BLUETOOTH_COLUMN_UUIDS, uuids,
 
501
                                   BLUETOOTH_COLUMN_PAIRED, paired,
 
502
                                   BLUETOOTH_COLUMN_CONNECTED, connected,
 
503
                                   BLUETOOTH_COLUMN_TRUSTED, trusted,
 
504
                                   BLUETOOTH_COLUMN_PROXY, device,
 
505
                                   BLUETOOTH_COLUMN_PROPERTIES, properties,
 
506
                                   -1);
 
507
        }
 
508
        g_strfreev (uuids);
 
509
 
 
510
        g_signal_connect (G_OBJECT (device), "g-properties-changed",
 
511
                          G_CALLBACK (device_g_properties_changed), client);
 
512
 
 
513
        g_object_unref (properties);
 
514
        g_object_unref (device);
 
515
        g_object_unref (adapter);
 
516
}
 
517
 
 
518
static void
 
519
device_removed (const char      *path,
 
520
                BluetoothClient *client)
 
521
{
 
522
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
523
        GtkTreeIter iter;
 
524
 
 
525
        if (get_iter_from_path(priv->store, &iter, path) == TRUE) {
 
526
                g_signal_emit (G_OBJECT (client), signals[DEVICE_REMOVED], 0, path);
 
527
                gtk_tree_store_remove(priv->store, &iter);
 
528
        }
 
529
}
 
530
 
 
531
static void
 
532
powered_callback (GDBusProxy   *proxy,
 
533
                  GAsyncResult *res,
 
534
                  gpointer      data)
 
535
{
 
536
        GError *error = NULL;
 
537
 
 
538
        if (!properties_call_set_finish (PROPERTIES(proxy), res, &error)) {
 
539
                g_debug ("Call to Set Powered failed %s: %s",
 
540
                         g_dbus_proxy_get_object_path (proxy), error->message);
 
541
                g_error_free (error);
 
542
        }
 
543
 
 
544
        g_object_unref (proxy);
 
545
}
 
546
 
 
547
static gboolean
 
548
adapter_set_powered (BluetoothClient *client,
 
549
                     const char *path,
 
550
                     gboolean powered)
 
551
{
 
552
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
553
        Properties *properties;
 
554
        GtkTreeIter iter;
 
555
 
 
556
        g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE);
 
557
 
 
558
        if (get_iter_from_path (priv->store, &iter, path) == FALSE)
 
559
                return FALSE;
 
560
 
 
561
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
 
562
                            BLUETOOTH_COLUMN_PROPERTIES, &properties, -1);
 
563
 
 
564
        if (properties == NULL)
 
565
                return FALSE;
 
566
 
 
567
 
 
568
        properties_call_set (properties,
 
569
                             BLUEZ_ADAPTER_INTERFACE,
 
570
                             "Powered",
 
571
                             g_variant_new_variant (g_variant_new_boolean (powered)),
 
572
                             NULL,
 
573
                             (GAsyncReadyCallback) powered_callback,
 
574
                             NULL);
 
575
 
 
576
        return TRUE;
 
577
}
 
578
 
 
579
static void
 
580
default_adapter_changed (ObjectManager   *manager,
 
581
                         const char      *path,
 
582
                         BluetoothClient *client)
 
583
{
 
584
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
585
        GtkTreeIter iter;
 
586
        GtkTreePath *tree_path;
 
587
        gboolean powered;
 
588
 
 
589
        g_assert (!priv->default_adapter);
 
590
 
 
591
        if (get_iter_from_path (priv->store, &iter, path) == FALSE)
 
592
                return;
 
593
 
 
594
        tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
 
595
        priv->default_adapter = gtk_tree_row_reference_new (GTK_TREE_MODEL (priv->store), tree_path);
 
596
        gtk_tree_path_free (tree_path);
 
597
 
 
598
        gtk_tree_store_set (priv->store, &iter,
 
599
                            BLUETOOTH_COLUMN_DEFAULT, TRUE, -1);
 
600
 
 
601
        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
602
                           BLUETOOTH_COLUMN_POWERED, &powered, -1);
 
603
 
 
604
        if (powered) {
 
605
                g_object_notify (G_OBJECT (client), "default-adapter");
 
606
                g_object_notify (G_OBJECT (client), "default-adapter-powered");
 
607
                g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
 
608
                g_object_notify (G_OBJECT (client), "default-adapter-discovering");
 
609
                g_object_notify (G_OBJECT (client), "default-adapter-name");
 
610
                return;
 
611
        }
 
612
 
 
613
        /*
 
614
         * If the adapter is turn off (Powered = False in bluetooth) object
 
615
         * notifications will be sent only when a Powered = True signal arrives
 
616
         * from bluetoothd
 
617
         */
 
618
        adapter_set_powered (client, path, TRUE);
 
619
}
 
620
 
 
621
static void
 
622
adapter_g_properties_changed (GDBusProxy      *adapter,
 
623
                              GVariant        *changed_p,
 
624
                              GStrv            invalidated_p,
 
625
                              BluetoothClient *client)
 
626
{
 
627
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
628
        GVariantIter i;
 
629
        const char *property;
 
630
        GtkTreeIter iter;
 
631
        GVariant *v;
 
632
        gboolean notify = FALSE;
 
633
 
 
634
        if (get_iter_from_proxy (priv->store, &iter, adapter) == FALSE)
 
635
                return;
 
636
 
 
637
        g_variant_iter_init (&i, changed_p);
 
638
        while (g_variant_iter_next (&i, "{&sv}", &property, &v)) {
 
639
                if (g_str_equal (property, "Name") == TRUE) {
 
640
                        const gchar *name = g_variant_get_string (v, NULL);
 
641
                        gboolean is_default;
 
642
 
 
643
                        gtk_tree_store_set (priv->store, &iter,
 
644
                                            BLUETOOTH_COLUMN_NAME, name, -1);
 
645
                        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
646
                                            BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
 
647
                        if (is_default != FALSE) {
 
648
                                g_object_notify (G_OBJECT (client), "default-adapter-powered");
 
649
                                g_object_notify (G_OBJECT (client), "default-adapter-name");
 
650
                        }
 
651
                        notify = TRUE;
 
652
                } else if (g_str_equal (property, "Discovering") == TRUE) {
 
653
                        gboolean discovering = g_variant_get_boolean (v);
 
654
                        gboolean is_default;
 
655
 
 
656
                        gtk_tree_store_set (priv->store, &iter,
 
657
                                            BLUETOOTH_COLUMN_DISCOVERING, discovering, -1);
 
658
                        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
659
                                            BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
 
660
                        if (is_default != FALSE)
 
661
                                g_object_notify (G_OBJECT (client), "default-adapter-discovering");
 
662
                        notify = TRUE;
 
663
                } else if (g_str_equal (property, "Powered") == TRUE) {
 
664
                        gboolean powered = g_variant_get_boolean (v);
 
665
                        gboolean is_default;
 
666
 
 
667
                        gtk_tree_store_set (priv->store, &iter,
 
668
                                            BLUETOOTH_COLUMN_POWERED, powered, -1);
 
669
                        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
670
                                            BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
 
671
                        if (is_default != FALSE && powered) {
 
672
                                g_object_notify (G_OBJECT (client), "default-adapter");
 
673
                                g_object_notify (G_OBJECT (client), "default-adapter-powered");
 
674
                                g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
 
675
                                g_object_notify (G_OBJECT (client), "default-adapter-discovering");
 
676
                                g_object_notify (G_OBJECT (client), "default-adapter-name");
 
677
                        }
 
678
                        notify = TRUE;
 
679
                } else if (g_str_equal (property, "Discoverable") == TRUE) {
 
680
                        gboolean discoverable = g_variant_get_boolean (v);
 
681
                        gboolean is_default;
 
682
 
 
683
                        gtk_tree_store_set (priv->store, &iter,
 
684
                                            BLUETOOTH_COLUMN_DISCOVERABLE, discoverable, -1);
 
685
                        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
686
                                            BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
 
687
                        if (is_default != FALSE)
 
688
                                g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
 
689
                        notify = TRUE;
 
690
                }
 
691
 
 
692
                if (notify != FALSE) {
 
693
                        GtkTreePath *path;
 
694
 
 
695
                        /* Tell the world */
 
696
                        path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
 
697
                        gtk_tree_model_row_changed (GTK_TREE_MODEL (priv->store), path, &iter);
 
698
                        gtk_tree_path_free (path);
 
699
                }
 
700
                g_variant_unref (v);
 
701
        }
 
702
}
 
703
 
 
704
static void
 
705
adapter_added (ObjectManager   *manager,
 
706
               const char      *path,
 
707
               GVariant        *variant,
 
708
               BluetoothClient *client)
 
709
{
 
710
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
711
        GtkTreeIter iter;
 
712
        Adapter1 *adapter;
 
713
        Properties *properties;
 
714
        const gchar *address, *name;
 
715
        GVariant *v, *dict;
 
716
        gboolean discovering, discoverable, powered;
 
717
 
 
718
        adapter = adapter1_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 
719
                                                   G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 
720
                                                   BLUEZ_SERVICE,
 
721
                                                   path,
 
722
                                                   NULL,
 
723
                                                   NULL);
 
724
 
 
725
        properties = properties_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 
726
                                                        G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 
727
                                                        BLUEZ_SERVICE,
 
728
                                                        path,
 
729
                                                        NULL,
 
730
                                                        NULL);
 
731
 
 
732
        dict = g_variant_lookup_value (variant, BLUEZ_ADAPTER_INTERFACE,
 
733
                              G_VARIANT_TYPE_DICTIONARY);
 
734
 
 
735
        v = g_variant_lookup_value (dict, "Address", G_VARIANT_TYPE_STRING);
 
736
        address = v ? g_variant_get_string (v, NULL) : NULL;
 
737
 
 
738
        v = g_variant_lookup_value (dict, "Name", G_VARIANT_TYPE_STRING);
 
739
        name = v ? g_variant_get_string (v, NULL) : NULL;
 
740
 
 
741
        v = g_variant_lookup_value (dict, "Discovering", G_VARIANT_TYPE_BOOLEAN);
 
742
        discovering = v ? g_variant_get_boolean (v) : FALSE;
 
743
 
 
744
        v = g_variant_lookup_value (dict, "Powered", G_VARIANT_TYPE_BOOLEAN);
 
745
        powered = v ? g_variant_get_boolean (v) : FALSE;
 
746
 
 
747
        v = g_variant_lookup_value (dict, "Discoverable", G_VARIANT_TYPE_BOOLEAN);
 
748
        discoverable = v ? g_variant_get_boolean (v) : FALSE;
 
749
 
 
750
        gtk_tree_store_insert_with_values(priv->store, &iter, NULL, -1,
 
751
                                          BLUETOOTH_COLUMN_PROXY, adapter,
 
752
                                          BLUETOOTH_COLUMN_PROPERTIES, properties,
 
753
                                          BLUETOOTH_COLUMN_ADDRESS, address,
 
754
                                          BLUETOOTH_COLUMN_NAME, name,
 
755
                                          BLUETOOTH_COLUMN_DISCOVERING, discovering,
 
756
                                          BLUETOOTH_COLUMN_DISCOVERABLE, discoverable,
 
757
                                          BLUETOOTH_COLUMN_POWERED, powered,
 
758
                                          -1);
 
759
 
 
760
        g_signal_connect (G_OBJECT (adapter), "g-properties-changed",
 
761
                          G_CALLBACK (adapter_g_properties_changed), client);
 
762
 
 
763
        if (!priv->default_adapter)
 
764
                default_adapter_changed (manager, path, client);
 
765
 
 
766
        g_object_unref (properties);
 
767
        g_object_unref (adapter);
 
768
}
 
769
 
 
770
static void
 
771
adapter_removed (ObjectManager   *manager,
 
772
                 const char      *path,
 
773
                 BluetoothClient *client)
 
774
{
 
775
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
776
        GtkTreeIter iter;
 
777
        gboolean was_default;
 
778
 
 
779
        if (get_iter_from_path (priv->store, &iter, path) == FALSE)
 
780
                return;
 
781
 
 
782
        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
783
                           BLUETOOTH_COLUMN_DEFAULT, &was_default, -1);
 
784
 
 
785
        if (!was_default)
 
786
                return;
 
787
 
 
788
        g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free);
 
789
        gtk_tree_store_remove (priv->store, &iter);
 
790
 
 
791
        if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(priv->store),
 
792
                                           &iter)) {
 
793
                GDBusProxy *adapter;
 
794
                const char *adapter_path;
 
795
 
 
796
                gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
797
                                   BLUETOOTH_COLUMN_PROXY, &adapter, -1);
 
798
 
 
799
                adapter_path = g_dbus_proxy_get_object_path (adapter);
 
800
                default_adapter_changed (manager, adapter_path, client);
 
801
 
 
802
                g_object_unref(adapter);
 
803
        } else {
 
804
                g_object_notify (G_OBJECT (client), "default-adapter");
 
805
                g_object_notify (G_OBJECT (client), "default-adapter-powered");
 
806
                g_object_notify (G_OBJECT (client), "default-adapter-discoverable");
 
807
                g_object_notify (G_OBJECT (client), "default-adapter-discovering");
 
808
        }
 
809
}
 
810
 
 
811
static void
 
812
interface_added (BluetoothClient *client,
 
813
                 const char *path,
 
814
                 GVariant   *variant)
 
815
{
 
816
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
817
 
 
818
        if (g_variant_lookup_value (variant, BLUEZ_ADAPTER_INTERFACE,
 
819
                                    G_VARIANT_TYPE_DICTIONARY)) {
 
820
                g_debug ("New Adapter interface added.");
 
821
                adapter_added (priv->manager, path, variant, client);
 
822
                return;
 
823
        }
 
824
 
 
825
        if (g_variant_lookup_value (variant, BLUEZ_DEVICE_INTERFACE,
 
826
                                    G_VARIANT_TYPE_DICTIONARY)) {
 
827
                g_debug ("New Device interface added.");
 
828
                device_added (priv->manager, client, path, variant);
 
829
                return;
 
830
        }
 
831
}
 
832
 
 
833
static void
 
834
interface_removed (BluetoothClient *client,
 
835
                   const char      *path,
 
836
                   GVariant        *variant)
 
837
{
 
838
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
839
        const char **ifaces;
 
840
        int i;
 
841
 
 
842
        ifaces = g_variant_get_strv (variant, NULL);
 
843
 
 
844
        for (i = 0 ; ifaces[i] != NULL ; i++) {
 
845
                if (g_strcmp0(ifaces[i], BLUEZ_ADAPTER_INTERFACE) == 0) {
 
846
                        adapter_removed(priv->manager, path, client);
 
847
                        return;
 
848
                }
 
849
 
 
850
                if (g_strcmp0(ifaces[i], BLUEZ_DEVICE_INTERFACE) == 0) {
 
851
                        device_removed (path, client);
 
852
                        return;
 
853
                }
 
854
        }
 
855
}
 
856
 
 
857
static void
 
858
object_manager_g_signal (GDBusProxy      *proxy,
 
859
                         gchar           *sender_name,
 
860
                         gchar           *signal_name,
 
861
                         GVariant        *parameters,
 
862
                         BluetoothClient *client)
 
863
{
 
864
        char *object_path;
 
865
        GVariant *variant;
 
866
 
 
867
        g_variant_get (parameters, "(o*)", &object_path, &variant);
 
868
 
 
869
        if (g_strcmp0 (signal_name, "InterfacesAdded") == 0) {
 
870
                interface_added (client, object_path, variant);
 
871
        } else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0) {
 
872
                interface_removed (client, object_path, variant);
 
873
        } else {
 
874
                g_assert_not_reached ();
 
875
        }
 
876
 
 
877
        g_free (object_path);
 
878
}
 
879
 
 
880
static void
 
881
bluez_appeared_cb (GDBusConnection *connection,
 
882
                   const gchar     *name,
 
883
                   const gchar     *name_owner,
 
884
                   BluetoothClient *client)
 
885
{
 
886
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
887
        GVariantIter iter;
 
888
        GVariant *variant, *v, *ifaces;
 
889
        char *key;
 
890
 
 
891
        priv->manager = object_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 
892
                                                               G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 
893
                                                               BLUEZ_SERVICE,
 
894
                                                               BLUEZ_MANAGER_PATH,
 
895
                                                               NULL,
 
896
                                                               NULL);
 
897
 
 
898
        g_signal_connect (G_OBJECT (priv->manager), "g-signal",
 
899
                          G_CALLBACK (object_manager_g_signal), client);
 
900
 
 
901
        variant = NULL;
 
902
        object_manager_call_get_managed_objects_sync (OBJECT_MANAGER (priv->manager),
 
903
                                                      &variant, NULL, NULL);
 
904
        if (variant == NULL)
 
905
                return;
 
906
 
 
907
        g_variant_iter_init (&iter, variant);
 
908
        while ((v = g_variant_iter_next_value (&iter))) {
 
909
                g_variant_get (v, "{o*}", &key, &ifaces);
 
910
                interface_added (client, key, ifaces);
 
911
                g_free (key);
 
912
        }
 
913
 
 
914
        g_variant_unref (variant);
 
915
}
 
916
 
 
917
static void
 
918
bluez_vanished_cb (GDBusConnection *connection,
 
919
                   const gchar     *name,
 
920
                   BluetoothClient *client)
 
921
{
 
922
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
923
 
 
924
        g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free);
 
925
 
 
926
        gtk_tree_store_clear (priv->store);
 
927
 
 
928
        g_clear_object (&priv->manager);
 
929
}
 
930
 
 
931
static void bluetooth_client_init(BluetoothClient *client)
 
932
{
 
933
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
934
 
 
935
        priv->store = gtk_tree_store_new(_BLUETOOTH_NUM_COLUMNS, G_TYPE_OBJECT,
 
936
                                         G_TYPE_OBJECT, G_TYPE_STRING,
 
937
                                         G_TYPE_STRING, G_TYPE_STRING,
 
938
                                         G_TYPE_UINT, G_TYPE_STRING,
 
939
                                         G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
 
940
                                         G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_INT,
 
941
                                         G_TYPE_BOOLEAN, G_TYPE_HASH_TABLE, G_TYPE_STRV);
 
942
 
 
943
        priv->owner_change_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
 
944
                                                  BLUEZ_SERVICE,
 
945
                                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
 
946
                                                  (GBusNameAppearedCallback) bluez_appeared_cb,
 
947
                                                  (GBusNameVanishedCallback) bluez_vanished_cb,
 
948
                                                  client, NULL);
 
949
}
 
950
 
 
951
static GDBusProxy *
 
952
_bluetooth_client_get_default_adapter(BluetoothClient *client)
 
953
{
 
954
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
955
        GtkTreePath *path;
 
956
        GtkTreeIter iter;
 
957
        GDBusProxy *adapter;
 
958
 
 
959
        g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), NULL);
 
960
 
 
961
        if (priv->default_adapter == NULL)
 
962
                return NULL;
 
963
 
 
964
        path = gtk_tree_row_reference_get_path (priv->default_adapter);
 
965
        gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
 
966
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
 
967
                            BLUETOOTH_COLUMN_PROXY, &adapter, -1);
 
968
        gtk_tree_path_free (path);
 
969
 
 
970
        return adapter;
 
971
}
 
972
 
 
973
static const char*
 
974
_bluetooth_client_get_default_adapter_path (BluetoothClient *self)
 
975
{
 
976
        GDBusProxy *adapter = _bluetooth_client_get_default_adapter (self);
 
977
 
 
978
        if (adapter != NULL) {
 
979
                const char *ret = g_dbus_proxy_get_object_path (adapter);
 
980
                g_object_unref (adapter);
 
981
                return ret;
 
982
        }
 
983
        return NULL;
 
984
}
 
985
 
 
986
static gboolean
 
987
_bluetooth_client_get_default_adapter_powered (BluetoothClient *self)
 
988
{
 
989
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (self);
 
990
        GtkTreePath *path;
 
991
        GtkTreeIter iter;
 
992
        gboolean ret;
 
993
 
 
994
        if (priv->default_adapter == NULL)
 
995
                return FALSE;
 
996
 
 
997
        path = gtk_tree_row_reference_get_path (priv->default_adapter);
 
998
        gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
 
999
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, BLUETOOTH_COLUMN_POWERED, &ret, -1);
 
1000
        gtk_tree_path_free (path);
 
1001
 
 
1002
        return ret;
 
1003
}
 
1004
 
 
1005
static char *
 
1006
_bluetooth_client_get_default_adapter_name (BluetoothClient *self)
 
1007
{
 
1008
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (self);
 
1009
        GtkTreePath *path;
 
1010
        GtkTreeIter iter;
 
1011
        char *ret;
 
1012
 
 
1013
        if (priv->default_adapter == NULL)
 
1014
                return NULL;
 
1015
 
 
1016
        path = gtk_tree_row_reference_get_path (priv->default_adapter);
 
1017
        gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
 
1018
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, BLUETOOTH_COLUMN_NAME, &ret, -1);
 
1019
        gtk_tree_path_free (path);
 
1020
 
 
1021
        return ret;
 
1022
}
 
1023
 
 
1024
/**
 
1025
 * _bluetooth_client_get_discoverable:
 
1026
 * @client: a #BluetoothClient
 
1027
 *
 
1028
 * Gets the default adapter's discoverable status, cached in the adapter model.
 
1029
 *
 
1030
 * Returns: the discoverable status, or FALSE if no default adapter exists
 
1031
 */
 
1032
static gboolean
 
1033
_bluetooth_client_get_discoverable (BluetoothClient *client)
 
1034
{
 
1035
        BluetoothClientPrivate *priv;
 
1036
        GtkTreePath *path;
 
1037
        GtkTreeIter iter;
 
1038
        gboolean ret;
 
1039
 
 
1040
        g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE);
 
1041
 
 
1042
        priv = BLUETOOTH_CLIENT_GET_PRIVATE (client);
 
1043
        if (priv->default_adapter == NULL)
 
1044
                return FALSE;
 
1045
 
 
1046
        path = gtk_tree_row_reference_get_path (priv->default_adapter);
 
1047
        gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
 
1048
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
 
1049
                            BLUETOOTH_COLUMN_DISCOVERABLE, &ret, -1);
 
1050
 
 
1051
        return ret;
 
1052
}
 
1053
 
 
1054
/**
 
1055
 * _bluetooth_client_set_discoverable:
 
1056
 * @client: a #BluetoothClient object
 
1057
 * @discoverable: whether the device should be discoverable
 
1058
 * @timeout: timeout in seconds for making undiscoverable, or 0 for never
 
1059
 *
 
1060
 * Sets the default adapter's discoverable status.
 
1061
 *
 
1062
 * Return value: Whether setting the state on the default adapter was successful.
 
1063
 **/
 
1064
static gboolean
 
1065
_bluetooth_client_set_discoverable (BluetoothClient *client,
 
1066
                                    gboolean discoverable,
 
1067
                                    guint timeout)
 
1068
{
 
1069
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (client);
 
1070
        GError *error = NULL;
 
1071
        GtkTreePath *path;
 
1072
        Properties *properties;
 
1073
        gboolean ret;
 
1074
        GtkTreeIter iter;
 
1075
 
 
1076
        g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE);
 
1077
 
 
1078
        if (priv->default_adapter == NULL)
 
1079
                return FALSE;
 
1080
 
 
1081
        path = gtk_tree_row_reference_get_path (priv->default_adapter);
 
1082
        gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
 
1083
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
 
1084
                            BLUETOOTH_COLUMN_PROPERTIES, &properties, -1);
 
1085
        gtk_tree_path_free (path);
 
1086
 
 
1087
        if (properties == NULL)
 
1088
                return FALSE;
 
1089
 
 
1090
        ret = properties_call_set_sync (properties,
 
1091
                                        BLUEZ_ADAPTER_INTERFACE,
 
1092
                                        "Discoverable",
 
1093
                                        g_variant_new_variant (g_variant_new_boolean (discoverable)),
 
1094
                                        NULL, &error);
 
1095
        if (ret == FALSE) {
 
1096
                g_warning ("Failed to set Discoverable to %d: %s", discoverable, error->message);
 
1097
                g_error_free (error);
 
1098
        } else if (discoverable) {
 
1099
                ret = properties_call_set_sync (properties,
 
1100
                                                BLUEZ_ADAPTER_INTERFACE,
 
1101
                                                "DiscoverableTimeout",
 
1102
                                                g_variant_new_variant (g_variant_new_uint32 (timeout)),
 
1103
                                                NULL, &error);
 
1104
                if (ret == FALSE) {
 
1105
                        g_warning ("Failed to set DiscoverableTimeout to %d: %s", timeout, error->message);
 
1106
                        g_error_free (error);
 
1107
                }
 
1108
        }
 
1109
 
 
1110
        g_object_unref (properties);
 
1111
 
 
1112
        return ret;
 
1113
}
 
1114
 
 
1115
static void
 
1116
_bluetooth_client_set_default_adapter_discovering (BluetoothClient *client,
 
1117
                                                   gboolean         discover)
 
1118
{
 
1119
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (client);
 
1120
        GtkTreeIter iter;
 
1121
        GDBusProxy *adapter;
 
1122
        gboolean current;
 
1123
 
 
1124
        adapter = _bluetooth_client_get_default_adapter (client);
 
1125
        if (adapter == NULL)
 
1126
                return;
 
1127
 
 
1128
        get_iter_from_proxy (priv->store, &iter, adapter);
 
1129
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
 
1130
                            BLUETOOTH_COLUMN_DISCOVERING, &current, -1);
 
1131
 
 
1132
        if (current == discover) {
 
1133
                g_object_unref(adapter);
 
1134
                return;
 
1135
        }
 
1136
 
 
1137
        if (discover)
 
1138
                adapter1_call_start_discovery_sync (ADAPTER1 (adapter), NULL, NULL);
 
1139
        else
 
1140
                adapter1_call_stop_discovery_sync (ADAPTER1 (adapter), NULL, NULL);
 
1141
 
 
1142
        g_object_unref(adapter);
 
1143
}
 
1144
 
 
1145
static gboolean
 
1146
_bluetooth_client_get_default_adapter_discovering (BluetoothClient *self)
 
1147
{
 
1148
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (self);
 
1149
        GtkTreePath *path;
 
1150
        GtkTreeIter iter;
 
1151
        gboolean ret;
 
1152
 
 
1153
        if (priv->default_adapter == NULL)
 
1154
                return FALSE;
 
1155
 
 
1156
        path = gtk_tree_row_reference_get_path (priv->default_adapter);
 
1157
        gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->store), &iter, path);
 
1158
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter, BLUETOOTH_COLUMN_DISCOVERING, &ret, -1);
 
1159
        gtk_tree_path_free (path);
 
1160
 
 
1161
        return ret;
 
1162
}
 
1163
 
 
1164
static void
 
1165
bluetooth_client_get_property (GObject        *object,
 
1166
                               guint           property_id,
 
1167
                               GValue         *value,
 
1168
                               GParamSpec     *pspec)
 
1169
{
 
1170
        BluetoothClient *self = BLUETOOTH_CLIENT (object);
 
1171
 
 
1172
        switch (property_id) {
 
1173
        case PROP_DEFAULT_ADAPTER:
 
1174
                g_value_set_string (value, _bluetooth_client_get_default_adapter_path (self));
 
1175
                break;
 
1176
        case PROP_DEFAULT_ADAPTER_POWERED:
 
1177
                g_value_set_boolean (value, _bluetooth_client_get_default_adapter_powered (self));
 
1178
                break;
 
1179
        case PROP_DEFAULT_ADAPTER_NAME:
 
1180
                g_value_take_string (value, _bluetooth_client_get_default_adapter_name (self));
 
1181
                break;
 
1182
        case PROP_DEFAULT_ADAPTER_DISCOVERABLE:
 
1183
                g_value_set_boolean (value, _bluetooth_client_get_discoverable (self));
 
1184
                break;
 
1185
        case PROP_DEFAULT_ADAPTER_DISCOVERING:
 
1186
                g_value_set_boolean (value, _bluetooth_client_get_default_adapter_discovering (self));
 
1187
                break;
 
1188
        default:
 
1189
                G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
 
1190
                break;
 
1191
        }
 
1192
}
 
1193
 
 
1194
static void
 
1195
bluetooth_client_set_property (GObject        *object,
 
1196
                               guint           property_id,
 
1197
                               const GValue   *value,
 
1198
                               GParamSpec     *pspec)
 
1199
{
 
1200
        BluetoothClient *self = BLUETOOTH_CLIENT (object);
 
1201
 
 
1202
        switch (property_id) {
 
1203
        case PROP_DEFAULT_ADAPTER_DISCOVERABLE:
 
1204
                _bluetooth_client_set_discoverable (self, g_value_get_boolean (value), 0);
 
1205
                break;
 
1206
        case PROP_DEFAULT_ADAPTER_DISCOVERING:
 
1207
                _bluetooth_client_set_default_adapter_discovering (self, g_value_get_boolean (value));
 
1208
                break;
 
1209
        default:
 
1210
                G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
 
1211
                break;
 
1212
        }
 
1213
}
 
1214
 
 
1215
static void bluetooth_client_finalize(GObject *object)
 
1216
{
 
1217
        BluetoothClient *client = BLUETOOTH_CLIENT (object);
 
1218
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE (client);
 
1219
 
 
1220
        g_bus_unwatch_name (priv->owner_change_id);
 
1221
 
 
1222
        g_clear_object (&priv->manager);
 
1223
        g_object_unref (priv->store);
 
1224
 
 
1225
        g_clear_pointer (&priv->default_adapter, gtk_tree_row_reference_free);
 
1226
 
 
1227
        G_OBJECT_CLASS(bluetooth_client_parent_class)->finalize (object);
 
1228
}
 
1229
 
 
1230
static void bluetooth_client_class_init(BluetoothClientClass *klass)
 
1231
{
 
1232
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
1233
 
 
1234
        object_class->finalize = bluetooth_client_finalize;
 
1235
        object_class->get_property = bluetooth_client_get_property;
 
1236
        object_class->set_property = bluetooth_client_set_property;
 
1237
 
 
1238
        /**
 
1239
         * BluetoothClient::device-removed:
 
1240
         * @client: a #BluetoothClient object which received the signal
 
1241
         * @device: the D-Bus object path for the now-removed device
 
1242
         *
 
1243
         * The #BluetoothClient::device-removed signal is launched when a
 
1244
         * device gets removed from the model.
 
1245
         **/
 
1246
        signals[DEVICE_REMOVED] =
 
1247
                g_signal_new ("device-removed",
 
1248
                              G_TYPE_FROM_CLASS (klass),
 
1249
                              G_SIGNAL_RUN_LAST,
 
1250
                              0,
 
1251
                              NULL, NULL,
 
1252
                              g_cclosure_marshal_VOID__STRING,
 
1253
                              G_TYPE_NONE, 1, G_TYPE_STRING);
 
1254
 
 
1255
        /**
 
1256
         * BluetoothClient:default-adapter:
 
1257
         *
 
1258
         * The D-Bus path of the default Bluetooth adapter or %NULL.
 
1259
         */
 
1260
        g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER,
 
1261
                                         g_param_spec_string ("default-adapter", NULL,
 
1262
                                                              "The D-Bus path of the default adapter",
 
1263
                                                              NULL, G_PARAM_READABLE));
 
1264
        /**
 
1265
         * BluetoothClient:default-adapter-powered:
 
1266
         *
 
1267
         * %TRUE if the default Bluetooth adapter is powered.
 
1268
         */
 
1269
        g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER_POWERED,
 
1270
                                         g_param_spec_boolean ("default-adapter-powered", NULL,
 
1271
                                                              "Whether the default adapter is powered",
 
1272
                                                               FALSE, G_PARAM_READABLE));
 
1273
        /**
 
1274
         * BluetoothClient:default-adapter-discoverable:
 
1275
         *
 
1276
         * %TRUE if the default Bluetooth adapter is discoverable.
 
1277
         */
 
1278
        g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER_DISCOVERABLE,
 
1279
                                         g_param_spec_boolean ("default-adapter-discoverable", NULL,
 
1280
                                                              "Whether the default adapter is visible by other devices",
 
1281
                                                               FALSE, G_PARAM_READWRITE));
 
1282
        /**
 
1283
         * BluetoothClient:default-adapter-name:
 
1284
         *
 
1285
         * The name of the default Bluetooth adapter or %NULL.
 
1286
         */
 
1287
        g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER_NAME,
 
1288
                                         g_param_spec_string ("default-adapter-name", NULL,
 
1289
                                                              "The human readable name of the default adapter",
 
1290
                                                              NULL, G_PARAM_READABLE));
 
1291
        /**
 
1292
         * BluetoothClient:default-adapter-discovering:
 
1293
         *
 
1294
         * %TRUE if the default Bluetooth adapter is discovering.
 
1295
         */
 
1296
        g_object_class_install_property (object_class, PROP_DEFAULT_ADAPTER_DISCOVERING,
 
1297
                                         g_param_spec_boolean ("default-adapter-discovering", NULL,
 
1298
                                                              "Whether the default adapter is searching for devices",
 
1299
                                                               FALSE, G_PARAM_READWRITE));
 
1300
}
 
1301
 
 
1302
/**
 
1303
 * bluetooth_client_new:
 
1304
 *
 
1305
 * Returns a reference to the #BluetoothClient singleton. Use g_object_unref() when done with the object.
 
1306
 *
 
1307
 * Return value: (transfer full): a #BluetoothClient object.
 
1308
 **/
 
1309
BluetoothClient *bluetooth_client_new(void)
 
1310
{
 
1311
        static BluetoothClient *bluetooth_client = NULL;
 
1312
 
 
1313
        if (bluetooth_client != NULL)
 
1314
                return g_object_ref(bluetooth_client);
 
1315
 
 
1316
        bluetooth_client = BLUETOOTH_CLIENT (g_object_new (BLUETOOTH_TYPE_CLIENT, NULL));
 
1317
        g_object_add_weak_pointer (G_OBJECT (bluetooth_client),
 
1318
                                   (gpointer) &bluetooth_client);
 
1319
 
 
1320
        return bluetooth_client;
 
1321
}
 
1322
 
 
1323
/**
 
1324
 * bluetooth_client_get_model:
 
1325
 * @client: a #BluetoothClient object
 
1326
 *
 
1327
 * Returns an unfiltered #GtkTreeModel representing the adapter and devices available on the system.
 
1328
 *
 
1329
 * Return value: (transfer full): a #GtkTreeModel object.
 
1330
 **/
 
1331
GtkTreeModel *bluetooth_client_get_model (BluetoothClient *client)
 
1332
{
 
1333
        BluetoothClientPrivate *priv;
 
1334
        GtkTreeModel *model;
 
1335
 
 
1336
        g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), NULL);
 
1337
 
 
1338
        priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
1339
        model = g_object_ref(priv->store);
 
1340
 
 
1341
        return model;
 
1342
}
 
1343
 
 
1344
/**
 
1345
 * bluetooth_client_get_filter_model:
 
1346
 * @client: a #BluetoothClient object
 
1347
 * @func: a #GtkTreeModelFilterVisibleFunc
 
1348
 * @data: user data to pass to gtk_tree_model_filter_set_visible_func()
 
1349
 * @destroy: a destroy function for gtk_tree_model_filter_set_visible_func()
 
1350
 *
 
1351
 * Returns a #GtkTreeModelFilter of devices filtered using the @func, @data and @destroy arguments to pass to gtk_tree_model_filter_set_visible_func().
 
1352
 *
 
1353
 * Return value: (transfer full): a #GtkTreeModel object.
 
1354
 **/
 
1355
GtkTreeModel *bluetooth_client_get_filter_model (BluetoothClient *client,
 
1356
                                                 GtkTreeModelFilterVisibleFunc func,
 
1357
                                                 gpointer data, GDestroyNotify destroy)
 
1358
{
 
1359
        BluetoothClientPrivate *priv;
 
1360
        GtkTreeModel *model;
 
1361
 
 
1362
        g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), NULL);
 
1363
 
 
1364
        priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
1365
        model = gtk_tree_model_filter_new(GTK_TREE_MODEL(priv->store), NULL);
 
1366
 
 
1367
        gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model),
 
1368
                                                        func, data, destroy);
 
1369
 
 
1370
        return model;
 
1371
}
 
1372
 
 
1373
static gboolean adapter_filter(GtkTreeModel *model,
 
1374
                                        GtkTreeIter *iter, gpointer user_data)
 
1375
{
 
1376
        GDBusProxy *proxy;
 
1377
        gboolean active;
 
1378
 
 
1379
        gtk_tree_model_get(model, iter, BLUETOOTH_COLUMN_PROXY, &proxy, -1);
 
1380
 
 
1381
        if (proxy == NULL)
 
1382
                return FALSE;
 
1383
 
 
1384
        active = g_str_equal(BLUEZ_ADAPTER_INTERFACE,
 
1385
                                        g_dbus_proxy_get_interface_name(proxy));
 
1386
 
 
1387
        g_object_unref(proxy);
 
1388
 
 
1389
        return active;
 
1390
}
 
1391
 
 
1392
/**
 
1393
 * bluetooth_client_get_adapter_model:
 
1394
 * @client: a #BluetoothClient object
 
1395
 *
 
1396
 * Returns a #GtkTreeModelFilter with only adapters present.
 
1397
 *
 
1398
 * Return value: (transfer full): a #GtkTreeModel object.
 
1399
 **/
 
1400
GtkTreeModel *bluetooth_client_get_adapter_model (BluetoothClient *client)
 
1401
{
 
1402
        return bluetooth_client_get_filter_model (client, adapter_filter,
 
1403
                                                  NULL, NULL);
 
1404
}
 
1405
 
 
1406
/**
 
1407
 * bluetooth_client_get_device_model:
 
1408
 * @client: a #BluetoothClient object
 
1409
 *
 
1410
 * Returns a #GtkTreeModelFilter with only devices belonging to the default adapter listed.
 
1411
 * Note that the model will follow a specific adapter, and will not follow the default adapter.
 
1412
 * Also note that due to the way #GtkTreeModelFilter works, you will probably want to
 
1413
 * monitor signals on the "child-model" #GtkTreeModel to monitor for changes.
 
1414
 *
 
1415
 * Return value: (transfer full): a #GtkTreeModel object.
 
1416
 **/
 
1417
GtkTreeModel *bluetooth_client_get_device_model (BluetoothClient *client)
 
1418
{
 
1419
        BluetoothClientPrivate *priv;
 
1420
        GtkTreeModel *model;
 
1421
        GtkTreePath *path;
 
1422
        GtkTreeIter iter;
 
1423
        gboolean cont, found = FALSE;
 
1424
 
 
1425
        g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), NULL);
 
1426
 
 
1427
        priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
1428
        cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(priv->store), &iter);
 
1429
 
 
1430
        while (cont == TRUE) {
 
1431
                gboolean is_default;
 
1432
 
 
1433
                gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
1434
                                    BLUETOOTH_COLUMN_DEFAULT, &is_default, -1);
 
1435
 
 
1436
                if (is_default == TRUE) {
 
1437
                        found = TRUE;
 
1438
                        break;
 
1439
                }
 
1440
 
 
1441
                cont = gtk_tree_model_iter_next (GTK_TREE_MODEL(priv->store), &iter);
 
1442
        }
 
1443
 
 
1444
        if (found == TRUE) {
 
1445
                path = gtk_tree_model_get_path (GTK_TREE_MODEL(priv->store), &iter);
 
1446
                model = gtk_tree_model_filter_new (GTK_TREE_MODEL(priv->store), path);
 
1447
                gtk_tree_path_free (path);
 
1448
        } else
 
1449
                model = NULL;
 
1450
 
 
1451
        return model;
 
1452
}
 
1453
 
 
1454
typedef struct {
 
1455
        BluetoothClientSetupFunc func;
 
1456
        BluetoothClient *client;
 
1457
} CreateDeviceData;
 
1458
 
 
1459
static void
 
1460
device_pair_callback (GDBusProxy         *proxy,
 
1461
                      GAsyncResult       *res,
 
1462
                      GSimpleAsyncResult *simple)
 
1463
{
 
1464
        GError *error = NULL;
 
1465
 
 
1466
        if (device1_call_pair_finish (DEVICE1(proxy), res, &error) == FALSE) {
 
1467
                g_debug ("Pair() failed for %s: %s",
 
1468
                         g_dbus_proxy_get_object_path (proxy),
 
1469
                         error->message);
 
1470
                g_simple_async_result_take_error (simple, error);
 
1471
        } else {
 
1472
                g_simple_async_result_set_op_res_gboolean (simple, TRUE);
 
1473
        }
 
1474
 
 
1475
        g_simple_async_result_complete_in_idle (simple);
 
1476
 
 
1477
        g_object_unref (simple);
 
1478
}
 
1479
 
 
1480
gboolean
 
1481
bluetooth_client_setup_device_finish (BluetoothClient  *client,
 
1482
                                      GAsyncResult     *res,
 
1483
                                      char            **path,
 
1484
                                      GError          **error)
 
1485
{
 
1486
        GSimpleAsyncResult *simple;
 
1487
 
 
1488
        simple = (GSimpleAsyncResult *) res;
 
1489
 
 
1490
        g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == bluetooth_client_setup_device);
 
1491
 
 
1492
        if (path != NULL)
 
1493
                *path = g_object_get_data (G_OBJECT (res), "device-object-path");
 
1494
 
 
1495
        if (g_simple_async_result_get_op_res_gboolean (simple))
 
1496
                return TRUE;
 
1497
        g_simple_async_result_propagate_error (simple, error);
 
1498
        return FALSE;
 
1499
}
 
1500
 
 
1501
void
 
1502
bluetooth_client_setup_device (BluetoothClient          *client,
 
1503
                               const char               *path,
 
1504
                               gboolean                  pair,
 
1505
                               GCancellable             *cancellable,
 
1506
                               GAsyncReadyCallback       callback,
 
1507
                               gpointer                  user_data)
 
1508
{
 
1509
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
1510
        GSimpleAsyncResult *simple;
 
1511
        GDBusProxy *device;
 
1512
        GtkTreeIter iter, adapter_iter;
 
1513
        gboolean paired;
 
1514
        GError *err = NULL;
 
1515
 
 
1516
        g_return_if_fail (BLUETOOTH_IS_CLIENT (client));
 
1517
 
 
1518
        simple = g_simple_async_result_new (G_OBJECT (client),
 
1519
                                            callback,
 
1520
                                            user_data,
 
1521
                                            bluetooth_client_setup_device);
 
1522
        g_simple_async_result_set_check_cancellable (simple, cancellable);
 
1523
        g_object_set_data (G_OBJECT (simple), "device-object-path", g_strdup (path));
 
1524
 
 
1525
        if (get_iter_from_path (priv->store, &iter, path) == FALSE) {
 
1526
                g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
 
1527
                                                 "Device with object path %s does not exist",
 
1528
                                                 path);
 
1529
                g_simple_async_result_complete_in_idle (simple);
 
1530
                g_object_unref (simple);
 
1531
                return;
 
1532
        }
 
1533
 
 
1534
        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
1535
                            BLUETOOTH_COLUMN_PROXY, &device,
 
1536
                            BLUETOOTH_COLUMN_PAIRED, &paired, -1);
 
1537
 
 
1538
        if (paired != FALSE &&
 
1539
            gtk_tree_model_iter_parent (GTK_TREE_MODEL(priv->store), &adapter_iter, &iter)) {
 
1540
                GDBusProxy *adapter;
 
1541
 
 
1542
                gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &adapter_iter,
 
1543
                                    BLUETOOTH_COLUMN_PROXY, &adapter,
 
1544
                                    -1);
 
1545
                adapter1_call_remove_device_sync (ADAPTER1 (adapter),
 
1546
                                                  path,
 
1547
                                                  NULL, &err);
 
1548
                if (err != NULL) {
 
1549
                        g_warning ("Failed to remove device: %s", err->message);
 
1550
                        g_error_free (err);
 
1551
                }
 
1552
                g_object_unref (adapter);
 
1553
        }
 
1554
 
 
1555
        if (pair == TRUE) {
 
1556
                device1_call_pair (DEVICE1(device),
 
1557
                                   cancellable,
 
1558
                                   (GAsyncReadyCallback) device_pair_callback,
 
1559
                                   simple);
 
1560
        } else {
 
1561
                g_simple_async_result_set_op_res_gboolean (simple, TRUE);
 
1562
                g_simple_async_result_complete_in_idle (simple);
 
1563
                g_object_unref (simple);
 
1564
        }
 
1565
 
 
1566
        g_object_unref (device);
 
1567
}
 
1568
 
 
1569
gboolean
 
1570
bluetooth_client_set_trusted (BluetoothClient *client,
 
1571
                              const char      *device,
 
1572
                              gboolean         trusted)
 
1573
{
 
1574
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
1575
        Properties *properties;
 
1576
        GError     *error = NULL;
 
1577
        GtkTreeIter iter;
 
1578
        gboolean   ret;
 
1579
 
 
1580
        g_return_val_if_fail (BLUETOOTH_IS_CLIENT (client), FALSE);
 
1581
        g_return_val_if_fail (device != NULL, FALSE);
 
1582
 
 
1583
        if (get_iter_from_path (priv->store, &iter, device) == FALSE) {
 
1584
                g_debug ("Couldn't find device '%s' in tree to mark it as trusted", device);
 
1585
                return FALSE;
 
1586
        }
 
1587
 
 
1588
        gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
 
1589
                            BLUETOOTH_COLUMN_PROPERTIES, &properties, -1);
 
1590
 
 
1591
        if (properties == NULL) {
 
1592
                g_debug ("Couldn't find properties for device '%s' in tree to mark it as trusted", device);
 
1593
                return FALSE;
 
1594
        }
 
1595
 
 
1596
        ret = properties_call_set_sync (properties, BLUEZ_DEVICE_INTERFACE, "Trusted",
 
1597
                                        g_variant_new_variant (g_variant_new_boolean (trusted)),
 
1598
                                        NULL, &error);
 
1599
        if (ret == FALSE) {
 
1600
                g_warning ("Failed to set Trusted to %d: %s", trusted, error->message);
 
1601
                g_error_free (error);
 
1602
        }
 
1603
 
 
1604
        g_object_unref (properties);
 
1605
        return ret;
 
1606
}
 
1607
 
 
1608
GDBusProxy *
 
1609
bluetooth_client_get_device (BluetoothClient *client,
 
1610
                             const char       *path)
 
1611
{
 
1612
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
1613
        GtkTreeIter iter;
 
1614
        GDBusProxy *proxy;
 
1615
 
 
1616
        if (get_iter_from_path (priv->store, &iter, path) == FALSE) {
 
1617
                return NULL;
 
1618
        }
 
1619
 
 
1620
        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
1621
                                        BLUETOOTH_COLUMN_PROXY, &proxy,
 
1622
                                        -1);
 
1623
        return proxy;
 
1624
}
 
1625
 
 
1626
static void
 
1627
connect_callback (GDBusProxy         *proxy,
 
1628
                  GAsyncResult       *res,
 
1629
                  GSimpleAsyncResult *simple)
 
1630
{
 
1631
        gboolean retval;
 
1632
        GError *error = NULL;
 
1633
 
 
1634
        retval = device1_call_connect_finish (DEVICE1(proxy), res, &error);
 
1635
        if (retval == FALSE) {
 
1636
                g_debug ("Connect failed for %s: %s",
 
1637
                         g_dbus_proxy_get_object_path (proxy), error->message);
 
1638
                g_simple_async_result_take_error (simple, error);
 
1639
        } else {
 
1640
                g_debug ("Connect succeeded for %s",
 
1641
                         g_dbus_proxy_get_object_path (proxy));
 
1642
                g_simple_async_result_set_op_res_gboolean (simple, retval);
 
1643
        }
 
1644
 
 
1645
        g_simple_async_result_complete_in_idle (simple);
 
1646
 
 
1647
        g_object_unref (simple);
 
1648
}
 
1649
 
 
1650
static void
 
1651
disconnect_callback (GDBusProxy   *proxy,
 
1652
                     GAsyncResult *res,
 
1653
                     GSimpleAsyncResult *simple)
 
1654
{
 
1655
        gboolean retval;
 
1656
        GError *error = NULL;
 
1657
 
 
1658
        retval = device1_call_disconnect_finish (DEVICE1(proxy), res, &error);
 
1659
        if (retval == FALSE) {
 
1660
                g_debug ("Disconnect failed for %s: %s",
 
1661
                         g_dbus_proxy_get_object_path (proxy),
 
1662
                         error->message);
 
1663
                g_simple_async_result_take_error (simple, error);
 
1664
        } else {
 
1665
                g_debug ("Disconnect succeeded for %s",
 
1666
                         g_dbus_proxy_get_object_path (proxy));
 
1667
                g_simple_async_result_set_op_res_gboolean (simple, retval);
 
1668
        }
 
1669
 
 
1670
        g_simple_async_result_complete_in_idle (simple);
 
1671
 
 
1672
        g_object_unref (simple);
 
1673
}
 
1674
 
 
1675
/**
 
1676
 * bluetooth_client_connect_service:
 
1677
 * @client: a #BluetoothClient
 
1678
 * @path: the object path on which to operate
 
1679
 * @connect: Whether try to connect or disconnect from services on a device
 
1680
 * @cancellable: optional #GCancellable object, %NULL to ignore
 
1681
 * @callback: (scope async): a #GAsyncReadyCallback to call when the connection is complete
 
1682
 * @user_data: the data to pass to callback function
 
1683
 *
 
1684
 * When the connection operation is finished, @callback will be called. You can
 
1685
 * then call bluetooth_client_connect_service_finish() to get the result of the
 
1686
 * operation.
 
1687
 **/
 
1688
void
 
1689
bluetooth_client_connect_service (BluetoothClient     *client,
 
1690
                                  const char          *path,
 
1691
                                  gboolean             connect,
 
1692
                                  GCancellable        *cancellable,
 
1693
                                  GAsyncReadyCallback  callback,
 
1694
                                  gpointer             user_data)
 
1695
{
 
1696
        BluetoothClientPrivate *priv = BLUETOOTH_CLIENT_GET_PRIVATE(client);
 
1697
        GtkTreeIter iter;
 
1698
        GSimpleAsyncResult *simple;
 
1699
        GDBusProxy *device;
 
1700
 
 
1701
        g_return_if_fail (BLUETOOTH_IS_CLIENT (client));
 
1702
        g_return_if_fail (path != NULL);
 
1703
 
 
1704
        if (get_iter_from_path (priv->store, &iter, path) == FALSE)
 
1705
                return;
 
1706
 
 
1707
        gtk_tree_model_get (GTK_TREE_MODEL(priv->store), &iter,
 
1708
                            BLUETOOTH_COLUMN_PROXY, &device,
 
1709
                            -1);
 
1710
 
 
1711
        simple = g_simple_async_result_new (G_OBJECT (client),
 
1712
                                            callback,
 
1713
                                            user_data,
 
1714
                                            bluetooth_client_connect_service);
 
1715
        g_simple_async_result_set_check_cancellable (simple, cancellable);
 
1716
 
 
1717
        if (connect) {
 
1718
                device1_call_connect (DEVICE1(device),
 
1719
                                      cancellable,
 
1720
                                      (GAsyncReadyCallback) connect_callback,
 
1721
                                      simple);
 
1722
        } else {
 
1723
                device1_call_disconnect (DEVICE1(device),
 
1724
                                         cancellable,
 
1725
                                         (GAsyncReadyCallback) disconnect_callback,
 
1726
                                         simple);
 
1727
        }
 
1728
 
 
1729
        g_object_unref (device);
 
1730
}
 
1731
 
 
1732
/**
 
1733
 * bluetooth_client_connect_service_finish:
 
1734
 * @client: a #BluetoothClient
 
1735
 * @res: a #GAsyncResult
 
1736
 * @error: a #GError
 
1737
 *
 
1738
 * Finishes the connection operation. See bluetooth_client_connect_service().
 
1739
 *
 
1740
 * Returns: %TRUE if the connection operation succeeded, %FALSE otherwise.
 
1741
 **/
 
1742
gboolean
 
1743
bluetooth_client_connect_service_finish (BluetoothClient *client,
 
1744
                                         GAsyncResult    *res,
 
1745
                                         GError         **error)
 
1746
{
 
1747
        GSimpleAsyncResult *simple;
 
1748
 
 
1749
        simple = (GSimpleAsyncResult *) res;
 
1750
 
 
1751
        g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == bluetooth_client_connect_service);
 
1752
 
 
1753
        if (g_simple_async_result_get_op_res_gboolean (simple))
 
1754
                return TRUE;
 
1755
        g_simple_async_result_propagate_error (simple, error);
 
1756
        return FALSE;
 
1757
}
 
1758
 
 
1759
#define BOOL_STR(x) (x ? "True" : "False")
 
1760
 
 
1761
void
 
1762
bluetooth_client_dump_device (GtkTreeModel *model,
 
1763
                              GtkTreeIter *iter)
 
1764
{
 
1765
        GDBusProxy *proxy;
 
1766
        char *address, *alias, *name, *icon, **uuids;
 
1767
        gboolean is_default, paired, trusted, connected, discoverable, discovering, powered, is_adapter;
 
1768
        GtkTreeIter parent;
 
1769
        BluetoothType type;
 
1770
 
 
1771
        gtk_tree_model_get (model, iter,
 
1772
                            BLUETOOTH_COLUMN_ADDRESS, &address,
 
1773
                            BLUETOOTH_COLUMN_ALIAS, &alias,
 
1774
                            BLUETOOTH_COLUMN_NAME, &name,
 
1775
                            BLUETOOTH_COLUMN_TYPE, &type,
 
1776
                            BLUETOOTH_COLUMN_ICON, &icon,
 
1777
                            BLUETOOTH_COLUMN_DEFAULT, &is_default,
 
1778
                            BLUETOOTH_COLUMN_PAIRED, &paired,
 
1779
                            BLUETOOTH_COLUMN_TRUSTED, &trusted,
 
1780
                            BLUETOOTH_COLUMN_CONNECTED, &connected,
 
1781
                            BLUETOOTH_COLUMN_DISCOVERABLE, &discoverable,
 
1782
                            BLUETOOTH_COLUMN_DISCOVERING, &discovering,
 
1783
                            BLUETOOTH_COLUMN_POWERED, &powered,
 
1784
                            BLUETOOTH_COLUMN_UUIDS, &uuids,
 
1785
                            BLUETOOTH_COLUMN_PROXY, &proxy,
 
1786
                            -1);
 
1787
        if (proxy) {
 
1788
                char *basename;
 
1789
                basename = g_path_get_basename(g_dbus_proxy_get_object_path(proxy));
 
1790
                is_adapter = !g_str_has_prefix (basename, "dev_");
 
1791
                g_free (basename);
 
1792
        } else {
 
1793
                is_adapter = !gtk_tree_model_iter_parent (model, &parent, iter);
 
1794
        }
 
1795
 
 
1796
        if (is_adapter != FALSE) {
 
1797
                /* Adapter */
 
1798
                g_print ("Adapter: %s (%s)\n", name, address);
 
1799
                if (is_default)
 
1800
                        g_print ("\tDefault adapter\n");
 
1801
                g_print ("\tD-Bus Path: %s\n", proxy ? g_dbus_proxy_get_object_path (proxy) : "(none)");
 
1802
                g_print ("\tDiscoverable: %s\n", BOOL_STR (discoverable));
 
1803
                if (discovering)
 
1804
                        g_print ("\tDiscovery in progress\n");
 
1805
                g_print ("\t%s\n", powered ? "Is powered" : "Is not powered");
 
1806
        } else {
 
1807
                /* Device */
 
1808
                g_print ("Device: %s (%s)\n", alias, address);
 
1809
                g_print ("\tD-Bus Path: %s\n", proxy ? g_dbus_proxy_get_object_path (proxy) : "(none)");
 
1810
                g_print ("\tType: %s Icon: %s\n", bluetooth_type_to_string (type), icon);
 
1811
                g_print ("\tPaired: %s Trusted: %s Connected: %s\n", BOOL_STR(paired), BOOL_STR(trusted), BOOL_STR(connected));
 
1812
                if (uuids != NULL) {
 
1813
                        guint i;
 
1814
                        g_print ("\tUUIDs: ");
 
1815
                        for (i = 0; uuids[i] != NULL; i++)
 
1816
                                g_print ("%s ", uuids[i]);
 
1817
                        g_print ("\n");
 
1818
                }
 
1819
        }
 
1820
        g_print ("\n");
 
1821
 
 
1822
        g_free (alias);
 
1823
        g_free (address);
 
1824
        g_free (icon);
 
1825
        g_clear_object (&proxy);
 
1826
        g_strfreev (uuids);
 
1827
}
 
1828