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, see <http://www.gnu.org/licenses/>.
20
* SECTION:bluetooth-chooser-button
21
* @short_description: a Bluetooth chooser button
23
* @include: bluetooth-chooser-button.h
25
* A button used to select Bluetooth devices which will pop-up a
26
* #BluetoothChooser widget inside a dialogue when clicked.
33
#include <glib/gi18n.h>
36
#include "bluetooth-chooser-button.h"
37
#include "bluetooth-client.h"
38
#include "bluetooth-chooser.h"
39
#include "bluetooth-utils.h"
41
struct _BluetoothChooserButton {
44
BluetoothClient *client;
49
guint is_available : 1;
50
guint has_selection : 1;
64
static int signals[LAST_SIGNAL] = { 0 };
66
static void bluetooth_chooser_button_class_init (BluetoothChooserButtonClass * klass);
67
static void bluetooth_chooser_button_init (BluetoothChooserButton * button);
69
G_DEFINE_TYPE(BluetoothChooserButton, bluetooth_chooser_button, GTK_TYPE_BUTTON);
71
#define DEFAULT_STR N_("Click to select device…")
74
set_btdevname (BluetoothChooserButton *button, const char *bdaddr, const char *name, const char *icon)
76
char *found_name, *found_icon;
81
if (bdaddr != NULL && (name == NULL || icon == NULL)) {
84
gboolean cont = FALSE;
86
model = bluetooth_client_get_device_model (button->client);
88
cont = gtk_tree_model_iter_children (GTK_TREE_MODEL(model),
92
while (cont == TRUE) {
95
gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
96
BLUETOOTH_COLUMN_ADDRESS, &value, -1);
97
if (g_ascii_strcasecmp(bdaddr, value) == 0) {
98
gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
99
BLUETOOTH_COLUMN_ALIAS, &found_name,
100
BLUETOOTH_COLUMN_ICON, &found_icon,
106
cont = gtk_tree_model_iter_next (GTK_TREE_MODEL(model), &iter);
110
g_object_unref (model);
112
if (found_name == NULL) {
113
found_name = g_strdup (bdaddr);
114
g_strdelimit (found_name, ":", '-');
116
if (found_icon == NULL)
117
found_icon = g_strdup ("bluetooth");
120
if (bdaddr != NULL) {
121
/* Update the name */
123
gtk_button_set_label (GTK_BUTTON (button), found_name);
125
gtk_button_set_label (GTK_BUTTON (button), name);
128
gtk_image_set_from_icon_name (GTK_IMAGE (button->image), found_icon, GTK_ICON_SIZE_MENU);
130
gtk_image_set_from_icon_name (GTK_IMAGE (button->image), icon, GTK_ICON_SIZE_MENU);
132
/* And our copy of the address, and notify if it's actually changed */
133
if (button->bdaddr == NULL || strcmp (bdaddr, button->bdaddr) != 0) {
134
g_free (button->bdaddr);
135
button->bdaddr = g_strdup (bdaddr);
136
g_object_notify (G_OBJECT (button), "device");
139
gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR));
140
if (button->bdaddr != NULL) {
141
g_free (button->bdaddr);
142
button->bdaddr = NULL;
143
gtk_image_clear (GTK_IMAGE (button->image));
144
g_object_notify (G_OBJECT (button), "device");
152
static void select_device_changed(BluetoothChooser *self, gchar *address, gpointer data)
154
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
156
button->has_selection = (address != NULL);
157
gtk_dialog_set_response_sensitive(GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT,
158
button->has_selection && button->is_available);
162
dialog_response_cb (GtkDialog *dialog, int response_id, gpointer data)
164
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
165
char *bdaddr, *icon, *name;
167
if (response_id == GTK_RESPONSE_ACCEPT) {
168
BluetoothChooser *chooser = BLUETOOTH_CHOOSER (button->chooser);
169
bdaddr = bluetooth_chooser_get_selected_device (chooser);
170
name = bluetooth_chooser_get_selected_device_name (chooser);
171
icon = bluetooth_chooser_get_selected_device_icon (chooser);
174
gtk_widget_destroy (GTK_WIDGET (dialog));
175
button->dialog = NULL;
177
if (response_id != GTK_RESPONSE_ACCEPT)
180
set_btdevname (button, bdaddr, name, icon);
187
bluetooth_chooser_button_clicked (GtkButton *widget)
189
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (widget);
192
if (button->dialog != NULL) {
193
gtk_window_present (GTK_WINDOW (button->dialog));
197
parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
199
button->dialog = gtk_dialog_new_with_buttons("", GTK_WINDOW (parent),
201
_("_Cancel"), GTK_RESPONSE_REJECT,
202
_("_OK"), GTK_RESPONSE_ACCEPT, NULL);
203
g_signal_connect (button->dialog, "response",
204
G_CALLBACK (dialog_response_cb), button);
205
gtk_dialog_set_response_sensitive (GTK_DIALOG(button->dialog),
206
GTK_RESPONSE_ACCEPT, FALSE);
207
gtk_window_set_default_size (GTK_WINDOW(button->dialog), 480, 400);
209
gtk_container_set_border_width (GTK_CONTAINER (button->dialog), 5);
210
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (button->dialog))), 2);
212
/* Create the button->chooser */
213
button->chooser = bluetooth_chooser_new ();
214
g_signal_connect(button->chooser, "selected-device-changed",
215
G_CALLBACK(select_device_changed), button);
216
g_signal_emit (G_OBJECT (button),
217
signals[CHOOSER_CREATED],
219
g_object_set (G_OBJECT (button->chooser), "device-selected", button->bdaddr, NULL);
220
gtk_container_set_border_width (GTK_CONTAINER(button->chooser), 5);
221
gtk_widget_show (button->chooser);
222
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (button->dialog))), button->chooser,
225
gtk_widget_show (button->dialog);
229
default_adapter_changed (GObject *object, GParamSpec *pspec, gpointer data)
231
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (data);
235
g_object_get (G_OBJECT (button->client),
236
"default-adapter", &adapter,
237
"default-adapter-powered", &powered,
240
button->is_available = powered;
242
button->is_available = FALSE;
244
if (adapter != NULL && button->bdaddr != NULL)
245
set_btdevname (button, button->bdaddr, NULL, NULL);
248
if (button->dialog != NULL)
249
gtk_dialog_set_response_sensitive (GTK_DIALOG (button->dialog), GTK_RESPONSE_ACCEPT,
250
button->has_selection && button->is_available);
252
g_object_notify (G_OBJECT (button), "is-available");
256
bluetooth_chooser_button_finalize (GObject *object)
258
BluetoothChooserButton *button = BLUETOOTH_CHOOSER_BUTTON (object);
260
g_clear_object (&button->client);
262
if (button->dialog != NULL) {
263
gtk_widget_destroy (button->dialog);
264
button->dialog = NULL;
265
button->chooser = NULL;
268
G_OBJECT_CLASS (bluetooth_chooser_button_parent_class)->finalize (object);
272
bluetooth_chooser_button_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
274
BluetoothChooserButton *button;
276
g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object));
277
button = BLUETOOTH_CHOOSER_BUTTON (object);
279
switch (property_id) {
281
const char *str = g_value_get_string (value);
282
g_return_if_fail (str == NULL || bluetooth_verify_address (str));
283
set_btdevname (button, str, NULL, NULL);
287
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
292
bluetooth_chooser_button_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
294
BluetoothChooserButton *button;
296
g_return_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (object));
297
button = BLUETOOTH_CHOOSER_BUTTON (object);
299
switch (property_id) {
301
g_value_set_string (value, button->bdaddr);
303
case PROP_IS_AVAILABLE:
304
g_value_set_boolean (value, button->is_available);
307
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
312
bluetooth_chooser_button_class_init (BluetoothChooserButtonClass *klass)
314
GObjectClass *object_class = G_OBJECT_CLASS (klass);
315
GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
317
object_class->finalize = bluetooth_chooser_button_finalize;
318
object_class->set_property = bluetooth_chooser_button_set_property;
319
object_class->get_property = bluetooth_chooser_button_get_property;
321
button_class->clicked = bluetooth_chooser_button_clicked;
324
* BluetoothChooserButton::chooser-created:
325
* @self: a #BluetoothChooserButton widget
326
* @chooser: a #BluetoothChooser widget
328
* The signal is sent when a popup dialogue is created for the user to select
329
* a device. This signal allows you to change the configuration and filtering
330
* of the tree from its defaults.
332
signals[CHOOSER_CREATED] =
333
g_signal_new ("chooser-created",
334
G_TYPE_FROM_CLASS (klass),
336
G_STRUCT_OFFSET (BluetoothChooserButtonClass, chooser_created),
338
g_cclosure_marshal_VOID__OBJECT,
339
G_TYPE_NONE, 1, G_TYPE_OBJECT);
342
* BluetoothChooserButton:device:
344
* The Bluetooth address of the selected device or %NULL.
346
g_object_class_install_property (object_class, PROP_DEVICE,
347
g_param_spec_string ("device", "Device", "The Bluetooth address of the selected device.",
348
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
350
* BluetoothChooserButton:is-available:
352
* %TRUE if there is a powered Bluetooth adapter available.
354
* See also: bluetooth_chooser_button_available()
356
g_object_class_install_property (object_class, PROP_IS_AVAILABLE,
357
g_param_spec_boolean ("is-available", "Bluetooth is available", "Whether Bluetooth is available.",
358
TRUE, G_PARAM_READABLE));
362
bluetooth_chooser_button_init (BluetoothChooserButton *button)
364
gtk_button_set_label (GTK_BUTTON (button), _(DEFAULT_STR));
366
button->image = gtk_image_new ();
367
gtk_button_set_image (GTK_BUTTON (button), button->image);
369
button->bdaddr = NULL;
370
button->dialog = NULL;
372
button->client = bluetooth_client_new ();
373
g_signal_connect (G_OBJECT (button->client), "notify::default-adapter",
374
G_CALLBACK (default_adapter_changed), button);
375
g_signal_connect (G_OBJECT (button->client), "notify::default-adapter-powered",
376
G_CALLBACK (default_adapter_changed), button);
378
/* And set the default value already */
379
default_adapter_changed (NULL, NULL, button);
383
* bluetooth_chooser_button_new:
385
* Returns a new #BluetoothChooserButton widget.
387
* Return value: a #BluetoothChooserButton widget.
390
bluetooth_chooser_button_new (void)
392
return g_object_new (BLUETOOTH_TYPE_CHOOSER_BUTTON,
397
* bluetooth_chooser_button_available:
398
* @button: a #BluetoothChooserButton
400
* Returns whether there is a powered Bluetooth adapter.
402
* Return value: %TRUE if there is a powered Bluetooth adapter available, and the button should be sensitive.
405
bluetooth_chooser_button_available (BluetoothChooserButton *button)
407
g_return_val_if_fail (BLUETOOTH_IS_CHOOSER_BUTTON (button), FALSE);
409
return button->is_available;