1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* (C) Copyright 2007-2009 Bastien Nocera <hadess@hadess.net>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Library General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Library General Public License for more details.
15
* You should have received a copy of the GNU Library General Public
16
* License along with this library; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
25
#include <glib/gi18n.h>
28
#include "bluetooth-chooser-button.h"
29
#include "bluetooth-client.h"
30
#include "bluetooth-chooser.h"
33
struct _BluetoothChooserButton {
36
BluetoothClient *client;
41
guint is_available : 1;
42
guint has_selection : 1;
56
static int signals[LAST_SIGNAL] = { 0 };
58
static void bluetooth_chooser_button_class_init (BluetoothChooserButtonClass * klass);
59
static void bluetooth_chooser_button_init (BluetoothChooserButton * button);
61
static GtkButtonClass *parent_class;
63
G_DEFINE_TYPE(BluetoothChooserButton, bluetooth_chooser_button, GTK_TYPE_BUTTON);
65
#define DEFAULT_STR N_("Click to select device...")
68
set_btdevname (BluetoothChooserButton *button, const char *bdaddr, const char *name, const char *icon)
70
char *found_name, *found_icon;
75
if (bdaddr != NULL && (name == NULL || icon == NULL)) {
78
gboolean cont = FALSE;
80
model = bluetooth_client_get_device_model (button->client, NULL);
82
cont = gtk_tree_model_iter_children (GTK_TREE_MODEL(model),
86
while (cont == TRUE) {
89
gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
90
BLUETOOTH_COLUMN_ADDRESS, &value, -1);
91
if (g_ascii_strcasecmp(bdaddr, value) == 0) {
92
gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
93
BLUETOOTH_COLUMN_ALIAS, &found_name,
94
BLUETOOTH_COLUMN_ICON, &found_icon,
100
cont = gtk_tree_model_iter_next (GTK_TREE_MODEL(model), &iter);
104
g_object_unref (model);
106
if (found_name == NULL) {
107
found_name = g_strdup (bdaddr);
108
g_strdelimit (found_name, ":", '-');
110
if (found_icon == NULL)
111
found_icon = g_strdup ("bluetooth");
114
if (bdaddr != NULL) {
115
/* Update the name */
117
gtk_button_set_label (GTK_BUTTON (button), found_name);
119
gtk_button_set_label (GTK_BUTTON (button), name);
122
gtk_image_set_from_icon_name (GTK_IMAGE (button->image), found_icon, GTK_ICON_SIZE_MENU);
124
gtk_image_set_from_icon_name (GTK_IMAGE (button->image), icon, GTK_ICON_SIZE_MENU);
126
/* And our copy of the address, and notify if it's actually changed */
127
if (button->bdaddr == NULL || strcmp (bdaddr, button->bdaddr) != 0) {
128
g_free (button->bdaddr);
129
button->bdaddr = g_strdup (bdaddr);
130
g_object_notify (G_OBJECT (button), "device");
133
gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR));
134
if (button->bdaddr != NULL) {
135
g_free (button->bdaddr);
136
button->bdaddr = NULL;
137
gtk_image_clear (GTK_IMAGE (button->image));
138
g_object_notify (G_OBJECT (button), "device");
146
static void select_device_changed(BluetoothChooser *self, gchar *address, gpointer data)
148
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
150
button->has_selection = (address != NULL);
151
gtk_dialog_set_response_sensitive(GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT,
152
button->has_selection && button->is_available);
156
dialog_response_cb (GtkDialog *dialog, int response_id, gpointer data)
158
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
159
char *bdaddr, *icon, *name;
161
if (response_id == GTK_RESPONSE_ACCEPT) {
162
g_object_get(button->chooser,
163
"device-selected", &bdaddr,
164
"device-selected-name", &name,
165
"device-selected-icon", &icon,
169
gtk_widget_destroy (GTK_WIDGET (dialog));
170
button->dialog = NULL;
172
if (response_id != GTK_RESPONSE_ACCEPT)
175
set_btdevname (button, bdaddr, name, icon);
182
bluetooth_chooser_button_clicked (GtkButton *widget)
184
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (widget);
187
if (button->dialog != NULL) {
188
gtk_window_present (GTK_WINDOW (button->dialog));
192
parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
194
button->dialog = gtk_dialog_new_with_buttons("", GTK_WINDOW (parent),
195
GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR,
196
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
197
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
198
g_signal_connect (button->dialog, "response",
199
G_CALLBACK (dialog_response_cb), button);
200
gtk_dialog_set_response_sensitive (GTK_DIALOG(button->dialog),
201
GTK_RESPONSE_ACCEPT, FALSE);
202
gtk_window_set_default_size (GTK_WINDOW(button->dialog), 480, 400);
204
gtk_container_set_border_width (GTK_CONTAINER (button->dialog), 5);
205
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (button->dialog)->vbox), 2);
207
/* Create the button->chooser */
208
button->chooser = bluetooth_chooser_new (NULL);
209
g_signal_connect(button->chooser, "selected-device-changed",
210
G_CALLBACK(select_device_changed), button);
211
g_signal_emit (G_OBJECT (button),
212
signals[CHOOSER_CREATED],
214
gtk_container_set_border_width (GTK_CONTAINER(button->chooser), 5);
215
gtk_widget_show (button->chooser);
216
gtk_container_add (GTK_CONTAINER(GTK_DIALOG(button->dialog)->vbox), button->chooser);
218
gtk_widget_show (button->dialog);
222
default_adapter_changed (GObject *object, GParamSpec *pspec, gpointer data)
224
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
228
g_object_get (G_OBJECT (button->client),
229
"default-adapter", &adapter,
230
"default-adapter-powered", &powered,
233
button->is_available = powered;
235
button->is_available = FALSE;
238
set_btdevname (button, button->bdaddr, NULL, NULL);
241
if (button->dialog != NULL)
242
gtk_dialog_set_response_sensitive (GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT,
243
button->has_selection && button->is_available);
245
g_object_notify (G_OBJECT (button), "is-available");
249
bluetooth_chooser_button_finalize (GObject *object)
251
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (object);
253
if (button->client != NULL) {
254
g_object_unref (button->client);
255
button->client = NULL;
257
if (button->dialog != NULL) {
258
gtk_widget_destroy (button->dialog);
259
button->dialog = NULL;
260
button->chooser = NULL;
263
G_OBJECT_CLASS (parent_class)->finalize (object);
267
bluetooth_chooser_button_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
269
BluetoothChooserButton *button;
271
g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object));
272
button = BLUETOOTH_CHOOSER_BUTTON (object);
276
g_return_if_fail (bluetooth_verify_address (g_value_get_string (value)) || g_value_get_string (value) == NULL);
277
set_btdevname (button, g_value_get_string (value), NULL, NULL);
280
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
285
bluetooth_chooser_button_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
287
BluetoothChooserButton *button;
289
g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object));
290
button = BLUETOOTH_CHOOSER_BUTTON (object);
292
switch (property_id) {
294
g_value_set_string (value, button->bdaddr);
296
case PROP_IS_AVAILABLE:
297
g_value_set_boolean (value, button->is_available);
300
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
305
bluetooth_chooser_button_class_init (BluetoothChooserButtonClass *klass)
307
GObjectClass *object_class = G_OBJECT_CLASS (klass);
308
GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
310
parent_class = g_type_class_peek_parent (klass);
312
object_class->finalize = bluetooth_chooser_button_finalize;
313
object_class->set_property = bluetooth_chooser_button_set_property;
314
object_class->get_property = bluetooth_chooser_button_get_property;
316
button_class->clicked = bluetooth_chooser_button_clicked;
319
* BluetoothChooserButton:chooser-created:
321
* @bluetoothchooserbutton: a #BluetoothChooserButton widget
322
* @arg1: a #BluetoothChooser widget
324
* The signal is sent when a popup dialogue is created for the user to select
325
* a device. This signal allows you to change the configuration and filtering
326
* of the tree from its defaults.
329
signals[CHOOSER_CREATED] =
330
g_signal_new ("chooser-created",
331
G_TYPE_FROM_CLASS (klass),
333
G_STRUCT_OFFSET (BluetoothChooserButtonClass, chooser_created),
335
g_cclosure_marshal_VOID__OBJECT,
336
G_TYPE_NONE, 1, G_TYPE_OBJECT);
339
* BluetoothChooserButton:device:
341
* The Bluetooth address of the selected device or %NULL
343
g_object_class_install_property (object_class, PROP_DEVICE,
344
g_param_spec_string ("device", "Device", "The Bluetooth address of the selected device.",
345
NULL, G_PARAM_READWRITE));
347
* BluetoothChooserButton:is-available:
349
* %TRUE if there is a powered Bluetooth adapter available.
351
* See also: bluetooth_chooser_button_available()
353
g_object_class_install_property (object_class, PROP_IS_AVAILABLE,
354
g_param_spec_boolean ("is-available", "Bluetooth is available", "Whether Bluetooth is available.",
355
TRUE, G_PARAM_READABLE));
359
bluetooth_chooser_button_init (BluetoothChooserButton *button)
361
gtk_button_set_label (GTK_BUTTON (button), _("Click to select device..."));
363
button->image = gtk_image_new ();
364
gtk_button_set_image (GTK_BUTTON (button), button->image);
366
button->bdaddr = NULL;
367
button->dialog = NULL;
369
button->client = bluetooth_client_new ();
370
g_signal_connect (G_OBJECT (button->client), "notify::default-adapter",
371
G_CALLBACK (default_adapter_changed), button);
372
g_signal_connect (G_OBJECT (button->client), "notify::default-adapter-powered",
373
G_CALLBACK (default_adapter_changed), button);
375
/* And set the default value already */
376
default_adapter_changed (NULL, NULL, button);
378
set_btdevname (button, NULL, NULL, NULL);
382
* bluetooth_chooser_button_new:
384
* Return value: a #BluetoothChooserButton
387
bluetooth_chooser_button_new (void)
389
return g_object_new (BLUETOOTH_TYPE_CHOOSER_BUTTON,
390
"label", _(DEFAULT_STR),
395
* bluetooth_chooser_button_available:
396
* @button: a #BluetoothChooserButton
398
* Return value: %TRUE if there is a powered Bluetooth adapter available, and the button should be sensitive.
401
bluetooth_chooser_button_available (BluetoothChooserButton *button)
403
g_return_val_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (button), FALSE);
405
return button->is_available;