Blame lib/bluetooth-pairing-dialog.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
Packit 8fb625
#include "bluetooth-pairing-dialog.h"
Packit 8fb625
#include "bluetooth-enums.h"
Packit 8fb625
#include "gnome-bluetooth-enum-types.h"
Packit 8fb625
#include "bluetooth-settings-resources.h"
Packit 8fb625
Packit 8fb625
#define BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE(obj) \
Packit 8fb625
	(bluetooth_pairing_dialog_get_instance_private (obj))
Packit 8fb625
Packit 8fb625
typedef struct _BluetoothPairingDialogPrivate BluetoothPairingDialogPrivate;
Packit 8fb625
Packit 8fb625
struct _BluetoothPairingDialogPrivate {
Packit 8fb625
	GtkWidget            *title;
Packit 8fb625
	GtkWidget            *help_label;
Packit 8fb625
	GtkWidget            *label_pin;
Packit 8fb625
	GtkWidget            *entry_pin;
Packit 8fb625
	GtkWidget            *pin_notebook;
Packit 8fb625
	GtkWidget            *done;
Packit 8fb625
	GtkWidget            *spinner;
Packit 8fb625
	GtkWidget            *cancel;
Packit 8fb625
Packit 8fb625
	BluetoothPairingMode  mode;
Packit 8fb625
	char                 *pin;
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
G_DEFINE_TYPE_WITH_PRIVATE(BluetoothPairingDialog, bluetooth_pairing_dialog, GTK_TYPE_DIALOG)
Packit 8fb625
Packit 8fb625
enum {
Packit 8fb625
	CONFIRMATION_PAGE,
Packit 8fb625
	DISPLAY_PAGE,
Packit 8fb625
	MESSAGE_PAGE
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
void
Packit 8fb625
bluetooth_pairing_dialog_set_mode (BluetoothPairingDialog *self,
Packit 8fb625
				   BluetoothPairingMode    mode,
Packit 8fb625
				   const char             *pin,
Packit 8fb625
				   const char             *device_name)
Packit 8fb625
{
Packit 8fb625
	BluetoothPairingDialogPrivate *priv = BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE (self);
Packit 8fb625
	char *title;
Packit 8fb625
	char *help;
Packit 8fb625
	GtkStyleContext *context;
Packit 8fb625
Packit 8fb625
	priv->mode = mode;
Packit 8fb625
Packit 8fb625
	g_clear_pointer (&priv->pin, g_free);
Packit 8fb625
	priv->pin = g_strdup (pin);
Packit 8fb625
	gtk_entry_set_text (GTK_ENTRY (priv->entry_pin), pin ? pin : "");
Packit 8fb625
	gtk_label_set_text (GTK_LABEL (priv->label_pin), pin);
Packit 8fb625
Packit 8fb625
	switch (mode) {
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_QUERY:
Packit 8fb625
		gtk_widget_show (priv->done);
Packit 8fb625
		gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->pin_notebook), CONFIRMATION_PAGE);
Packit 8fb625
		title = g_strdup(_("Confirm Bluetooth PIN"));
Packit 8fb625
		help = g_strdup_printf (_("Please confirm the PIN that was entered on “%s”."), device_name);
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_CONFIRMATION:
Packit 8fb625
		gtk_widget_show (priv->done);
Packit 8fb625
		gtk_button_set_label (GTK_BUTTON (priv->done), _("Confirm"));
Packit 8fb625
		gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->pin_notebook), CONFIRMATION_PAGE);
Packit 8fb625
		title = g_strdup(_("Confirm Bluetooth PIN"));
Packit 8fb625
		help = g_strdup_printf (_("Confirm the Bluetooth PIN for “%s”. This can usually be found in the device’s manual."), device_name);
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_NORMAL:
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_KEYBOARD:
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_ICADE:
Packit 8fb625
		gtk_widget_hide (priv->done);
Packit 8fb625
		title = g_strdup_printf (_("Pairing “%s”"), device_name);
Packit 8fb625
		gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->pin_notebook), DISPLAY_PAGE);
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_MATCH:
Packit 8fb625
		gtk_button_set_label (GTK_BUTTON (priv->done), _("Confirm"));
Packit 8fb625
		gtk_widget_show (priv->done);
Packit 8fb625
		gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->pin_notebook), DISPLAY_PAGE);
Packit 8fb625
		title = g_strdup(_("Confirm Bluetooth PIN"));
Packit 8fb625
		help = g_strdup_printf (_("Please confirm that the following PIN matches the one displayed on “%s”."), device_name);
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_YES_NO:
Packit 8fb625
		gtk_widget_show (priv->done);
Packit 8fb625
		gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->pin_notebook), MESSAGE_PAGE);
Packit 8fb625
		title = g_strdup (_("Bluetooth Pairing Request"));
Packit 8fb625
		help = g_strdup_printf (_("“%s” wants to pair with this device. Do you want to allow pairing?"), device_name);
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_CONFIRM_AUTH:
Packit 8fb625
		gtk_widget_show (priv->done);
Packit 8fb625
		gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->pin_notebook), MESSAGE_PAGE);
Packit 8fb625
		title = g_strdup (_("Confirm Bluetooth Connection"));
Packit 8fb625
		help = g_strdup_printf (_("“%s” wants to connect with this device. Do you want to allow it?"), device_name);
Packit 8fb625
		break;
Packit 8fb625
	default:
Packit 8fb625
		g_assert_not_reached ();
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	switch (mode) {
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_NORMAL:
Packit 8fb625
		help = g_strdup_printf (_("Please enter the following PIN on “%s”."), device_name);
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_KEYBOARD:
Packit 8fb625
		help = g_strdup_printf (_("Please enter the following PIN on “%s”. Then press “Return” on the keyboard."), device_name);
Packit 8fb625
		break;
Packit 8fb625
	case BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_ICADE:
Packit 8fb625
		help = g_strdup (_("Please move the joystick of your iCade in the following directions. Then press any of the white buttons."));
Packit 8fb625
		break;
Packit 8fb625
	default:
Packit 8fb625
		g_assert (help);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	if (mode == BLUETOOTH_PAIRING_MODE_YES_NO ||
Packit 8fb625
	    mode == BLUETOOTH_PAIRING_MODE_CONFIRM_AUTH) {
Packit 8fb625
		gtk_button_set_label (GTK_BUTTON (priv->done), _("Allow"));
Packit 8fb625
		context = gtk_widget_get_style_context (priv->done);
Packit 8fb625
		gtk_style_context_remove_class (context, "suggested-action");
Packit 8fb625
Packit 8fb625
		gtk_button_set_label (GTK_BUTTON (priv->cancel), _("Dismiss"));
Packit 8fb625
		context = gtk_widget_get_style_context (priv->cancel);
Packit 8fb625
		gtk_style_context_add_class (context, "destructive-action");
Packit 8fb625
Packit 8fb625
		gtk_widget_hide (priv->pin_notebook);
Packit 8fb625
	} else {
Packit 8fb625
		gtk_button_set_label (GTK_BUTTON (priv->done), _("Confirm"));
Packit 8fb625
		context = gtk_widget_get_style_context (priv->done);
Packit 8fb625
		gtk_style_context_add_class (context, "suggested-action");
Packit 8fb625
Packit 8fb625
		gtk_button_set_label (GTK_BUTTON (priv->cancel), _("Cancel"));
Packit 8fb625
		context = gtk_widget_get_style_context (priv->cancel);
Packit 8fb625
		gtk_style_context_remove_class (context, "destructive-action");
Packit 8fb625
Packit 8fb625
		gtk_widget_show (priv->pin_notebook);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_label_set_text (GTK_LABEL (priv->title), title);
Packit 8fb625
	gtk_label_set_text (GTK_LABEL (priv->help_label), help);
Packit 8fb625
	g_free (title);
Packit 8fb625
	g_free (help);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
BluetoothPairingMode
Packit 8fb625
bluetooth_pairing_dialog_get_mode (BluetoothPairingDialog *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothPairingDialogPrivate *priv = BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE (self);
Packit 8fb625
Packit 8fb625
	return priv->mode;
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
char *
Packit 8fb625
bluetooth_pairing_dialog_get_pin (BluetoothPairingDialog *self)
Packit 8fb625
{
Packit 8fb625
	BluetoothPairingDialogPrivate *priv = BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE (self);
Packit 8fb625
Packit 8fb625
	g_assert (priv->mode == BLUETOOTH_PAIRING_MODE_PIN_CONFIRMATION ||
Packit 8fb625
		  priv->mode == BLUETOOTH_PAIRING_MODE_PIN_QUERY);
Packit 8fb625
	g_assert (gtk_widget_is_sensitive (GTK_WIDGET (priv->done)));
Packit 8fb625
Packit 8fb625
	return g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->entry_pin)));
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
void
Packit 8fb625
bluetooth_pairing_dialog_set_pin_entered (BluetoothPairingDialog *self,
Packit 8fb625
					  guint                   entered)
Packit 8fb625
{
Packit 8fb625
	BluetoothPairingDialogPrivate *priv = BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE (self);
Packit 8fb625
	char *done;
Packit 8fb625
Packit 8fb625
	g_assert (priv->mode == BLUETOOTH_PAIRING_MODE_PIN_DISPLAY_KEYBOARD);
Packit 8fb625
	g_assert (priv->pin);
Packit 8fb625
Packit 8fb625
	if (entered > 0) {
Packit 8fb625
		gunichar invisible;
Packit 8fb625
		GString *str;
Packit 8fb625
		guint i;
Packit 8fb625
Packit 8fb625
		invisible = gtk_entry_get_invisible_char (GTK_ENTRY (priv->entry_pin));
Packit 8fb625
Packit 8fb625
		str = g_string_new (NULL);
Packit 8fb625
		for (i = 0; i < entered; i++)
Packit 8fb625
			g_string_append_unichar (str, invisible);
Packit 8fb625
		if (entered < strlen (priv->pin))
Packit 8fb625
			g_string_append (str, priv->pin + entered);
Packit 8fb625
Packit 8fb625
		done = g_string_free (str, FALSE);
Packit 8fb625
	} else {
Packit 8fb625
		done = g_strdup (priv->pin);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_label_set_text (GTK_LABEL (priv->label_pin), done);
Packit 8fb625
	g_free (done);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
response_cb (GtkWidget *button,
Packit 8fb625
	     gpointer   user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothPairingDialogPrivate *priv = BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE (user_data);
Packit 8fb625
	int response;
Packit 8fb625
Packit 8fb625
	if (button == priv->done)
Packit 8fb625
		response = GTK_RESPONSE_ACCEPT;
Packit 8fb625
	else if (button == priv->cancel)
Packit 8fb625
		response = GTK_RESPONSE_CANCEL;
Packit 8fb625
	else
Packit 8fb625
		g_assert_not_reached ();
Packit 8fb625
Packit 8fb625
	gtk_dialog_response (GTK_DIALOG (user_data), response);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
text_changed_cb (GObject    *gobject,
Packit 8fb625
		 GParamSpec *pspec,
Packit 8fb625
		 gpointer    user_data)
Packit 8fb625
{
Packit 8fb625
	BluetoothPairingDialogPrivate *priv = BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE (user_data);
Packit 8fb625
	const char *text;
Packit 8fb625
Packit 8fb625
	if (priv->mode != BLUETOOTH_PAIRING_MODE_PIN_CONFIRMATION &&
Packit 8fb625
	    priv->mode != BLUETOOTH_PAIRING_MODE_PIN_QUERY)
Packit 8fb625
		return;
Packit 8fb625
Packit 8fb625
	text = gtk_entry_get_text (GTK_ENTRY (priv->entry_pin));
Packit 8fb625
	if (!text || strlen (text) < 4)
Packit 8fb625
		gtk_widget_set_sensitive (GTK_WIDGET (priv->done), FALSE);
Packit 8fb625
	else
Packit 8fb625
		gtk_widget_set_sensitive (GTK_WIDGET (priv->done), TRUE);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_pairing_dialog_init (BluetoothPairingDialog *self)
Packit 8fb625
{
Packit 8fb625
	GtkCssProvider *provider;
Packit 8fb625
Packit 8fb625
	gtk_widget_init_template (GTK_WIDGET (self));
Packit 8fb625
Packit 8fb625
	gtk_widget_set_size_request (GTK_WIDGET (self), 380, -1);
Packit 8fb625
	gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
Packit 8fb625
Packit 8fb625
	provider = gtk_css_provider_new ();
Packit 8fb625
	gtk_css_provider_load_from_resource (provider, "/org/gnome/bluetooth/bluetooth-settings.css");
Packit 8fb625
	gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
Packit 8fb625
						   GTK_STYLE_PROVIDER (provider),
Packit 8fb625
						   GTK_STYLE_PROVIDER_PRIORITY_USER);
Packit 8fb625
	g_object_unref (provider);
Packit 8fb625
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_pairing_dialog_constructed (GObject *object)
Packit 8fb625
{
Packit 8fb625
	BluetoothPairingDialog *self = BLUETOOTH_PAIRING_DIALOG (object);
Packit 8fb625
	BluetoothPairingDialogPrivate *priv = BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE (self);
Packit 8fb625
	GtkWidget *header;
Packit 8fb625
	GtkStyleContext *context;
Packit 8fb625
Packit 8fb625
	/* Header */
Packit 8fb625
	header = gtk_dialog_get_header_bar (GTK_DIALOG (self));
Packit 8fb625
	priv->title = gtk_label_new ("");
Packit 8fb625
	gtk_header_bar_set_custom_title (GTK_HEADER_BAR (header), priv->title);
Packit 8fb625
	gtk_widget_show (priv->title);
Packit 8fb625
	gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (header), FALSE);
Packit 8fb625
Packit 8fb625
	/* OK button */
Packit 8fb625
	priv->done = gtk_button_new_with_label (_("Accept"));
Packit 8fb625
	gtk_widget_set_no_show_all (priv->done, TRUE);
Packit 8fb625
	gtk_widget_set_can_default (GTK_WIDGET (priv->done), TRUE);
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->done), "clicked",
Packit 8fb625
			  G_CALLBACK (response_cb), self);
Packit 8fb625
	gtk_header_bar_pack_end (GTK_HEADER_BAR (header), priv->done);
Packit 8fb625
Packit 8fb625
	/* Spinner */
Packit 8fb625
	priv->spinner = gtk_spinner_new ();
Packit 8fb625
	gtk_widget_set_margin_end (priv->spinner, 12);
Packit 8fb625
	gtk_widget_set_no_show_all (priv->spinner, TRUE);
Packit 8fb625
	gtk_header_bar_pack_end (GTK_HEADER_BAR (header), priv->spinner);
Packit 8fb625
	g_object_bind_property (priv->spinner, "visible",
Packit 8fb625
				priv->spinner, "active", 0);
Packit 8fb625
	g_object_bind_property (priv->spinner, "visible",
Packit 8fb625
				priv->done, "visible",
Packit 8fb625
				G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN | G_BINDING_BIDIRECTIONAL);
Packit 8fb625
Packit 8fb625
	/* Cancel button */
Packit 8fb625
	priv->cancel = gtk_button_new_with_label (_("Cancel"));
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->cancel), "clicked",
Packit 8fb625
			  G_CALLBACK (response_cb), self);
Packit 8fb625
	gtk_header_bar_pack_start (GTK_HEADER_BAR (header), priv->cancel);
Packit 8fb625
	gtk_widget_show (priv->cancel);
Packit 8fb625
	gtk_widget_grab_default (GTK_WIDGET (priv->done));
Packit 8fb625
Packit 8fb625
	g_signal_connect (G_OBJECT (priv->entry_pin), "notify::text",
Packit 8fb625
			  G_CALLBACK (text_changed_cb), self);
Packit 8fb625
Packit 8fb625
	context = gtk_widget_get_style_context (priv->done);
Packit 8fb625
	gtk_style_context_add_class (context, "suggested-action");
Packit 8fb625
	context = gtk_widget_get_style_context (priv->title);
Packit 8fb625
	gtk_style_context_add_class (context, "title");
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_pairing_dialog_finalize (GObject *object)
Packit 8fb625
{
Packit 8fb625
	BluetoothPairingDialogPrivate *priv = BLUETOOTH_PAIRING_DIALOG_GET_PRIVATE (BLUETOOTH_PAIRING_DIALOG (object));
Packit 8fb625
Packit 8fb625
	g_free (priv->pin);
Packit 8fb625
Packit 8fb625
	G_OBJECT_CLASS(bluetooth_pairing_dialog_parent_class)->finalize(object);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_pairing_dialog_class_init (BluetoothPairingDialogClass *klass)
Packit 8fb625
{
Packit 8fb625
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 8fb625
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
Packit 8fb625
Packit 8fb625
	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Packit 8fb625
Packit 8fb625
	object_class->constructed = bluetooth_pairing_dialog_constructed;
Packit 8fb625
	object_class->finalize = bluetooth_pairing_dialog_finalize;
Packit 8fb625
Packit 8fb625
	/* Bind class to template */
Packit 8fb625
	gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/bluetooth/bluetooth-pairing-dialog.ui");
Packit 8fb625
	gtk_widget_class_bind_template_child_private (widget_class, BluetoothPairingDialog, help_label);
Packit 8fb625
	gtk_widget_class_bind_template_child_private (widget_class, BluetoothPairingDialog, pin_notebook);
Packit 8fb625
	gtk_widget_class_bind_template_child_private (widget_class, BluetoothPairingDialog, entry_pin);
Packit 8fb625
	gtk_widget_class_bind_template_child_private (widget_class, BluetoothPairingDialog, label_pin);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
/**
Packit 8fb625
 * bluetooth_pairing_dialog_new:
Packit 8fb625
 *
Packit 8fb625
 * Returns a new #BluetoothPairingDialog widget.
Packit 8fb625
 *
Packit 8fb625
 * Return value: A #BluetoothPairingDialog widget
Packit 8fb625
 **/
Packit 8fb625
GtkWidget *
Packit 8fb625
bluetooth_pairing_dialog_new (void)
Packit 8fb625
{
Packit 8fb625
	return g_object_new (BLUETOOTH_TYPE_PAIRING_DIALOG,
Packit 8fb625
	                     "use-header-bar", 1,
Packit 8fb625
	                     NULL);
Packit 8fb625
}