Blame lib/bluetooth-chooser-button.c

Packit 8fb625
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
Packit 8fb625
/*
Packit 8fb625
 * (C) Copyright 2007-2009 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 Library General Public
Packit 8fb625
 * License as published by the Free Software Foundation; either
Packit 8fb625
 * version 2 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
 * Library General Public License for more details.
Packit 8fb625
 *
Packit 8fb625
 * You should have received a copy of the GNU Library General Public
Packit 8fb625
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit 8fb625
 */
Packit 8fb625
Packit 8fb625
/**
Packit 8fb625
 * SECTION:bluetooth-chooser-button
Packit 8fb625
 * @short_description: a Bluetooth chooser button
Packit 8fb625
 * @stability: Stable
Packit 8fb625
 * @include: bluetooth-chooser-button.h
Packit 8fb625
 *
Packit 8fb625
 * A button used to select Bluetooth devices which will pop-up a
Packit 8fb625
 * #BluetoothChooser widget inside a dialogue when clicked.
Packit 8fb625
 **/
Packit 8fb625
Packit 8fb625
#ifdef HAVE_CONFIG_H
Packit 8fb625
#include "config.h"
Packit 8fb625
#endif
Packit 8fb625
Packit 8fb625
#include <glib/gi18n.h>
Packit 8fb625
#include <gtk/gtk.h>
Packit 8fb625
Packit 8fb625
#include "bluetooth-chooser-button.h"
Packit 8fb625
#include "bluetooth-client.h"
Packit 8fb625
#include "bluetooth-chooser.h"
Packit 8fb625
#include "bluetooth-utils.h"
Packit 8fb625
Packit 8fb625
struct _BluetoothChooserButton {
Packit 8fb625
	GtkButton          parent;
Packit 8fb625
Packit 8fb625
	BluetoothClient   *client;
Packit 8fb625
	GtkWidget         *image;
Packit 8fb625
	GtkWidget         *dialog;
Packit 8fb625
	GtkWidget         *chooser;
Packit 8fb625
	char              *bdaddr;
Packit 8fb625
	guint              is_available : 1;
Packit 8fb625
	guint              has_selection : 1;
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
enum {
Packit 8fb625
	PROP_0,
Packit 8fb625
	PROP_DEVICE,
Packit 8fb625
	PROP_IS_AVAILABLE,
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
enum {
Packit 8fb625
	CHOOSER_CREATED,
Packit 8fb625
	LAST_SIGNAL
Packit 8fb625
};
Packit 8fb625
Packit 8fb625
static int signals[LAST_SIGNAL] = { 0 };
Packit 8fb625
Packit 8fb625
static void	bluetooth_chooser_button_class_init	(BluetoothChooserButtonClass * klass);
Packit 8fb625
static void	bluetooth_chooser_button_init		(BluetoothChooserButton      * button);
Packit 8fb625
Packit 8fb625
G_DEFINE_TYPE(BluetoothChooserButton, bluetooth_chooser_button, GTK_TYPE_BUTTON);
Packit 8fb625
Packit 8fb625
#define DEFAULT_STR N_("Click to select deviceā€¦")
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
set_btdevname (BluetoothChooserButton *button, const char *bdaddr, const char *name, const char *icon)
Packit 8fb625
{
Packit 8fb625
	char *found_name, *found_icon;
Packit 8fb625
Packit 8fb625
	found_name = NULL;
Packit 8fb625
	found_icon = NULL;
Packit 8fb625
Packit 8fb625
	if (bdaddr != NULL && (name == NULL || icon == NULL)) {
Packit 8fb625
		GtkTreeModel *model;
Packit 8fb625
		GtkTreeIter iter;
Packit 8fb625
		gboolean cont = FALSE;
Packit 8fb625
Packit 8fb625
		model = bluetooth_client_get_device_model (button->client);
Packit 8fb625
		if (model != NULL) {
Packit 8fb625
			cont = gtk_tree_model_iter_children (GTK_TREE_MODEL(model),
Packit 8fb625
							     &iter, NULL);
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		while (cont == TRUE) {
Packit 8fb625
			char *value;
Packit 8fb625
Packit 8fb625
			gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
Packit 8fb625
					   BLUETOOTH_COLUMN_ADDRESS, &value, -1);
Packit 8fb625
			if (g_ascii_strcasecmp(bdaddr, value) == 0) {
Packit 8fb625
				gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
Packit 8fb625
						   BLUETOOTH_COLUMN_ALIAS, &found_name,
Packit 8fb625
						   BLUETOOTH_COLUMN_ICON, &found_icon,
Packit 8fb625
						   -1);
Packit 8fb625
				g_free (value);
Packit 8fb625
				break;
Packit 8fb625
			}
Packit 8fb625
			g_free (value);
Packit 8fb625
			cont = gtk_tree_model_iter_next (GTK_TREE_MODEL(model), &iter);
Packit 8fb625
		}
Packit 8fb625
Packit 8fb625
		if (model != NULL)
Packit 8fb625
			g_object_unref (model);
Packit 8fb625
Packit 8fb625
		if (found_name == NULL) {
Packit 8fb625
			found_name = g_strdup (bdaddr);
Packit 8fb625
			g_strdelimit (found_name, ":", '-');
Packit 8fb625
		}
Packit 8fb625
		if (found_icon == NULL)
Packit 8fb625
			found_icon = g_strdup ("bluetooth");
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	if (bdaddr != NULL) {
Packit 8fb625
		/* Update the name */
Packit 8fb625
		if (name == NULL)
Packit 8fb625
			gtk_button_set_label (GTK_BUTTON (button), found_name);
Packit 8fb625
		else
Packit 8fb625
			gtk_button_set_label (GTK_BUTTON (button), name);
Packit 8fb625
		/* And the icon */
Packit 8fb625
		if (icon == NULL)
Packit 8fb625
			gtk_image_set_from_icon_name (GTK_IMAGE (button->image), found_icon, GTK_ICON_SIZE_MENU);
Packit 8fb625
		else
Packit 8fb625
			gtk_image_set_from_icon_name (GTK_IMAGE (button->image), icon, GTK_ICON_SIZE_MENU);
Packit 8fb625
Packit 8fb625
		/* And our copy of the address, and notify if it's actually changed */
Packit 8fb625
		if (button->bdaddr == NULL || strcmp (bdaddr, button->bdaddr) != 0) {
Packit 8fb625
			g_free (button->bdaddr);
Packit 8fb625
			button->bdaddr = g_strdup (bdaddr);
Packit 8fb625
			g_object_notify (G_OBJECT (button), "device");
Packit 8fb625
		}
Packit 8fb625
	} else {
Packit 8fb625
		gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR));
Packit 8fb625
		if (button->bdaddr != NULL) {
Packit 8fb625
			g_free (button->bdaddr);
Packit 8fb625
			button->bdaddr = NULL;
Packit 8fb625
			gtk_image_clear (GTK_IMAGE (button->image));
Packit 8fb625
			g_object_notify (G_OBJECT (button), "device");
Packit 8fb625
		}
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	g_free (found_name);
Packit 8fb625
	g_free (found_icon);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void select_device_changed(BluetoothChooser *self, gchar *address, gpointer data)
Packit 8fb625
{
Packit 8fb625
	BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
Packit 8fb625
Packit 8fb625
	button->has_selection = (address != NULL);
Packit 8fb625
	gtk_dialog_set_response_sensitive(GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT,
Packit 8fb625
					  button->has_selection && button->is_available);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
dialog_response_cb (GtkDialog *dialog, int response_id, gpointer data)
Packit 8fb625
{
Packit 8fb625
	BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
Packit 8fb625
	char *bdaddr, *icon, *name;
Packit 8fb625
Packit 8fb625
	if (response_id == GTK_RESPONSE_ACCEPT) {
Packit 8fb625
		BluetoothChooser *chooser = BLUETOOTH_CHOOSER (button->chooser);
Packit 8fb625
		bdaddr = bluetooth_chooser_get_selected_device (chooser);
Packit 8fb625
		name = bluetooth_chooser_get_selected_device_name (chooser);
Packit 8fb625
		icon = bluetooth_chooser_get_selected_device_icon (chooser);
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	gtk_widget_destroy (GTK_WIDGET (dialog));
Packit 8fb625
	button->dialog = NULL;
Packit 8fb625
Packit 8fb625
	if (response_id != GTK_RESPONSE_ACCEPT)
Packit 8fb625
		return;
Packit 8fb625
Packit 8fb625
	set_btdevname (button, bdaddr, name, icon);
Packit 8fb625
	g_free (bdaddr);
Packit 8fb625
	g_free (name);
Packit 8fb625
	g_free (icon);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_chooser_button_clicked (GtkButton *widget)
Packit 8fb625
{
Packit 8fb625
	BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (widget);
Packit 8fb625
	GtkWidget *parent;
Packit 8fb625
Packit 8fb625
	if (button->dialog != NULL) {
Packit 8fb625
		gtk_window_present (GTK_WINDOW (button->dialog));
Packit 8fb625
		return;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
Packit 8fb625
	//FIXME title
Packit 8fb625
	button->dialog = gtk_dialog_new_with_buttons("", GTK_WINDOW (parent),
Packit 8fb625
						     GTK_DIALOG_MODAL,
Packit 8fb625
						     _("_Cancel"), GTK_RESPONSE_REJECT,
Packit 8fb625
						     _("_OK"), GTK_RESPONSE_ACCEPT, NULL);
Packit 8fb625
	g_signal_connect (button->dialog, "response",
Packit 8fb625
			  G_CALLBACK (dialog_response_cb), button);
Packit 8fb625
	gtk_dialog_set_response_sensitive (GTK_DIALOG(button->dialog),
Packit 8fb625
					   GTK_RESPONSE_ACCEPT, FALSE);
Packit 8fb625
	gtk_window_set_default_size (GTK_WINDOW(button->dialog), 480, 400);
Packit 8fb625
Packit 8fb625
	gtk_container_set_border_width (GTK_CONTAINER (button->dialog), 5);
Packit 8fb625
	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (button->dialog))), 2);
Packit 8fb625
Packit 8fb625
	/* Create the button->chooser */
Packit 8fb625
	button->chooser = bluetooth_chooser_new ();
Packit 8fb625
	g_signal_connect(button->chooser, "selected-device-changed",
Packit 8fb625
			 G_CALLBACK(select_device_changed), button);
Packit 8fb625
	g_signal_emit (G_OBJECT (button),
Packit 8fb625
		       signals[CHOOSER_CREATED],
Packit 8fb625
		       0, button->chooser);
Packit 8fb625
	g_object_set (G_OBJECT (button->chooser), "device-selected", button->bdaddr, NULL);
Packit 8fb625
	gtk_container_set_border_width (GTK_CONTAINER(button->chooser), 5);
Packit 8fb625
	gtk_widget_show (button->chooser);
Packit 8fb625
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (button->dialog))), button->chooser,
Packit 8fb625
			    TRUE, TRUE, 0);
Packit 8fb625
Packit 8fb625
	gtk_widget_show (button->dialog);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
default_adapter_changed (GObject *object, GParamSpec *pspec, gpointer data)
Packit 8fb625
{
Packit 8fb625
	BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
Packit 8fb625
	char *adapter;
Packit 8fb625
	gboolean powered;
Packit 8fb625
Packit 8fb625
	g_object_get (G_OBJECT (button->client),
Packit 8fb625
		      "default-adapter", &adapter,
Packit 8fb625
		      "default-adapter-powered", &powered,
Packit 8fb625
		      NULL);
Packit 8fb625
	if (adapter != NULL)
Packit 8fb625
		button->is_available = powered;
Packit 8fb625
	else
Packit 8fb625
		button->is_available = FALSE;
Packit 8fb625
Packit 8fb625
	if (adapter != NULL && button->bdaddr != NULL)
Packit 8fb625
		set_btdevname (button, button->bdaddr, NULL, NULL);
Packit 8fb625
	g_free (adapter);
Packit 8fb625
Packit 8fb625
	if (button->dialog != NULL)
Packit 8fb625
		gtk_dialog_set_response_sensitive (GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT,
Packit 8fb625
						   button->has_selection && button->is_available);
Packit 8fb625
Packit 8fb625
	g_object_notify (G_OBJECT (button), "is-available");
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_chooser_button_finalize (GObject *object)
Packit 8fb625
{
Packit 8fb625
	BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (object);
Packit 8fb625
Packit 8fb625
	g_clear_object (&button->client);
Packit 8fb625
Packit 8fb625
	if (button->dialog != NULL) {
Packit 8fb625
		gtk_widget_destroy (button->dialog);
Packit 8fb625
		button->dialog = NULL;
Packit 8fb625
		button->chooser = NULL;
Packit 8fb625
	}
Packit 8fb625
Packit 8fb625
	G_OBJECT_CLASS (bluetooth_chooser_button_parent_class)->finalize (object);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_chooser_button_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
Packit 8fb625
{
Packit 8fb625
	BluetoothChooserButton *button;
Packit 8fb625
Packit 8fb625
	g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object));
Packit 8fb625
	button = BLUETOOTH_CHOOSER_BUTTON (object);
Packit 8fb625
Packit 8fb625
	switch (property_id) {
Packit 8fb625
	case PROP_DEVICE: {
Packit 8fb625
		const char *str = g_value_get_string (value);
Packit 8fb625
		g_return_if_fail (str == NULL || bluetooth_verify_address (str));
Packit 8fb625
		set_btdevname (button, str, NULL, NULL);
Packit 8fb625
		break;
Packit 8fb625
		}
Packit 8fb625
	default:
Packit 8fb625
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_chooser_button_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
Packit 8fb625
{
Packit 8fb625
	BluetoothChooserButton *button;
Packit 8fb625
Packit 8fb625
	g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object));
Packit 8fb625
	button = BLUETOOTH_CHOOSER_BUTTON (object);
Packit 8fb625
Packit 8fb625
	switch (property_id) {
Packit 8fb625
	case PROP_DEVICE:
Packit 8fb625
		g_value_set_string (value, button->bdaddr);
Packit 8fb625
		break;
Packit 8fb625
	case PROP_IS_AVAILABLE:
Packit 8fb625
		g_value_set_boolean (value, button->is_available);
Packit 8fb625
		break;
Packit 8fb625
	default:
Packit 8fb625
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
Packit 8fb625
	}
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_chooser_button_class_init (BluetoothChooserButtonClass *klass)
Packit 8fb625
{
Packit 8fb625
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 8fb625
	GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
Packit 8fb625
Packit 8fb625
	object_class->finalize = bluetooth_chooser_button_finalize;
Packit 8fb625
	object_class->set_property = bluetooth_chooser_button_set_property;
Packit 8fb625
	object_class->get_property = bluetooth_chooser_button_get_property;
Packit 8fb625
Packit 8fb625
	button_class->clicked = bluetooth_chooser_button_clicked;
Packit 8fb625
Packit 8fb625
	/**
Packit 8fb625
	 * BluetoothChooserButton::chooser-created:
Packit 8fb625
	 * @self: a #BluetoothChooserButton widget
Packit 8fb625
	 * @chooser: a #BluetoothChooser widget
Packit 8fb625
	 *
Packit 8fb625
	 * The signal is sent when a popup dialogue is created for the user to select
Packit 8fb625
	 * a device. This signal allows you to change the configuration and filtering
Packit 8fb625
	 * of the tree from its defaults.
Packit 8fb625
	 **/
Packit 8fb625
	signals[CHOOSER_CREATED] =
Packit 8fb625
		g_signal_new ("chooser-created",
Packit 8fb625
			      G_TYPE_FROM_CLASS (klass),
Packit 8fb625
			      G_SIGNAL_RUN_LAST,
Packit 8fb625
			      G_STRUCT_OFFSET (BluetoothChooserButtonClass, chooser_created),
Packit 8fb625
			      NULL, NULL,
Packit 8fb625
			      g_cclosure_marshal_VOID__OBJECT,
Packit 8fb625
			      G_TYPE_NONE, 1, G_TYPE_OBJECT);
Packit 8fb625
Packit 8fb625
	/**
Packit 8fb625
	 * BluetoothChooserButton:device:
Packit 8fb625
	 *
Packit 8fb625
	 * The Bluetooth address of the selected device or %NULL.
Packit 8fb625
	 **/
Packit 8fb625
	g_object_class_install_property (object_class, PROP_DEVICE,
Packit 8fb625
					 g_param_spec_string ("device", "Device", "The Bluetooth address of the selected device.",
Packit 8fb625
							      NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
Packit 8fb625
	/**
Packit 8fb625
	 * BluetoothChooserButton:is-available:
Packit 8fb625
	 *
Packit 8fb625
	 * %TRUE if there is a powered Bluetooth adapter available.
Packit 8fb625
	 *
Packit 8fb625
	 * See also: bluetooth_chooser_button_available()
Packit 8fb625
	 **/
Packit 8fb625
	g_object_class_install_property (object_class, PROP_IS_AVAILABLE,
Packit 8fb625
					 g_param_spec_boolean ("is-available", "Bluetooth is available", "Whether Bluetooth is available.",
Packit 8fb625
							       TRUE, G_PARAM_READABLE));
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
static void
Packit 8fb625
bluetooth_chooser_button_init (BluetoothChooserButton *button)
Packit 8fb625
{
Packit 8fb625
	gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR));
Packit 8fb625
Packit 8fb625
	button->image = gtk_image_new ();
Packit 8fb625
	gtk_button_set_image (GTK_BUTTON (button), button->image);
Packit 8fb625
Packit 8fb625
	button->bdaddr = NULL;
Packit 8fb625
	button->dialog = NULL;
Packit 8fb625
Packit 8fb625
	button->client = bluetooth_client_new ();
Packit 8fb625
	g_signal_connect (G_OBJECT (button->client), "notify::default-adapter",
Packit 8fb625
			  G_CALLBACK (default_adapter_changed), button);
Packit 8fb625
	g_signal_connect (G_OBJECT (button->client), "notify::default-adapter-powered",
Packit 8fb625
			  G_CALLBACK (default_adapter_changed), button);
Packit 8fb625
Packit 8fb625
	/* And set the default value already */
Packit 8fb625
	default_adapter_changed (NULL, NULL, button);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
/**
Packit 8fb625
 * bluetooth_chooser_button_new:
Packit 8fb625
 *
Packit 8fb625
 * Returns a new #BluetoothChooserButton widget.
Packit 8fb625
 *
Packit 8fb625
 * Return value: a #BluetoothChooserButton widget.
Packit 8fb625
 **/
Packit 8fb625
GtkWidget *
Packit 8fb625
bluetooth_chooser_button_new (void)
Packit 8fb625
{
Packit 8fb625
	return g_object_new (BLUETOOTH_TYPE_CHOOSER_BUTTON,
Packit 8fb625
			     NULL);
Packit 8fb625
}
Packit 8fb625
Packit 8fb625
/**
Packit 8fb625
 * bluetooth_chooser_button_available:
Packit 8fb625
 * @button: a #BluetoothChooserButton
Packit 8fb625
 *
Packit 8fb625
 * Returns whether there is a powered Bluetooth adapter.
Packit 8fb625
 *
Packit 8fb625
 * Return value: %TRUE if there is a powered Bluetooth adapter available, and the button should be sensitive.
Packit 8fb625
 **/
Packit 8fb625
gboolean
Packit 8fb625
bluetooth_chooser_button_available (BluetoothChooserButton *button)
Packit 8fb625
{
Packit 8fb625
	g_return_val_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (button), FALSE);
Packit 8fb625
Packit 8fb625
	return button->is_available;
Packit 8fb625
}
Packit 8fb625