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

« back to all changes in this revision

Viewing changes to lib/bluetooth-chooser.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) 2006-2007  Bastien Nocera <hadess@hadess.net>
 
7
 *
 
8
 *
 
9
 *  This library is free software; you can redistribute it and/or
 
10
 *  modify it under the terms of the GNU Lesser General Public
 
11
 *  License as published by the Free Software Foundation; either
 
12
 *  version 2.1 of the License, or (at your option) any later version.
 
13
 *
 
14
 *  This library is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 *  Lesser General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU Lesser General Public
 
20
 *  License along with this library; if not, write to the Free Software
 
21
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
22
 *
 
23
 */
 
24
 
 
25
/**
 
26
 * SECTION:bluetooth-chooser
 
27
 * @short_description: a Bluetooth chooser widget
 
28
 * @stability: Stable
 
29
 * @include: bluetooth-chooser.h
 
30
 *
 
31
 * A tree-like widget used to select Bluetooth devices.
 
32
 **/
 
33
 
 
34
#ifdef HAVE_CONFIG_H
 
35
#include <config.h>
 
36
#endif
 
37
 
 
38
#include <gtk/gtk.h>
 
39
 
 
40
#include <glib/gi18n-lib.h>
 
41
 
 
42
#include "bluetooth-client.h"
 
43
#include "bluetooth-client-private.h"
 
44
#include "bluetooth-utils.h"
 
45
#include "bluetooth-chooser.h"
 
46
#include "bluetooth-chooser-private.h"
 
47
#include "gnome-bluetooth-enum-types.h"
 
48
#include "bluetooth-filter-widget.h"
 
49
 
 
50
enum {
 
51
        SELECTED_DEVICE_CHANGED,
 
52
        SELECTED_DEVICE_ACTIVATED,
 
53
        LAST_SIGNAL
 
54
};
 
55
 
 
56
static guint selection_table_signals[LAST_SIGNAL] = { 0 };
 
57
 
 
58
#define BLUETOOTH_CHOOSER_GET_PRIVATE(obj) \
 
59
        (bluetooth_chooser_get_instance_private (obj))
 
60
 
 
61
typedef struct _BluetoothChooserPrivate BluetoothChooserPrivate;
 
62
 
 
63
struct _BluetoothChooserPrivate {
 
64
        BluetoothClient *client;
 
65
        GtkTreeSelection *selection;
 
66
        GtkTreeModel *model, *filter, *adapter_model;
 
67
 
 
68
        gulong default_adapter_changed_id;
 
69
 
 
70
        /* Widgets/UI bits that can be shown or hidden */
 
71
        GtkCellRenderer *bonded_cell;
 
72
        GtkCellRenderer *connected_cell;
 
73
        GtkWidget *treeview, *scrolled_window;
 
74
        GtkWidget *search_hbox, *search_label, *spinner;
 
75
        GtkWidget *filters_vbox;
 
76
 
 
77
        /* Current filter */
 
78
        int device_type_filter;
 
79
        GtkTreeModel *device_type_filter_model;
 
80
        int device_category_filter;
 
81
        char *device_service_filter;
 
82
 
 
83
        guint show_paired : 1;
 
84
        guint show_connected : 1;
 
85
        guint show_searching : 1;
 
86
        guint show_device_type : 1;
 
87
        guint show_device_category : 1;
 
88
        guint disco_rq : 1;
 
89
        guint internal_filter : 1;
 
90
};
 
91
 
 
92
G_DEFINE_TYPE_WITH_PRIVATE(BluetoothChooser, bluetooth_chooser, GTK_TYPE_BOX)
 
93
 
 
94
enum {
 
95
        DEVICE_TYPE_FILTER_COL_NAME = 0,
 
96
        DEVICE_TYPE_FILTER_COL_MASK,
 
97
        DEVICE_TYPE_FILTER_NUM_COLS
 
98
};
 
99
 
 
100
enum {
 
101
        TREEVIEW_COLUMN_DEVICE = 0,
 
102
        TREEVIEW_COLUMN_TYPE = 1
 
103
};
 
104
 
 
105
static void
 
106
bonded_to_icon (GtkTreeViewColumn *column, GtkCellRenderer *cell,
 
107
              GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
 
108
{
 
109
        gboolean bonded;
 
110
 
 
111
        gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_PAIRED, &bonded, -1);
 
112
 
 
113
        g_object_set (cell, "icon-name", bonded ? "bluetooth-paired" : NULL, NULL);
 
114
}
 
115
 
 
116
static void
 
117
connected_to_icon (GtkTreeViewColumn *column, GtkCellRenderer *cell,
 
118
              GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
 
119
{
 
120
        gboolean connected;
 
121
 
 
122
        gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_CONNECTED, &connected, -1);
 
123
 
 
124
        g_object_set (cell, "icon-name", connected ? "gtk-connected" : NULL, NULL);
 
125
}
 
126
 
 
127
static void
 
128
type_to_text (GtkTreeViewColumn *column, GtkCellRenderer *cell,
 
129
              GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
 
130
{
 
131
        guint type;
 
132
 
 
133
        gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_TYPE, &type, -1);
 
134
 
 
135
        g_object_set (cell, "text", (type == 0) ? _("Unknown") : bluetooth_type_to_string (type), NULL);
 
136
}
 
137
 
 
138
static void
 
139
alias_to_label (GtkTreeViewColumn *column, GtkCellRenderer *cell,
 
140
                GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
 
141
{
 
142
        char *alias, *escaped, *label;
 
143
        gboolean connected;
 
144
 
 
145
        gtk_tree_model_get (model, iter,
 
146
                            BLUETOOTH_COLUMN_ALIAS, &alias,
 
147
                            BLUETOOTH_COLUMN_CONNECTED, &connected,
 
148
                            -1);
 
149
 
 
150
        if (connected == FALSE) {
 
151
                g_object_set (cell, "text", alias, NULL);
 
152
        } else {
 
153
                escaped = g_markup_escape_text (alias, -1);
 
154
                label = g_strdup_printf ("<b>%s</b>", escaped);
 
155
                g_free (escaped);
 
156
 
 
157
                g_object_set (cell, "markup", label, NULL);
 
158
                g_free (label);
 
159
        }
 
160
        g_free (alias);
 
161
}
 
162
 
 
163
static void
 
164
set_search_label (BluetoothChooser *self, gboolean state)
 
165
{
 
166
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
167
 
 
168
        if (priv->show_searching == FALSE) {
 
169
                /* Just making sure */
 
170
                gtk_spinner_stop (GTK_SPINNER (priv->spinner));
 
171
                return;
 
172
        }
 
173
        if (state == FALSE) {
 
174
                gtk_spinner_stop (GTK_SPINNER (priv->spinner));
 
175
                gtk_widget_hide (priv->spinner);
 
176
                gtk_label_set_text (GTK_LABEL (priv->search_label), _("No adapters available"));
 
177
        } else {
 
178
                gtk_widget_show (priv->spinner);
 
179
                gtk_spinner_start (GTK_SPINNER (priv->spinner));
 
180
                gtk_label_set_text (GTK_LABEL (priv->search_label), _("Searching for devices…"));
 
181
        }
 
182
}
 
183
 
 
184
/**
 
185
 * bluetooth_chooser_start_discovery:
 
186
 * @self: a #BluetoothChooser widget.
 
187
 *
 
188
 * Starts a discovery on the default Bluetooth adapter. Note that this will
 
189
 * only work if the Search label is visible, as otherwise the user has no
 
190
 * visual feedback that the process is on-going.
 
191
 *
 
192
 * See also: #BluetoothChooser:show-searching
 
193
 **/
 
194
void
 
195
bluetooth_chooser_start_discovery (BluetoothChooser *self)
 
196
{
 
197
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
198
 
 
199
        g_return_if_fail (priv->show_searching);
 
200
 
 
201
        g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", TRUE, NULL);
 
202
        set_search_label (self, TRUE);
 
203
        priv->disco_rq = TRUE;
 
204
}
 
205
 
 
206
/**
 
207
 * bluetooth_chooser_stop_discovery:
 
208
 * @self: a #BluetoothChooser widget.
 
209
 *
 
210
 * Stops a discovery started with #bluetooth_chooser_start_discovery.
 
211
 **/
 
212
void
 
213
bluetooth_chooser_stop_discovery (BluetoothChooser *self)
 
214
{
 
215
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
216
 
 
217
        g_return_if_fail (priv->show_searching);
 
218
 
 
219
        priv->disco_rq = FALSE;
 
220
        g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", FALSE, NULL);
 
221
}
 
222
 
 
223
static char *
 
224
bluetooth_chooser_get_selected_device_data (BluetoothChooser *self, guint column)
 
225
{
 
226
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
227
        GtkTreeIter iter;
 
228
        gchar *str;
 
229
        gboolean selected;
 
230
 
 
231
        selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter);
 
232
        if (selected == FALSE)
 
233
                return NULL;
 
234
 
 
235
        gtk_tree_model_get (priv->filter, &iter, column, &str, -1);
 
236
        return str;
 
237
}
 
238
 
 
239
/**
 
240
 * bluetooth_chooser_get_selected_device:
 
241
 * @self: a #BluetoothChooser widget.
 
242
 *
 
243
 * Returns the Bluetooth address for the currently selected device.
 
244
 *
 
245
 * Return value: the Bluetooth address for the currently selected device, or %NULL.
 
246
 **/
 
247
gchar *
 
248
bluetooth_chooser_get_selected_device (BluetoothChooser *self)
 
249
{
 
250
        return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_ADDRESS);
 
251
}
 
252
 
 
253
/**
 
254
 * bluetooth_chooser_get_selected_device_name:
 
255
 * @self: a #BluetoothChooser widget.
 
256
 *
 
257
 * Returns the name for the currently selected device.
 
258
 *
 
259
 * Return value: the name for the currently selected device, or %NULL.
 
260
 **/
 
261
gchar *
 
262
bluetooth_chooser_get_selected_device_name (BluetoothChooser *self)
 
263
{
 
264
        return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_NAME);
 
265
}
 
266
 
 
267
/**
 
268
 * bluetooth_chooser_get_selected_device_icon:
 
269
 * @self: a #BluetoothChooser widget.
 
270
 *
 
271
 * Returns the icon name to use to represent the currently selected device.
 
272
 *
 
273
 * Return value: the icon name to use to represent the currently selected device, or %NULL.
 
274
 **/
 
275
gchar *
 
276
bluetooth_chooser_get_selected_device_icon (BluetoothChooser *self)
 
277
{
 
278
        return bluetooth_chooser_get_selected_device_data (self, BLUETOOTH_COLUMN_ICON);
 
279
}
 
280
 
 
281
/**
 
282
 * bluetooth_chooser_get_selected_device_type:
 
283
 * @self: a #BluetoothChooser widget.
 
284
 *
 
285
 * Returns the #BluetoothType of the device selected.
 
286
 *
 
287
 * Return value: the #BluetoothType of the device selected, or '0' if unknown.
 
288
 **/
 
289
BluetoothType
 
290
bluetooth_chooser_get_selected_device_type (BluetoothChooser *self)
 
291
{
 
292
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
293
        GtkTreeIter iter;
 
294
        guint type;
 
295
        gboolean selected;
 
296
 
 
297
        selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter);
 
298
        if (selected == FALSE)
 
299
                return 0;
 
300
 
 
301
        gtk_tree_model_get (priv->filter, &iter, BLUETOOTH_COLUMN_TYPE, &type, -1);
 
302
        return type;
 
303
}
 
304
 
 
305
/**
 
306
 * bluetooth_chooser_get_selected_device_is_connected:
 
307
 * @self: a #BluetoothChooser widget.
 
308
 *
 
309
 * Returns whether the selected device is connected to this computer.
 
310
 *
 
311
 * Return value: whether the selected device is connected to this computer,
 
312
 * will always be %FALSE if no devices are selected.
 
313
 **/
 
314
gboolean
 
315
bluetooth_chooser_get_selected_device_is_connected (BluetoothChooser *self)
 
316
{
 
317
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
318
        GtkTreeIter iter;
 
319
        gboolean selected, connected;
 
320
 
 
321
        selected = gtk_tree_selection_get_selected (priv->selection, NULL, &iter);
 
322
        if (selected == FALSE)
 
323
                return 0;
 
324
 
 
325
        gtk_tree_model_get (priv->filter, &iter, BLUETOOTH_COLUMN_CONNECTED, &connected, -1);
 
326
        return connected;
 
327
}
 
328
 
 
329
/**
 
330
 * bluetooth_chooser_get_selected_device_info:
 
331
 * @self: A #BluetoothChooser widget.
 
332
 * @field: The identifier for the field to get data for.
 
333
 * @value: An empty #GValue to set.
 
334
 *
 
335
 * Returns whether the @value has been set.
 
336
 *
 
337
 * Return value: %TRUE if the @value has been set.
 
338
 **/
 
339
gboolean
 
340
bluetooth_chooser_get_selected_device_info (BluetoothChooser *self,
 
341
                                            const char *field,
 
342
                                            GValue *value)
 
343
{
 
344
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
345
        GEnumClass *eclass;
 
346
        GEnumValue *ev;
 
347
        GtkTreeIter iter;
 
348
 
 
349
        g_return_val_if_fail (field != NULL, FALSE);
 
350
 
 
351
        if (gtk_tree_selection_get_selected (priv->selection, NULL, &iter) == FALSE)
 
352
                return FALSE;
 
353
 
 
354
        eclass = g_type_class_ref (BLUETOOTH_TYPE_COLUMN);
 
355
        ev = g_enum_get_value_by_nick (eclass, field);
 
356
        if (ev == NULL) {
 
357
                g_warning ("Unknown field '%s'", field);
 
358
                g_type_class_unref (eclass);
 
359
                return FALSE;
 
360
        }
 
361
 
 
362
        gtk_tree_model_get_value (priv->filter, &iter, ev->value, value);
 
363
 
 
364
        g_type_class_unref (eclass);
 
365
 
 
366
        return TRUE;
 
367
}
 
368
 
 
369
/**
 
370
 * bluetooth_chooser_dump_selected_device:
 
371
 * @self: A #BluetoothChooser widget.
 
372
 *
 
373
 * Prints all the known attributes for the currently selected device
 
374
 * on the standard output. Useful for debugging.
 
375
 **/
 
376
void
 
377
bluetooth_chooser_dump_selected_device (BluetoothChooser *self)
 
378
{
 
379
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
380
        GtkTreeIter iter;
 
381
        GtkTreeModel *model;
 
382
 
 
383
        gtk_tree_selection_get_selected (priv->selection, &model, &iter);
 
384
 
 
385
        bluetooth_client_dump_device (model, &iter);
 
386
}
 
387
 
 
388
/**
 
389
 * bluetooth_chooser_get_model:
 
390
 * @self: A #BluetoothChooser widget.
 
391
 *
 
392
 * Returns the #BluetoothChooser's #GtkTreeModel.
 
393
 *
 
394
 * Return value: a #GtkTreeModel object.
 
395
 **/
 
396
GtkTreeModel *
 
397
bluetooth_chooser_get_model (BluetoothChooser *self)
 
398
{
 
399
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
400
 
 
401
        return priv->model;
 
402
}
 
403
 
 
404
/**
 
405
 * bluetooth_chooser_get_treeview:
 
406
 * @self: A #BluetoothChooser widget.
 
407
 *
 
408
 * Returns the #GtkTreeView object for the #BluetoothChooser.
 
409
 *
 
410
 * Return value: a #GtkTreeView object.
 
411
 **/
 
412
GtkWidget *
 
413
bluetooth_chooser_get_treeview (BluetoothChooser *self)
 
414
{
 
415
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
416
 
 
417
        return priv->treeview;
 
418
}
 
419
 
 
420
/**
 
421
 * bluetooth_chooser_get_scrolled_window:
 
422
 * @self: A #BluetoothChooser widget.
 
423
 *
 
424
 * Returns the #GtkScrolledWindow object for the #BluetoothChooser.
 
425
 * This is useful to set a minimum height to the chooser using
 
426
 * gtk_scrolled_window_set_min_content_height() or to join the
 
427
 * chooser with a toolbar.
 
428
 *
 
429
 * Return value: (transfer none): a #GtkScrolledWindow object.
 
430
 **/
 
431
GtkWidget *
 
432
bluetooth_chooser_get_scrolled_window (BluetoothChooser *self)
 
433
{
 
434
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
435
 
 
436
        return priv->scrolled_window;
 
437
}
 
438
 
 
439
static void
 
440
device_model_row_changed (GtkTreeModel *model,
 
441
                           GtkTreePath  *path,
 
442
                           GtkTreeIter  *iter,
 
443
                           gpointer      data)
 
444
{
 
445
        BluetoothChooser *self = BLUETOOTH_CHOOSER (data);
 
446
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
447
        char *address;
 
448
 
 
449
        /* Not the selection changing? */
 
450
        if (gtk_tree_selection_path_is_selected (priv->selection, path) == FALSE)
 
451
                return;
 
452
 
 
453
        g_object_notify (G_OBJECT (self), "device-selected");
 
454
        address = bluetooth_chooser_get_selected_device (self);
 
455
        g_signal_emit (G_OBJECT (self),
 
456
                       selection_table_signals[SELECTED_DEVICE_CHANGED],
 
457
                       0, address);
 
458
        g_free (address);
 
459
}
 
460
 
 
461
static void
 
462
select_browse_device_callback (GtkTreeSelection *selection, gpointer user_data)
 
463
{
 
464
        BluetoothChooser *self = user_data;
 
465
        char *address;
 
466
 
 
467
        g_object_notify (G_OBJECT(self), "device-selected");
 
468
        address = bluetooth_chooser_get_selected_device (self);
 
469
        g_signal_emit (G_OBJECT (self),
 
470
                       selection_table_signals[SELECTED_DEVICE_CHANGED],
 
471
                       0, address);
 
472
        g_free (address);
 
473
}
 
474
 
 
475
static void
 
476
row_activated_cb (GtkTreeView       *tree_view,
 
477
                  GtkTreePath       *path,
 
478
                  GtkTreeViewColumn *column,
 
479
                  BluetoothChooser  *self)
 
480
{
 
481
        char *address;
 
482
 
 
483
        address = bluetooth_chooser_get_selected_device (self);
 
484
        g_signal_emit (G_OBJECT (self),
 
485
                       selection_table_signals[SELECTED_DEVICE_ACTIVATED],
 
486
                       0, address);
 
487
        g_free (address);
 
488
}
 
489
 
 
490
static gboolean
 
491
filter_type_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv)
 
492
{
 
493
        int type;
 
494
 
 
495
        if (priv->device_type_filter == BLUETOOTH_TYPE_ANY)
 
496
                return TRUE;
 
497
 
 
498
        gtk_tree_model_get (model, iter, BLUETOOTH_COLUMN_TYPE, &type, -1);
 
499
        return (type & priv->device_type_filter);
 
500
}
 
501
 
 
502
static gboolean
 
503
filter_category_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv)
 
504
{
 
505
        gboolean bonded, trusted;
 
506
 
 
507
        if (priv->device_category_filter == BLUETOOTH_CATEGORY_ALL)
 
508
                return TRUE;
 
509
 
 
510
        gtk_tree_model_get (model, iter,
 
511
                            BLUETOOTH_COLUMN_PAIRED, &bonded,
 
512
                            BLUETOOTH_COLUMN_TRUSTED, &trusted,
 
513
                            -1);
 
514
 
 
515
        if (priv->device_category_filter == BLUETOOTH_CATEGORY_PAIRED)
 
516
                return bonded;
 
517
        if (priv->device_category_filter == BLUETOOTH_CATEGORY_TRUSTED)
 
518
                return trusted;
 
519
        if (priv->device_category_filter == BLUETOOTH_CATEGORY_NOT_PAIRED_OR_TRUSTED)
 
520
                return (!bonded && !trusted);
 
521
        if (priv->device_category_filter == BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED)
 
522
                return (bonded || trusted);
 
523
 
 
524
        g_assert_not_reached ();
 
525
 
 
526
        return FALSE;
 
527
}
 
528
 
 
529
static gboolean
 
530
filter_service_func (GtkTreeModel *model, GtkTreeIter *iter, BluetoothChooserPrivate *priv)
 
531
{
 
532
        char **services;
 
533
        gboolean ret = FALSE;
 
534
        guint i;
 
535
 
 
536
        if (priv->device_service_filter == NULL)
 
537
                return TRUE;
 
538
 
 
539
        gtk_tree_model_get (model, iter,
 
540
                            BLUETOOTH_COLUMN_UUIDS, &services,
 
541
                            -1);
 
542
        if (services == NULL) {
 
543
                /* FIXME we need a way to discover the services here */
 
544
                return FALSE;
 
545
        }
 
546
 
 
547
        for (i = 0; services[i] != NULL; i++) {
 
548
                if (g_str_equal (priv->device_service_filter, services[i]) != FALSE) {
 
549
                        ret = TRUE;
 
550
                        break;
 
551
                }
 
552
        }
 
553
 
 
554
        g_strfreev (services);
 
555
 
 
556
        return ret;
 
557
}
 
558
 
 
559
static gboolean
 
560
filter_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
 
561
{
 
562
        BluetoothChooser *self = BLUETOOTH_CHOOSER (data);
 
563
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
564
 
 
565
        return filter_type_func (model, iter, priv)
 
566
                && filter_category_func (model, iter, priv)
 
567
                && filter_service_func (model, iter, priv);
 
568
}
 
569
 
 
570
static void
 
571
filter_type_changed_cb (GObject *object, GParamSpec *spec, gpointer user_data)
 
572
{
 
573
        BluetoothChooser *self = BLUETOOTH_CHOOSER (object);
 
574
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
575
 
 
576
        if (priv->filter)
 
577
                gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
 
578
}
 
579
 
 
580
static void
 
581
filter_category_changed_cb (GObject *object, GParamSpec *spec, gpointer user_data)
 
582
{
 
583
        BluetoothChooser *self = BLUETOOTH_CHOOSER (object);
 
584
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
585
 
 
586
        if (priv->filter)
 
587
                gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
 
588
}
 
589
 
 
590
static void
 
591
adapter_model_row_changed (GtkTreeModel *model,
 
592
                           GtkTreePath  *path,
 
593
                           GtkTreeIter  *iter,
 
594
                           gpointer      data)
 
595
{
 
596
        BluetoothChooser *self = BLUETOOTH_CHOOSER (data);
 
597
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
598
        gboolean discovering, is_default, powered;
 
599
 
 
600
        /* Not an adapter changing? */
 
601
        if (gtk_tree_path_get_depth (path) != 1)
 
602
                return;
 
603
 
 
604
        gtk_tree_model_get (model, iter,
 
605
                            BLUETOOTH_COLUMN_DEFAULT, &is_default,
 
606
                            BLUETOOTH_COLUMN_DISCOVERING, &discovering,
 
607
                            BLUETOOTH_COLUMN_POWERED, &powered,
 
608
                            -1);
 
609
 
 
610
        if (is_default == FALSE)
 
611
                return;
 
612
        if (powered != FALSE && discovering == FALSE && priv->disco_rq != FALSE) {
 
613
                g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", TRUE, NULL);
 
614
                set_search_label (self, TRUE);
 
615
                return;
 
616
        }
 
617
        gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), powered);
 
618
        set_search_label (self, discovering);
 
619
}
 
620
 
 
621
static void default_adapter_changed (GObject    *gobject,
 
622
                                     GParamSpec *arg1,
 
623
                                     gpointer    data)
 
624
{
 
625
        BluetoothChooser *self = BLUETOOTH_CHOOSER (data);
 
626
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
627
        char *adapter;
 
628
 
 
629
        g_object_get (gobject, "default-adapter", &adapter, NULL);
 
630
 
 
631
        if (adapter == NULL) {
 
632
                gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), FALSE);
 
633
                set_search_label (self, FALSE);
 
634
                gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), NULL);
 
635
        }
 
636
 
 
637
        if (priv->model) {
 
638
                g_object_unref (priv->model);
 
639
                priv->model = NULL;
 
640
        }
 
641
 
 
642
        if (adapter == NULL)
 
643
                return;
 
644
 
 
645
        g_free (adapter);
 
646
 
 
647
        priv->model = bluetooth_client_get_device_model (priv->client);
 
648
        if (priv->model) {
 
649
                priv->filter = gtk_tree_model_filter_new (priv->model, NULL);
 
650
                gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter),
 
651
                                                        filter_func, self, NULL);
 
652
                gtk_tree_view_set_model (GTK_TREE_VIEW(priv->treeview), priv->filter);
 
653
                g_signal_connect (priv->filter, "row-changed",
 
654
                                  G_CALLBACK (device_model_row_changed), self);
 
655
                g_object_unref (priv->filter);
 
656
                gtk_widget_set_sensitive (GTK_WIDGET (priv->treeview), TRUE);
 
657
 
 
658
                /* Start a discovery if it was requested before we
 
659
                 * had an adapter available */
 
660
                if (priv->disco_rq != FALSE) {
 
661
                        bluetooth_chooser_start_discovery (self);
 
662
                        set_search_label (self, TRUE);
 
663
                }
 
664
        }
 
665
}
 
666
 
 
667
static GtkWidget *
 
668
create_treeview (BluetoothChooser *self)
 
669
{
 
670
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
671
        GtkWidget *scrolled, *tree;
 
672
        GtkCellRenderer *renderer;
 
673
        GtkTreeViewColumn *column;
 
674
 
 
675
        /* Create the scrolled window */
 
676
        scrolled = gtk_scrolled_window_new (NULL, NULL);
 
677
 
 
678
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolled),
 
679
                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
680
 
 
681
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolled),
 
682
                                             GTK_SHADOW_OUT);
 
683
 
 
684
        /* Create the tree view */
 
685
        tree = gtk_tree_view_new ();
 
686
 
 
687
        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(tree), TRUE);
 
688
 
 
689
        gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(tree), TRUE);
 
690
 
 
691
        g_object_set (tree, "show-expanders", FALSE, NULL);
 
692
 
 
693
        g_signal_connect (G_OBJECT (tree), "row-activated",
 
694
                          G_CALLBACK (row_activated_cb), self);
 
695
 
 
696
        column = gtk_tree_view_column_new ();
 
697
 
 
698
        gtk_tree_view_column_set_title (column, _("Device"));
 
699
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN(column), TRUE);
 
700
 
 
701
        /* The type icon */
 
702
        renderer = gtk_cell_renderer_pixbuf_new ();
 
703
        gtk_tree_view_column_set_spacing (column, 4);
 
704
        gtk_tree_view_column_pack_start (column, renderer, FALSE);
 
705
        gtk_tree_view_column_set_attributes (column, renderer,
 
706
                                             "icon-name", BLUETOOTH_COLUMN_ICON, NULL);
 
707
 
 
708
        /* The device name */
 
709
        renderer = gtk_cell_renderer_text_new ();
 
710
        gtk_tree_view_column_pack_start (column, renderer, TRUE);
 
711
        g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 
712
        gtk_tree_view_column_set_cell_data_func (column, renderer,
 
713
                                                 alias_to_label, NULL, NULL);
 
714
 
 
715
        /* The connected icon */
 
716
        priv->connected_cell = gtk_cell_renderer_pixbuf_new ();
 
717
        gtk_tree_view_column_pack_start (column, priv->connected_cell, FALSE);
 
718
 
 
719
        gtk_tree_view_column_set_cell_data_func (column, priv->connected_cell,
 
720
                                                 connected_to_icon, NULL, NULL);
 
721
        g_object_set (G_OBJECT (priv->connected_cell), "visible", priv->show_connected, NULL);
 
722
 
 
723
        /* The bonded icon */
 
724
        priv->bonded_cell = gtk_cell_renderer_pixbuf_new ();
 
725
        gtk_tree_view_column_pack_end (column, priv->bonded_cell, FALSE);
 
726
 
 
727
        gtk_tree_view_column_set_cell_data_func (column, priv->bonded_cell,
 
728
                                                 bonded_to_icon, NULL, NULL);
 
729
        g_object_set (G_OBJECT (priv->bonded_cell), "visible", priv->show_paired, NULL);
 
730
 
 
731
        gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);
 
732
 
 
733
        gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW(tree), -1,
 
734
                                                    _("Type"), gtk_cell_renderer_text_new(),
 
735
                                                    type_to_text, NULL, NULL);
 
736
 
 
737
        priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree));
 
738
 
 
739
        gtk_tree_selection_set_mode (priv->selection, GTK_SELECTION_SINGLE);
 
740
 
 
741
        g_signal_connect (G_OBJECT(priv->selection), "changed",
 
742
                          G_CALLBACK(select_browse_device_callback), self);
 
743
 
 
744
        /* Set the model, and filter */
 
745
        priv->model = bluetooth_client_get_device_model (priv->client);
 
746
        if (priv->model) {
 
747
                priv->filter = gtk_tree_model_filter_new (priv->model, NULL);
 
748
                gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter),
 
749
                                                        filter_func, self, NULL);
 
750
                gtk_tree_view_set_model (GTK_TREE_VIEW(tree), priv->filter);
 
751
                g_signal_connect (priv->filter, "row-changed",
 
752
                                  G_CALLBACK (device_model_row_changed), self);
 
753
                g_object_unref (priv->filter);
 
754
        } else {
 
755
                gtk_widget_set_sensitive (GTK_WIDGET (tree), FALSE);
 
756
                set_search_label (self, FALSE);
 
757
        }
 
758
 
 
759
        gtk_container_add (GTK_CONTAINER(scrolled), tree);
 
760
        priv->treeview = tree;
 
761
 
 
762
        return scrolled;
 
763
}
 
764
 
 
765
static void
 
766
bluetooth_chooser_init(BluetoothChooser *self)
 
767
{
 
768
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
769
 
 
770
        GtkWidget *vbox;
 
771
        GtkWidget *hbox;
 
772
 
 
773
        gtk_widget_push_composite_child ();
 
774
 
 
775
        g_object_set (G_OBJECT (self), "orientation", GTK_ORIENTATION_VERTICAL, NULL);
 
776
 
 
777
        priv->client = bluetooth_client_new ();
 
778
 
 
779
        /* Setup the widget itself */
 
780
        gtk_box_set_spacing (GTK_BOX(self), 18);
 
781
        gtk_container_set_border_width (GTK_CONTAINER(self), 0);
 
782
 
 
783
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
 
784
        gtk_widget_show (vbox);
 
785
        gtk_box_pack_start (GTK_BOX (self), vbox, TRUE, TRUE, 0);
 
786
 
 
787
        /* The treeview label */
 
788
        priv->search_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 24);
 
789
        gtk_widget_set_name (priv->search_hbox, "search_hbox");
 
790
        if (priv->show_searching)
 
791
                gtk_widget_show (priv->search_hbox);
 
792
        gtk_box_pack_end (GTK_BOX (vbox), priv->search_hbox, FALSE, TRUE, 0);
 
793
        gtk_widget_set_no_show_all (priv->search_hbox, TRUE);
 
794
 
 
795
        /* Setup the adapter disco mode callback for the search button */
 
796
        priv->adapter_model = bluetooth_client_get_adapter_model (priv->client);
 
797
        g_signal_connect (priv->adapter_model, "row-changed",
 
798
                          G_CALLBACK (adapter_model_row_changed), self);
 
799
 
 
800
        /* The searching label */
 
801
        hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
 
802
        gtk_widget_set_name (hbox, "searching label hbox");
 
803
        priv->spinner = gtk_spinner_new ();
 
804
        gtk_container_add (GTK_CONTAINER (hbox), priv->spinner);
 
805
        gtk_widget_show (priv->spinner);
 
806
        priv->search_label = gtk_label_new (_("Searching for devices…"));
 
807
        gtk_container_add (GTK_CONTAINER (hbox), priv->search_label);
 
808
        gtk_widget_show (priv->search_label);
 
809
        gtk_widget_show (hbox);
 
810
 
 
811
        if (priv->show_searching) {
 
812
                gboolean discovering;
 
813
 
 
814
                g_object_get (G_OBJECT (priv->client), "default-adapter-discovering", &discovering, NULL);
 
815
                set_search_label (self, discovering);
 
816
        }
 
817
 
 
818
        gtk_box_pack_start (GTK_BOX (priv->search_hbox), hbox, FALSE, TRUE, 0);
 
819
 
 
820
        /* The treeview */
 
821
        priv->scrolled_window = create_treeview (self);
 
822
        gtk_widget_show_all (priv->scrolled_window);
 
823
        gtk_box_pack_start (GTK_BOX (vbox), priv->scrolled_window, TRUE, TRUE, 0);
 
824
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
825
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window), GTK_SHADOW_IN);
 
826
 
 
827
        /* The filters */
 
828
        priv->device_type_filter_model = GTK_TREE_MODEL (gtk_list_store_new (DEVICE_TYPE_FILTER_NUM_COLS,
 
829
                                                         G_TYPE_STRING, G_TYPE_INT));
 
830
        priv->filters_vbox = bluetooth_filter_widget_new ();
 
831
        gtk_widget_show (priv->filters_vbox);
 
832
        gtk_box_pack_start (GTK_BOX (self), priv->filters_vbox, FALSE, TRUE, 0);
 
833
        gtk_widget_set_no_show_all (priv->filters_vbox, TRUE);
 
834
 
 
835
        /* if filters are not visible hide the vbox */
 
836
        if (!priv->show_device_type && !priv->show_device_category)
 
837
                gtk_widget_hide (priv->filters_vbox);
 
838
 
 
839
        priv->default_adapter_changed_id = g_signal_connect (priv->client, "notify::default-adapter",
 
840
                                                             G_CALLBACK (default_adapter_changed), self);
 
841
 
 
842
        g_signal_connect(self, "notify::device-type-filter",
 
843
                         G_CALLBACK(filter_type_changed_cb), NULL);
 
844
        g_signal_connect(self, "notify::device-category-filter",
 
845
                         G_CALLBACK(filter_category_changed_cb), NULL);
 
846
 
 
847
        gtk_widget_pop_composite_child ();
 
848
}
 
849
 
 
850
static GObject *
 
851
bluetooth_chooser_constructor (GType                  type,
 
852
                               guint                  n_construct_params,
 
853
                               GObjectConstructParam *construct_params)
 
854
{
 
855
        BluetoothChooser *self;
 
856
        BluetoothChooserPrivate *priv;
 
857
        GObject *object;
 
858
 
 
859
        object = G_OBJECT_CLASS (bluetooth_chooser_parent_class)->constructor (type,
 
860
                                                                               n_construct_params,
 
861
                                                                               construct_params);
 
862
        self = BLUETOOTH_CHOOSER (object);
 
863
        priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
864
 
 
865
        if (priv->internal_filter) {
 
866
                bluetooth_filter_widget_bind_filter (BLUETOOTH_FILTER_WIDGET (priv->filters_vbox), self);
 
867
        }
 
868
        return object;
 
869
}
 
870
 
 
871
static void
 
872
bluetooth_chooser_finalize (GObject *object)
 
873
{
 
874
        BluetoothChooser *self = BLUETOOTH_CHOOSER (object);
 
875
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
876
 
 
877
        if (priv->client) {
 
878
                g_signal_handler_disconnect (G_OBJECT(priv->client), priv->default_adapter_changed_id);
 
879
                priv->default_adapter_changed_id = 0;
 
880
 
 
881
                g_object_set (G_OBJECT (priv->client), "default-adapter-discovering", FALSE, NULL);
 
882
                g_object_unref (priv->client);
 
883
                priv->client = NULL;
 
884
        }
 
885
        if (priv->adapter_model) {
 
886
                g_object_unref (priv->adapter_model);
 
887
                priv->adapter_model = NULL;
 
888
        }
 
889
        if (priv->model != NULL) {
 
890
                g_object_unref (priv->model);
 
891
                priv->model = NULL;
 
892
        }
 
893
        g_free (priv->device_service_filter);
 
894
 
 
895
        G_OBJECT_CLASS(bluetooth_chooser_parent_class)->finalize(object);
 
896
}
 
897
 
 
898
enum {
 
899
        PROP_0,
 
900
        PROP_DEVICE_SELECTED,
 
901
        PROP_SHOW_PAIRING,
 
902
        PROP_SHOW_CONNECTED,
 
903
        PROP_SHOW_SEARCHING,
 
904
        PROP_SHOW_DEVICE_TYPE,
 
905
        PROP_SHOW_DEVICE_TYPE_COLUMN,
 
906
        PROP_SHOW_DEVICE_CATEGORY,
 
907
        PROP_DEVICE_TYPE_FILTER,
 
908
        PROP_DEVICE_CATEGORY_FILTER,
 
909
        PROP_DEVICE_SERVICE_FILTER,
 
910
        PROP_INTERNAL_FILTER
 
911
};
 
912
 
 
913
static void
 
914
bluetooth_chooser_set_property (GObject *object, guint prop_id,
 
915
                                         const GValue *value, GParamSpec *pspec)
 
916
{
 
917
        BluetoothChooser *self = BLUETOOTH_CHOOSER (object);
 
918
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE (self);
 
919
 
 
920
        switch (prop_id) {
 
921
        case PROP_DEVICE_SELECTED: {
 
922
                const char *address;
 
923
                char *selected;
 
924
                GtkTreeIter iter;
 
925
                gboolean cont;
 
926
 
 
927
                address = g_value_get_string (value);
 
928
                if (address == NULL) {
 
929
                        gtk_tree_selection_unselect_all (priv->selection);
 
930
                        return;
 
931
                }
 
932
 
 
933
                selected = bluetooth_chooser_get_selected_device (self);
 
934
                if (g_strcmp0 (selected, address) == 0) {
 
935
                        g_free (selected);
 
936
                        return;
 
937
                }
 
938
                g_free (selected);
 
939
 
 
940
                cont = gtk_tree_model_get_iter_first (priv->filter, &iter);
 
941
                while (cont == TRUE) {
 
942
                        char *iaddress;
 
943
                        gtk_tree_model_get (priv->filter, &iter,
 
944
                                            BLUETOOTH_COLUMN_ADDRESS, &iaddress, -1);
 
945
                        if (g_strcmp0 (iaddress, address) == 0) {
 
946
                                gtk_tree_selection_select_iter (priv->selection, &iter);
 
947
                                g_free (iaddress);
 
948
                                return;
 
949
                        }
 
950
                        g_free (iaddress);
 
951
 
 
952
                        cont = gtk_tree_model_iter_next (priv->filter, &iter);
 
953
                }
 
954
                break;
 
955
        }
 
956
        case PROP_SHOW_PAIRING:
 
957
                priv->show_paired = g_value_get_boolean (value);
 
958
                if (priv->bonded_cell != NULL)
 
959
                        g_object_set (G_OBJECT (priv->bonded_cell), "visible", priv->show_paired, NULL);
 
960
                break;
 
961
        case PROP_SHOW_CONNECTED:
 
962
                priv->show_connected = g_value_get_boolean (value);
 
963
                if (priv->connected_cell != NULL)
 
964
                        g_object_set (G_OBJECT (priv->connected_cell), "visible", priv->show_connected, NULL);
 
965
                break;
 
966
        case PROP_SHOW_SEARCHING:
 
967
                priv->show_searching = g_value_get_boolean (value);
 
968
                g_object_set (G_OBJECT (priv->search_hbox), "visible", priv->show_searching, NULL);
 
969
                break;
 
970
        case PROP_SHOW_DEVICE_TYPE:
 
971
                priv->show_device_type = g_value_get_boolean (value);
 
972
                if (priv->internal_filter) {
 
973
                        if (priv->show_device_type || priv->show_device_category)
 
974
                                g_object_set (G_OBJECT (priv->filters_vbox), "visible", TRUE, NULL);
 
975
                        else
 
976
                                g_object_set (G_OBJECT (priv->filters_vbox), "visible", FALSE, NULL);
 
977
                }
 
978
                break;
 
979
        case PROP_SHOW_DEVICE_TYPE_COLUMN: {
 
980
                GtkTreeViewColumn *column;
 
981
 
 
982
                column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_TYPE);
 
983
                gtk_tree_view_column_set_visible (column,
 
984
                                                  g_value_get_boolean (value));
 
985
 
 
986
                column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_DEVICE);
 
987
                if (g_value_get_boolean (value))
 
988
                        gtk_tree_view_column_set_title (column, _("Device"));
 
989
                else
 
990
                        gtk_tree_view_column_set_title (column, _("Devices"));
 
991
                break;
 
992
                }
 
993
        case PROP_SHOW_DEVICE_CATEGORY:
 
994
                priv->show_device_category = g_value_get_boolean (value);
 
995
                if (priv->internal_filter) {
 
996
                        if (priv->show_device_type || priv->show_device_category)
 
997
                                g_object_set (G_OBJECT (priv->filters_vbox), "visible", TRUE, NULL);
 
998
                        else
 
999
                                g_object_set (G_OBJECT (priv->filters_vbox), "visible", FALSE, NULL);
 
1000
                }
 
1001
                break;
 
1002
        case PROP_DEVICE_TYPE_FILTER:
 
1003
                priv->device_type_filter = g_value_get_int (value);
 
1004
                g_object_notify (object, "device-type-filter");
 
1005
                break;
 
1006
        case PROP_DEVICE_CATEGORY_FILTER:
 
1007
                priv->device_category_filter = g_value_get_enum (value);
 
1008
                g_object_notify (object, "device-category-filter");
 
1009
                break;
 
1010
        case PROP_DEVICE_SERVICE_FILTER:
 
1011
                g_free (priv->device_service_filter);
 
1012
                priv->device_service_filter = g_value_dup_string (value);
 
1013
                if (priv->filter)
 
1014
                        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter));
 
1015
                break;
 
1016
        case PROP_INTERNAL_FILTER:
 
1017
                priv->internal_filter = g_value_get_boolean (value);
 
1018
                g_object_set (G_OBJECT (priv->filters_vbox), "visible", priv->internal_filter, NULL);
 
1019
                break;
 
1020
        default:
 
1021
                G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
 
1022
                break;
 
1023
        }
 
1024
}
 
1025
 
 
1026
static void
 
1027
bluetooth_chooser_get_property (GObject *object, guint prop_id,
 
1028
                                         GValue *value, GParamSpec *pspec)
 
1029
{
 
1030
        BluetoothChooser *self = BLUETOOTH_CHOOSER(object);
 
1031
        BluetoothChooserPrivate *priv = BLUETOOTH_CHOOSER_GET_PRIVATE(self);
 
1032
 
 
1033
        switch (prop_id) {
 
1034
        case PROP_DEVICE_SELECTED:
 
1035
                g_value_take_string (value, bluetooth_chooser_get_selected_device (self));
 
1036
                break;
 
1037
        case PROP_SHOW_PAIRING:
 
1038
                g_value_set_boolean (value, priv->show_paired);
 
1039
                break;
 
1040
        case PROP_SHOW_CONNECTED:
 
1041
                g_value_set_boolean (value, priv->show_connected);
 
1042
                break;
 
1043
        case PROP_SHOW_SEARCHING:
 
1044
                g_value_set_boolean (value, priv->show_searching);
 
1045
                break;
 
1046
        case PROP_SHOW_DEVICE_TYPE:
 
1047
                g_value_set_boolean (value, priv->show_device_type);
 
1048
                break;
 
1049
        case PROP_SHOW_DEVICE_TYPE_COLUMN:
 
1050
                g_value_set_boolean (value,
 
1051
                                     gtk_tree_view_column_get_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (priv->treeview), TREEVIEW_COLUMN_TYPE)));
 
1052
                break;
 
1053
        case PROP_SHOW_DEVICE_CATEGORY:
 
1054
                g_value_set_boolean (value, priv->show_device_category);
 
1055
                break;
 
1056
        case PROP_DEVICE_TYPE_FILTER:
 
1057
                g_value_set_int (value, priv->device_type_filter);
 
1058
                break;
 
1059
        case PROP_DEVICE_CATEGORY_FILTER:
 
1060
                g_value_set_enum (value, priv->device_category_filter);
 
1061
                break;
 
1062
        case PROP_DEVICE_SERVICE_FILTER:
 
1063
                g_value_set_string (value, priv->device_service_filter);
 
1064
                break;
 
1065
        case PROP_INTERNAL_FILTER:
 
1066
                g_value_set_boolean (value, priv->internal_filter);
 
1067
                break;
 
1068
        default:
 
1069
                G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
 
1070
                break;
 
1071
        }
 
1072
}
 
1073
 
 
1074
static void
 
1075
bluetooth_chooser_class_init (BluetoothChooserClass *klass)
 
1076
{
 
1077
        /* Use to calculate the maximum value for the
 
1078
         * device-type-filter value */
 
1079
        guint i;
 
1080
        int max_filter_val;
 
1081
 
 
1082
        bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
 
1083
 
 
1084
        G_OBJECT_CLASS(klass)->constructor = bluetooth_chooser_constructor;
 
1085
        G_OBJECT_CLASS(klass)->finalize = bluetooth_chooser_finalize;
 
1086
 
 
1087
        G_OBJECT_CLASS(klass)->set_property = bluetooth_chooser_set_property;
 
1088
        G_OBJECT_CLASS(klass)->get_property = bluetooth_chooser_get_property;
 
1089
 
 
1090
        /**
 
1091
         * BluetoothChooser::selected-device-changed:
 
1092
         * @chooser: a #BluetoothChooser widget which received the signal
 
1093
         * @address: the Bluetooth address for the currently selected device, or %NULL
 
1094
         *
 
1095
         * The #BluetoothChooser::selected-device-changed signal is launched when the
 
1096
         * selected device is changed, it will be %NULL if a device was unselected.
 
1097
         **/
 
1098
        selection_table_signals[SELECTED_DEVICE_CHANGED] =
 
1099
                g_signal_new ("selected-device-changed",
 
1100
                              G_TYPE_FROM_CLASS (klass),
 
1101
                              G_SIGNAL_RUN_LAST,
 
1102
                              G_STRUCT_OFFSET (BluetoothChooserClass, selected_device_changed),
 
1103
                              NULL, NULL,
 
1104
                              g_cclosure_marshal_VOID__STRING,
 
1105
                              G_TYPE_NONE, 1, G_TYPE_STRING);
 
1106
        /**
 
1107
         * BluetoothChooser::selected-device-activated:
 
1108
         * @chooser: a #BluetoothChooser widget which received the signal
 
1109
         * @address: the Bluetooth address for the currently selected device, or %NULL
 
1110
         *
 
1111
         * The #BluetoothChooser::selected-device-activated signal is launched when a
 
1112
         * device is double-clicked in the chooser.
 
1113
         **/
 
1114
        selection_table_signals[SELECTED_DEVICE_ACTIVATED] =
 
1115
                g_signal_new ("selected-device-activated",
 
1116
                              G_TYPE_FROM_CLASS (klass),
 
1117
                              G_SIGNAL_RUN_LAST,
 
1118
                              G_STRUCT_OFFSET (BluetoothChooserClass, selected_device_activated),
 
1119
                              NULL, NULL,
 
1120
                              g_cclosure_marshal_VOID__STRING,
 
1121
                              G_TYPE_NONE, 1, G_TYPE_STRING);
 
1122
 
 
1123
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1124
                                         PROP_DEVICE_SELECTED, g_param_spec_string ("device-selected",
 
1125
                                                                                    "device-selected", "The Bluetooth address for the currently selected device, or %NULL", NULL, G_PARAM_READABLE | G_PARAM_WRITABLE));
 
1126
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1127
                                         PROP_SHOW_PAIRING, g_param_spec_boolean ("show-pairing",
 
1128
                                                                                  "show-pairing", "Whether to show the pairing column in the tree.", FALSE, G_PARAM_READWRITE));
 
1129
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1130
                                         PROP_SHOW_CONNECTED, g_param_spec_boolean ("show-connected",
 
1131
                                                                                    "show-connected", "Whether to show the connected column in the tree.", FALSE, G_PARAM_READWRITE));
 
1132
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1133
                                         PROP_SHOW_SEARCHING, g_param_spec_boolean ("show-searching",
 
1134
                                                                                    "show-searching",
 
1135
                                                                                    "Whether to show the Searching label , this is necessary if you want to programmatically start a discovery, using bluetooth_chooser_start_discovery()",
 
1136
                                                                                    FALSE, G_PARAM_READWRITE));
 
1137
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1138
                                         PROP_SHOW_DEVICE_TYPE, g_param_spec_boolean ("show-device-type",
 
1139
                                                                                      "show-device-type", "Whether to show the device type filter", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
1140
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1141
                                         PROP_SHOW_DEVICE_TYPE_COLUMN, g_param_spec_boolean ("show-device-type-column",
 
1142
                                                                                             "show-device-type-column", "Whether to show the device type column", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
1143
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1144
                                         PROP_SHOW_DEVICE_CATEGORY, g_param_spec_boolean ("show-device-category",
 
1145
                                                                                          "show-device-category", "Whether to show the device category filter", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
1146
        for (i = 0, max_filter_val = 0 ; i < _BLUETOOTH_TYPE_NUM_TYPES; i++)
 
1147
                max_filter_val += 1 << i;
 
1148
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1149
                                         PROP_DEVICE_TYPE_FILTER, g_param_spec_int ("device-type-filter",
 
1150
                                                                                    "device-type-filter", "A bitmask of #BluetoothType to show", BLUETOOTH_TYPE_ANY, max_filter_val, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
1151
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1152
                                         PROP_DEVICE_CATEGORY_FILTER, g_param_spec_enum ("device-category-filter",
 
1153
                                                                                         "device-category-filter", "The #BluetoothCategory to show", BLUETOOTH_TYPE_CATEGORY, BLUETOOTH_CATEGORY_ALL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
1154
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1155
                                         PROP_DEVICE_SERVICE_FILTER, g_param_spec_string ("device-service-filter",
 
1156
                                                                                          "device-service-filter", "A string representing the service to filter for", NULL, G_PARAM_WRITABLE));
 
1157
        g_object_class_install_property (G_OBJECT_CLASS(klass),
 
1158
                                         PROP_INTERNAL_FILTER, g_param_spec_boolean ("has-internal-device-filter",
 
1159
                                                                                          "has-internal-device-filter", "Whether the #BluetoothChooser should be constructed with a visible #BluetoothFilterWidget", TRUE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
 
1160
}
 
1161
 
 
1162
/**
 
1163
 * bluetooth_chooser_new:
 
1164
 *
 
1165
 * Returns a new #BluetoothChooser widget.
 
1166
 *
 
1167
 * Return value: A #BluetoothChooser widget
 
1168
 **/
 
1169
GtkWidget *
 
1170
bluetooth_chooser_new (void)
 
1171
{
 
1172
        return g_object_new(BLUETOOTH_TYPE_CHOOSER, NULL);
 
1173
}
 
1174