~ubuntu-branches/ubuntu/utopic/gnome-control-center/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/53_use_ubuntu_help.patch/panels/bluetooth/cc-bluetooth-panel.c

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher, Sebastien Bacher, Robert Ancell, Iain Lane, Edward Donovan, Rico Tzschichholz, Jeremy Bicha, David Henningsson
  • Date: 2012-11-21 19:32:45 UTC
  • mfrom: (1.1.63)
  • Revision ID: package-import@ubuntu.com-20121121193245-mj61nzz1z4fk3z25
Tags: 1:3.6.3-0ubuntu1
[ Sebastien Bacher ]
* New upstream version
* debian/control.in: recommends libcanberra-pulse (lp: #1004973)
* debian/patches/58_ubuntu_icon_views_redesign.patch:
  - drop most of the changes, keep the different grid size though
    to fit on screen with our extra icons
* debian/patches/91_dont_show_in_unity.patch:
  - dropped, show the upstream printer panel and the layout tab
* debian/patches/revert_git_keyboard_gsettings.patch,
  debian/patches/revert_git_stop_using_gconf.patch:
  - dropped the gconf->gsettings reverts

[ Robert Ancell ]
* New upstream release (LP: #1010317)
* debian/control:
  - Bump build-depends on libgnome-desktop-3-dev, libwacom-dev
  - Add build-depends on libclutter-1.0-dev, libclutter-gtk-1.0-dev,
    libpwquality-dev
  - Drop build-depends on libgnomekbd-dev
* debian/patches/60_ubuntu_nav_bar.patch:
  - Disabled for now, doesn't apply
* debian/patches/revert_ua_gsettings.patch:
  - We can use GSettings for universal access now
* debian/patches/00git_online_accounts_gtkgrid.patch:
* debian/patches/00git_online_accounts_layout.part:
* debian/patches/git_wacom_translations.patch:
  - Applied upstream

[ Iain Lane ]
* Add Build-Depends on libxkbfile-dev
* New upstream release.
* Refresh all patches to apply cleanly.

[ Edward Donovan ]
* debian/source_gnome-control-center.py: Fix for Python 3. (LP: #1013171)

[ Rico Tzschichholz ]
* debian/control.in:
  - Build-depend on gtk-doc-tools instead of docbook directly
  - Bump minimum glib-2.0, gnome-desktop3, gnome-settings-daemon
     and gsettings-desktop-schemas

[ Jeremy Bicha ]
* Dropped more patches applied in new version:
  - git_unmute_sound_event.patch
  - git_fix_big_editable_labels.patch
  - 96_sound_nua_panel.patch
* debian/patches/04_new_appearance_settings.patch:
  - Dropped, this is now packaged separately as gnome-control-center-unity
* debian/patches/10_keyboard_layout_on_unity.patch:
  - Don't change the keyboard panel name when not running Unity
* debian/patches/52_ubuntu_language_list_mods.patch:
  - Don't disable adding current language to the list. While this
    fix shows the current language twice, at least it avoids the
    "Ubuntu suddenly in Chinese" bug (LP: #1035219)
* debian/patches/53_use_ubuntu_help.patch:
  - Only show Ubuntu help when running Unity
* debian/patches/58_hide_gdm_notifications.patch:
  - Hide "Show notifications when locked" settings when running Unity
    since it's a GNOME Shell-specific feature
* debian/patches/63_normal_scrollbar_in_a11y.patch:
  - Drop, overlay-scrollbars should handle this instead
* debian/patches/91_dont_show_in_unity.patch:
  - Hide Printers & Region panels in Unity until we're ready to switch
    to them.
* debian/patches/fix-crash-on-user-panel.patch:
  - Dropped, GNOME says it's obsolete
* debian/rules:
  - Build with -z,defs again
  - Explicitly disable ibus support since ibus 1.4 isn't supported in
    this version
* debian/control.in:
  - Drop ubuntu-docs and gnome-user-guide from recommends to suggests
  - Don't recommend indicators; let's leave that to Unity

[ David Henningsson ]
* sound_nua_panel.patch: Rebase to gnome 3.6 

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) 2006-2010  Bastien Nocera <hadess@hadess.net>
 
6
 *
 
7
 *
 
8
 *  This program is free software; you can redistribute it and/or modify
 
9
 *  it under the terms of the GNU General Public License as published by
 
10
 *  the Free Software Foundation; either version 2 of the License, or
 
11
 *  (at your option) any later version.
 
12
 *
 
13
 *  This program is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 *  GNU General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU General Public License
 
19
 *  along with this program; if not, write to the Free Software
 
20
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
21
 *
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include <config.h>
 
26
#endif
 
27
 
 
28
#include <glib/gi18n-lib.h>
 
29
#include <shell/cc-shell.h>
 
30
 
 
31
#include "cc-bluetooth-panel.h"
 
32
 
 
33
#include <bluetooth-client.h>
 
34
#include <bluetooth-utils.h>
 
35
#include <bluetooth-killswitch.h>
 
36
#include <bluetooth-chooser.h>
 
37
#include <bluetooth-plugin-manager.h>
 
38
 
 
39
CC_PANEL_REGISTER (CcBluetoothPanel, cc_bluetooth_panel)
 
40
 
 
41
#define BLUETOOTH_PANEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_BLUETOOTH_PANEL, CcBluetoothPanelPrivate))
 
42
 
 
43
#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s))
 
44
 
 
45
#define KEYBOARD_PREFS          "keyboard"
 
46
#define MOUSE_PREFS             "mouse"
 
47
#define SOUND_PREFS             "sound"
 
48
#define WIZARD                  "bluetooth-wizard"
 
49
 
 
50
struct CcBluetoothPanelPrivate {
 
51
        GtkBuilder          *builder;
 
52
        GtkWidget           *chooser;
 
53
        char                *selected_bdaddr;
 
54
        BluetoothClient     *client;
 
55
        BluetoothKillswitch *killswitch;
 
56
        gboolean             debug;
 
57
        GHashTable          *connecting_devices;
 
58
};
 
59
 
 
60
static void cc_bluetooth_panel_finalize (GObject *object);
 
61
 
 
62
static void
 
63
launch_command (const char *command)
 
64
{
 
65
        GError *error = NULL;
 
66
 
 
67
        if (!g_spawn_command_line_async(command, &error)) {
 
68
                g_warning ("Couldn't execute command '%s': %s\n", command, error->message);
 
69
                g_error_free (error);
 
70
        }
 
71
}
 
72
 
 
73
static const char *
 
74
cc_bluetooth_panel_get_help_uri (CcPanel *panel)
 
75
{
 
76
  return "help:gnome-help/bluetooth";
 
77
}
 
78
 
 
79
static void
 
80
cc_bluetooth_panel_class_init (CcBluetoothPanelClass *klass)
 
81
{
 
82
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
83
        CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
 
84
 
 
85
        object_class->finalize = cc_bluetooth_panel_finalize;
 
86
 
 
87
        panel_class->get_help_uri = cc_bluetooth_panel_get_help_uri;
 
88
 
 
89
        g_type_class_add_private (klass, sizeof (CcBluetoothPanelPrivate));
 
90
}
 
91
 
 
92
static void
 
93
cc_bluetooth_panel_finalize (GObject *object)
 
94
{
 
95
        CcBluetoothPanel *self;
 
96
 
 
97
        bluetooth_plugin_manager_cleanup ();
 
98
 
 
99
        self = CC_BLUETOOTH_PANEL (object);
 
100
        g_clear_object (&self->priv->builder);
 
101
        g_clear_object (&self->priv->killswitch);
 
102
        g_clear_object (&self->priv->client);
 
103
 
 
104
        g_clear_pointer (&self->priv->connecting_devices, g_hash_table_destroy);
 
105
        g_clear_pointer (&self->priv->selected_bdaddr, g_free);
 
106
 
 
107
        G_OBJECT_CLASS (cc_bluetooth_panel_parent_class)->finalize (object);
 
108
}
 
109
 
 
110
enum {
 
111
        CONNECTING_NOTEBOOK_PAGE_SWITCH = 0,
 
112
        CONNECTING_NOTEBOOK_PAGE_SPINNER = 1
 
113
};
 
114
 
 
115
static void
 
116
set_connecting_page (CcBluetoothPanel *self,
 
117
                     int               page)
 
118
{
 
119
        if (page == CONNECTING_NOTEBOOK_PAGE_SPINNER)
 
120
                gtk_spinner_start (GTK_SPINNER (WID ("connecting_spinner")));
 
121
        gtk_notebook_set_current_page (GTK_NOTEBOOK (WID ("connecting_notebook")), page);
 
122
        if (page == CONNECTING_NOTEBOOK_PAGE_SWITCH)
 
123
                gtk_spinner_start (GTK_SPINNER (WID ("connecting_spinner")));
 
124
}
 
125
 
 
126
static void
 
127
remove_connecting (CcBluetoothPanel *self,
 
128
                   const char       *bdaddr)
 
129
{
 
130
        g_hash_table_remove (self->priv->connecting_devices, bdaddr);
 
131
}
 
132
 
 
133
static void
 
134
add_connecting (CcBluetoothPanel *self,
 
135
                const char       *bdaddr)
 
136
{
 
137
        g_hash_table_insert (self->priv->connecting_devices,
 
138
                             g_strdup (bdaddr),
 
139
                             GINT_TO_POINTER (1));
 
140
}
 
141
 
 
142
static gboolean
 
143
is_connecting (CcBluetoothPanel *self,
 
144
               const char       *bdaddr)
 
145
{
 
146
        return GPOINTER_TO_INT (g_hash_table_lookup (self->priv->connecting_devices,
 
147
                                                     bdaddr));
 
148
}
 
149
 
 
150
typedef struct {
 
151
        char             *bdaddr;
 
152
        CcBluetoothPanel *self;
 
153
} ConnectData;
 
154
 
 
155
static void
 
156
connect_done (GObject      *source_object,
 
157
              GAsyncResult *res,
 
158
              gpointer      user_data)
 
159
{
 
160
        CcBluetoothPanel *self;
 
161
        char *bdaddr;
 
162
        gboolean success;
 
163
        ConnectData *data = (ConnectData *) user_data;
 
164
 
 
165
        success = bluetooth_client_connect_service_finish (BLUETOOTH_CLIENT (source_object),
 
166
                                                           res, NULL);
 
167
 
 
168
        self = data->self;
 
169
 
 
170
        /* Check whether the same device is now selected, and update the UI */
 
171
        bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
 
172
        if (g_strcmp0 (bdaddr, data->bdaddr) == 0) {
 
173
                GtkSwitch *button;
 
174
 
 
175
                button = GTK_SWITCH (WID ("switch_connection"));
 
176
                /* Reset the switch if it failed */
 
177
                if (success == FALSE)
 
178
                        gtk_switch_set_active (button, !gtk_switch_get_active (button));
 
179
                set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SWITCH);
 
180
        }
 
181
 
 
182
        remove_connecting (self, data->bdaddr);
 
183
 
 
184
        g_free (bdaddr);
 
185
        g_object_unref (data->self);
 
186
        g_free (data->bdaddr);
 
187
        g_free (data);
 
188
}
 
189
 
 
190
static void
 
191
switch_connected_active_changed (GtkSwitch        *button,
 
192
                                 GParamSpec       *spec,
 
193
                                 CcBluetoothPanel *self)
 
194
{
 
195
        char *proxy;
 
196
        GValue value = { 0, };
 
197
        ConnectData *data;
 
198
        char *bdaddr;
 
199
 
 
200
        bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
 
201
        if (is_connecting (self, bdaddr)) {
 
202
                g_free (bdaddr);
 
203
                return;
 
204
        }
 
205
 
 
206
        if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
 
207
                                                        "proxy", &value) == FALSE) {
 
208
                g_warning ("Could not get D-Bus proxy for selected device");
 
209
                return;
 
210
        }
 
211
        proxy = g_strdup (g_dbus_proxy_get_object_path (g_value_get_object (&value)));
 
212
        g_value_unset (&value);
 
213
 
 
214
        if (proxy == NULL)
 
215
                return;
 
216
 
 
217
        data = g_new0 (ConnectData, 1);
 
218
        data->bdaddr = bdaddr;
 
219
        data->self = g_object_ref (self);
 
220
 
 
221
        bluetooth_client_connect_service (self->priv->client,
 
222
                                          proxy,
 
223
                                          gtk_switch_get_active (button),
 
224
                                          NULL,
 
225
                                          connect_done,
 
226
                                          data);
 
227
 
 
228
        add_connecting (self, data->bdaddr);
 
229
        set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SPINNER);
 
230
        g_free (proxy);
 
231
}
 
232
 
 
233
enum {
 
234
        NOTEBOOK_PAGE_EMPTY = 0,
 
235
        NOTEBOOK_PAGE_PROPS = 1
 
236
};
 
237
 
 
238
static void
 
239
set_notebook_page (CcBluetoothPanel *self,
 
240
                   int               page)
 
241
{
 
242
        gtk_notebook_set_current_page (GTK_NOTEBOOK (WID ("props_notebook")), page);
 
243
}
 
244
 
 
245
static void
 
246
add_extra_setup_widgets (CcBluetoothPanel *self,
 
247
                         const char       *bdaddr)
 
248
{
 
249
        GValue value = { 0 };
 
250
        char **uuids;
 
251
        GList *list, *l;
 
252
        GtkWidget *container;
 
253
 
 
254
        if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
 
255
                                                        "uuids", &value) == FALSE)
 
256
                return;
 
257
 
 
258
        uuids = (char **) g_value_get_boxed (&value);
 
259
        list = bluetooth_plugin_manager_get_widgets (bdaddr, (const char **) uuids);
 
260
        if (list == NULL) {
 
261
                g_value_unset (&value);
 
262
                return;
 
263
        }
 
264
 
 
265
        container = WID ("additional_setup_box");
 
266
        for (l = list; l != NULL; l = l->next) {
 
267
                GtkWidget *widget = l->data;
 
268
                gtk_box_pack_start (GTK_BOX (container), widget,
 
269
                                    FALSE, FALSE, 0);
 
270
                gtk_widget_show_all (widget);
 
271
        }
 
272
        gtk_widget_show (container);
 
273
        g_value_unset (&value);
 
274
}
 
275
 
 
276
static void
 
277
remove_extra_setup_widgets (CcBluetoothPanel *self)
 
278
{
 
279
        GtkWidget *box;
 
280
 
 
281
        box = WID ("additional_setup_box");
 
282
        gtk_container_forall (GTK_CONTAINER (box), (GtkCallback) gtk_widget_destroy, NULL);
 
283
        gtk_widget_hide (WID ("additional_setup_box"));
 
284
}
 
285
 
 
286
static void
 
287
cc_bluetooth_panel_update_properties (CcBluetoothPanel *self)
 
288
{
 
289
        char *bdaddr;
 
290
        GtkSwitch *button;
 
291
 
 
292
        button = GTK_SWITCH (WID ("switch_connection"));
 
293
        g_signal_handlers_block_by_func (button, switch_connected_active_changed, self);
 
294
 
 
295
        /* Hide all the buttons now, and show them again if we need to */
 
296
        gtk_widget_hide (WID ("keyboard_box"));
 
297
        gtk_widget_hide (WID ("sound_box"));
 
298
        gtk_widget_hide (WID ("mouse_box"));
 
299
        gtk_widget_hide (WID ("browse_box"));
 
300
        gtk_widget_hide (WID ("send_box"));
 
301
 
 
302
        bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
 
303
 
 
304
        /* Remove the extra setup widgets */
 
305
        if (g_strcmp0 (self->priv->selected_bdaddr, bdaddr) != 0)
 
306
                remove_extra_setup_widgets (self);
 
307
 
 
308
        if (bdaddr == NULL) {
 
309
                gtk_widget_set_sensitive (WID ("properties_vbox"), FALSE);
 
310
                gtk_switch_set_active (button, FALSE);
 
311
                gtk_widget_set_sensitive (WID ("button_delete"), FALSE);
 
312
                set_notebook_page (self, NOTEBOOK_PAGE_EMPTY);
 
313
        } else {
 
314
                BluetoothType type;
 
315
                gboolean connected;
 
316
                GValue value = { 0 };
 
317
                GHashTable *services;
 
318
 
 
319
                if (self->priv->debug)
 
320
                        bluetooth_chooser_dump_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
 
321
 
 
322
                gtk_widget_set_sensitive (WID ("properties_vbox"), TRUE);
 
323
 
 
324
                if (is_connecting (self, bdaddr)) {
 
325
                        gtk_switch_set_active (button, TRUE);
 
326
                        set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SPINNER);
 
327
                } else {
 
328
                        connected = bluetooth_chooser_get_selected_device_is_connected (BLUETOOTH_CHOOSER (self->priv->chooser));
 
329
                        gtk_switch_set_active (button, connected);
 
330
                        set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SWITCH);
 
331
                }
 
332
 
 
333
                /* Paired */
 
334
                bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
 
335
                                                            "paired", &value);
 
336
                gtk_label_set_text (GTK_LABEL (WID ("paired_label")),
 
337
                                    g_value_get_boolean (&value) ? _("Yes") : _("No"));
 
338
                g_value_unset (&value);
 
339
 
 
340
                /* Connection */
 
341
                bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
 
342
                                                            "services", &value);
 
343
                services = g_value_get_boxed (&value);
 
344
                gtk_widget_set_sensitive (GTK_WIDGET (button), (services != NULL));
 
345
                g_value_unset (&value);
 
346
 
 
347
                /* UUIDs */
 
348
                if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
 
349
                                                                "uuids", &value)) {
 
350
                        const char **uuids;
 
351
                        guint i;
 
352
 
 
353
                        uuids = (const char **) g_value_get_boxed (&value);
 
354
                        for (i = 0; uuids && uuids[i] != NULL; i++) {
 
355
                                if (g_str_equal (uuids[i], "OBEXObjectPush"))
 
356
                                        gtk_widget_show (WID ("send_box"));
 
357
                                else if (g_str_equal (uuids[i], "OBEXFileTransfer"))
 
358
                                        gtk_widget_show (WID ("browse_box"));
 
359
                        }
 
360
                        g_value_unset (&value);
 
361
                }
 
362
 
 
363
                /* Type */
 
364
                type = bluetooth_chooser_get_selected_device_type (BLUETOOTH_CHOOSER (self->priv->chooser));
 
365
                gtk_label_set_text (GTK_LABEL (WID ("type_label")), bluetooth_type_to_string (type));
 
366
                switch (type) {
 
367
                case BLUETOOTH_TYPE_KEYBOARD:
 
368
                        gtk_widget_show (WID ("keyboard_box"));
 
369
                        break;
 
370
                case BLUETOOTH_TYPE_MOUSE:
 
371
                case BLUETOOTH_TYPE_TABLET:
 
372
                        gtk_widget_show (WID ("mouse_box"));
 
373
                        break;
 
374
                case BLUETOOTH_TYPE_HEADSET:
 
375
                case BLUETOOTH_TYPE_HEADPHONES:
 
376
                case BLUETOOTH_TYPE_OTHER_AUDIO:
 
377
                        gtk_widget_show (WID ("sound_box"));
 
378
                default:
 
379
                        /* others? */
 
380
                        ;
 
381
                }
 
382
 
 
383
                /* Extra widgets */
 
384
                if (g_strcmp0 (self->priv->selected_bdaddr, bdaddr) != 0)
 
385
                        add_extra_setup_widgets (self, bdaddr);
 
386
 
 
387
                gtk_label_set_text (GTK_LABEL (WID ("address_label")), bdaddr);
 
388
 
 
389
                gtk_widget_set_sensitive (WID ("button_delete"), TRUE);
 
390
                set_notebook_page (self, NOTEBOOK_PAGE_PROPS);
 
391
        }
 
392
 
 
393
        g_free (self->priv->selected_bdaddr);
 
394
        self->priv->selected_bdaddr = bdaddr;
 
395
 
 
396
        g_signal_handlers_unblock_by_func (button, switch_connected_active_changed, self);
 
397
}
 
398
 
 
399
static void
 
400
power_callback (GObject          *object,
 
401
                GParamSpec       *spec,
 
402
                CcBluetoothPanel *self)
 
403
{
 
404
        gboolean state;
 
405
 
 
406
        state = gtk_switch_get_active (GTK_SWITCH (WID ("switch_bluetooth")));
 
407
        g_debug ("Power switched to %s", state ? "off" : "on");
 
408
        bluetooth_killswitch_set_state (self->priv->killswitch,
 
409
                                        state ? BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED : BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED);
 
410
}
 
411
 
 
412
static void
 
413
cc_bluetooth_panel_update_treeview_message (CcBluetoothPanel *self,
 
414
                                            const char       *message)
 
415
{
 
416
        if (message != NULL) {
 
417
                gtk_widget_hide (self->priv->chooser);
 
418
                gtk_widget_show (WID ("message_scrolledwindow"));
 
419
 
 
420
                gtk_label_set_text (GTK_LABEL (WID ("message_label")),
 
421
                                    message);
 
422
        } else {
 
423
                gtk_widget_hide (WID ("message_scrolledwindow"));
 
424
                gtk_widget_show (self->priv->chooser);
 
425
        }
 
426
}
 
427
 
 
428
static void
 
429
cc_bluetooth_panel_update_power (CcBluetoothPanel *self)
 
430
{
 
431
        BluetoothKillswitchState state;
 
432
        char *path;
 
433
        gboolean powered, sensitive;
 
434
 
 
435
        g_object_get (G_OBJECT (self->priv->client),
 
436
                      "default-adapter", &path,
 
437
                      "default-adapter-powered", &powered,
 
438
                      NULL);
 
439
        state = bluetooth_killswitch_get_state (self->priv->killswitch);
 
440
 
 
441
        g_debug ("Updating power, default adapter: %s (powered: %s), killswitch: %s",
 
442
                 path ? path : "(none)",
 
443
                 powered ? "on" : "off",
 
444
                 bluetooth_killswitch_state_to_string (state));
 
445
 
 
446
        if (path == NULL &&
 
447
            bluetooth_killswitch_has_killswitches (self->priv->killswitch) &&
 
448
            state != BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) {
 
449
                g_debug ("Default adapter is unpowered, but should be available");
 
450
                sensitive = TRUE;
 
451
                cc_bluetooth_panel_update_treeview_message (self, _("Bluetooth is disabled"));
 
452
        } else if (path == NULL &&
 
453
                   state == BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) {
 
454
                g_debug ("Bluetooth is Hard blocked");
 
455
                sensitive = FALSE;
 
456
                cc_bluetooth_panel_update_treeview_message (self, _("Bluetooth is disabled by hardware switch"));
 
457
        } else if (path == NULL) {
 
458
                sensitive = FALSE;
 
459
                g_debug ("No Bluetooth available");
 
460
                cc_bluetooth_panel_update_treeview_message (self, _("No Bluetooth adapters found"));
 
461
        } else {
 
462
                sensitive = TRUE;
 
463
                g_debug ("Bluetooth is available and powered");
 
464
                cc_bluetooth_panel_update_treeview_message (self, NULL);
 
465
        }
 
466
 
 
467
        g_free (path);
 
468
        gtk_widget_set_sensitive (WID ("box_power") , sensitive);
 
469
        gtk_widget_set_sensitive (WID ("box_vis") , sensitive);
 
470
}
 
471
 
 
472
static void
 
473
switch_panel (CcBluetoothPanel *self,
 
474
              const char       *panel)
 
475
{
 
476
  CcShell *shell;
 
477
  GError *error = NULL;
 
478
 
 
479
  shell = cc_panel_get_shell (CC_PANEL (self));
 
480
  if (cc_shell_set_active_panel_from_id (shell, panel, NULL, &error) == FALSE)
 
481
    {
 
482
      g_warning ("Failed to activate '%s' panel: %s", panel, error->message);
 
483
      g_error_free (error);
 
484
    }
 
485
}
 
486
 
 
487
static gboolean
 
488
keyboard_callback (GtkButton        *button,
 
489
                   CcBluetoothPanel *self)
 
490
{
 
491
        switch_panel (self, KEYBOARD_PREFS);
 
492
        return TRUE;
 
493
}
 
494
 
 
495
static gboolean
 
496
mouse_callback (GtkButton        *button,
 
497
                CcBluetoothPanel *self)
 
498
{
 
499
        switch_panel (self, MOUSE_PREFS);
 
500
        return TRUE;
 
501
}
 
502
 
 
503
static gboolean
 
504
sound_callback (GtkButton        *button,
 
505
                CcBluetoothPanel *self)
 
506
{
 
507
        switch_panel (self, SOUND_PREFS);
 
508
        return TRUE;
 
509
}
 
510
 
 
511
static void
 
512
send_callback (GtkButton        *button,
 
513
               CcBluetoothPanel *self)
 
514
{
 
515
        char *bdaddr, *alias;
 
516
 
 
517
        bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
 
518
        alias = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (self->priv->chooser));
 
519
 
 
520
        bluetooth_send_to_address (bdaddr, alias);
 
521
 
 
522
        g_free (bdaddr);
 
523
        g_free (alias);
 
524
}
 
525
 
 
526
static void
 
527
mount_finish_cb (GObject *source_object,
 
528
                 GAsyncResult *res,
 
529
                 gpointer user_data)
 
530
{
 
531
        GError *error = NULL;
 
532
 
 
533
        if (bluetooth_browse_address_finish (source_object, res, &error) == FALSE) {
 
534
                g_printerr ("Failed to mount OBEX volume: %s", error->message);
 
535
                g_error_free (error);
 
536
                return;
 
537
        }
 
538
}
 
539
 
 
540
static void
 
541
browse_callback (GtkButton        *button,
 
542
                 CcBluetoothPanel *self)
 
543
{
 
544
        char *bdaddr;
 
545
 
 
546
        bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
 
547
 
 
548
        bluetooth_browse_address (G_OBJECT (self), bdaddr,
 
549
                                  GDK_CURRENT_TIME, mount_finish_cb, NULL);
 
550
 
 
551
        g_free (bdaddr);
 
552
}
 
553
 
 
554
/* Visibility/Discoverable */
 
555
static void discoverable_changed (BluetoothClient  *client,
 
556
                                  GParamSpec       *spec,
 
557
                                  CcBluetoothPanel *self);
 
558
 
 
559
static void
 
560
switch_discoverable_active_changed (GtkSwitch        *button,
 
561
                                    GParamSpec       *spec,
 
562
                                    CcBluetoothPanel *self)
 
563
{
 
564
        g_signal_handlers_block_by_func (self->priv->client, discoverable_changed, self);
 
565
        g_object_set (G_OBJECT (self->priv->client), "default-adapter-discoverable",
 
566
                      gtk_switch_get_active (button), NULL);
 
567
        g_signal_handlers_unblock_by_func (self->priv->client, discoverable_changed, self);
 
568
}
 
569
 
 
570
static void
 
571
cc_bluetooth_panel_update_visibility (CcBluetoothPanel *self)
 
572
{
 
573
        gboolean discoverable;
 
574
        GtkSwitch *button;
 
575
        char *name;
 
576
 
 
577
        button = GTK_SWITCH (WID ("switch_discoverable"));
 
578
        g_object_get (G_OBJECT (self->priv->client), "default-adapter-discoverable", &discoverable, NULL);
 
579
        g_signal_handlers_block_by_func (button, switch_discoverable_active_changed, self);
 
580
        gtk_switch_set_active (button, discoverable);
 
581
        g_signal_handlers_unblock_by_func (button, switch_discoverable_active_changed, self);
 
582
 
 
583
        g_object_get (G_OBJECT (self->priv->client), "default-adapter-name", &name, NULL);
 
584
        if (name == NULL) {
 
585
                gtk_widget_set_sensitive (WID ("switch_discoverable"), FALSE);
 
586
                gtk_widget_set_sensitive (WID ("visible_label"), FALSE);
 
587
                gtk_label_set_text (GTK_LABEL (WID ("visible_label")), _("Visibility"));
 
588
        } else {
 
589
                char *label;
 
590
 
 
591
                label = g_strdup_printf (_("Visibility of “%s”"), name);
 
592
                g_free (name);
 
593
                gtk_label_set_text (GTK_LABEL (WID ("visible_label")), label);
 
594
                g_free (label);
 
595
 
 
596
                gtk_widget_set_sensitive (WID ("switch_discoverable"), TRUE);
 
597
                gtk_widget_set_sensitive (WID ("visible_label"), TRUE);
 
598
        }
 
599
}
 
600
 
 
601
static void
 
602
discoverable_changed (BluetoothClient  *client,
 
603
                      GParamSpec       *spec,
 
604
                      CcBluetoothPanel *self)
 
605
{
 
606
        cc_bluetooth_panel_update_visibility (self);
 
607
}
 
608
 
 
609
static void
 
610
name_changed (BluetoothClient  *client,
 
611
              GParamSpec       *spec,
 
612
              CcBluetoothPanel *self)
 
613
{
 
614
        cc_bluetooth_panel_update_visibility (self);
 
615
}
 
616
 
 
617
static void
 
618
device_selected_changed (BluetoothChooser *chooser,
 
619
                         GParamSpec       *spec,
 
620
                         CcBluetoothPanel *self)
 
621
{
 
622
        cc_bluetooth_panel_update_properties (self);
 
623
}
 
624
 
 
625
static gboolean
 
626
show_confirm_dialog (CcBluetoothPanel *self,
 
627
                     const char *name)
 
628
{
 
629
        GtkWidget *dialog, *parent;
 
630
        gint response;
 
631
 
 
632
        parent = gtk_widget_get_toplevel (GTK_WIDGET (self));
 
633
        dialog = gtk_message_dialog_new (GTK_WINDOW (parent), GTK_DIALOG_MODAL,
 
634
                                         GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
 
635
                                         _("Remove '%s' from the list of devices?"), name);
 
636
        g_object_set (G_OBJECT (dialog), "secondary-text",
 
637
                      _("If you remove the device, you will have to set it up again before next use."),
 
638
                      NULL);
 
639
 
 
640
        gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
 
641
        gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_REMOVE, GTK_RESPONSE_ACCEPT);
 
642
 
 
643
        response = gtk_dialog_run (GTK_DIALOG (dialog));
 
644
 
 
645
        gtk_widget_destroy (dialog);
 
646
 
 
647
        if (response == GTK_RESPONSE_ACCEPT)
 
648
                return TRUE;
 
649
 
 
650
        return FALSE;
 
651
}
 
652
 
 
653
static gboolean
 
654
remove_selected_device (CcBluetoothPanel *self)
 
655
{
 
656
        GValue value = { 0, };
 
657
        char *device, *adapter;
 
658
        GDBusProxy *adapter_proxy;
 
659
        GError *error = NULL;
 
660
        GVariant *ret;
 
661
 
 
662
        if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
 
663
                                                        "proxy", &value) == FALSE) {
 
664
                return FALSE;
 
665
        }
 
666
        device = g_strdup (g_dbus_proxy_get_object_path (g_value_get_object (&value)));
 
667
        g_value_unset (&value);
 
668
 
 
669
        g_object_get (G_OBJECT (self->priv->client), "default-adapter", &adapter, NULL);
 
670
        adapter_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
 
671
                                                       G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 
672
                                                       NULL,
 
673
                                                       "org.bluez",
 
674
                                                       adapter,
 
675
                                                       "org.bluez.Adapter",
 
676
                                                       NULL,
 
677
                                                       &error);
 
678
        g_free (adapter);
 
679
        if (adapter_proxy == NULL) {
 
680
                g_warning ("Failed to create a GDBusProxy for the default adapter: %s", error->message);
 
681
                g_error_free (error);
 
682
                g_free (device);
 
683
                return FALSE;
 
684
        }
 
685
 
 
686
        ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (adapter_proxy),
 
687
                                      "RemoveDevice",
 
688
                                      g_variant_new ("(o)", device),
 
689
                                      G_DBUS_CALL_FLAGS_NONE,
 
690
                                      -1,
 
691
                                      NULL,
 
692
                                      &error);
 
693
        if (ret == NULL) {
 
694
                g_warning ("Failed to remove device '%s': %s", device, error->message);
 
695
                g_error_free (error);
 
696
        } else {
 
697
                g_variant_unref (ret);
 
698
        }
 
699
 
 
700
        g_object_unref (adapter_proxy);
 
701
        g_free (device);
 
702
 
 
703
        return (ret != NULL);
 
704
}
 
705
 
 
706
/* Treeview buttons */
 
707
static void
 
708
delete_clicked (GtkToolButton    *button,
 
709
                CcBluetoothPanel *self)
 
710
{
 
711
        char *address, *name;
 
712
 
 
713
        address = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
 
714
        g_assert (address);
 
715
 
 
716
        name = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (self->priv->chooser));
 
717
 
 
718
        if (show_confirm_dialog (self, name) != FALSE) {
 
719
                if (remove_selected_device (self))
 
720
                        bluetooth_plugin_manager_device_deleted (address);
 
721
        }
 
722
 
 
723
        g_free (address);
 
724
        g_free (name);
 
725
}
 
726
 
 
727
static void
 
728
setup_clicked (GtkToolButton    *button,
 
729
               CcBluetoothPanel *self)
 
730
{
 
731
        launch_command (WIZARD);
 
732
}
 
733
 
 
734
/* Overall device state */
 
735
static void
 
736
cc_bluetooth_panel_update_state (CcBluetoothPanel *self)
 
737
{
 
738
        char *bdaddr;
 
739
 
 
740
        g_object_get (G_OBJECT (self->priv->client),
 
741
                      "default-adapter", &bdaddr,
 
742
                      NULL);
 
743
        gtk_widget_set_sensitive (WID ("toolbar"), (bdaddr != NULL));
 
744
        g_free (bdaddr);
 
745
}
 
746
 
 
747
static void
 
748
cc_bluetooth_panel_update_powered_state (CcBluetoothPanel *self)
 
749
{
 
750
        gboolean powered;
 
751
 
 
752
        g_object_get (G_OBJECT (self->priv->client),
 
753
                      "default-adapter-powered", &powered,
 
754
                      NULL);
 
755
        gtk_switch_set_active (GTK_SWITCH (WID ("switch_bluetooth")), powered);
 
756
}
 
757
 
 
758
static void
 
759
default_adapter_power_changed (BluetoothClient  *client,
 
760
                               GParamSpec       *spec,
 
761
                               CcBluetoothPanel *self)
 
762
{
 
763
        g_debug ("Default adapter power changed");
 
764
        cc_bluetooth_panel_update_powered_state (self);
 
765
}
 
766
 
 
767
static void
 
768
default_adapter_changed (BluetoothClient  *client,
 
769
                         GParamSpec       *spec,
 
770
                         CcBluetoothPanel *self)
 
771
{
 
772
        g_debug ("Default adapter changed");
 
773
        cc_bluetooth_panel_update_state (self);
 
774
        cc_bluetooth_panel_update_power (self);
 
775
        cc_bluetooth_panel_update_powered_state (self);
 
776
}
 
777
 
 
778
static void
 
779
killswitch_changed (BluetoothKillswitch      *killswitch,
 
780
                    BluetoothKillswitchState  state,
 
781
                    CcBluetoothPanel         *self)
 
782
{
 
783
        g_debug ("Killswitch changed to state '%s' (%d)", bluetooth_killswitch_state_to_string (state) , state);
 
784
        cc_bluetooth_panel_update_state (self);
 
785
        cc_bluetooth_panel_update_power (self);
 
786
}
 
787
 
 
788
static void
 
789
cc_bluetooth_panel_init (CcBluetoothPanel *self)
 
790
{
 
791
        GtkWidget *widget;
 
792
        GError *error = NULL;
 
793
        GtkStyleContext *context;
 
794
 
 
795
        self->priv = BLUETOOTH_PANEL_PRIVATE (self);
 
796
 
 
797
        bluetooth_plugin_manager_init ();
 
798
        self->priv->killswitch = bluetooth_killswitch_new ();
 
799
        self->priv->client = bluetooth_client_new ();
 
800
        self->priv->connecting_devices = g_hash_table_new_full (g_str_hash,
 
801
                                                                g_str_equal,
 
802
                                                                (GDestroyNotify) g_free,
 
803
                                                                NULL);
 
804
        self->priv->debug = g_getenv ("BLUETOOTH_DEBUG") != NULL;
 
805
 
 
806
        self->priv->builder = gtk_builder_new ();
 
807
        gtk_builder_set_translation_domain (self->priv->builder, GETTEXT_PACKAGE);
 
808
        gtk_builder_add_from_file (self->priv->builder,
 
809
                                   PKGDATADIR "/bluetooth.ui",
 
810
                                   &error);
 
811
        if (error != NULL) {
 
812
                g_warning ("Failed to load '%s': %s", PKGDATADIR "/bluetooth.ui", error->message);
 
813
                g_error_free (error);
 
814
                return;
 
815
        }
 
816
 
 
817
        widget = WID ("grid");
 
818
        gtk_widget_reparent (widget, GTK_WIDGET (self));
 
819
 
 
820
        /* Overall device state */
 
821
        cc_bluetooth_panel_update_state (self);
 
822
        g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter",
 
823
                          G_CALLBACK (default_adapter_changed), self);
 
824
        g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter-powered",
 
825
                          G_CALLBACK (default_adapter_power_changed), self);
 
826
 
 
827
        /* The discoverable button */
 
828
        cc_bluetooth_panel_update_visibility (self);
 
829
        g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter-discoverable",
 
830
                          G_CALLBACK (discoverable_changed), self);
 
831
        g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter-name",
 
832
                          G_CALLBACK (name_changed), self);
 
833
        g_signal_connect (G_OBJECT (WID ("switch_discoverable")), "notify::active",
 
834
                          G_CALLBACK (switch_discoverable_active_changed), self);
 
835
 
 
836
        /* The known devices */
 
837
        widget = WID ("devices_table");
 
838
 
 
839
        context = gtk_widget_get_style_context (WID ("message_scrolledwindow"));
 
840
        gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
 
841
 
 
842
        /* Note that this will only ever show the devices on the default
 
843
         * adapter, this is on purpose */
 
844
        self->priv->chooser = bluetooth_chooser_new ();
 
845
        gtk_box_pack_start (GTK_BOX (WID ("box_devices")), self->priv->chooser, TRUE, TRUE, 0);
 
846
        g_object_set (self->priv->chooser,
 
847
                      "show-searching", FALSE,
 
848
                      "show-device-type", FALSE,
 
849
                      "show-device-type-column", FALSE,
 
850
                      "show-device-category", FALSE,
 
851
                      "show-pairing", FALSE,
 
852
                      "show-connected", FALSE,
 
853
                      "device-category-filter", BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED,
 
854
                      "no-show-all", TRUE,
 
855
                      NULL);
 
856
 
 
857
        /* Join treeview and buttons */
 
858
        widget = bluetooth_chooser_get_scrolled_window (BLUETOOTH_CHOOSER (self->priv->chooser));
 
859
        gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget), 250);
 
860
        gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (widget), 200);
 
861
        context = gtk_widget_get_style_context (widget);
 
862
        gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
 
863
        widget = WID ("toolbar");
 
864
        context = gtk_widget_get_style_context (widget);
 
865
        gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
 
866
 
 
867
        g_signal_connect (G_OBJECT (self->priv->chooser), "notify::device-selected",
 
868
                          G_CALLBACK (device_selected_changed), self);
 
869
        g_signal_connect (G_OBJECT (WID ("button_delete")), "clicked",
 
870
                          G_CALLBACK (delete_clicked), self);
 
871
        g_signal_connect (G_OBJECT (WID ("button_setup")), "clicked",
 
872
                          G_CALLBACK (setup_clicked), self);
 
873
 
 
874
        /* Set the initial state of the properties */
 
875
        cc_bluetooth_panel_update_properties (self);
 
876
        g_signal_connect (G_OBJECT (WID ("mouse_link")), "activate-link",
 
877
                          G_CALLBACK (mouse_callback), self);
 
878
        g_signal_connect (G_OBJECT (WID ("keyboard_link")), "activate-link",
 
879
                          G_CALLBACK (keyboard_callback), self);
 
880
        g_signal_connect (G_OBJECT (WID ("sound_link")), "activate-link",
 
881
                          G_CALLBACK (sound_callback), self);
 
882
        g_signal_connect (G_OBJECT (WID ("browse_button")), "clicked",
 
883
                          G_CALLBACK (browse_callback), self);
 
884
        g_signal_connect (G_OBJECT (WID ("send_button")), "clicked",
 
885
                          G_CALLBACK (send_callback), self);
 
886
        g_signal_connect (G_OBJECT (WID ("switch_connection")), "notify::active",
 
887
                          G_CALLBACK (switch_connected_active_changed), self);
 
888
 
 
889
        /* Set the initial state of power */
 
890
        g_signal_connect (G_OBJECT (WID ("switch_bluetooth")), "notify::active",
 
891
                          G_CALLBACK (power_callback), self);
 
892
        g_signal_connect (G_OBJECT (self->priv->killswitch), "state-changed",
 
893
                          G_CALLBACK (killswitch_changed), self);
 
894
        cc_bluetooth_panel_update_power (self);
 
895
 
 
896
        gtk_widget_show_all (GTK_WIDGET (self));
 
897
}
 
898
 
 
899
void
 
900
cc_bluetooth_panel_register (GIOModule *module)
 
901
{
 
902
        cc_bluetooth_panel_register_type (G_TYPE_MODULE (module));
 
903
        g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
 
904
                                        CC_TYPE_BLUETOOTH_PANEL,
 
905
                                        "bluetooth", 0);
 
906
}
 
907
 
 
908
/* GIO extension stuff */
 
909
void
 
910
g_io_module_load (GIOModule *module)
 
911
{
 
912
        bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
 
913
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 
914
 
 
915
        /* register the panel */
 
916
        cc_bluetooth_panel_register (module);
 
917
}
 
918
 
 
919
void
 
920
g_io_module_unload (GIOModule *module)
 
921
{
 
922
}
 
923