Blob Blame History Raw
/*
 *
 *  BlueZ - Bluetooth protocol stack for Linux
 *
 *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
 *  Copyright (C) 2006-2007  Bastien Nocera <hadess@hadess.net>
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <gtk/gtk.h>
#include <stdlib.h>

#include "bluetooth-chooser.h"
#include "bluetooth-chooser-button.h"
#include "bluetooth-chooser-combo.h"
#include "bluetooth-chooser-private.h"
#include "bluetooth-client.h"
#include "bluetooth-client-private.h"
#include "bluetooth-utils.h"
#include "bluetooth-filter-widget.h"

static void select_device_changed(BluetoothChooser *sel,
				  gchar *address, gpointer user_data)
{
	GtkDialog *dialog = user_data;
	char *name;

	name = bluetooth_chooser_get_selected_device_name (sel);
	gtk_dialog_set_response_sensitive(dialog,
				GTK_RESPONSE_ACCEPT, (address != NULL && name != NULL));
	g_free (name);
}

static void selected_device_activated(BluetoothChooser *sel,
				      gchar *address, gpointer user_data)
{
	GtkDialog *dialog = user_data;

	gtk_dialog_response(dialog, GTK_RESPONSE_ACCEPT);
}

static void device_selected_cb(GObject *object,
			       GParamSpec *spec, gpointer user_data)
{
	g_message ("Property \"device-selected\" changed");
	if (bluetooth_chooser_get_selected_device (BLUETOOTH_CHOOSER (object)))
		bluetooth_chooser_dump_selected_device (BLUETOOTH_CHOOSER (object));
}

static void device_type_filter_selected_cb(GObject *object,
					   GParamSpec *spec, gpointer user_data)
{
	g_message ("Property \"device-type-filter\" changed");
}

static void device_category_filter_selected_cb(GObject *object,
				GParamSpec *spec, gpointer user_data)
{
	g_message ("Property \"device-category-filter\" changed");
}

/* Phone chooser */

static void
chooser_created (BluetoothChooserButton *button, BluetoothChooser *chooser, gpointer data)
{
	g_object_set(chooser,
		     "show-searching", FALSE,
		     "show-pairing", FALSE,
		     "show-device-type", FALSE,
		     "device-type-filter", BLUETOOTH_TYPE_PHONE,
		     "show-device-category", FALSE,
		     "device-category-filter", BLUETOOTH_CATEGORY_PAIRED,
		     NULL);
}

static void
is_available_changed (GObject    *gobject,
		      GParamSpec *pspec,
		      gpointer    user_data)
{
	gboolean is_available;

	g_object_get (gobject, "is-available", &is_available, NULL);
	g_message ("button is available: %d", is_available);
	gtk_widget_set_sensitive (GTK_WIDGET (gobject), is_available);
}

static void
device_changed (GObject    *gobject,
		GParamSpec *pspec,
		gpointer    user_data)
{
	char *device;

	g_object_get (gobject, "device", &device, NULL);
	g_message ("Property \"device\" changed to '%s'", device);

	g_free (device);
}

static GtkWidget *
create_phone_dialogue (const char *bdaddr)
{
	GtkWidget *dialog, *button;

	dialog = g_object_new(GTK_TYPE_DIALOG,
			      "use-header-bar", 1,
			      "title", "My test prefs",
			      NULL);
	button = bluetooth_chooser_button_new ();
	if (bdaddr != NULL)
		g_object_set (G_OBJECT (button), "device", bdaddr, NULL);
	g_signal_connect (G_OBJECT (button), "chooser-created",
			  G_CALLBACK (chooser_created), NULL);
	g_signal_connect (G_OBJECT (button), "notify::is-available",
			  G_CALLBACK (is_available_changed), NULL);
	g_signal_connect (G_OBJECT (button), "notify::device",
			  G_CALLBACK (device_changed), NULL);
	is_available_changed (G_OBJECT (button), NULL, NULL);
	gtk_widget_show (button);
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
			    button, TRUE, TRUE, 0);

	g_signal_connect (G_OBJECT (dialog), "response",
			  G_CALLBACK (gtk_main_quit), NULL);

	g_object_add_weak_pointer (G_OBJECT(dialog), (gpointer *) (&dialog));

	return dialog;
}

/* Wizard and co. */
static GtkWidget *
create_dialogue (const char *title)
{
	GtkWidget *dialog, *button;
	GtkStyleContext *context;

	dialog = g_object_new (GTK_TYPE_DIALOG,
			       "use-header-bar", 1,
			       "title", title,
			       NULL);
	gtk_dialog_add_buttons(GTK_DIALOG (dialog),
			       "_Cancel", GTK_RESPONSE_CANCEL,
			       "Connect", GTK_RESPONSE_ACCEPT, NULL);
	gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog),
					GTK_RESPONSE_ACCEPT, FALSE);
	gtk_window_set_default_size(GTK_WINDOW(dialog), 480, 400);

	gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);

	button = gtk_dialog_get_widget_for_response(GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
	context = gtk_widget_get_style_context(button);
	gtk_style_context_add_class (context, "suggested-action");

	return dialog;
}

static void
response_cb (GtkDialog *dialog, gint response_id, BluetoothChooser *selector)
{
	if (response_id == GTK_RESPONSE_ACCEPT) {
		char *address, *name, *icon;
		guint type;

		address = bluetooth_chooser_get_selected_device (selector);
		name = bluetooth_chooser_get_selected_device_name (selector);
		icon = bluetooth_chooser_get_selected_device_icon (selector);
		type = bluetooth_chooser_get_selected_device_type (selector);
		g_message("Selected device is: %s (address: %s, icon: %s, type: %s)",
			  name, address, icon, bluetooth_type_to_string (type));
		g_free(address);
		g_free (name);
		g_free (icon);
	} else {
		g_message ("No selected device");
	}

	if (response_id == GTK_RESPONSE_DELETE_EVENT)
		exit (0);

	gtk_main_quit ();
}

static GtkWidget *
create_wizard_dialogue (void)
{
	GtkWidget *dialog, *selector;

	dialog = create_dialogue ("Add a Device");

	selector = bluetooth_chooser_new();
	gtk_container_set_border_width(GTK_CONTAINER(selector), 5);
	gtk_widget_show(selector);
	g_object_set(selector,
		     "show-searching", TRUE,
		     "show-device-type", TRUE,
		     "show-device-category", FALSE,
		     "device-category-filter", BLUETOOTH_CATEGORY_NOT_PAIRED_OR_TRUSTED,
		     NULL);

	g_signal_connect(selector, "selected-device-changed",
			 G_CALLBACK(select_device_changed), dialog);
	g_signal_connect(selector, "notify::device-selected",
			 G_CALLBACK(device_selected_cb), dialog);
	g_signal_connect(selector, "notify::device-type-filter",
			 G_CALLBACK(device_type_filter_selected_cb), dialog);
	g_signal_connect(selector, "notify::device-category-filter",
			 G_CALLBACK(device_category_filter_selected_cb), dialog);
	g_signal_connect(selector, "selected-device-activated",
			 G_CALLBACK(selected_device_activated), dialog);
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG(dialog))), selector,
			    TRUE, TRUE, 0);
	bluetooth_chooser_start_discovery (BLUETOOTH_CHOOSER (selector));

	g_signal_connect (G_OBJECT (dialog), "response",
			  G_CALLBACK (response_cb), selector);

	return dialog;
}

static GtkWidget *
create_props_dialogue (void)
{
	GtkWidget *dialog, *selector;

	dialog = create_dialogue ("Add a Device");

	selector = bluetooth_chooser_new();
	gtk_container_set_border_width(GTK_CONTAINER(selector), 5);
	gtk_widget_show(selector);
	g_object_set(selector,
		     "show-searching", FALSE,
		     "show-device-type", FALSE,
		     "show-device-category", FALSE,
		     "show-pairing", TRUE,
		     "show-connected", TRUE,
		     "device-category-filter", BLUETOOTH_CATEGORY_PAIRED_OR_TRUSTED,
		     NULL);

	g_signal_connect(selector, "selected-device-changed",
			 G_CALLBACK(select_device_changed), dialog);
	g_signal_connect(selector, "notify::device-selected",
			 G_CALLBACK(device_selected_cb), dialog);
	g_signal_connect(selector, "notify::device-type-filter",
			 G_CALLBACK(device_type_filter_selected_cb), dialog);
	g_signal_connect(selector, "notify::device-category-filter",
			 G_CALLBACK(device_category_filter_selected_cb), dialog);
	g_signal_connect(selector, "selected-device-activated",
			 G_CALLBACK(selected_device_activated), dialog);
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG(dialog))), selector,
			    TRUE, TRUE, 0);

	g_signal_connect (G_OBJECT (dialog), "response",
			  G_CALLBACK (response_cb), selector);

	return dialog;
}

static void device_changed_cb (GObject *object,
			       GParamSpec *spec,
			       GtkDialog *dialog)
{
	char *device;
	BluetoothChooser *chooser;
	GtkWidget *tree;
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter iter;

	g_object_get (object, "device", &device, NULL);
	g_message ("Property \"device\" changed to '%s'", device);

	gtk_dialog_set_response_sensitive (dialog,
					  GTK_RESPONSE_ACCEPT,
					  device != NULL);

	g_object_get (object, "chooser", &chooser, NULL);
	tree = bluetooth_chooser_get_treeview (BLUETOOTH_CHOOSER (chooser));
	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
	gtk_tree_selection_get_selected (selection, &model, &iter);
	if (model != NULL)
		bluetooth_client_dump_device (model, &iter);

	g_object_unref (chooser);
	g_free (device);
}

static GtkWidget *
create_combo_dialogue (const char *bdaddr)
{
	GtkWidget *dialog, *selector, *chooser;
	const char *filter = "OBEXObjectPush";
//	const char *filter[] = { "OBEXObjectPush", "OBEXFileTransfer", NULL };

	dialog = create_dialogue ("Add a Device");

	selector = bluetooth_chooser_combo_new ();
	g_signal_connect (G_OBJECT (selector), "notify::device",
			  G_CALLBACK (device_changed_cb), dialog);
	g_object_get (G_OBJECT (selector), "chooser", &chooser, NULL);
	g_object_set(chooser,
		     "show-searching", TRUE,
		     "show-device-type", TRUE,
		     "show-device-category", TRUE,
		     "show-pairing", TRUE,
		     "show-connected", FALSE,
		     "device-service-filter", filter,
		     NULL);
	g_object_set (G_OBJECT (selector), "device", bdaddr, NULL);
	bluetooth_chooser_start_discovery (BLUETOOTH_CHOOSER (chooser));
	gtk_container_set_border_width(GTK_CONTAINER(selector), 5);
	gtk_widget_show(selector);
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
			    selector, TRUE, FALSE, 6);

	g_signal_connect (G_OBJECT (dialog), "response",
			  G_CALLBACK (response_cb), chooser);

	return dialog;
}

static GtkWidget *
create_filter_dialogue (void)
{
	GtkWidget *dialog, *selector, *filter, *vbox, *hbox;

	dialog = create_dialogue ("Add a Device");

	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
	gtk_widget_show (hbox);

	selector = bluetooth_chooser_new();
	gtk_container_set_border_width(GTK_CONTAINER(selector), 5);
	gtk_widget_show(selector);
	g_object_set(selector,
		     "show-searching", TRUE,
		     "device-category-filter", BLUETOOTH_CATEGORY_NOT_PAIRED_OR_TRUSTED,
		     NULL);
	gtk_box_pack_start (GTK_BOX (hbox), selector, TRUE, TRUE, 6);

	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
	gtk_widget_show (vbox);
	gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
	filter = bluetooth_filter_widget_new ();
	g_object_set (filter,
		      "show-device-type", TRUE,
		      "show-device-category", FALSE,
		      NULL);
	gtk_widget_show (filter);
	bluetooth_filter_widget_bind_filter (BLUETOOTH_FILTER_WIDGET (filter), BLUETOOTH_CHOOSER (selector));
	gtk_box_pack_start (GTK_BOX (vbox), filter, FALSE, FALSE, 6);

	g_signal_connect(selector, "selected-device-changed",
			 G_CALLBACK(select_device_changed), dialog);
	g_signal_connect(selector, "notify::device-selected",
			 G_CALLBACK(device_selected_cb), dialog);
	g_signal_connect(selector, "notify::device-type-filter",
			 G_CALLBACK(device_type_filter_selected_cb), dialog);
	g_signal_connect(selector, "notify::device-category-filter",
			 G_CALLBACK(device_category_filter_selected_cb), dialog);
	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
			    hbox, TRUE, TRUE, 0);
	bluetooth_chooser_start_discovery (BLUETOOTH_CHOOSER (selector));

	g_signal_connect (G_OBJECT (dialog), "response",
			  G_CALLBACK (response_cb), selector);

	return dialog;
}

int main(int argc, char **argv)
{
	GtkWidget *dialog;
	const char *selection;

	gtk_init(&argc, &argv);
	if (argc < 2)
		selection = "wizard";
	else
		selection = argv[1];

	if (g_str_equal (selection, "phone")) {
		if (argc == 3)
			dialog = create_phone_dialogue (argv[2]);
		else
			dialog = create_phone_dialogue (NULL);
	} else if (g_str_equal (selection, "wizard")) {
		dialog = create_wizard_dialogue ();
	} else if (g_str_equal (selection, "props")) {
		dialog = create_props_dialogue ();
	} else if (g_str_equal (selection, "combo")) {
		if (argc == 3)
			dialog = create_combo_dialogue (argv[2]);
		else
			dialog = create_combo_dialogue (BLUETOOTH_CHOOSER_COMBO_FIRST_DEVICE);
	} else if (g_str_equal (selection, "filter")) {
		dialog = create_filter_dialogue ();
	} else {
		g_warning ("Unknown dialogue type, try either \"phone\", \"props\", \"combo\", \"filter\"  or \"wizard\"");
		return 1;
	}

	gtk_widget_show(dialog);

	gtk_main ();

	if (dialog)
		gtk_widget_destroy(dialog);

	return 0;
}