Blame lib/bluetooth-settings-widget.c

Packit 8fb625
/*
Packit 8fb625
 *
Packit 8fb625
 *  Copyright (C) 2013  Bastien Nocera <hadess@hadess.net>
Packit 8fb625
 *
Packit 8fb625
 *  This library is free software; you can redistribute it and/or
Packit 8fb625
 *  modify it under the terms of the GNU Lesser General Public
Packit 8fb625
 *  License as published by the Free Software Foundation; either
Packit 8fb625
 *  version 2.1 of the License, or (at your option) any later version.
Packit 8fb625
 *
Packit 8fb625
 *  This library is distributed in the hope that it will be useful,
Packit 8fb625
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8fb625
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 8fb625
 *  Lesser General Public License for more details.
Packit 8fb625
 *
Packit 8fb625
 *  You should have received a copy of the GNU Lesser General Public
Packit 8fb625
 *  License along with this library; if not, write to the Free Software
Packit 8fb625
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 8fb625
 *
Packit 8fb625
 */
Packit 8fb625
Packit 8fb625
#ifdef HAVE_CONFIG_H
Packit 8fb625
#include <config.h>
Packit 8fb625
#endif
Packit 8fb625
Packit 8fb625
#include <gtk/gtk.h>
Packit 8fb625
Packit 8fb625
#include <glib/gi18n-lib.h>
Packit 8fb625
#include <math.h>
Packit 8fb625
Packit 8fb625
#include "bluetooth-client.h"
Packit 8fb625
#include "bluetooth-client-private.h"
Packit 8fb625
#include "bluetooth-client-glue.h"
Packit 8fb625
#include "bluetooth-agent.h"
Packit 8fb625
#include "bluetooth-utils.h"
Packit 8fb625
#include "bluetooth-settings-widget.h"
Packit 8fb625
#include "bluetooth-settings-resources.h"
Packit 8fb625
#include "bluetooth-settings-row.h"
Packit 8fb625
#include "bluetooth-settings-obexpush.h"
Packit 8fb625
#include "bluetooth-pairing-dialog.h"
Packit 8fb625
#include "pin.h"
Packit 8fb625
Packit 8fb625
#define BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE(obj) \
Packit 8fb625
	(bluetooth_settings_widget_get_instance_private (obj))
Packit 8fb625
Packit 8fb625
typedef struct _BluetoothSettingsWidgetPrivate BluetoothSettingsWidgetPrivate;
Packit 8fb625
Packit 8fb625
struct _BluetoothSettingsWidgetPrivate {
Packit 8fb625
	GtkBuilder          *builder;
Packit 8fb625
	GtkWidget           *child_box;
Packit 8fb625
	BluetoothClient     *client;
Packit 8fb625
	GtkTreeModel        *model;
Packit 8fb625
	gboolean             debug;
Packit 8fb625
	GCancellable        *cancellable;
Packit 8fb625
Packit 8fb625
	/* Pairing */
Packit 8fb625
	BluetoothAgent      *agent;
Packit 8fb625
	GtkWidget           *pairing_dialog;
Packit 8fb625
	GHashTable          *pairing_devices; /* key=object-path, value=boolean */
Packit 8fb625
Packit 8fb625
	/* Properties */
Packit 8fb625
	GtkWidget           *properties_dialog;
Packit 8fb625
	char                *selected_bdaddr;
Packit 8fb625
	char                *selected_name;
Packit 8fb625
	char                *selected_object_path;
Packit 8fb625
Packit 8fb625
	/* Device section */
Packit 8fb625
	GtkWidget           *device_list;
Packit 8fb625
	GtkAdjustment       *focus_adjustment;
Packit 8fb625
	GtkSizeGroup        *row_sizegroup;
Packit 8fb625
	GtkWidget           *device_stack;
Packit 8fb625
	GtkWidget           *device_spinner;
Packit 8fb625
	GHashTable          *connecting_devices; /* key=bdaddr, value=boolean */
Packit 8fb625
Packit 8fb625
	/* Hack to work-around:
Packit 8fb625
	 * http://thread.gmane.org/gmane.linux.bluez.kernel/41471 */
Packit 8fb625
	GHashTable          *devices_type; /* key=bdaddr, value=guint32 */
Packit 8fb625
Packit 8fb625
	/* Sharing section */
Packit 8fb625
	GtkWidget           *visible_label;
Packit 8fb625
	gboolean             has_console;
Packit 8fb625
	GDBusProxy          *session_proxy;
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
G_DEFINE_TYPE_WITH_PRIVATE(BluetoothSettingsWidget, bluetooth_settings_widget, GTK_TYPE_BOX)
Packit 8fb625
Packit 8fb625
enum {
Packit 8fb625
	PANEL_CHANGED,
Packit 8fb625
	ADAPTER_STATUS_CHANGED,
Packit 8fb625
	LAST_SIGNAL
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
static guint signals[LAST_SIGNAL] = { 0 };
Packit 8fb625
Packit 8fb625
#define WID(s) GTK_WIDGET (gtk_builder_get_object (priv->builder, s))
Packit 8fb625
Packit 8fb625
#define KEYBOARD_PREFS		"keyboard"
Packit 8fb625
#define MOUSE_PREFS		"mouse"
Packit 8fb625
#define SOUND_PREFS		"sound"
Packit 8fb625
Packit 8fb625
#define ICON_SIZE 128
Packit 8fb625
Packit 8fb625
/* We'll try to connect to the device repeatedly for that
Packit 8fb625
 * amount of time before we bail out */
Packit 8fb625
#define CONNECT_TIMEOUT 3.0
Packit 8fb625
Packit 8fb625
#define BLUEZ_SERVICE	"org.bluez"
Packit 8fb625
#define ADAPTER_IFACE	"org.bluez.Adapter1"
Packit 8fb625
Packit 8fb625
#define AGENT_PATH "/org/gnome/bluetooth/settings"
Packit 8fb625
Packit 8fb625
#define GNOME_SESSION_DBUS_NAME      "org.gnome.SessionManager"
Packit 8fb625
#define GNOME_SESSION_DBUS_OBJECT    "/org/gnome/SessionManager"
Packit 8fb625
#define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager"
Packit 8fb625
Packit 8fb625
#define FILLER_PAGE                  "filler-page"
Packit 8fb625
#define DEVICES_PAGE                 "devices-page"
Packit 8fb625
Packit 8fb625
enum {
Packit 8fb625
	CONNECTING_NOTEBOOK_PAGE_SWITCH = 0,
Packit 8fb625
	CONNECTING_NOTEBOOK_PAGE_SPINNER = 1
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
set_connecting_page (BluetoothSettingsWidget *self,
Packit 8fb625
		     int               page)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
Packit 8fb625
	if (page == CONNECTING_NOTEBOOK_PAGE_SPINNER)
Packit 8fb625
		gtk_spinner_start (GTK_SPINNER (WID ("connecting_spinner")));
Packit 8fb625
	gtk_notebook_set_current_page (GTK_NOTEBOOK (WID ("connecting_notebook")), page);
Packit 8fb625
	if (page == CONNECTING_NOTEBOOK_PAGE_SWITCH)
Packit 8fb625
		gtk_spinner_stop (GTK_SPINNER (WID ("connecting_spinner")));
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
remove_connecting (BluetoothSettingsWidget *self,
Packit 8fb625
		   const char       *bdaddr)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	g_hash_table_remove (priv->connecting_devices, bdaddr);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
add_connecting (BluetoothSettingsWidget *self,
Packit 8fb625
		const char       *bdaddr)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	g_hash_table_insert (priv->connecting_devices,
Packit 8fb625
			     g_strdup (bdaddr),
Packit 8fb625
			     GINT_TO_POINTER (1));
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
is_connecting (BluetoothSettingsWidget *self,
Packit 8fb625
	       const char       *bdaddr)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	return GPOINTER_TO_INT (g_hash_table_lookup (priv->connecting_devices,
Packit 8fb625
						     bdaddr));
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
typedef struct {
Packit 8fb625
	char             *bdaddr;
Packit 8fb625
	BluetoothSettingsWidget *self;
Packit 8fb625
} ConnectData;
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
connect_done (GObject      *source_object,
Packit 8fb625
	      GAsyncResult *res,
Packit 8fb625
	      gpointer      user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv;
Packit 8fb625
	gboolean success;
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
	ConnectData *data = (ConnectData *) user_data;
Packit 8fb625
Packit 8fb625
	success = bluetooth_client_connect_service_finish (BLUETOOTH_CLIENT (source_object),
Packit 8fb625
							   res, &error);
Packit 8fb625
	if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit 8fb625
		goto out;
Packit 8fb625
Packit 8fb625
	self = data->self;
Packit 8fb625
	priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
Packit 8fb625
	/* Check whether the same device is now selected, and update the UI */
Packit 8fb625
	if (g_strcmp0 (priv->selected_bdaddr, data->bdaddr) == 0) {
Packit 8fb625
		GtkSwitch *button;
Packit 8fb625
Packit 8fb625
		button = GTK_SWITCH (WID ("switch_connection"));
Packit 8fb625
Packit 8fb625
		/* Ensure the switch position is in the correct place. */
Packit 8fb625
		gtk_switch_set_active (button, gtk_switch_get_state (button));
Packit 8fb625
Packit 8fb625
		if (success == FALSE) {
Packit 8fb625
			g_debug ("Connection failed to %s: %s", data->bdaddr, error->message);
Packit 8fb625
		}
Packit 8fb625
		set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SWITCH);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_clear_error (&error);
Packit 8fb625
	remove_connecting (self, data->bdaddr);
Packit 8fb625
Packit 8fb625
	//FIXME show an error if it failed?
Packit 8fb625
Packit 8fb625
out:
Packit 8fb625
	g_clear_error (&error);
Packit 8fb625
	g_free (data->bdaddr);
Packit 8fb625
	g_free (data);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
add_device_type (BluetoothSettingsWidget *self,
Packit 8fb625
		 const char              *bdaddr,
Packit 8fb625
		 BluetoothType            type)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	BluetoothType t;
Packit 8fb625
Packit 8fb625
	t = GPOINTER_TO_UINT (g_hash_table_lookup (priv->devices_type, bdaddr));
Packit 8fb625
	if (t == 0 || t == BLUETOOTH_TYPE_ANY) {
Packit 8fb625
		g_hash_table_insert (priv->devices_type, g_strdup (bdaddr), GUINT_TO_POINTER (type));
Packit 8fb625
		g_debug ("Saving device type %s for %s", bluetooth_type_to_string (type), bdaddr);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
setup_pairing_dialog (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GtkWidget *toplevel;
Packit 8fb625
Packit 8fb625
	g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
	priv->pairing_dialog = bluetooth_pairing_dialog_new ();
Packit 8fb625
	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
Packit 8fb625
	gtk_window_set_transient_for (GTK_WINDOW (priv->pairing_dialog), GTK_WINDOW (toplevel));
Packit 8fb625
	gtk_window_set_modal (GTK_WINDOW (priv->pairing_dialog), TRUE);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
get_properties_for_device (BluetoothSettingsWidget  *self,
Packit 8fb625
			   GDBusProxy               *device,
Packit 8fb625
			   char                    **name,
Packit 8fb625
			   char                    **ret_bdaddr,
Packit 8fb625
			   BluetoothType            *type)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GVariant *value;
Packit 8fb625
	char *bdaddr;
Packit 8fb625
Packit 8fb625
	g_return_val_if_fail (name != NULL, FALSE);
Packit 8fb625
Packit 8fb625
	value = g_dbus_proxy_get_cached_property (device, "Name");
Packit 8fb625
	if (value == NULL) {
Packit 8fb625
		/* What?! */
Packit 8fb625
		return FALSE;
Packit 8fb625
	}
Packit 8fb625
	*name = g_variant_dup_string (value, NULL);
Packit 8fb625
	g_variant_unref (value);
Packit 8fb625
Packit 8fb625
	value = g_dbus_proxy_get_cached_property (device, "Address");
Packit 8fb625
	bdaddr = g_variant_dup_string (value, NULL);
Packit 8fb625
	g_variant_unref (value);
Packit 8fb625
Packit 8fb625
	if (ret_bdaddr)
Packit 8fb625
		*ret_bdaddr = g_strdup (bdaddr);
Packit 8fb625
Packit 8fb625
	if (type) {
Packit 8fb625
		value = g_dbus_proxy_get_cached_property (device, "Class");
Packit 8fb625
		if (value != NULL) {
Packit 8fb625
			*type = bluetooth_class_to_type (g_variant_get_uint32 (value));
Packit 8fb625
			g_variant_unref (value);
Packit 8fb625
		} else {
Packit 8fb625
			*type = GPOINTER_TO_UINT (g_hash_table_lookup (priv->devices_type, bdaddr));
Packit 8fb625
			if (*type == 0)
Packit 8fb625
				*type = BLUETOOTH_TYPE_ANY;
Packit 8fb625
		}
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_free (bdaddr);
Packit 8fb625
Packit 8fb625
	return TRUE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static char *
Packit 8fb625
get_random_pincode (guint num_digits)
Packit 8fb625
{
Packit 8fb625
	if (num_digits == 0)
Packit 8fb625
		num_digits = PIN_NUM_DIGITS;
Packit 8fb625
	return g_strdup_printf ("%d", g_random_int_range (pow (10, num_digits - 1),
Packit 8fb625
							  pow (10, num_digits)));
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static char *
Packit 8fb625
get_icade_pincode (char **pin_display_str)
Packit 8fb625
{
Packit 8fb625
	GString *pin, *pin_display;
Packit 8fb625
	guint i;
Packit 8fb625
	static char *arrows[] = {
Packit 8fb625
		NULL,
Packit 8fb625
		"⬆", /* up = 1    */
Packit 8fb625
		"⬇", /* down = 2  */
Packit 8fb625
		"⬅", /* left = 3  */
Packit 8fb625
		"➡"  /* right = 4 */
Packit 8fb625
	};
Packit 8fb625
Packit 8fb625
	pin = g_string_new (NULL);
Packit 8fb625
	pin_display = g_string_new (NULL);
Packit 8fb625
Packit 8fb625
	for (i = 0; i < PIN_NUM_DIGITS; i++) {
Packit 8fb625
		int r;
Packit 8fb625
		char *c;
Packit 8fb625
Packit 8fb625
		r = g_random_int_range (1, 5);
Packit 8fb625
Packit 8fb625
		c = g_strdup_printf ("%d", r);
Packit 8fb625
		g_string_append (pin, c);
Packit 8fb625
		g_free (c);
Packit 8fb625
Packit 8fb625
		g_string_append (pin_display, arrows[r]);
Packit 8fb625
	}
Packit 8fb625
	g_string_append (pin_display, "❍");
Packit 8fb625
Packit 8fb625
	*pin_display_str = g_string_free (pin_display, FALSE);
Packit 8fb625
	return g_string_free (pin, FALSE);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
display_cb (GtkDialog *dialog,
Packit 8fb625
	    int        response,
Packit 8fb625
	    gpointer   user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
Packit 8fb625
	g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
enter_pin_cb (GtkDialog *dialog,
Packit 8fb625
	      int        response,
Packit 8fb625
	      gpointer   user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	GDBusMethodInvocation *invocation;
Packit 8fb625
Packit 8fb625
	invocation = g_object_get_data (G_OBJECT (dialog), "invocation");
Packit 8fb625
Packit 8fb625
	if (response == GTK_RESPONSE_ACCEPT) {
Packit 8fb625
		const char *name;
Packit 8fb625
		char *pin;
Packit 8fb625
		BluetoothPairingMode mode;
Packit 8fb625
Packit 8fb625
		mode = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (dialog), "mode"));
Packit 8fb625
		name = g_object_get_data (G_OBJECT (dialog), "name");
Packit 8fb625
		pin = bluetooth_pairing_dialog_get_pin (BLUETOOTH_PAIRING_DIALOG (dialog));
Packit 8fb625
		g_dbus_method_invocation_return_value (invocation,
Packit 8fb625
						       g_variant_new ("(s)", pin));
Packit 8fb625
Packit 8fb625
		if (bluetooth_pairing_dialog_get_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog)) == BLUETOOTH_PAIRING_MODE_PIN_QUERY) {
Packit 8fb625
			g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
			return;
Packit 8fb625
		}
Packit 8fb625
		bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
						   mode, pin, name);
Packit 8fb625
		g_free (pin);
Packit 8fb625
		g_signal_connect (G_OBJECT (priv->pairing_dialog), "response",
Packit 8fb625
				  G_CALLBACK (display_cb), user_data);
Packit 8fb625
	} else {
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation,
Packit 8fb625
							    "org.bluez.Error.Canceled",
Packit 8fb625
							    "User cancelled pairing");
Packit 8fb625
		g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_object_set_data (G_OBJECT (priv->pairing_dialog), "invocation", NULL);
Packit 8fb625
	g_object_set_data (G_OBJECT (priv->pairing_dialog), "mode", NULL);
Packit 8fb625
	g_object_set_data (G_OBJECT (priv->pairing_dialog), "name", NULL);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
confirm_remote_pin_cb (GtkDialog *dialog,
Packit 8fb625
		       int        response,
Packit 8fb625
		       gpointer   user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	GDBusMethodInvocation *invocation;
Packit 8fb625
Packit 8fb625
	invocation = g_object_get_data (G_OBJECT (dialog), "invocation");
Packit 8fb625
Packit 8fb625
	if (response == GTK_RESPONSE_ACCEPT) {
Packit 8fb625
		GDBusProxy *device;
Packit 8fb625
		const char *pin;
Packit 8fb625
Packit 8fb625
		pin = g_object_get_data (G_OBJECT (invocation), "pin");
Packit 8fb625
		device = g_object_get_data (G_OBJECT (invocation), "device");
Packit 8fb625
Packit 8fb625
		bluetooth_client_set_trusted (priv->client, g_dbus_proxy_get_object_path (device), TRUE);
Packit 8fb625
Packit 8fb625
		g_dbus_method_invocation_return_value (invocation,
Packit 8fb625
						       g_variant_new ("(s)", pin));
Packit 8fb625
	} else {
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation, "org.bluez.Error.Rejected", "Pairing refused from settings panel");
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
pincode_callback (GDBusMethodInvocation *invocation,
Packit 8fb625
		  GDBusProxy            *device,
Packit 8fb625
		  gpointer               user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self = user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	BluetoothType type;
Packit 8fb625
	char *name, *bdaddr;
Packit 8fb625
	guint max_digits;
Packit 8fb625
	gboolean confirm_pin = TRUE;
Packit 8fb625
	char *default_pin;
Packit 8fb625
	char *display_pin = NULL;
Packit 8fb625
	BluetoothPairingMode mode;
Packit 8fb625
	gboolean remote_initiated;
Packit 8fb625
Packit 8fb625
	g_debug ("pincode_callback (%s)", g_dbus_proxy_get_object_path (device));
Packit 8fb625
Packit 8fb625
	if (!get_properties_for_device (self, device, &name, &bdaddr, &type)) {
Packit 8fb625
		char *msg;
Packit 8fb625
Packit 8fb625
		msg = g_strdup_printf ("Missing information for %s", g_dbus_proxy_get_object_path (device));
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation, "org.bluez.Error.Rejected", msg);
Packit 8fb625
		g_free (msg);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	remote_initiated = !GPOINTER_TO_UINT (g_hash_table_lookup (priv->pairing_devices,
Packit 8fb625
								   g_dbus_proxy_get_object_path (device)));
Packit 8fb625
Packit 8fb625
	default_pin = get_pincode_for_device (type, bdaddr, name, &max_digits, &confirm_pin);
Packit 8fb625
	if (g_strcmp0 (default_pin, "KEYBOARD") == 0) {
Packit 8fb625
		mode = BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_KEYBOARD;
Packit 8fb625
		g_free (default_pin);
Packit 8fb625
		default_pin = get_random_pincode (max_digits);
Packit 8fb625
		display_pin = g_strdup_printf ("%s⏎", default_pin);
Packit 8fb625
	} else if (g_strcmp0 (default_pin, "ICADE") == 0) {
Packit 8fb625
		mode = BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_ICADE;
Packit 8fb625
		confirm_pin = FALSE;
Packit 8fb625
		g_free (default_pin);
Packit 8fb625
		default_pin = get_icade_pincode (&display_pin);
Packit 8fb625
	} else if (default_pin == NULL) {
Packit 8fb625
		mode = BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_NORMAL;
Packit 8fb625
		confirm_pin = TRUE;
Packit 8fb625
		default_pin = get_random_pincode (0);
Packit 8fb625
	} else if (g_strcmp0 (default_pin, "NULL") == 0) {
Packit 8fb625
		g_assert_not_reached ();
Packit 8fb625
	} else {
Packit 8fb625
		mode = BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_NORMAL;
Packit 8fb625
		display_pin = g_strdup (default_pin);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	setup_pairing_dialog (BLUETOOTH_SETTINGS_WIDGET (user_data));
Packit 8fb625
Packit 8fb625
	g_object_set_data_full (G_OBJECT (priv->pairing_dialog), "name", g_strdup (name), g_free);
Packit 8fb625
	g_object_set_data (G_OBJECT (priv->pairing_dialog), "mode", GUINT_TO_POINTER (mode));
Packit 8fb625
Packit 8fb625
	if (confirm_pin) {
Packit 8fb625
		g_object_set_data (G_OBJECT (priv->pairing_dialog), "invocation", invocation);
Packit 8fb625
		if (remote_initiated) {
Packit 8fb625
			bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
							   BLUETOOTH_PAIRING_MODE_PIN_QUERY,
Packit 8fb625
							   default_pin,
Packit 8fb625
							   name);
Packit 8fb625
		} else {
Packit 8fb625
			bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
							   BLUETOOTH_PAIRING_MODE_PIN_CONFIRMATION,
Packit 8fb625
							   default_pin,
Packit 8fb625
							   name);
Packit 8fb625
		}
Packit 8fb625
		g_signal_connect (G_OBJECT (priv->pairing_dialog), "response",
Packit 8fb625
				  G_CALLBACK (enter_pin_cb), user_data);
Packit 8fb625
	} else if (!remote_initiated) {
Packit 8fb625
		bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
						   mode, display_pin, name);
Packit 8fb625
		g_dbus_method_invocation_return_value (invocation,
Packit 8fb625
						       g_variant_new ("(s)", default_pin));
Packit 8fb625
		g_signal_connect (G_OBJECT (priv->pairing_dialog), "response",
Packit 8fb625
				  G_CALLBACK (display_cb), user_data);
Packit 8fb625
	} else {
Packit 8fb625
		bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
						   BLUETOOTH_PAIRING_MODE_YES_NO,
Packit 8fb625
						   default_pin, name);
Packit 8fb625
Packit 8fb625
		g_object_set_data_full (G_OBJECT (invocation), "pin", g_strdup (default_pin), g_free);
Packit 8fb625
		g_object_set_data_full (G_OBJECT (invocation), "device", g_object_ref (device), g_object_unref);
Packit 8fb625
		g_object_set_data (G_OBJECT (priv->pairing_dialog), "invocation", invocation);
Packit 8fb625
Packit 8fb625
		g_signal_connect (G_OBJECT (priv->pairing_dialog), "response",
Packit 8fb625
				  G_CALLBACK (confirm_remote_pin_cb), user_data);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_free (name);
Packit 8fb625
	g_free (bdaddr);
Packit 8fb625
	g_free (default_pin);
Packit 8fb625
	g_free (display_pin);
Packit 8fb625
Packit 8fb625
	gtk_widget_show (priv->pairing_dialog);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
display_callback (GDBusMethodInvocation *invocation,
Packit 8fb625
		  GDBusProxy            *device,
Packit 8fb625
		  guint                  pin,
Packit 8fb625
		  guint                  entered,
Packit 8fb625
		  gpointer               user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self = user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	char *pin_str, *name;
Packit 8fb625
Packit 8fb625
	g_debug ("display_callback (%s, %i, %i)", g_dbus_proxy_get_object_path (device), pin, entered);
Packit 8fb625
Packit 8fb625
	if (priv->pairing_dialog == NULL ||
Packit 8fb625
	    bluetooth_pairing_dialog_get_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog)) != BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_KEYBOARD)
Packit 8fb625
		setup_pairing_dialog (BLUETOOTH_SETTINGS_WIDGET (user_data));
Packit 8fb625
Packit 8fb625
	pin_str = g_strdup_printf ("%06d", pin);
Packit 8fb625
	get_properties_for_device (self, device, &name, NULL, NULL);
Packit 8fb625
	bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
					   BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_KEYBOARD,
Packit 8fb625
					   pin_str,
Packit 8fb625
					   name);
Packit 8fb625
	bluetooth_pairing_dialog_set_pin_entered (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
						  entered);
Packit 8fb625
	g_free (pin_str);
Packit 8fb625
	g_free (name);
Packit 8fb625
Packit 8fb625
	gtk_widget_show (priv->pairing_dialog);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
display_pincode_callback (GDBusMethodInvocation *invocation,
Packit 8fb625
			  GDBusProxy            *device,
Packit 8fb625
			  const char            *pincode,
Packit 8fb625
			  gpointer               user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self = user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	BluetoothType type;
Packit 8fb625
	char *display_pin = NULL;
Packit 8fb625
	char *name, *bdaddr;
Packit 8fb625
	char *db_pin;
Packit 8fb625
Packit 8fb625
	g_debug ("display_pincode_callback (%s, %s)", g_dbus_proxy_get_object_path (device), pincode);
Packit 8fb625
Packit 8fb625
	if (!get_properties_for_device (self, device, &name, &bdaddr, &type)) {
Packit 8fb625
		char *msg;
Packit 8fb625
Packit 8fb625
		msg = g_strdup_printf ("Missing information for %s", g_dbus_proxy_get_object_path (device));
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation, "org.bluez.Error.Rejected", msg);
Packit 8fb625
		g_free (msg);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* Verify PIN code validity */
Packit 8fb625
	db_pin = get_pincode_for_device (type,
Packit 8fb625
					 bdaddr,
Packit 8fb625
					 name,
Packit 8fb625
					 NULL,
Packit 8fb625
					 NULL);
Packit 8fb625
	if (g_strcmp0 (db_pin, "KEYBOARD") == 0) {
Packit 8fb625
		/* Should work, follow through */
Packit 8fb625
	} else if (g_strcmp0 (db_pin, "ICADE") == 0) {
Packit 8fb625
		char *msg;
Packit 8fb625
Packit 8fb625
		msg = g_strdup_printf ("Generated pincode for %s when it shouldn't have", name);
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation, "org.bluez.Error.Rejected", msg);
Packit 8fb625
		g_free (msg);
Packit 8fb625
		goto bail;
Packit 8fb625
	} else if (g_strcmp0 (db_pin, "0000") == 0) {
Packit 8fb625
		g_debug ("Ignoring generated keyboard PIN '%s', should get 0000 soon", pincode);
Packit 8fb625
		g_dbus_method_invocation_return_value (invocation, NULL);
Packit 8fb625
		goto bail;
Packit 8fb625
	} else if (g_strcmp0 (db_pin, "NULL") == 0) {
Packit 8fb625
		char *msg;
Packit 8fb625
Packit 8fb625
		msg = g_strdup_printf ("Attempting pairing for %s that doesn't support pairing", name);
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation, "org.bluez.Error.Rejected", msg);
Packit 8fb625
		g_free (msg);
Packit 8fb625
		goto bail;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	setup_pairing_dialog (BLUETOOTH_SETTINGS_WIDGET (user_data));
Packit 8fb625
Packit 8fb625
	display_pin = g_strdup_printf ("%s⏎", pincode);
Packit 8fb625
	bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
					   BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_KEYBOARD,
Packit 8fb625
					   display_pin,
Packit 8fb625
					   name);
Packit 8fb625
	gtk_widget_show (priv->pairing_dialog);
Packit 8fb625
Packit 8fb625
	g_dbus_method_invocation_return_value (invocation, NULL);
Packit 8fb625
Packit 8fb625
bail:
Packit 8fb625
	g_free (db_pin);
Packit 8fb625
	g_free (display_pin);
Packit 8fb625
	g_free (bdaddr);
Packit 8fb625
	g_free (name);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
passkey_callback (GDBusMethodInvocation *invocation,
Packit 8fb625
		  GDBusProxy            *device,
Packit 8fb625
		  gpointer               data)
Packit 8fb625
{
Packit 8fb625
	g_warning ("RequestPasskey(): not implemented");
Packit 8fb625
	g_dbus_method_invocation_return_dbus_error (invocation,
Packit 8fb625
						    "org.bluez.Error.Rejected",
Packit 8fb625
						    "RequestPasskey not implemented");
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
cancel_callback (GDBusMethodInvocation *invocation,
Packit 8fb625
		 gpointer               user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	GList *l, *children;
Packit 8fb625
Packit 8fb625
	g_debug ("cancel_callback ()");
Packit 8fb625
Packit 8fb625
	g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
Packit 8fb625
	children = gtk_container_get_children (GTK_CONTAINER (priv->device_list));
Packit 8fb625
	for (l = children; l != NULL; l = l->next)
Packit 8fb625
		g_object_set (l->data, "pairing", FALSE, NULL);
Packit 8fb625
	g_list_free (children);
Packit 8fb625
Packit 8fb625
	g_dbus_method_invocation_return_value (invocation, NULL);
Packit 8fb625
Packit 8fb625
	return TRUE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
confirm_cb (GtkDialog *dialog,
Packit 8fb625
	    int        response,
Packit 8fb625
	    gpointer   user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	GDBusMethodInvocation *invocation;
Packit 8fb625
Packit 8fb625
	invocation = g_object_get_data (G_OBJECT (dialog), "invocation");
Packit 8fb625
	if (response == GTK_RESPONSE_ACCEPT) {
Packit 8fb625
		g_dbus_method_invocation_return_value (invocation, NULL);
Packit 8fb625
	} else {
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation,
Packit 8fb625
							    "org.bluez.Error.Canceled",
Packit 8fb625
							    "User cancelled pairing");
Packit 8fb625
	}
Packit 8fb625
	g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
confirm_callback (GDBusMethodInvocation *invocation,
Packit 8fb625
		  GDBusProxy            *device,
Packit 8fb625
		  guint                  pin,
Packit 8fb625
		  gpointer               user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self = user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	char *name, *pin_str;
Packit 8fb625
Packit 8fb625
	g_debug ("confirm_callback (%s, %i)", g_dbus_proxy_get_object_path (device), pin);
Packit 8fb625
Packit 8fb625
	setup_pairing_dialog (BLUETOOTH_SETTINGS_WIDGET (user_data));
Packit 8fb625
Packit 8fb625
	pin_str = g_strdup_printf ("%06d", pin);
Packit 8fb625
	get_properties_for_device (self, device, &name, NULL, NULL);
Packit 8fb625
	bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
					   BLUETOOTH_PAIRING_MODE_PIN_MATCH,
Packit 8fb625
					   pin_str, name);
Packit 8fb625
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->pairing_dialog), "response",
Packit 8fb625
			  G_CALLBACK (confirm_cb), user_data);
Packit 8fb625
	g_object_set_data (G_OBJECT (priv->pairing_dialog), "invocation", invocation);
Packit 8fb625
Packit 8fb625
	gtk_widget_show (priv->pairing_dialog);
Packit 8fb625
Packit 8fb625
	g_free (pin_str);
Packit 8fb625
	g_free (name);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
authorize_callback (GDBusMethodInvocation *invocation,
Packit 8fb625
		    GDBusProxy            *device,
Packit 8fb625
		    gpointer               user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self = user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	char *name;
Packit 8fb625
Packit 8fb625
	g_debug ("authorize_callback (%s)", g_dbus_proxy_get_object_path (device));
Packit 8fb625
Packit 8fb625
	setup_pairing_dialog (BLUETOOTH_SETTINGS_WIDGET (user_data));
Packit 8fb625
	get_properties_for_device (self, device, &name, NULL, NULL);
Packit 8fb625
	bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
					   BLUETOOTH_PAIRING_MODE_YES_NO,
Packit 8fb625
					   NULL, name);
Packit 8fb625
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->pairing_dialog), "response",
Packit 8fb625
			  G_CALLBACK (confirm_cb), user_data);
Packit 8fb625
	g_object_set_data (G_OBJECT (priv->pairing_dialog), "invocation", invocation);
Packit 8fb625
Packit 8fb625
	gtk_widget_show (priv->pairing_dialog);
Packit 8fb625
Packit 8fb625
	g_free (name);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
authorize_service_cb (GtkDialog *dialog,
Packit 8fb625
		      int        response,
Packit 8fb625
		      gpointer   user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	GDBusMethodInvocation *invocation;
Packit 8fb625
Packit 8fb625
	invocation = g_object_get_data (G_OBJECT (dialog), "invocation");
Packit 8fb625
Packit 8fb625
	if (response == GTK_RESPONSE_ACCEPT) {
Packit 8fb625
		GDBusProxy *device;
Packit 8fb625
Packit 8fb625
		device = g_object_get_data (G_OBJECT (invocation), "device");
Packit 8fb625
		bluetooth_client_set_trusted (priv->client, g_dbus_proxy_get_object_path (device), TRUE);
Packit 8fb625
		g_dbus_method_invocation_return_value (invocation, NULL);
Packit 8fb625
	} else {
Packit 8fb625
		char *msg;
Packit 8fb625
Packit 8fb625
		msg = g_strdup_printf ("Rejecting service auth (HID): not paired or trusted");
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation, "org.bluez.Error.Rejected", msg);
Packit 8fb625
		g_free (msg);
Packit 8fb625
	}
Packit 8fb625
	g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
authorize_service_callback (GDBusMethodInvocation *invocation,
Packit 8fb625
			    GDBusProxy            *device,
Packit 8fb625
			    const char            *uuid,
Packit 8fb625
			    gpointer               user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self = user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	char *msg;
Packit 8fb625
	GVariant *value;
Packit 8fb625
	gboolean paired, trusted;
Packit 8fb625
Packit 8fb625
	g_debug ("authorize_service_callback (%s, %s)", g_dbus_proxy_get_object_path (device), uuid);
Packit 8fb625
Packit 8fb625
	value = g_dbus_proxy_get_cached_property (device, "Paired");
Packit 8fb625
	paired = g_variant_get_boolean (value);
Packit 8fb625
	g_variant_unref (value);
Packit 8fb625
Packit 8fb625
	value = g_dbus_proxy_get_cached_property (device, "Trusted");
Packit 8fb625
	trusted = g_variant_get_boolean (value);
Packit 8fb625
	g_variant_unref (value);
Packit 8fb625
Packit 8fb625
	/* Device was paired, initiated from the remote device,
Packit 8fb625
	 * so we didn't get the opportunity to set the trusted bit */
Packit 8fb625
	if (paired && !trusted) {
Packit 8fb625
		bluetooth_client_set_trusted (priv->client,
Packit 8fb625
					      g_dbus_proxy_get_object_path (device), TRUE);
Packit 8fb625
		g_dbus_method_invocation_return_value (invocation, NULL);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	if (g_strcmp0 (bluetooth_uuid_to_string (uuid), "HumanInterfaceDeviceService") != 0) {
Packit 8fb625
		msg = g_strdup_printf ("Rejecting service auth (%s) for %s: not HID",
Packit 8fb625
				       uuid, g_dbus_proxy_get_object_path (device));
Packit 8fb625
		g_dbus_method_invocation_return_dbus_error (invocation, "org.bluez.Error.Rejected", msg);
Packit 8fb625
		g_free (msg);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* We shouldn't get asked, but shizzle happens */
Packit 8fb625
	if (paired || trusted) {
Packit 8fb625
		g_dbus_method_invocation_return_value (invocation, NULL);
Packit 8fb625
	} else {
Packit 8fb625
		char *name;
Packit 8fb625
Packit 8fb625
		setup_pairing_dialog (BLUETOOTH_SETTINGS_WIDGET (user_data));
Packit 8fb625
		get_properties_for_device (self, device, &name, NULL, NULL);
Packit 8fb625
		bluetooth_pairing_dialog_set_mode (BLUETOOTH_PAIRING_DIALOG (priv->pairing_dialog),
Packit 8fb625
						   BLUETOOTH_PAIRING_MODE_CONFIRM_AUTH,
Packit 8fb625
						   NULL, name);
Packit 8fb625
Packit 8fb625
		g_signal_connect (G_OBJECT (priv->pairing_dialog), "response",
Packit 8fb625
				  G_CALLBACK (authorize_service_cb), user_data);
Packit 8fb625
		g_object_set_data_full (G_OBJECT (invocation), "device", g_object_ref (device), g_object_unref);
Packit 8fb625
		g_object_set_data (G_OBJECT (priv->pairing_dialog), "invocation", invocation);
Packit 8fb625
Packit 8fb625
		gtk_widget_show (priv->pairing_dialog);
Packit 8fb625
Packit 8fb625
		g_free (name);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
turn_off_pairing (BluetoothSettingsWidget *self,
Packit 8fb625
		  const char              *object_path)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GList *l, *children;
Packit 8fb625
Packit 8fb625
	children = gtk_container_get_children (GTK_CONTAINER (priv->device_list));
Packit 8fb625
	for (l = children; l != NULL; l = l->next) {
Packit 8fb625
		GDBusProxy *proxy;
Packit 8fb625
Packit 8fb625
		g_object_get (l->data, "proxy", &proxy, NULL);
Packit 8fb625
		if (g_strcmp0 (g_dbus_proxy_get_object_path (proxy), object_path) == 0) {
Packit 8fb625
			g_object_set (l->data, "pairing", FALSE, NULL);
Packit 8fb625
			g_object_unref (proxy);
Packit 8fb625
			break;
Packit 8fb625
		}
Packit 8fb625
		g_object_unref (proxy);
Packit 8fb625
	}
Packit 8fb625
	g_list_free (children);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
typedef struct {
Packit 8fb625
	BluetoothSettingsWidget *self;
Packit 8fb625
	char *device;
Packit 8fb625
	GTimer *timer;
Packit 8fb625
	guint timeout_id;
Packit 8fb625
} SetupConnectData;
Packit 8fb625
Packit 8fb625
static void connect_callback (GObject      *source_object,
Packit 8fb625
			      GAsyncResult *res,
Packit 8fb625
			      gpointer      user_data);
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
connect_timeout_cb (gpointer user_data)
Packit 8fb625
{
Packit 8fb625
	SetupConnectData *data = (SetupConnectData *) user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (data->self);
Packit 8fb625
Packit 8fb625
	bluetooth_client_connect_service (priv->client, data->device, TRUE, NULL, connect_callback, data);
Packit 8fb625
	data->timeout_id = 0;
Packit 8fb625
Packit 8fb625
	return G_SOURCE_REMOVE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
connect_callback (GObject      *source_object,
Packit 8fb625
		  GAsyncResult *res,
Packit 8fb625
		  gpointer      user_data)
Packit 8fb625
{
Packit 8fb625
	SetupConnectData *data = (SetupConnectData *) user_data;
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
	gboolean success;
Packit 8fb625
Packit 8fb625
	success = bluetooth_client_connect_service_finish (BLUETOOTH_CLIENT (source_object), res, &error);
Packit 8fb625
Packit 8fb625
	if (success == FALSE) {
Packit 8fb625
		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
Packit 8fb625
			g_error_free (error);
Packit 8fb625
			goto bail;
Packit 8fb625
		} else if (g_timer_elapsed (data->timer, NULL) < CONNECT_TIMEOUT) {
Packit 8fb625
			g_assert (data->timeout_id == 0);
Packit 8fb625
			data->timeout_id = g_timeout_add (500, connect_timeout_cb, data);
Packit 8fb625
			g_error_free (error);
Packit 8fb625
			return;
Packit 8fb625
		}
Packit 8fb625
		g_debug ("Failed to connect to device %s", data->device);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	turn_off_pairing (data->self, data->device);
Packit 8fb625
Packit 8fb625
bail:
Packit 8fb625
	if (data->timeout_id > 0)
Packit 8fb625
		g_source_remove (data->timeout_id);
Packit 8fb625
Packit 8fb625
	g_timer_destroy (data->timer);
Packit 8fb625
	g_free (data);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
create_callback (GObject      *source_object,
Packit 8fb625
		 GAsyncResult *res,
Packit 8fb625
		 gpointer      user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	SetupConnectData *data;
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
	gboolean ret;
Packit 8fb625
	char *path;
Packit 8fb625
Packit 8fb625
	ret = bluetooth_client_setup_device_finish (BLUETOOTH_CLIENT (source_object),
Packit 8fb625
						    res, &path, &error);
Packit 8fb625
Packit 8fb625
	/* Create failed */
Packit 8fb625
	if (ret == FALSE) {
Packit 8fb625
		//char *text;
Packit 8fb625
		char *dbus_error;
Packit 8fb625
Packit 8fb625
		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
Packit 8fb625
			g_error_free (error);
Packit 8fb625
			g_free (path);
Packit 8fb625
			return;
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		turn_off_pairing (user_data, path);
Packit 8fb625
Packit 8fb625
		dbus_error = g_dbus_error_get_remote_error (error);
Packit 8fb625
		if (g_strcmp0 (dbus_error, "org.bluez.Error.AuthenticationCanceled") != 0) {
Packit 8fb625
			//FIXME show an error?
Packit 8fb625
			/* translators:
Packit 8fb625
			 * The “%s” is the device name, for example:
Packit 8fb625
			 * Setting up “Sony Bluetooth Headset” failed
Packit 8fb625
			 */
Packit 8fb625
			//text = g_strdup_printf(_("Setting up “%s” failed"), target_name);
Packit 8fb625
Packit 8fb625
			g_warning ("Setting up %s failed: %s", path, error->message);
Packit 8fb625
Packit 8fb625
			//gtk_label_set_markup(GTK_LABEL(label_summary), text);
Packit 8fb625
			//g_free (text);
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		g_free (dbus_error);
Packit 8fb625
		g_error_free (error);
Packit 8fb625
		g_free (path);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
Packit 8fb625
	g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
Packit 8fb625
	g_hash_table_remove (priv->pairing_devices, path);
Packit 8fb625
Packit 8fb625
	bluetooth_client_set_trusted (BLUETOOTH_CLIENT (source_object), path, TRUE);
Packit 8fb625
Packit 8fb625
	data = g_new0 (SetupConnectData, 1);
Packit 8fb625
	data->self = user_data;
Packit 8fb625
	data->device = path;
Packit 8fb625
	data->timer = g_timer_new ();
Packit 8fb625
Packit 8fb625
	bluetooth_client_connect_service (BLUETOOTH_CLIENT (source_object),
Packit 8fb625
					  path, TRUE, priv->cancellable, connect_callback, data);
Packit 8fb625
	//gtk_assistant_set_current_page (window_assistant, PAGE_FINISHING);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void start_pairing (BluetoothSettingsWidget *self,
Packit 8fb625
			   GtkListBoxRow           *row);
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
device_name_appeared (GObject    *gobject,
Packit 8fb625
		      GParamSpec *pspec,
Packit 8fb625
		      gpointer    user_data)
Packit 8fb625
{
Packit 8fb625
	char *name;
Packit 8fb625
Packit 8fb625
	g_object_get (G_OBJECT (gobject),
Packit 8fb625
		      "name", &name,
Packit 8fb625
		      NULL);
Packit 8fb625
	if (!name)
Packit 8fb625
		return;
Packit 8fb625
Packit 8fb625
	g_debug ("Pairing device name is now '%s'", name);
Packit 8fb625
	start_pairing (user_data, GTK_LIST_BOX_ROW (gobject));
Packit 8fb625
	g_free (name);
Packit 8fb625
Packit 8fb625
	g_signal_handlers_disconnect_by_func (gobject, device_name_appeared, user_data);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
start_pairing (BluetoothSettingsWidget *self,
Packit 8fb625
	       GtkListBoxRow           *row)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GDBusProxy *proxy;
Packit 8fb625
	gboolean pair = TRUE;
Packit 8fb625
	BluetoothType type;
Packit 8fb625
	char *bdaddr, *name;
Packit 8fb625
	gboolean legacy_pairing;
Packit 8fb625
	const char *pincode;
Packit 8fb625
Packit 8fb625
	g_object_set (G_OBJECT (row), "pairing", TRUE, NULL);
Packit 8fb625
	g_object_get (G_OBJECT (row),
Packit 8fb625
		      "proxy", &proxy,
Packit 8fb625
		      "type", &type,
Packit 8fb625
		      "address", &bdaddr,
Packit 8fb625
		      "name", &name,
Packit 8fb625
		      "legacy-pairing", &legacy_pairing,
Packit 8fb625
		      NULL);
Packit 8fb625
Packit 8fb625
	if (name == NULL) {
Packit 8fb625
		g_debug ("No name yet, will start pairing later");
Packit 8fb625
		g_signal_connect (G_OBJECT (row), "notify::name",
Packit 8fb625
				  G_CALLBACK (device_name_appeared), self);
Packit 8fb625
		g_object_unref (proxy);
Packit 8fb625
		g_free (bdaddr);
Packit 8fb625
		g_free (name);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_debug ("Starting pairing for '%s'", name);
Packit 8fb625
Packit 8fb625
	/* Legacy pairing might not have been detected yet,
Packit 8fb625
	 * so don't check for it */
Packit 8fb625
	pincode = get_pincode_for_device (type,
Packit 8fb625
					  bdaddr,
Packit 8fb625
					  name,
Packit 8fb625
					  NULL,
Packit 8fb625
					  NULL);
Packit 8fb625
	if (g_strcmp0 (pincode, "NULL") == 0)
Packit 8fb625
		pair = FALSE;
Packit 8fb625
Packit 8fb625
	g_debug ("About to setup %s (legacy pairing: %d pair: %d)",
Packit 8fb625
		 g_dbus_proxy_get_object_path (proxy),
Packit 8fb625
		 legacy_pairing, pair);
Packit 8fb625
Packit 8fb625
	g_hash_table_insert (priv->pairing_devices,
Packit 8fb625
			     g_strdup (g_dbus_proxy_get_object_path (proxy)),
Packit 8fb625
			     GINT_TO_POINTER (1));
Packit 8fb625
Packit 8fb625
	bluetooth_client_setup_device (priv->client,
Packit 8fb625
				       g_dbus_proxy_get_object_path (proxy),
Packit 8fb625
				       pair,
Packit 8fb625
				       priv->cancellable,
Packit 8fb625
				       (GAsyncReadyCallback) create_callback,
Packit 8fb625
				       self);
Packit 8fb625
	g_object_unref (proxy);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
switch_connected_state_set (GtkSwitch               *button,
Packit 8fb625
			    gboolean                 state,
Packit 8fb625
			    BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	ConnectData *data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
Packit 8fb625
	if (gtk_switch_get_state (button) == state)
Packit 8fb625
		return TRUE;
Packit 8fb625
Packit 8fb625
	if (is_connecting (self, priv->selected_bdaddr))
Packit 8fb625
		return TRUE;
Packit 8fb625
Packit 8fb625
	data = g_new0 (ConnectData, 1);
Packit 8fb625
	data->bdaddr = g_strdup (priv->selected_bdaddr);
Packit 8fb625
	data->self = self;
Packit 8fb625
Packit 8fb625
	bluetooth_client_connect_service (priv->client,
Packit 8fb625
					  priv->selected_object_path,
Packit 8fb625
					  gtk_switch_get_active (button),
Packit 8fb625
					  priv->cancellable,
Packit 8fb625
					  connect_done,
Packit 8fb625
					  data);
Packit 8fb625
Packit 8fb625
	add_connecting (self, data->bdaddr);
Packit 8fb625
	set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SPINNER);
Packit 8fb625
Packit 8fb625
	return TRUE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
update_properties (BluetoothSettingsWidget *self,
Packit 8fb625
		   GDBusProxy              *proxy)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GtkSwitch *button;
Packit 8fb625
	GtkTreeModel *model;
Packit 8fb625
	GtkTreeIter iter;
Packit 8fb625
	gboolean ret;
Packit 8fb625
	BluetoothType type;
Packit 8fb625
	gboolean connected, paired;
Packit 8fb625
	char **uuids, *bdaddr, *name, *icon;
Packit 8fb625
	guint i;
Packit 8fb625
Packit 8fb625
	model = bluetooth_client_get_device_model (priv->client);
Packit 8fb625
	g_assert (model);
Packit 8fb625
Packit 8fb625
	ret = gtk_tree_model_get_iter_first (model, &iter);
Packit 8fb625
	while (ret) {
Packit 8fb625
		GDBusProxy *p;
Packit 8fb625
Packit 8fb625
		gtk_tree_model_get (model, &iter,
Packit 8fb625
				    BLUETOOTH_COLUMN_PROXY, &p,
Packit 8fb625
				    -1);
Packit 8fb625
Packit 8fb625
		if (g_strcmp0 (g_dbus_proxy_get_object_path (proxy),
Packit 8fb625
			       g_dbus_proxy_get_object_path (p)) == 0) {
Packit 8fb625
			g_object_unref (p);
Packit 8fb625
			break;
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		g_object_unref (p);
Packit 8fb625
Packit 8fb625
		ret = gtk_tree_model_iter_next (model, &iter);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* This means we've found the device */
Packit 8fb625
	g_assert (ret);
Packit 8fb625
Packit 8fb625
	gtk_tree_model_get (model, &iter,
Packit 8fb625
			    BLUETOOTH_COLUMN_ADDRESS, &bdaddr,
Packit 8fb625
			    BLUETOOTH_COLUMN_NAME, &name,
Packit 8fb625
			    BLUETOOTH_COLUMN_ICON, &icon,
Packit 8fb625
			    BLUETOOTH_COLUMN_PAIRED, &paired,
Packit 8fb625
			    BLUETOOTH_COLUMN_CONNECTED, &connected,
Packit 8fb625
			    BLUETOOTH_COLUMN_UUIDS, &uuids,
Packit 8fb625
			    BLUETOOTH_COLUMN_TYPE, &type,
Packit 8fb625
			    -1);
Packit 8fb625
	if (priv->debug)
Packit 8fb625
		bluetooth_client_dump_device (model, &iter);
Packit 8fb625
	g_object_unref (model);
Packit 8fb625
Packit 8fb625
	g_free (priv->selected_object_path);
Packit 8fb625
	priv->selected_object_path = g_strdup (g_dbus_proxy_get_object_path (proxy));
Packit 8fb625
Packit 8fb625
	/* Hide all the buttons now, and show them again if we need to */
Packit 8fb625
	gtk_widget_hide (WID ("keyboard_button"));
Packit 8fb625
	gtk_widget_hide (WID ("sound_button"));
Packit 8fb625
	gtk_widget_hide (WID ("mouse_button"));
Packit 8fb625
	gtk_widget_hide (WID ("send_button"));
Packit 8fb625
Packit 8fb625
	/* Name */
Packit 8fb625
	gtk_window_set_title (GTK_WINDOW (priv->properties_dialog), name);
Packit 8fb625
	g_free (priv->selected_name);
Packit 8fb625
	priv->selected_name = name;
Packit 8fb625
Packit 8fb625
	/* Icon */
Packit 8fb625
	gtk_image_set_from_icon_name (GTK_IMAGE (WID ("image")), icon, GTK_ICON_SIZE_DIALOG);
Packit 8fb625
Packit 8fb625
	/* Connection */
Packit 8fb625
	button = GTK_SWITCH (WID ("switch_connection"));
Packit 8fb625
Packit 8fb625
	gtk_switch_set_state (button, connected);
Packit 8fb625
	if (is_connecting (self, bdaddr)) {
Packit 8fb625
		set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SPINNER);
Packit 8fb625
	} else {
Packit 8fb625
		set_connecting_page (self, CONNECTING_NOTEBOOK_PAGE_SWITCH);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* Paired */
Packit 8fb625
	gtk_label_set_text (GTK_LABEL (WID ("paired_label")),
Packit 8fb625
			    paired ? _("Yes") : _("No"));
Packit 8fb625
Packit 8fb625
	/* UUIDs */
Packit 8fb625
	gtk_widget_set_sensitive (GTK_WIDGET (button),
Packit 8fb625
				  bluetooth_client_get_connectable ((const char **) uuids));
Packit 8fb625
	for (i = 0; uuids && uuids[i] != NULL; i++) {
Packit 8fb625
		if (g_str_equal (uuids[i], "OBEXObjectPush")) {
Packit 8fb625
			gtk_widget_show (WID ("send_button"));
Packit 8fb625
			break;
Packit 8fb625
		}
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* Type */
Packit 8fb625
	gtk_label_set_text (GTK_LABEL (WID ("type_label")), bluetooth_type_to_string (type));
Packit 8fb625
	switch (type) {
Packit 8fb625
	case BLUETOOTH_TYPE_KEYBOARD:
Packit 8fb625
		gtk_widget_show (WID ("keyboard_button"));
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_TYPE_MOUSE:
Packit 8fb625
	case BLUETOOTH_TYPE_TABLET:
Packit 8fb625
		gtk_widget_show (WID ("mouse_button"));
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_TYPE_HEADSET:
Packit 8fb625
	case BLUETOOTH_TYPE_HEADPHONES:
Packit 8fb625
	case BLUETOOTH_TYPE_OTHER_AUDIO:
Packit 8fb625
		gtk_widget_show (WID ("sound_button"));
Packit 8fb625
	default:
Packit 8fb625
		/* others? */
Packit 8fb625
		;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* Address */
Packit 8fb625
	gtk_label_set_text (GTK_LABEL (WID ("address_label")), bdaddr);
Packit 8fb625
Packit 8fb625
	g_free (priv->selected_bdaddr);
Packit 8fb625
	priv->selected_bdaddr = bdaddr;
Packit 8fb625
Packit 8fb625
	g_free (icon);
Packit 8fb625
	g_strfreev (uuids);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
switch_panel (BluetoothSettingsWidget *self,
Packit 8fb625
	      const char       *panel)
Packit 8fb625
{
Packit 8fb625
	g_signal_emit (G_OBJECT (self),
Packit 8fb625
		       signals[PANEL_CHANGED],
Packit 8fb625
		       0, panel);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
keyboard_callback (GtkButton        *button,
Packit 8fb625
		   BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	switch_panel (self, KEYBOARD_PREFS);
Packit 8fb625
	return TRUE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
mouse_callback (GtkButton        *button,
Packit 8fb625
		BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	switch_panel (self, MOUSE_PREFS);
Packit 8fb625
	return TRUE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
sound_callback (GtkButton        *button,
Packit 8fb625
		BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	switch_panel (self, SOUND_PREFS);
Packit 8fb625
	return TRUE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
send_callback (GtkButton        *button,
Packit 8fb625
	       BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	bluetooth_send_to_address (priv->selected_bdaddr, priv->selected_name);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
/* Visibility/Discoverable */
Packit 8fb625
static void
Packit 8fb625
update_visibility (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	char *name;
Packit 8fb625
Packit 8fb625
	g_object_get (G_OBJECT (priv->client), "default-adapter-name", &name, NULL);
Packit 8fb625
	if (name != NULL) {
Packit 8fb625
		char *label, *path, *uri;
Packit 8fb625
Packit 8fb625
		path = lookup_download_dir ();
Packit 8fb625
		uri = g_filename_to_uri (path, NULL, NULL);
Packit 8fb625
		g_free (path);
Packit 8fb625
Packit 8fb625
		/* translators: first %s is the name of the computer, for example:
Packit 8fb625
		 * Visible as “Bastien Nocera’s Computer” followed by the
Packit 8fb625
		 * location of the Downloads folder.*/
Packit 8fb625
		label = g_strdup_printf (_("Visible as “%s” and available for Bluetooth file transfers. Transferred files are placed in the Downloads folder."), name, uri);
Packit 8fb625
		g_free (uri);
Packit 8fb625
		g_free (name);
Packit 8fb625
		gtk_label_set_markup (GTK_LABEL (priv->visible_label), label);
Packit 8fb625
		g_free (label);
Packit 8fb625
	}
Packit 8fb625
	gtk_widget_set_visible (priv->visible_label, name != NULL);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
name_changed (BluetoothClient  *client,
Packit 8fb625
	      GParamSpec       *spec,
Packit 8fb625
	      BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	update_visibility (self);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
show_confirm_dialog (BluetoothSettingsWidget *self,
Packit 8fb625
		     const char *name)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GtkWidget *dialog;
Packit 8fb625
	gint response;
Packit 8fb625
Packit 8fb625
	dialog = gtk_message_dialog_new (GTK_WINDOW (priv->properties_dialog), GTK_DIALOG_MODAL,
Packit 8fb625
					 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
Packit 8fb625
					 _("Remove “%s” from the list of devices?"), name);
Packit 8fb625
	g_object_set (G_OBJECT (dialog), "secondary-text",
Packit 8fb625
		      _("If you remove the device, you will have to set it up again before next use."),
Packit 8fb625
		      NULL);
Packit 8fb625
Packit 8fb625
	gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL);
Packit 8fb625
	gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Remove"), GTK_RESPONSE_ACCEPT);
Packit 8fb625
Packit 8fb625
	response = gtk_dialog_run (GTK_DIALOG (dialog));
Packit 8fb625
Packit 8fb625
	gtk_widget_destroy (dialog);
Packit 8fb625
Packit 8fb625
	if (response == GTK_RESPONSE_ACCEPT)
Packit 8fb625
		return TRUE;
Packit 8fb625
Packit 8fb625
	return FALSE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
remove_selected_device (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GDBusProxy *adapter_proxy;
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
	GVariant *ret;
Packit 8fb625
Packit 8fb625
	g_debug ("About to call RemoveDevice for %s", priv->selected_object_path);
Packit 8fb625
Packit 8fb625
	adapter_proxy = _bluetooth_client_get_default_adapter (priv->client);
Packit 8fb625
Packit 8fb625
	if (adapter_proxy == NULL) {
Packit 8fb625
		g_warning ("Failed to get a GDBusProxy for the default adapter");
Packit 8fb625
		return FALSE;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	//FIXME use adapter1_call_remove_device_sync()
Packit 8fb625
	ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (adapter_proxy),
Packit 8fb625
				      "RemoveDevice",
Packit 8fb625
				      g_variant_new ("(o)", priv->selected_object_path),
Packit 8fb625
				      G_DBUS_CALL_FLAGS_NONE,
Packit 8fb625
				      -1,
Packit 8fb625
				      NULL,
Packit 8fb625
				      &error);
Packit 8fb625
Packit 8fb625
	if (ret == NULL) {
Packit 8fb625
		g_warning ("Failed to remove device '%s': %s",
Packit 8fb625
			   priv->selected_object_path, error->message);
Packit 8fb625
		g_error_free (error);
Packit 8fb625
	} else {
Packit 8fb625
		g_variant_unref (ret);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_object_unref (adapter_proxy);
Packit 8fb625
Packit 8fb625
	return (ret != NULL);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
delete_clicked (GtkButton        *button,
Packit 8fb625
		BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	if (show_confirm_dialog (self, priv->selected_name) != FALSE) {
Packit 8fb625
		remove_selected_device (self);
Packit 8fb625
		gtk_widget_hide (priv->properties_dialog);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
default_adapter_changed (BluetoothClient  *client,
Packit 8fb625
			 GParamSpec       *spec,
Packit 8fb625
			 BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	char *default_adapter;
Packit 8fb625
Packit 8fb625
	g_object_get (priv->client, "default-adapter", &default_adapter, NULL);
Packit 8fb625
Packit 8fb625
	g_debug ("Default adapter changed to: %s", default_adapter ? default_adapter : "(none)");
Packit 8fb625
Packit 8fb625
	g_object_set (G_OBJECT (client), "default-adapter-discovering", default_adapter != NULL, NULL);
Packit 8fb625
Packit 8fb625
	/* FIXME: This should turn off automatically when
Packit 8fb625
	 * the settings panel goes away */
Packit 8fb625
	g_object_set (G_OBJECT (client), "default-adapter-discoverable", default_adapter != NULL, NULL);
Packit 8fb625
Packit 8fb625
	g_signal_emit (G_OBJECT (self), signals[ADAPTER_STATUS_CHANGED], 0);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gint
Packit 8fb625
device_sort_func (gconstpointer a, gconstpointer b, gpointer data)
Packit 8fb625
{
Packit 8fb625
	GObject *row_a = (GObject*)a;
Packit 8fb625
	GObject *row_b = (GObject*)b;
Packit 8fb625
	gboolean setup_a, setup_b;
Packit 8fb625
	gboolean paired_a, paired_b;
Packit 8fb625
	gboolean trusted_a, trusted_b;
Packit 8fb625
	gboolean connected_a, connected_b;
Packit 8fb625
	char *name_a, *name_b;
Packit 8fb625
	int ret;
Packit 8fb625
Packit 8fb625
	g_object_get (row_a,
Packit 8fb625
		      "paired", &paired_a,
Packit 8fb625
		      "trusted", &trusted_a,
Packit 8fb625
		      "connected", &connected_a,
Packit 8fb625
		      "name", &name_a,
Packit 8fb625
		      NULL);
Packit 8fb625
	g_object_get (row_b,
Packit 8fb625
		      "paired", &paired_b,
Packit 8fb625
		      "trusted", &trusted_b,
Packit 8fb625
		      "connected", &connected_b,
Packit 8fb625
		      "name", &name_b,
Packit 8fb625
		      NULL);
Packit 8fb625
Packit 8fb625
	/* First, paired or trusted devices (setup devices) */
Packit 8fb625
	setup_a = paired_a || trusted_a;
Packit 8fb625
	setup_b = paired_b || trusted_b;
Packit 8fb625
	if (setup_a != setup_b) {
Packit 8fb625
		if (setup_a)
Packit 8fb625
			ret = -1;
Packit 8fb625
		else
Packit 8fb625
			ret = 1;
Packit 8fb625
		goto out;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* Then connected ones */
Packit 8fb625
	if (connected_a != connected_b) {
Packit 8fb625
		if (connected_a)
Packit 8fb625
			ret = -1;
Packit 8fb625
		else
Packit 8fb625
			ret = 1;
Packit 8fb625
		goto out;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	if (name_a == NULL) {
Packit 8fb625
		ret = 1;
Packit 8fb625
		goto out;
Packit 8fb625
	}
Packit 8fb625
	if (name_b == NULL) {
Packit 8fb625
		ret = -1;
Packit 8fb625
		goto out;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	/* And all being equal, alphabetically */
Packit 8fb625
	ret = g_utf8_collate (name_a, name_b);
Packit 8fb625
Packit 8fb625
out:
Packit 8fb625
	g_free (name_a);
Packit 8fb625
	g_free (name_b);
Packit 8fb625
	return ret;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
update_header_func (GtkListBoxRow  *row,
Packit 8fb625
		    GtkListBoxRow  *before,
Packit 8fb625
		    gpointer    user_data)
Packit 8fb625
{
Packit 8fb625
	GtkWidget *current;
Packit 8fb625
Packit 8fb625
	if (before == NULL)
Packit 8fb625
		return;
Packit 8fb625
Packit 8fb625
	current = gtk_list_box_row_get_header (row);
Packit 8fb625
	if (current == NULL) {
Packit 8fb625
		current = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
Packit 8fb625
		gtk_widget_show (current);
Packit 8fb625
		gtk_list_box_row_set_header (row, current);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
keynav_failed (GtkWidget *list, GtkDirectionType direction, BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GList *children, *item;
Packit 8fb625
Packit 8fb625
	children = gtk_container_get_children (GTK_CONTAINER (priv->device_list));
Packit 8fb625
Packit 8fb625
	if (direction == GTK_DIR_DOWN) {
Packit 8fb625
		item = children;
Packit 8fb625
	} else {
Packit 8fb625
		item = g_list_last (children);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_widget_child_focus (item->data, direction);
Packit 8fb625
Packit 8fb625
	g_list_free (children);
Packit 8fb625
Packit 8fb625
	return TRUE;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
activate_row (BluetoothSettingsWidget *self,
Packit 8fb625
              GtkListBoxRow    *row)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GtkWidget *w;
Packit 8fb625
	GtkWidget *toplevel;
Packit 8fb625
	gboolean paired, trusted, is_setup;
Packit 8fb625
Packit 8fb625
	g_object_get (G_OBJECT (row),
Packit 8fb625
		      "paired", &paired,
Packit 8fb625
		      "trusted", &trusted,
Packit 8fb625
		      NULL);
Packit 8fb625
	is_setup = paired || trusted;
Packit 8fb625
Packit 8fb625
	if (is_setup) {
Packit 8fb625
		GDBusProxy *proxy;
Packit 8fb625
Packit 8fb625
		//FIXME pass the row
Packit 8fb625
		//FIXME add UUIDs to the row
Packit 8fb625
		//FIXME add icon to the row
Packit 8fb625
		g_object_get (G_OBJECT (row), "proxy", &proxy, NULL);
Packit 8fb625
		update_properties (self, proxy);
Packit 8fb625
		g_object_unref (proxy);
Packit 8fb625
Packit 8fb625
		w = priv->properties_dialog;
Packit 8fb625
		toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
Packit 8fb625
		gtk_window_set_transient_for (GTK_WINDOW (w), GTK_WINDOW (toplevel));
Packit 8fb625
		gtk_window_set_modal (GTK_WINDOW (w), TRUE);
Packit 8fb625
		gtk_window_present (GTK_WINDOW (w));
Packit 8fb625
	} else {
Packit 8fb625
		start_pairing (self, row);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
add_device_section (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GtkWidget *vbox;
Packit 8fb625
	GtkWidget *widget, *box, *hbox, *spinner;
Packit 8fb625
	GtkWidget *frame, *label;
Packit 8fb625
	gchar *s;
Packit 8fb625
Packit 8fb625
	vbox = WID ("vbox_bluetooth");
Packit 8fb625
Packit 8fb625
	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
Packit 8fb625
	gtk_widget_set_margin_top (box, 6);
Packit 8fb625
	gtk_widget_set_margin_bottom (box, 24);
Packit 8fb625
	gtk_box_pack_start (GTK_BOX (vbox), box, TRUE, TRUE, 0);
Packit 8fb625
	priv->child_box = box;
Packit 8fb625
Packit 8fb625
	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
Packit 8fb625
	gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, TRUE, 0);
Packit 8fb625
Packit 8fb625
	s = g_markup_printf_escaped ("%s", _("Devices"));
Packit 8fb625
	widget = gtk_label_new (s);
Packit 8fb625
	g_free (s);
Packit 8fb625
	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
Packit 8fb625
	gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
Packit 8fb625
	gtk_widget_set_margin_end (widget, 6);
Packit 8fb625
	gtk_widget_set_margin_bottom (widget, 12);
Packit 8fb625
	gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, TRUE, 0);
Packit 8fb625
Packit 8fb625
	/* Discoverable spinner */
Packit 8fb625
	priv->device_spinner = spinner = gtk_spinner_new ();
Packit 8fb625
	g_object_bind_property (G_OBJECT (priv->client), "default-adapter-discovering",
Packit 8fb625
				G_OBJECT (priv->device_spinner), "active",
Packit 8fb625
				G_BINDING_SYNC_CREATE);
Packit 8fb625
	gtk_widget_set_margin_bottom (spinner, 12);
Packit 8fb625
	gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, TRUE, 0);
Packit 8fb625
Packit 8fb625
	/* Discoverable label placeholder, the real name is set in update_visibility().
Packit 8fb625
	 * If you ever see this string during normal use, please file a bug. */
Packit 8fb625
	priv->visible_label = WID ("explanation-label");
Packit 8fb625
	gtk_label_set_use_markup (GTK_LABEL (priv->visible_label), TRUE);
Packit 8fb625
	update_visibility (self);
Packit 8fb625
Packit 8fb625
	priv->device_list = widget = gtk_list_box_new ();
Packit 8fb625
	g_signal_connect (widget, "keynav-failed", G_CALLBACK (keynav_failed), self);
Packit 8fb625
	gtk_list_box_set_selection_mode (GTK_LIST_BOX (widget), GTK_SELECTION_NONE);
Packit 8fb625
	gtk_list_box_set_header_func (GTK_LIST_BOX (widget),
Packit 8fb625
				      update_header_func,
Packit 8fb625
				      NULL, NULL);
Packit 8fb625
	gtk_list_box_set_sort_func (GTK_LIST_BOX (widget),
Packit 8fb625
				    (GtkListBoxSortFunc)device_sort_func, NULL, NULL);
Packit 8fb625
	g_signal_connect_swapped (widget, "row-activated",
Packit 8fb625
				  G_CALLBACK (activate_row), self);
Packit 8fb625
Packit 8fb625
	priv->device_stack = gtk_stack_new ();
Packit 8fb625
	gtk_stack_set_homogeneous (GTK_STACK (priv->device_stack), FALSE);
Packit 8fb625
Packit 8fb625
	label = gtk_label_new (_("Searching for devices…"));
Packit 8fb625
	gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
Packit 8fb625
	gtk_stack_add_named (GTK_STACK (priv->device_stack), label, FILLER_PAGE);
Packit 8fb625
Packit 8fb625
	frame = gtk_frame_new (NULL);
Packit 8fb625
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Packit 8fb625
	gtk_container_add (GTK_CONTAINER (frame), widget);
Packit 8fb625
	gtk_stack_add_named (GTK_STACK (priv->device_stack), frame, DEVICES_PAGE);
Packit 8fb625
	gtk_box_pack_start (GTK_BOX (box), priv->device_stack, TRUE, TRUE, 0);
Packit 8fb625
Packit 8fb625
	gtk_widget_show_all (box);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
is_interesting_device (GtkTreeModel *model,
Packit 8fb625
		       GtkTreeIter  *iter)
Packit 8fb625
{
Packit 8fb625
	GtkTreeIter parent_iter;
Packit 8fb625
	gboolean is_default;
Packit 8fb625
Packit 8fb625
	/* Not a child */
Packit 8fb625
	if (gtk_tree_model_iter_parent (model, &parent_iter, iter) == FALSE)
Packit 8fb625
		return FALSE;
Packit 8fb625
Packit 8fb625
	/* Not the default adapter */
Packit 8fb625
	gtk_tree_model_get (model, &parent_iter,
Packit 8fb625
			    BLUETOOTH_COLUMN_DEFAULT, &is_default,
Packit 8fb625
			    -1);
Packit 8fb625
	return is_default;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
row_inserted_cb (GtkTreeModel *tree_model,
Packit 8fb625
		 GtkTreePath  *path,
Packit 8fb625
		 GtkTreeIter  *iter,
Packit 8fb625
		 gpointer      user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self = user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	GDBusProxy *proxy;
Packit 8fb625
	char *name, *bdaddr;
Packit 8fb625
	BluetoothType type;
Packit 8fb625
	gboolean paired, trusted, connected, legacy_pairing;
Packit 8fb625
	GtkWidget *row;
Packit 8fb625
Packit 8fb625
	if (is_interesting_device (tree_model, iter) == FALSE) {
Packit 8fb625
		gtk_tree_model_get (tree_model, iter,
Packit 8fb625
				    BLUETOOTH_COLUMN_NAME, &name,
Packit 8fb625
				    -1);
Packit 8fb625
		g_debug ("Not adding device '%s'", name);
Packit 8fb625
		g_free (name);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_tree_model_get (tree_model, iter,
Packit 8fb625
			    BLUETOOTH_COLUMN_PROXY, &proxy,
Packit 8fb625
			    BLUETOOTH_COLUMN_NAME, &name,
Packit 8fb625
			    BLUETOOTH_COLUMN_PAIRED, &paired,
Packit 8fb625
			    BLUETOOTH_COLUMN_TRUSTED, &trusted,
Packit 8fb625
			    BLUETOOTH_COLUMN_CONNECTED, &connected,
Packit 8fb625
			    BLUETOOTH_COLUMN_ADDRESS, &bdaddr,
Packit 8fb625
			    BLUETOOTH_COLUMN_TYPE, &type,
Packit 8fb625
			    BLUETOOTH_COLUMN_LEGACYPAIRING, &legacy_pairing,
Packit 8fb625
			    -1);
Packit 8fb625
Packit 8fb625
	g_debug ("Adding device %s (%s)", name, g_dbus_proxy_get_object_path (proxy));
Packit 8fb625
Packit 8fb625
	add_device_type (self, bdaddr, type);
Packit 8fb625
Packit 8fb625
	row = g_object_new (BLUETOOTH_TYPE_SETTINGS_ROW,
Packit 8fb625
			    "proxy", proxy,
Packit 8fb625
			    "paired", paired,
Packit 8fb625
			    "trusted", trusted,
Packit 8fb625
			    "type", type,
Packit 8fb625
			    "connected", connected,
Packit 8fb625
			    "name", name,
Packit 8fb625
			    "address", bdaddr,
Packit 8fb625
			    "legacy-pairing", legacy_pairing,
Packit 8fb625
			    NULL);
Packit 8fb625
	g_object_set_data_full (G_OBJECT (row), "object-path", g_strdup (g_dbus_proxy_get_object_path (proxy)), g_free);
Packit 8fb625
Packit 8fb625
	gtk_container_add (GTK_CONTAINER (priv->device_list), row);
Packit 8fb625
	gtk_size_group_add_widget (priv->row_sizegroup, row);
Packit 8fb625
Packit 8fb625
	g_object_unref (proxy);
Packit 8fb625
	g_free (name);
Packit 8fb625
	g_free (bdaddr);
Packit 8fb625
Packit 8fb625
	gtk_stack_set_transition_type (GTK_STACK (priv->device_stack),
Packit 8fb625
				       GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN);
Packit 8fb625
	gtk_container_child_set (GTK_CONTAINER (WID ("vbox_bluetooth")),
Packit 8fb625
				 priv->child_box, "expand", FALSE, NULL);
Packit 8fb625
	gtk_stack_set_visible_child_name (GTK_STACK (priv->device_stack), DEVICES_PAGE);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
row_changed_cb (GtkTreeModel *tree_model,
Packit 8fb625
		GtkTreePath  *path,
Packit 8fb625
		GtkTreeIter  *iter,
Packit 8fb625
		gpointer      user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *self = user_data;
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	GDBusProxy *proxy;
Packit 8fb625
	GList *l, *children;
Packit 8fb625
	const char *object_path;
Packit 8fb625
Packit 8fb625
	if (is_interesting_device (tree_model, iter) == FALSE) {
Packit 8fb625
		char *name;
Packit 8fb625
Packit 8fb625
		gtk_tree_model_get (tree_model, iter,
Packit 8fb625
				    BLUETOOTH_COLUMN_NAME, &name,
Packit 8fb625
				    -1);
Packit 8fb625
		g_debug ("Not interested in device '%s'", name);
Packit 8fb625
		g_free (name);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_tree_model_get (tree_model, iter,
Packit 8fb625
			    BLUETOOTH_COLUMN_PROXY, &proxy,
Packit 8fb625
			    -1);
Packit 8fb625
	object_path = g_dbus_proxy_get_object_path (proxy);
Packit 8fb625
Packit 8fb625
	children = gtk_container_get_children (GTK_CONTAINER (priv->device_list));
Packit 8fb625
	for (l = children; l != NULL; l = l->next) {
Packit 8fb625
		const char *path;
Packit 8fb625
Packit 8fb625
		path = g_object_get_data (G_OBJECT (l->data), "object-path");
Packit 8fb625
		if (g_str_equal (object_path, path)) {
Packit 8fb625
			char *name, *bdaddr;
Packit 8fb625
			BluetoothType type;
Packit 8fb625
			gboolean paired, trusted, connected, legacy_pairing;
Packit 8fb625
Packit 8fb625
			gtk_tree_model_get (tree_model, iter,
Packit 8fb625
					    BLUETOOTH_COLUMN_NAME, &name,
Packit 8fb625
					    BLUETOOTH_COLUMN_PAIRED, &paired,
Packit 8fb625
					    BLUETOOTH_COLUMN_TRUSTED, &trusted,
Packit 8fb625
					    BLUETOOTH_COLUMN_CONNECTED, &connected,
Packit 8fb625
					    BLUETOOTH_COLUMN_ADDRESS, &bdaddr,
Packit 8fb625
					    BLUETOOTH_COLUMN_TYPE, &type,
Packit 8fb625
					    BLUETOOTH_COLUMN_LEGACYPAIRING, &legacy_pairing,
Packit 8fb625
					    -1);
Packit 8fb625
Packit 8fb625
			add_device_type (self, bdaddr, type);
Packit 8fb625
Packit 8fb625
			g_object_set (G_OBJECT (l->data),
Packit 8fb625
				      "paired", paired,
Packit 8fb625
				      "trusted", trusted,
Packit 8fb625
				      "type", type,
Packit 8fb625
				      "connected", connected,
Packit 8fb625
				      "name", name,
Packit 8fb625
				      "legacy-pairing", legacy_pairing,
Packit 8fb625
				      NULL);
Packit 8fb625
Packit 8fb625
			/* Update the properties if necessary */
Packit 8fb625
			if (g_strcmp0 (priv->selected_object_path, object_path) == 0)
Packit 8fb625
				update_properties (user_data, proxy);
Packit 8fb625
			break;
Packit 8fb625
		}
Packit 8fb625
	}
Packit 8fb625
	g_list_free (children);
Packit 8fb625
	g_object_unref (proxy);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
device_removed_cb (BluetoothClient *client,
Packit 8fb625
		   const char      *object_path,
Packit 8fb625
		   gpointer         user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (user_data);
Packit 8fb625
	GList *children, *l;
Packit 8fb625
	gboolean found = FALSE;
Packit 8fb625
Packit 8fb625
	children = gtk_container_get_children (GTK_CONTAINER (priv->device_list));
Packit 8fb625
	for (l = children; l != NULL; l = l->next) {
Packit 8fb625
		const char *path;
Packit 8fb625
Packit 8fb625
		path = g_object_get_data (G_OBJECT (l->data), "object-path");
Packit 8fb625
		if (g_str_equal (path, object_path)) {
Packit 8fb625
			char *name;
Packit 8fb625
Packit 8fb625
			g_object_get (G_OBJECT (l->data), "name", &name, NULL);
Packit 8fb625
			g_debug ("Removing device '%s'", name);
Packit 8fb625
			g_free (name);
Packit 8fb625
Packit 8fb625
			gtk_widget_destroy (GTK_WIDGET (l->data));
Packit 8fb625
			found = TRUE;
Packit 8fb625
			break;
Packit 8fb625
		}
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	if (found) {
Packit 8fb625
		if (gtk_container_get_children (GTK_CONTAINER (priv->device_list)) == NULL) {
Packit 8fb625
			gtk_stack_set_transition_type (GTK_STACK (priv->device_stack),
Packit 8fb625
						       GTK_STACK_TRANSITION_TYPE_NONE);
Packit 8fb625
			gtk_container_child_set (GTK_CONTAINER (WID ("vbox_bluetooth")),
Packit 8fb625
						 priv->child_box, "expand", TRUE, NULL);
Packit 8fb625
			gtk_stack_set_visible_child_name (GTK_STACK (priv->device_stack), FILLER_PAGE);
Packit 8fb625
		}
Packit 8fb625
	} else {
Packit 8fb625
		g_debug ("Didn't find a row to remove for tree path %s", object_path);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
setup_properties_dialog (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GtkWidget *container;
Packit 8fb625
	GtkStyleContext *context;
Packit 8fb625
Packit 8fb625
	priv->properties_dialog = g_object_new (GTK_TYPE_DIALOG, "use-header-bar", TRUE, NULL);
Packit 8fb625
	gtk_widget_set_size_request (priv->properties_dialog, 380, -1);
Packit 8fb625
	gtk_window_set_resizable (GTK_WINDOW (priv->properties_dialog), FALSE);
Packit 8fb625
	container = gtk_dialog_get_content_area (GTK_DIALOG (priv->properties_dialog));
Packit 8fb625
	gtk_container_add (GTK_CONTAINER (container), WID ("properties_vbox"));
Packit 8fb625
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->properties_dialog), "delete-event",
Packit 8fb625
			  G_CALLBACK (gtk_widget_hide_on_delete), NULL);
Packit 8fb625
	g_signal_connect (G_OBJECT (WID ("delete_button")), "clicked",
Packit 8fb625
			  G_CALLBACK (delete_clicked), self);
Packit 8fb625
	g_signal_connect (G_OBJECT (WID ("mouse_button")), "clicked",
Packit 8fb625
			  G_CALLBACK (mouse_callback), self);
Packit 8fb625
	g_signal_connect (G_OBJECT (WID ("keyboard_button")), "clicked",
Packit 8fb625
			  G_CALLBACK (keyboard_callback), self);
Packit 8fb625
	g_signal_connect (G_OBJECT (WID ("sound_button")), "clicked",
Packit 8fb625
			  G_CALLBACK (sound_callback), self);
Packit 8fb625
	g_signal_connect (G_OBJECT (WID ("send_button")), "clicked",
Packit 8fb625
			  G_CALLBACK (send_callback), self);
Packit 8fb625
	g_signal_connect (G_OBJECT (WID ("switch_connection")), "state-set",
Packit 8fb625
			  G_CALLBACK (switch_connected_state_set), self);
Packit 8fb625
Packit 8fb625
	/* Styling */
Packit 8fb625
	gtk_image_set_pixel_size (GTK_IMAGE (WID ("image")), ICON_SIZE);
Packit 8fb625
Packit 8fb625
	context = gtk_widget_get_style_context (WID ("delete_button"));
Packit 8fb625
	gtk_style_context_add_class (context, "destructive-action");
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
setup_pairing_agent (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
Packit 8fb625
	priv->agent = bluetooth_agent_new (AGENT_PATH);
Packit 8fb625
	if (bluetooth_agent_register (priv->agent) == FALSE) {
Packit 8fb625
		g_clear_object (&priv->agent);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	bluetooth_agent_set_pincode_func (priv->agent, pincode_callback, self);
Packit 8fb625
	bluetooth_agent_set_passkey_func (priv->agent, passkey_callback, self);
Packit 8fb625
	bluetooth_agent_set_display_func (priv->agent, display_callback, self);
Packit 8fb625
	bluetooth_agent_set_display_pincode_func (priv->agent, display_pincode_callback, self);
Packit 8fb625
	bluetooth_agent_set_cancel_func (priv->agent, cancel_callback, self);
Packit 8fb625
	bluetooth_agent_set_confirm_func (priv->agent, confirm_callback, self);
Packit 8fb625
	bluetooth_agent_set_authorize_func (priv->agent, authorize_callback, self);
Packit 8fb625
	bluetooth_agent_set_authorize_service_func (priv->agent, authorize_service_callback, self);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
session_properties_changed_cb (GDBusProxy               *session,
Packit 8fb625
			       GVariant                 *changed,
Packit 8fb625
			       char                    **invalidated,
Packit 8fb625
			       BluetoothSettingsWidget  *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GVariant *v;
Packit 8fb625
Packit 8fb625
	v = g_variant_lookup_value (changed, "SessionIsActive", G_VARIANT_TYPE_BOOLEAN);
Packit 8fb625
	if (v) {
Packit 8fb625
		priv->has_console = g_variant_get_boolean (v);
Packit 8fb625
		g_debug ("Received session is active change: now %s", priv->has_console ? "active" : "inactive");
Packit 8fb625
		g_variant_unref (v);
Packit 8fb625
Packit 8fb625
		if (priv->has_console)
Packit 8fb625
			obex_agent_up ();
Packit 8fb625
		else
Packit 8fb625
			obex_agent_down ();
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static gboolean
Packit 8fb625
is_session_active (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GVariant *variant;
Packit 8fb625
	gboolean is_session_active = FALSE;
Packit 8fb625
Packit 8fb625
	variant = g_dbus_proxy_get_cached_property (priv->session_proxy,
Packit 8fb625
						    "SessionIsActive");
Packit 8fb625
	if (variant) {
Packit 8fb625
		is_session_active = g_variant_get_boolean (variant);
Packit 8fb625
		g_variant_unref (variant);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	return is_session_active;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
setup_obex (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
Packit 8fb625
	priv->session_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
Packit 8fb625
							     G_DBUS_PROXY_FLAGS_NONE,
Packit 8fb625
							     NULL,
Packit 8fb625
							     GNOME_SESSION_DBUS_NAME,
Packit 8fb625
							     GNOME_SESSION_DBUS_OBJECT,
Packit 8fb625
							     GNOME_SESSION_DBUS_INTERFACE,
Packit 8fb625
							     NULL,
Packit 8fb625
							     &error);
Packit 8fb625
Packit 8fb625
	if (priv->session_proxy == NULL) {
Packit 8fb625
		g_warning ("Failed to get session proxy: %s", error->message);
Packit 8fb625
		g_error_free (error);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
	g_signal_connect (priv->session_proxy, "g-properties-changed",
Packit 8fb625
			  G_CALLBACK (session_properties_changed_cb), self);
Packit 8fb625
	priv->has_console = is_session_active (self);
Packit 8fb625
Packit 8fb625
	if (priv->has_console)
Packit 8fb625
		obex_agent_up ();
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_settings_widget_init (BluetoothSettingsWidget *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (self);
Packit 8fb625
	GtkWidget *widget;
Packit 8fb625
	GError *error = NULL;
Packit 8fb625
Packit 8fb625
	priv->cancellable = g_cancellable_new ();
Packit 8fb625
	priv->debug = g_getenv ("BLUETOOTH_DEBUG") != NULL;
Packit 8fb625
Packit 8fb625
	g_resources_register (bluetooth_settings_get_resource ());
Packit 8fb625
	priv->builder = gtk_builder_new ();
Packit 8fb625
	gtk_builder_set_translation_domain (priv->builder, GETTEXT_PACKAGE);
Packit 8fb625
	gtk_builder_add_from_resource (priv->builder,
Packit 8fb625
                                       "/org/gnome/bluetooth/settings.ui",
Packit 8fb625
                                       &error);
Packit 8fb625
	if (error != NULL) {
Packit 8fb625
		g_warning ("Could not load ui: %s", error->message);
Packit 8fb625
		g_error_free (error);
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	widget = WID ("scrolledwindow1");
Packit 8fb625
Packit 8fb625
	priv->connecting_devices = g_hash_table_new_full (g_str_hash,
Packit 8fb625
								g_str_equal,
Packit 8fb625
								(GDestroyNotify) g_free,
Packit 8fb625
								NULL);
Packit 8fb625
	priv->pairing_devices = g_hash_table_new_full (g_str_hash,
Packit 8fb625
						       g_str_equal,
Packit 8fb625
						       (GDestroyNotify) g_free,
Packit 8fb625
						       NULL);
Packit 8fb625
	priv->devices_type = g_hash_table_new_full (g_str_hash,
Packit 8fb625
						    g_str_equal,
Packit 8fb625
						    (GDestroyNotify) g_free,
Packit 8fb625
						    NULL);
Packit 8fb625
Packit 8fb625
	setup_pairing_agent (self);
Packit 8fb625
	priv->client = bluetooth_client_new ();
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->client), "notify::default-adapter-name",
Packit 8fb625
			  G_CALLBACK (name_changed), self);
Packit 8fb625
	priv->model = bluetooth_client_get_model (priv->client);
Packit 8fb625
	g_signal_connect (priv->model, "row-changed",
Packit 8fb625
			  G_CALLBACK (row_changed_cb), self);
Packit 8fb625
	g_signal_connect (priv->model, "row-inserted",
Packit 8fb625
			  G_CALLBACK (row_inserted_cb), self);
Packit 8fb625
	g_signal_connect (priv->client, "device-removed",
Packit 8fb625
			  G_CALLBACK (device_removed_cb), self);
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->client), "notify::default-adapter",
Packit 8fb625
			  G_CALLBACK (default_adapter_changed), self);
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->client), "notify::default-adapter-powered",
Packit 8fb625
			  G_CALLBACK (default_adapter_changed), self);
Packit 8fb625
	default_adapter_changed (priv->client, NULL, self);
Packit 8fb625
Packit 8fb625
	priv->row_sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
Packit 8fb625
Packit 8fb625
	add_device_section (self);
Packit 8fb625
Packit 8fb625
	gtk_widget_set_hexpand (widget, TRUE);
Packit 8fb625
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget),
Packit 8fb625
					GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
Packit 8fb625
	gtk_container_add (GTK_CONTAINER (self), widget);
Packit 8fb625
Packit 8fb625
	setup_properties_dialog (self);
Packit 8fb625
Packit 8fb625
	gtk_widget_show_all (GTK_WIDGET (self));
Packit 8fb625
Packit 8fb625
	setup_obex (self);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_settings_widget_finalize (GObject *object)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidget *widget = BLUETOOTH_SETTINGS_WIDGET(object);
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (widget);
Packit 8fb625
Packit 8fb625
	g_clear_object (&priv->agent);
Packit 8fb625
	g_clear_pointer (&priv->properties_dialog, gtk_widget_destroy);
Packit 8fb625
	g_clear_pointer (&priv->pairing_dialog, gtk_widget_destroy);
Packit 8fb625
	g_clear_object (&priv->session_proxy);
Packit 8fb625
Packit 8fb625
	obex_agent_down ();
Packit 8fb625
Packit 8fb625
	/* See default_adapter_changed () */
Packit 8fb625
	/* FIXME: This is blocking */
Packit 8fb625
	if (priv->client)
Packit 8fb625
		g_object_set (G_OBJECT (priv->client), "default-adapter-discoverable", FALSE, NULL);
Packit 8fb625
Packit 8fb625
	g_cancellable_cancel (priv->cancellable);
Packit 8fb625
	g_clear_object (&priv->cancellable);
Packit 8fb625
Packit 8fb625
	g_clear_object (&priv->model);
Packit 8fb625
	g_clear_object (&priv->client);
Packit 8fb625
	g_clear_object (&priv->builder);
Packit 8fb625
Packit 8fb625
	g_clear_pointer (&priv->devices_type, g_hash_table_destroy);
Packit 8fb625
	g_clear_pointer (&priv->connecting_devices, g_hash_table_destroy);
Packit 8fb625
	g_clear_pointer (&priv->pairing_devices, g_hash_table_destroy);
Packit 8fb625
	g_clear_pointer (&priv->selected_name, g_free);
Packit 8fb625
	g_clear_pointer (&priv->selected_object_path, g_free);
Packit 8fb625
Packit 8fb625
	G_OBJECT_CLASS(bluetooth_settings_widget_parent_class)->finalize(object);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_settings_widget_class_init (BluetoothSettingsWidgetClass *klass)
Packit 8fb625
{
Packit 8fb625
	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Packit 8fb625
	bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
Packit 8fb625
Packit 8fb625
	G_OBJECT_CLASS (klass)->finalize = bluetooth_settings_widget_finalize;
Packit 8fb625
Packit 8fb625
	/**
Packit 8fb625
	 * BluetoothSettingsWidget::panel-changed:
Packit 8fb625
	 * @chooser: a #BluetoothSettingsWidget widget which received the signal
Packit 8fb625
	 * @panel: the new panel that the Settings application should now open
Packit 8fb625
	 *
Packit 8fb625
	 * The #BluetoothChooser::panel-changed signal is launched when a
Packit 8fb625
	 * link to another settings panel is clicked.
Packit 8fb625
	 **/
Packit 8fb625
	signals[PANEL_CHANGED] =
Packit 8fb625
		g_signal_new ("panel-changed",
Packit 8fb625
			      G_TYPE_FROM_CLASS (klass),
Packit 8fb625
			      G_SIGNAL_RUN_LAST,
Packit 8fb625
			      0,
Packit 8fb625
			      NULL, NULL,
Packit 8fb625
			      g_cclosure_marshal_VOID__STRING,
Packit 8fb625
			      G_TYPE_NONE, 1, G_TYPE_STRING);
Packit 8fb625
Packit 8fb625
	/**
Packit 8fb625
	 * BluetoothSettingsWidget::adapter-status-changed:
Packit 8fb625
	 * @chooser: a #BluetoothSettingsWidget widget which received the signal
Packit 8fb625
	 *
Packit 8fb625
	 * The #BluetoothChooser::adapter-status-changed signal is launched when the status
Packit 8fb625
	 * of the adapter changes (powered, available, etc.).
Packit 8fb625
	 **/
Packit 8fb625
	signals[ADAPTER_STATUS_CHANGED] =
Packit 8fb625
		g_signal_new ("adapter-status-changed",
Packit 8fb625
			      G_TYPE_FROM_CLASS (klass),
Packit 8fb625
			      G_SIGNAL_RUN_LAST,
Packit 8fb625
			      0,
Packit 8fb625
			      NULL, NULL,
Packit 8fb625
			      g_cclosure_marshal_VOID__VOID,
Packit 8fb625
			      G_TYPE_NONE, 0, G_TYPE_NONE);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
/**
Packit 8fb625
 * bluetooth_settings_widget_new:
Packit 8fb625
 *
Packit 8fb625
 * Returns a new #BluetoothSettingsWidget widget.
Packit 8fb625
 *
Packit 8fb625
 * Return value: A #BluetoothSettingsWidget widget
Packit 8fb625
 **/
Packit 8fb625
GtkWidget *
Packit 8fb625
bluetooth_settings_widget_new (void)
Packit 8fb625
{
Packit 8fb625
	return g_object_new (BLUETOOTH_TYPE_SETTINGS_WIDGET, NULL);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
/**
Packit 8fb625
 * bluetooth_settings_widget_get_default_adapter_powered:
Packit 8fb625
 * @widget: a #BluetoothSettingsWidget widget.
Packit 8fb625
 *
Packit 8fb625
 * Return value: Whether the default Bluetooth adapter is powered.
Packit 8fb625
 **/
Packit 8fb625
gboolean
Packit 8fb625
bluetooth_settings_widget_get_default_adapter_powered (BluetoothSettingsWidget *widget)
Packit 8fb625
{
Packit 8fb625
	BluetoothSettingsWidgetPrivate *priv;
Packit 8fb625
	gboolean ret;
Packit 8fb625
Packit 8fb625
	g_return_val_if_fail (BLUETOOTH_IS_SETTINGS_WIDGET (widget), FALSE);
Packit 8fb625
Packit 8fb625
	priv = BLUETOOTH_SETTINGS_WIDGET_GET_PRIVATE (widget);
Packit 8fb625
	g_object_get (G_OBJECT (priv->client),
Packit 8fb625
		      "default-adapter-powered", &ret,
Packit 8fb625
		      NULL);
Packit 8fb625
Packit 8fb625
	return ret;
Packit 8fb625
}