gnome-control-center/panels/bluetooth/cc-bluetooth-panel.c
Bastien Nocera 12a319875a bluetooth: Don't break the custom widgets on connect
We used to destroy and recreate the custom widgets whenever any of
the properties changed. Now we make sure that the custom widgets are
only destroyed and recreated when the device selected is a different one.

This fixes NetworkManager's Bluetooth plugins getting destroyed
because the Connected property changed, as it was trying to connect to
the device.

https://bugzilla.gnome.org/show_bug.cgi?id=681456
2012-09-07 13:32:06 +01:00

856 lines
25 KiB
C

/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2006-2010 Bastien Nocera <hadess@hadess.net>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <glib/gi18n-lib.h>
#include <shell/cc-shell.h>
#include "cc-bluetooth-panel.h"
#include <bluetooth-client.h>
#include <bluetooth-utils.h>
#include <bluetooth-killswitch.h>
#include <bluetooth-chooser.h>
#include <bluetooth-plugin-manager.h>
CC_PANEL_REGISTER (CcBluetoothPanel, cc_bluetooth_panel)
#define BLUETOOTH_PANEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_BLUETOOTH_PANEL, CcBluetoothPanelPrivate))
#define WID(s) GTK_WIDGET (gtk_builder_get_object (self->priv->builder, s))
#define KEYBOARD_PREFS "keyboard"
#define MOUSE_PREFS "mouse"
#define SOUND_PREFS "sound"
#define WIZARD "bluetooth-wizard"
struct CcBluetoothPanelPrivate {
GtkBuilder *builder;
GtkWidget *chooser;
char *selected_bdaddr;
BluetoothClient *client;
BluetoothKillswitch *killswitch;
gboolean debug;
};
static void cc_bluetooth_panel_finalize (GObject *object);
static void
launch_command (const char *command)
{
GError *error = NULL;
if (!g_spawn_command_line_async(command, &error)) {
g_warning ("Couldn't execute command '%s': %s\n", command, error->message);
g_error_free (error);
}
}
static const char *
cc_bluetooth_panel_get_help_uri (CcPanel *panel)
{
return "help:gnome-help/bluetooth";
}
static void
cc_bluetooth_panel_class_init (CcBluetoothPanelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
object_class->finalize = cc_bluetooth_panel_finalize;
panel_class->get_help_uri = cc_bluetooth_panel_get_help_uri;
g_type_class_add_private (klass, sizeof (CcBluetoothPanelPrivate));
}
static void
cc_bluetooth_panel_finalize (GObject *object)
{
CcBluetoothPanel *self;
bluetooth_plugin_manager_cleanup ();
self = CC_BLUETOOTH_PANEL (object);
if (self->priv->builder) {
g_object_unref (self->priv->builder);
self->priv->builder = NULL;
}
if (self->priv->killswitch) {
g_object_unref (self->priv->killswitch);
self->priv->killswitch = NULL;
}
if (self->priv->client) {
g_object_unref (self->priv->client);
self->priv->client = NULL;
}
g_clear_pointer (&self->priv->selected_bdaddr, g_free);
G_OBJECT_CLASS (cc_bluetooth_panel_parent_class)->finalize (object);
}
typedef struct {
char *bdaddr;
CcBluetoothPanel *self;
} ConnectData;
static void
connect_done (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
CcBluetoothPanel *self;
char *bdaddr;
gboolean success;
ConnectData *data = (ConnectData *) user_data;
success = bluetooth_client_connect_service_finish (BLUETOOTH_CLIENT (source_object),
res, NULL);
self = data->self;
/* Check whether the same device is now selected */
bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
if (g_strcmp0 (bdaddr, data->bdaddr) == 0) {
GtkSwitch *button;
button = GTK_SWITCH (WID ("switch_connection"));
/* Reset the switch if it failed */
if (success == FALSE)
gtk_switch_set_active (button, !gtk_switch_get_active (button));
gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
}
g_free (bdaddr);
g_object_unref (data->self);
g_free (data->bdaddr);
g_free (data);
}
static void
switch_connected_active_changed (GtkSwitch *button,
GParamSpec *spec,
CcBluetoothPanel *self)
{
char *proxy;
GValue value = { 0, };
ConnectData *data;
if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
"proxy", &value) == FALSE) {
g_warning ("Could not get D-Bus proxy for selected device");
return;
}
proxy = g_strdup (g_dbus_proxy_get_object_path (g_value_get_object (&value)));
g_value_unset (&value);
if (proxy == NULL)
return;
data = g_new0 (ConnectData, 1);
data->bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
data->self = g_object_ref (self);
bluetooth_client_connect_service (self->priv->client,
proxy,
gtk_switch_get_active (button),
NULL,
connect_done,
data);
/* FIXME: make a note somewhere that the button for that
* device should be disabled */
gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
g_free (proxy);
}
enum {
NOTEBOOK_PAGE_EMPTY = 0,
NOTEBOOK_PAGE_PROPS = 1
};
static void
set_notebook_page (CcBluetoothPanel *self,
int page)
{
gtk_notebook_set_current_page (GTK_NOTEBOOK (WID ("props_notebook")), page);
}
static void
add_extra_setup_widgets (CcBluetoothPanel *self,
const char *bdaddr)
{
GValue value = { 0 };
char **uuids;
GList *list, *l;
GtkWidget *container;
if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
"uuids", &value) == FALSE)
return;
uuids = (char **) g_value_get_boxed (&value);
list = bluetooth_plugin_manager_get_widgets (bdaddr, (const char **) uuids);
if (list == NULL) {
g_value_unset (&value);
return;
}
container = WID ("additional_setup_box");
for (l = list; l != NULL; l = l->next) {
GtkWidget *widget = l->data;
gtk_box_pack_start (GTK_BOX (container), widget,
FALSE, FALSE, 0);
gtk_widget_show_all (widget);
}
gtk_widget_show (container);
g_value_unset (&value);
}
static void
remove_extra_setup_widgets (CcBluetoothPanel *self)
{
GtkWidget *box;
box = WID ("additional_setup_box");
gtk_container_forall (GTK_CONTAINER (box), (GtkCallback) gtk_widget_destroy, NULL);
gtk_widget_hide (WID ("additional_setup_box"));
}
static void
cc_bluetooth_panel_update_properties (CcBluetoothPanel *self)
{
char *bdaddr;
GtkSwitch *button;
button = GTK_SWITCH (WID ("switch_connection"));
g_signal_handlers_block_by_func (button, switch_connected_active_changed, self);
/* Hide all the buttons now, and show them again if we need to */
gtk_widget_hide (WID ("keyboard_box"));
gtk_widget_hide (WID ("sound_box"));
gtk_widget_hide (WID ("mouse_box"));
gtk_widget_hide (WID ("browse_box"));
gtk_widget_hide (WID ("send_box"));
bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
/* Remove the extra setup widgets */
if (g_strcmp0 (self->priv->selected_bdaddr, bdaddr) != 0)
remove_extra_setup_widgets (self);
if (bdaddr == NULL) {
gtk_widget_set_sensitive (WID ("properties_vbox"), FALSE);
gtk_switch_set_active (button, FALSE);
gtk_widget_set_sensitive (WID ("button_delete"), FALSE);
set_notebook_page (self, NOTEBOOK_PAGE_EMPTY);
} else {
BluetoothType type;
gboolean connected;
GValue value = { 0 };
GHashTable *services;
if (self->priv->debug)
bluetooth_chooser_dump_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
gtk_widget_set_sensitive (WID ("properties_vbox"), TRUE);
connected = bluetooth_chooser_get_selected_device_is_connected (BLUETOOTH_CHOOSER (self->priv->chooser));
gtk_switch_set_active (button, connected);
/* Paired */
bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
"paired", &value);
gtk_label_set_text (GTK_LABEL (WID ("paired_label")),
g_value_get_boolean (&value) ? _("Yes") : _("No"));
g_value_unset (&value);
/* Connection */
bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
"services", &value);
services = g_value_get_boxed (&value);
gtk_widget_set_sensitive (GTK_WIDGET (button), (services != NULL));
g_value_unset (&value);
/* UUIDs */
if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
"uuids", &value)) {
const char **uuids;
guint i;
uuids = (const char **) g_value_get_boxed (&value);
for (i = 0; uuids && uuids[i] != NULL; i++) {
if (g_str_equal (uuids[i], "OBEXObjectPush"))
gtk_widget_show (WID ("send_box"));
else if (g_str_equal (uuids[i], "OBEXFileTransfer"))
gtk_widget_show (WID ("browse_box"));
}
g_value_unset (&value);
}
/* Type */
type = bluetooth_chooser_get_selected_device_type (BLUETOOTH_CHOOSER (self->priv->chooser));
gtk_label_set_text (GTK_LABEL (WID ("type_label")), bluetooth_type_to_string (type));
switch (type) {
case BLUETOOTH_TYPE_KEYBOARD:
gtk_widget_show (WID ("keyboard_box"));
break;
case BLUETOOTH_TYPE_MOUSE:
case BLUETOOTH_TYPE_TABLET:
gtk_widget_show (WID ("mouse_box"));
break;
case BLUETOOTH_TYPE_HEADSET:
case BLUETOOTH_TYPE_HEADPHONES:
case BLUETOOTH_TYPE_OTHER_AUDIO:
gtk_widget_show (WID ("sound_box"));
default:
/* others? */
;
}
/* Extra widgets */
if (g_strcmp0 (self->priv->selected_bdaddr, bdaddr) != 0)
add_extra_setup_widgets (self, bdaddr);
gtk_label_set_text (GTK_LABEL (WID ("address_label")), bdaddr);
gtk_widget_set_sensitive (WID ("button_delete"), TRUE);
set_notebook_page (self, NOTEBOOK_PAGE_PROPS);
}
g_free (self->priv->selected_bdaddr);
self->priv->selected_bdaddr = bdaddr;
g_signal_handlers_unblock_by_func (button, switch_connected_active_changed, self);
}
static void
power_callback (GObject *object,
GParamSpec *spec,
CcBluetoothPanel *self)
{
gboolean state;
state = gtk_switch_get_active (GTK_SWITCH (WID ("switch_bluetooth")));
g_debug ("Power switched to %s", state ? "off" : "on");
bluetooth_killswitch_set_state (self->priv->killswitch,
state ? BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED : BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED);
}
static void
cc_bluetooth_panel_update_treeview_message (CcBluetoothPanel *self,
const char *message)
{
if (message != NULL) {
gtk_widget_hide (self->priv->chooser);
gtk_widget_show (WID ("message_scrolledwindow"));
gtk_label_set_text (GTK_LABEL (WID ("message_label")),
message);
} else {
gtk_widget_hide (WID ("message_scrolledwindow"));
gtk_widget_show (self->priv->chooser);
}
}
static void
cc_bluetooth_panel_update_power (CcBluetoothPanel *self)
{
BluetoothKillswitchState state;
char *path;
gboolean powered, sensitive;
GtkSwitch *button;
g_object_get (G_OBJECT (self->priv->client),
"default-adapter", &path,
"default-adapter-powered", &powered,
NULL);
state = bluetooth_killswitch_get_state (self->priv->killswitch);
g_debug ("Updating power, default adapter: %s (powered: %s), killswitch: %s",
path ? path : "(none)",
powered ? "on" : "off",
bluetooth_killswitch_state_to_string (state));
if (path == NULL &&
bluetooth_killswitch_has_killswitches (self->priv->killswitch) &&
state != BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) {
g_debug ("Default adapter is unpowered, but should be available");
sensitive = TRUE;
cc_bluetooth_panel_update_treeview_message (self, _("Bluetooth is disabled"));
} else if (path == NULL &&
state == BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) {
g_debug ("Bluetooth is Hard blocked");
sensitive = FALSE;
cc_bluetooth_panel_update_treeview_message (self, _("Bluetooth is disabled by hardware switch"));
} else if (path == NULL) {
sensitive = FALSE;
g_debug ("No Bluetooth available");
cc_bluetooth_panel_update_treeview_message (self, _("No Bluetooth adapters found"));
} else {
sensitive = TRUE;
g_debug ("Bluetooth is available and powered");
cc_bluetooth_panel_update_treeview_message (self, NULL);
}
g_free (path);
gtk_widget_set_sensitive (WID ("box_power") , sensitive);
gtk_widget_set_sensitive (WID ("box_vis") , sensitive);
button = GTK_SWITCH (WID ("switch_bluetooth"));
g_signal_handlers_block_by_func (button, power_callback, self);
gtk_switch_set_active (button, powered);
g_signal_handlers_unblock_by_func (button, power_callback, self);
}
static void
switch_panel (CcBluetoothPanel *self,
const char *panel)
{
CcShell *shell;
GError *error = NULL;
shell = cc_panel_get_shell (CC_PANEL (self));
if (cc_shell_set_active_panel_from_id (shell, panel, NULL, &error) == FALSE)
{
g_warning ("Failed to activate '%s' panel: %s", panel, error->message);
g_error_free (error);
}
}
static gboolean
keyboard_callback (GtkButton *button,
CcBluetoothPanel *self)
{
switch_panel (self, KEYBOARD_PREFS);
return TRUE;
}
static gboolean
mouse_callback (GtkButton *button,
CcBluetoothPanel *self)
{
switch_panel (self, MOUSE_PREFS);
return TRUE;
}
static gboolean
sound_callback (GtkButton *button,
CcBluetoothPanel *self)
{
switch_panel (self, SOUND_PREFS);
return TRUE;
}
static void
send_callback (GtkButton *button,
CcBluetoothPanel *self)
{
char *bdaddr, *alias;
bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
alias = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (self->priv->chooser));
bluetooth_send_to_address (bdaddr, alias);
g_free (bdaddr);
g_free (alias);
}
static void
mount_finish_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GError *error = NULL;
if (bluetooth_browse_address_finish (source_object, res, &error) == FALSE) {
g_printerr ("Failed to mount OBEX volume: %s", error->message);
g_error_free (error);
return;
}
}
static void
browse_callback (GtkButton *button,
CcBluetoothPanel *self)
{
char *bdaddr;
bdaddr = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
bluetooth_browse_address (G_OBJECT (self), bdaddr,
GDK_CURRENT_TIME, mount_finish_cb, NULL);
g_free (bdaddr);
}
/* Visibility/Discoverable */
static void discoverable_changed (BluetoothClient *client,
GParamSpec *spec,
CcBluetoothPanel *self);
static void
switch_discoverable_active_changed (GtkSwitch *button,
GParamSpec *spec,
CcBluetoothPanel *self)
{
g_signal_handlers_block_by_func (self->priv->client, discoverable_changed, self);
g_object_set (G_OBJECT (self->priv->client), "default-adapter-discoverable",
gtk_switch_get_active (button), NULL);
g_signal_handlers_unblock_by_func (self->priv->client, discoverable_changed, self);
}
static void
cc_bluetooth_panel_update_visibility (CcBluetoothPanel *self)
{
gboolean discoverable;
GtkSwitch *button;
char *name;
button = GTK_SWITCH (WID ("switch_discoverable"));
g_object_get (G_OBJECT (self->priv->client), "default-adapter-discoverable", &discoverable, NULL);
g_signal_handlers_block_by_func (button, switch_discoverable_active_changed, self);
gtk_switch_set_active (button, discoverable);
g_signal_handlers_unblock_by_func (button, switch_discoverable_active_changed, self);
g_object_get (G_OBJECT (self->priv->client), "default-adapter-name", &name, NULL);
if (name == NULL) {
gtk_widget_set_sensitive (WID ("switch_discoverable"), FALSE);
gtk_widget_set_sensitive (WID ("visible_label"), FALSE);
gtk_label_set_text (GTK_LABEL (WID ("visible_label")), _("Visibility"));
} else {
char *label;
label = g_strdup_printf (_("Visibility of “%s”"), name);
g_free (name);
gtk_label_set_text (GTK_LABEL (WID ("visible_label")), label);
g_free (label);
gtk_widget_set_sensitive (WID ("switch_discoverable"), TRUE);
gtk_widget_set_sensitive (WID ("visible_label"), TRUE);
}
}
static void
discoverable_changed (BluetoothClient *client,
GParamSpec *spec,
CcBluetoothPanel *self)
{
cc_bluetooth_panel_update_visibility (self);
}
static void
name_changed (BluetoothClient *client,
GParamSpec *spec,
CcBluetoothPanel *self)
{
cc_bluetooth_panel_update_visibility (self);
}
static void
device_selected_changed (BluetoothChooser *chooser,
GParamSpec *spec,
CcBluetoothPanel *self)
{
cc_bluetooth_panel_update_properties (self);
}
static gboolean
show_confirm_dialog (CcBluetoothPanel *self,
const char *name)
{
GtkWidget *dialog, *parent;
gint response;
parent = gtk_widget_get_toplevel (GTK_WIDGET (self));
dialog = gtk_message_dialog_new (GTK_WINDOW (parent), GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
_("Remove '%s' from the list of devices?"), name);
g_object_set (G_OBJECT (dialog), "secondary-text",
_("If you remove the device, you will have to set it up again before next use."),
NULL);
gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_REMOVE, GTK_RESPONSE_ACCEPT);
response = gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
if (response == GTK_RESPONSE_ACCEPT)
return TRUE;
return FALSE;
}
static gboolean
remove_selected_device (CcBluetoothPanel *self)
{
GValue value = { 0, };
char *device, *adapter;
GDBusProxy *adapter_proxy;
GError *error = NULL;
GVariant *ret;
if (bluetooth_chooser_get_selected_device_info (BLUETOOTH_CHOOSER (self->priv->chooser),
"proxy", &value) == FALSE) {
return FALSE;
}
device = g_strdup (g_dbus_proxy_get_object_path (g_value_get_object (&value)));
g_value_unset (&value);
g_object_get (G_OBJECT (self->priv->client), "default-adapter", &adapter, NULL);
adapter_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
NULL,
"org.bluez",
adapter,
"org.bluez.Adapter",
NULL,
&error);
g_free (adapter);
if (adapter_proxy == NULL) {
g_warning ("Failed to create a GDBusProxy for the default adapter: %s", error->message);
g_error_free (error);
g_free (device);
return FALSE;
}
ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (adapter_proxy),
"RemoveDevice",
g_variant_new ("(o)", device),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (ret == NULL) {
g_warning ("Failed to remove device '%s': %s", device, error->message);
g_error_free (error);
} else {
g_variant_unref (ret);
}
g_object_unref (adapter_proxy);
g_free (device);
return (ret != NULL);
}
/* Treeview buttons */
static void
delete_clicked (GtkToolButton *button,
CcBluetoothPanel *self)
{
char *address, *name;
address = bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (self->priv->chooser));
g_assert (address);
name = bluetooth_chooser_get_selected_device_name (BLUETOOTH_CHOOSER (self->priv->chooser));
if (show_confirm_dialog (self, name) != FALSE) {
if (remove_selected_device (self))
bluetooth_plugin_manager_device_deleted (address);
}
g_free (address);
g_free (name);
}
static void
setup_clicked (GtkToolButton *button,
CcBluetoothPanel *self)
{
launch_command (WIZARD);
}
/* Overall device state */
static void
cc_bluetooth_panel_update_state (CcBluetoothPanel *self)
{
char *bdaddr;
gboolean powered;
g_object_get (G_OBJECT (self->priv->client),
"default-adapter", &bdaddr,
"default-adapter-powered", &powered,
NULL);
gtk_widget_set_sensitive (WID ("toolbar"), (bdaddr != NULL));
g_free (bdaddr);
}
static void
default_adapter_changed (BluetoothClient *client,
GParamSpec *spec,
CcBluetoothPanel *self)
{
cc_bluetooth_panel_update_state (self);
cc_bluetooth_panel_update_power (self);
}
static void
killswitch_changed (BluetoothKillswitch *killswitch,
BluetoothKillswitchState state,
CcBluetoothPanel *self)
{
cc_bluetooth_panel_update_state (self);
cc_bluetooth_panel_update_power (self);
}
static void
cc_bluetooth_panel_init (CcBluetoothPanel *self)
{
GtkWidget *widget;
GError *error = NULL;
GtkStyleContext *context;
self->priv = BLUETOOTH_PANEL_PRIVATE (self);
bluetooth_plugin_manager_init ();
self->priv->killswitch = bluetooth_killswitch_new ();
self->priv->client = bluetooth_client_new ();
self->priv->debug = g_getenv ("BLUETOOTH_DEBUG") != NULL;
self->priv->builder = gtk_builder_new ();
gtk_builder_set_translation_domain (self->priv->builder, GETTEXT_PACKAGE);
gtk_builder_add_from_file (self->priv->builder,
PKGDATADIR "/bluetooth.ui",
&error);
if (error != NULL) {
g_warning ("Failed to load '%s': %s", PKGDATADIR "/bluetooth.ui", error->message);
g_error_free (error);
return;
}
widget = WID ("grid");
gtk_widget_reparent (widget, GTK_WIDGET (self));
/* Overall device state */
cc_bluetooth_panel_update_state (self);
g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter",
G_CALLBACK (default_adapter_changed), self);
/* The discoverable button */
cc_bluetooth_panel_update_visibility (self);
g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter-discoverable",
G_CALLBACK (discoverable_changed), self);
g_signal_connect (G_OBJECT (self->priv->client), "notify::default-adapter-name",
G_CALLBACK (name_changed), self);
g_signal_connect (G_OBJECT (WID ("switch_discoverable")), "notify::active",
G_CALLBACK (switch_discoverable_active_changed), self);
/* The known devices */
widget = WID ("devices_table");
context = gtk_widget_get_style_context (WID ("message_scrolledwindow"));
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
/* Note that this will only ever show the devices on the default
* adapter, this is on purpose */
self->priv->chooser = bluetooth_chooser_new ();
gtk_box_pack_start (GTK_BOX (WID ("box_devices")), self->priv->chooser, TRUE, TRUE, 0);
g_object_set (self->priv->chooser,
"show-searching", FALSE,
"show-device-type", FALSE,
"show-device-type-column", FALSE,
"show-device-category", FALSE,
"show-pairing", FALSE,
"show-connected", FALSE,
"device-category-filter", BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED,
"no-show-all", TRUE,
NULL);
/* Join treeview and buttons */
widget = bluetooth_chooser_get_scrolled_window (BLUETOOTH_CHOOSER (self->priv->chooser));
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget), 250);
gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (widget), 200);
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
widget = WID ("toolbar");
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
g_signal_connect (G_OBJECT (self->priv->chooser), "notify::device-selected",
G_CALLBACK (device_selected_changed), self);
g_signal_connect (G_OBJECT (WID ("button_delete")), "clicked",
G_CALLBACK (delete_clicked), self);
g_signal_connect (G_OBJECT (WID ("button_setup")), "clicked",
G_CALLBACK (setup_clicked), self);
/* Set the initial state of the properties */
cc_bluetooth_panel_update_properties (self);
g_signal_connect (G_OBJECT (WID ("mouse_link")), "activate-link",
G_CALLBACK (mouse_callback), self);
g_signal_connect (G_OBJECT (WID ("keyboard_link")), "activate-link",
G_CALLBACK (keyboard_callback), self);
g_signal_connect (G_OBJECT (WID ("sound_link")), "activate-link",
G_CALLBACK (sound_callback), self);
g_signal_connect (G_OBJECT (WID ("browse_button")), "clicked",
G_CALLBACK (browse_callback), self);
g_signal_connect (G_OBJECT (WID ("send_button")), "clicked",
G_CALLBACK (send_callback), self);
g_signal_connect (G_OBJECT (WID ("switch_connection")), "notify::active",
G_CALLBACK (switch_connected_active_changed), self);
/* Set the initial state of power */
g_signal_connect (G_OBJECT (WID ("switch_bluetooth")), "notify::active",
G_CALLBACK (power_callback), self);
g_signal_connect (G_OBJECT (self->priv->killswitch), "state-changed",
G_CALLBACK (killswitch_changed), self);
cc_bluetooth_panel_update_power (self);
gtk_widget_show_all (GTK_WIDGET (self));
}
void
cc_bluetooth_panel_register (GIOModule *module)
{
cc_bluetooth_panel_register_type (G_TYPE_MODULE (module));
g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
CC_TYPE_BLUETOOTH_PANEL,
"bluetooth", 0);
}
/* GIO extension stuff */
void
g_io_module_load (GIOModule *module)
{
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
/* register the panel */
cc_bluetooth_panel_register (module);
}
void
g_io_module_unload (GIOModule *module)
{
}