29
29
#include <glib/gi18n.h>
30
30
#include <gtk/gtk.h>
32
#include <gconf/gconf-client.h>
33
#include <unique/uniqueapp.h>
32
#include <bluetooth-chooser.h>
35
33
#include <bluetooth-client.h>
36
#include <bluetooth-client-private.h>
37
#include <bluetooth-chooser.h>
38
#include <bluetooth-killswitch.h>
35
#include "bluetooth-applet.h"
40
36
#include "notify.h"
43
39
static gboolean option_debug = FALSE;
44
static BluetoothClient *client;
45
static GtkTreeModel *devices_model;
46
static guint num_adapters_present = 0;
47
static guint num_adapters_powered = 0;
40
static BluetoothApplet *applet = NULL;
41
static GSettings *settings = NULL;
48
42
static gboolean show_icon_pref = TRUE;
50
#define PREF_DIR "/apps/bluetooth-manager"
51
#define PREF_SHOW_ICON PREF_DIR "/show_icon"
53
#define KEYBOARD_PREFS "gnome-keyboard-properties"
54
#define MOUSE_PREFS "gnome-mouse-properties"
43
static gboolean discover_lock = FALSE;
45
#define SCHEMA_NAME "org.gnome.Bluetooth"
46
#define PREF_SHOW_ICON "show-icon"
48
#define GNOMECC "gnome-control-center"
49
#define KEYBOARD_PREFS GNOMECC " keyboard"
50
#define MOUSE_PREFS GNOMECC " mouse"
51
#define SOUND_PREFS GNOMECC " sound"
101
96
GTK_RESPONSE_ACCEPT, address != NULL);
100
mount_finish_cb (GObject *source_object,
104
GError *error = NULL;
107
if (bluetooth_applet_browse_address_finish (applet, res, &error) == FALSE) {
108
g_printerr ("Failed to mount OBEX volume: %s", error->message);
109
g_error_free (error);
113
uri = g_file_get_uri (G_FILE (source_object));
114
if (gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, &error) == FALSE) {
115
g_printerr ("Failed to open %s: %s", uri, error->message);
116
g_error_free (error);
104
121
void browse_callback(GObject *widget, gpointer user_data)
108
125
address = g_strdup (g_object_get_data (widget, "address"));
109
126
if (address == NULL) {
110
GtkWidget *dialog, *selector;
127
GtkWidget *dialog, *selector, *content_area;
113
130
dialog = gtk_dialog_new_with_buttons(_("Select Device to Browse"), NULL,
114
GTK_DIALOG_NO_SEPARATOR,
115
132
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
117
134
gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Browse"), GTK_RESPONSE_ACCEPT);
150
cmd = g_strdup_printf("%s --no-default-window \"obex://[%s]\"",
151
"nautilus", address);
154
if (!g_spawn_command_line_async(cmd, NULL))
155
g_printerr("Couldn't execute command: %s\n", cmd);
168
bluetooth_applet_browse_address (applet, address,
169
GDK_CURRENT_TIME, mount_finish_cb, NULL);
160
173
void sendto_callback(GObject *widget, gpointer user_data)
165
175
const char *address, *alias;
167
177
address = g_object_get_data (widget, "address");
168
178
alias = g_object_get_data (widget, "alias");
170
a = g_ptr_array_new ();
171
g_ptr_array_add (a, "bluetooth-sendto");
172
if (address != NULL) {
175
s = g_strdup_printf ("--device=\"%s\"", address);
176
g_ptr_array_add (a, s);
178
if (address != NULL && alias != NULL) {
181
s = g_strdup_printf ("--name=\"%s\"", alias);
182
g_ptr_array_add (a, s);
184
g_ptr_array_add (a, NULL);
186
if (g_spawn_async(NULL, (char **) a->pdata, NULL,
187
G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &err) == FALSE) {
188
g_printerr("Couldn't execute command: %s\n", err->message);
192
for (i = 1; a->pdata[i] != NULL; i++)
193
g_free (a->pdata[i]);
195
g_ptr_array_free (a, TRUE);
180
bluetooth_applet_send_to_address (applet, address, alias);
198
183
static void keyboard_callback(GObject *widget, gpointer user_data)
269
264
guint32 activate_time = gtk_get_current_event_time();
271
if (query_blinking() == TRUE) {
266
/* Always show the menu, whatever button is pressed.
267
* Agent dialog can be shown from the notification (or should
268
* be shown automatically in the background).
276
270
popup_callback(widget, 0, activate_time, user_data);
280
killswitch_state_changed (BluetoothKillswitch *killswitch, KillswitchState state)
274
killswitch_state_changed (GObject *gobject,
279
BluetoothApplet *applet = BLUETOOTH_APPLET (gobject);
280
BluetoothKillswitchState state = bluetooth_applet_get_killswitch_state (applet);
283
281
gboolean sensitive = TRUE;
284
282
gboolean bstate = FALSE;
285
283
const char *label, *status_label;
287
if (state == KILLSWITCH_STATE_NO_ADAPTER) {
285
if (state == BLUETOOTH_KILLSWITCH_STATE_NO_ADAPTER) {
288
286
object = gtk_builder_get_object (xml, "bluetooth-applet-popup");
289
287
gtk_menu_popdown (GTK_MENU (object));
288
update_icon_visibility ();
293
if (state == KILLSWITCH_STATE_SOFT_BLOCKED) {
292
if (state == BLUETOOTH_KILLSWITCH_STATE_SOFT_BLOCKED) {
294
293
label = N_("Turn On Bluetooth");
295
294
status_label = N_("Bluetooth: Off");
297
} else if (state == KILLSWITCH_STATE_UNBLOCKED) {
296
} else if (state == BLUETOOTH_KILLSWITCH_STATE_UNBLOCKED) {
298
297
label = N_("Turn Off Bluetooth");
299
298
status_label = N_("Bluetooth: On");
301
} else if (state == KILLSWITCH_STATE_HARD_BLOCKED) {
300
} else if (state == BLUETOOTH_KILLSWITCH_STATE_HARD_BLOCKED) {
302
301
sensitive = FALSE;
304
303
status_label = N_("Bluetooth: Disabled");
708
689
actions = g_list_remove_all (actions, NULL);
710
cont = gtk_tree_model_iter_children (devices_model, &iter, parent);
712
GHashTable *services;
714
char *alias, *address, **uuids, *name;
715
gboolean is_connected;
691
for (l = devices; l != NULL; l = g_list_next (l)) {
692
BluetoothSimpleDevice *device = l->data;
717
693
GtkAction *action, *status, *oper;
719
gtk_tree_model_get (devices_model, &iter,
720
BLUETOOTH_COLUMN_PROXY, &proxy,
721
BLUETOOTH_COLUMN_ADDRESS, &address,
722
BLUETOOTH_COLUMN_SERVICES, &services,
723
BLUETOOTH_COLUMN_ALIAS, &alias,
724
BLUETOOTH_COLUMN_UUIDS, &uuids,
725
BLUETOOTH_COLUMN_TYPE, &type,
728
if (device_has_submenu ((const char **) uuids, services, type) == FALSE ||
729
address == NULL || proxy == NULL || alias == NULL) {
731
g_object_unref (proxy);
733
if (services != NULL)
734
g_hash_table_unref (services);
738
cont = gtk_tree_model_iter_next (devices_model, &iter);
696
if (device_has_submenu (device) == FALSE) {
697
g_boxed_free (BLUETOOTH_TYPE_SIMPLE_DEVICE, device);
742
action = gtk_action_group_get_action (devices_action_group, address);
703
action = gtk_action_group_get_action (devices_action_group, device->bdaddr);
748
709
actions = g_list_remove (actions, action);
750
action_name = g_strdup_printf ("%s-status", address);
711
action_name = g_strdup_printf ("%s-status", device->bdaddr);
751
712
status = gtk_action_group_get_action (devices_action_group, action_name);
752
713
g_free (action_name);
754
action_name = g_strdup_printf ("%s-action", address);
715
action_name = g_strdup_printf ("%s-action", device->bdaddr);
755
716
oper = gtk_action_group_get_action (devices_action_group, action_name);
756
717
g_free (action_name);
759
/* If one service is connected, then we're connected */
760
is_connected = FALSE;
761
if (services != NULL) {
764
list = g_hash_table_get_values (services);
765
for (l = list; l != NULL; l = l->next) {
766
BluetoothStatus val = GPOINTER_TO_INT (l->data);
767
if (val == BLUETOOTH_STATUS_CONNECTED ||
768
val == BLUETOOTH_STATUS_PLAYING) {
776
name = escape_label_for_action (alias);
720
name = escape_label_for_action (device->alias);
778
722
if (action == NULL) {
779
723
guint menu_merge_id;
780
724
char *action_path;
782
726
/* The menu item with descendants */
783
action = gtk_action_new (address, name, NULL, NULL);
727
action = gtk_action_new (device->bdaddr, name, NULL, NULL);
785
729
gtk_action_group_add_action (devices_action_group, action);
786
730
g_object_unref (action);
787
731
menu_merge_id = gtk_ui_manager_new_merge_id (uimanager);
788
732
gtk_ui_manager_add_ui (uimanager, menu_merge_id,
789
"/bluetooth-applet-popup/devices-placeholder", address, address,
733
"/bluetooth-applet-popup/devices-placeholder", device->bdaddr, device->bdaddr,
790
734
GTK_UI_MANAGER_MENU, FALSE);
791
735
g_object_set_data_full (G_OBJECT (action),
792
736
"merge-id", GUINT_TO_POINTER (menu_merge_id), NULL);
794
738
/* The status menu item */
795
status = add_menu_item (address,
739
status = add_menu_item (device->bdaddr,
797
is_connected ? _("Connected") : _("Disconnected"),
741
device->connected ? _("Connected") : _("Disconnected"),
801
745
gtk_action_set_sensitive (status, FALSE);
803
if (services != NULL) {
747
if (device->can_connect) {
804
748
action_path = g_strdup_printf ("/bluetooth-applet-popup/devices-placeholder/%s/%s-status",
749
device->bdaddr, device->bdaddr);
806
750
action_set_bold (uimanager, status, action_path);
807
751
g_free (action_path);
812
756
/* The connect button */
813
oper = add_menu_item (address,
757
oper = add_menu_item (device->bdaddr,
815
is_connected ? _("Disconnect") : _("Connect"),
759
device->connected ? _("Disconnect") : _("Connect"),
818
762
G_CALLBACK (on_connect_activate));
819
if (services == NULL)
763
if (!device->can_connect)
820
764
gtk_action_set_visible (oper, FALSE);
822
add_separator_item (address, "connect-sep", uimanager, menu_merge_id);
766
add_separator_item (device->bdaddr, "connect-sep", uimanager, menu_merge_id);
824
768
/* The Send to... button */
825
if (device_has_uuid ((const char **) uuids, "OBEXObjectPush") != FALSE) {
826
add_menu_item (address,
769
if (device->capabilities & BLUETOOTH_CAPABILITIES_OBEX_PUSH) {
770
add_menu_item (device->bdaddr,
828
772
_("Send files..."),
831
775
G_CALLBACK (sendto_callback));
832
776
g_object_set_data_full (G_OBJECT (action),
833
"alias", g_strdup (alias), g_free);
777
"alias", g_strdup (device->alias), g_free);
835
if (device_has_uuid ((const char **) uuids, "OBEXFileTransfer") != FALSE) {
836
add_menu_item (address,
779
if (device->capabilities & BLUETOOTH_CAPABILITIES_OBEX_FILE_TRANSFER) {
780
add_menu_item (device->bdaddr,
838
782
_("Browse files..."),
841
785
G_CALLBACK (browse_callback));
844
add_separator_item (address, "files-sep", uimanager, menu_merge_id);
788
add_separator_item (device->bdaddr, "files-sep", uimanager, menu_merge_id);
846
if (type == BLUETOOTH_TYPE_KEYBOARD && program_available (KEYBOARD_PREFS)) {
847
add_menu_item (address,
790
if (device->type == BLUETOOTH_TYPE_KEYBOARD && program_available (GNOMECC)) {
791
add_menu_item (device->bdaddr,
849
793
_("Open Keyboard Preferences..."),
852
796
G_CALLBACK (keyboard_callback));
854
if (type == BLUETOOTH_TYPE_MOUSE && program_available (MOUSE_PREFS)) {
855
add_menu_item (address,
798
if (device->type == BLUETOOTH_TYPE_MOUSE && program_available (GNOMECC)) {
799
add_menu_item (device->bdaddr,
857
801
_("Open Mouse Preferences..."),
860
804
G_CALLBACK (mouse_callback));
806
if ((device->type == BLUETOOTH_TYPE_HEADSET ||
807
device->type == BLUETOOTH_TYPE_HEADPHONES ||
808
device->type == BLUETOOTH_TYPE_OTHER_AUDIO) && program_available (GNOMECC)) {
809
add_menu_item (device->bdaddr,
811
_("Open Sound Preferences..."),
814
G_CALLBACK (sound_callback));
863
817
gtk_action_set_label (action, name);
865
gtk_action_set_visible (status, services != NULL);
866
gtk_action_set_visible (oper, services != NULL);
867
if (services != NULL) {
868
set_device_status_label (address, is_connected ? CONNECTED : DISCONNECTED);
869
gtk_action_set_label (oper, is_connected ? _("Disconnect") : _("Connect"));
819
if (device->can_connect) {
820
gtk_action_set_visible (status, TRUE);
821
gtk_action_set_visible (oper, TRUE);
822
set_device_status_label (device->bdaddr, device->connected ? CONNECTED : DISCONNECTED);
823
gtk_action_set_label (oper, device->connected ? _("Disconnect") : _("Connect"));
825
gtk_action_set_visible (status, FALSE);
826
gtk_action_set_visible (oper, FALSE);
874
831
if (oper != NULL) {
875
832
g_object_set_data_full (G_OBJECT (oper),
876
"connected", GINT_TO_POINTER (is_connected ? CONNECTED : DISCONNECTED), NULL);
833
"connected", GINT_TO_POINTER (device->connected ? CONNECTED : DISCONNECTED), NULL);
877
834
g_object_set_data_full (G_OBJECT (oper),
878
"device-path", g_strdup (dbus_g_proxy_get_path (proxy)), g_free);
835
"device-path", g_strdup (device->device_path), g_free);
881
838
/* And now for the trick of the day */
882
if (is_connected != FALSE) {
839
if (device->connected != FALSE) {
885
path = g_strdup_printf ("/bluetooth-applet-popup/devices-placeholder/%s", address);
842
path = g_strdup_printf ("/bluetooth-applet-popup/devices-placeholder/%s", device->bdaddr);
886
843
action_set_bold (uimanager, action, path);
893
g_object_unref (proxy);
895
if (services != NULL)
896
g_hash_table_unref (services);
900
cont = gtk_tree_model_iter_next (devices_model, &iter);
847
g_boxed_free (BLUETOOTH_TYPE_SIMPLE_DEVICE, device);
903
850
/* Remove the left-over devices */
904
851
g_list_foreach (actions, (GFunc) remove_action_item, uimanager);
905
852
g_list_free (actions);
855
g_list_free (devices);
908
857
gtk_ui_manager_ensure_update (uimanager);
910
859
gtk_action_set_visible (GTK_ACTION (gtk_builder_get_object (xml, "devices-label")),
914
static void device_changed (GtkTreeModel *model,
919
GtkTreeIter iter, *default_iter;
920
gboolean powered, cont;
923
num_adapters_present = num_adapters_powered = 0;
925
cont = gtk_tree_model_get_iter_first (model, &iter);
929
num_adapters_present++;
931
gtk_tree_model_get (model, &iter,
932
BLUETOOTH_COLUMN_DEFAULT, &is_default,
933
BLUETOOTH_COLUMN_POWERED, &powered,
936
num_adapters_powered++;
937
if (is_default && powered)
938
default_iter = gtk_tree_iter_copy (&iter);
940
cont = gtk_tree_model_iter_next (model, &iter);
943
update_discoverability (default_iter);
944
update_icon_visibility ();
945
update_menu_items ();
946
update_device_list (default_iter);
948
if (default_iter != NULL)
949
gtk_tree_iter_free (default_iter);
952
static void device_added(GtkTreeModel *model,
957
device_changed (model, path, iter, user_data);
960
static void device_removed(GtkTreeModel *model,
964
device_changed (model, path, NULL, user_data);
967
static void gconf_callback(GConfClient *client, guint cnxn_id,
968
GConfEntry *entry, gpointer user_data)
972
value = gconf_entry_get_value(entry);
976
if (g_str_equal(entry->key, PREF_SHOW_ICON) == TRUE) {
977
show_icon_pref = gconf_value_get_bool(value);
978
update_icon_visibility();
864
show_icon_changed (GSettings *settings,
868
show_icon_pref = g_settings_get_boolean (settings, PREF_SHOW_ICON);
869
update_icon_visibility();
983
872
static GOptionEntry options[] = {
1028
925
gtk_window_set_default_icon_name("bluetooth");
1030
killswitch = bluetooth_killswitch_new ();
1031
g_signal_connect (G_OBJECT (killswitch), "state-changed",
1032
G_CALLBACK (killswitch_state_changed), NULL);
927
applet = g_object_new (BLUETOOTH_TYPE_APPLET, NULL);
928
g_signal_connect (G_OBJECT (applet), "notify::killswitch-state",
929
G_CALLBACK (killswitch_state_changed), NULL);
1034
931
menu = create_popupmenu();
1036
client = bluetooth_client_new();
1038
devices_model = bluetooth_client_get_model(client);
1040
g_signal_connect(G_OBJECT(devices_model), "row-inserted",
1041
G_CALLBACK(device_added), NULL);
1042
g_signal_connect(G_OBJECT(devices_model), "row-deleted",
1043
G_CALLBACK(device_removed), NULL);
1044
g_signal_connect (G_OBJECT (devices_model), "row-changed",
1045
G_CALLBACK (device_changed), NULL);
1046
/* Set the default */
1047
device_changed (devices_model, NULL, NULL, NULL);
1048
if (bluetooth_killswitch_has_killswitches (killswitch) != FALSE) {
1049
killswitch_state_changed (killswitch,
1050
bluetooth_killswitch_get_state (killswitch));
1053
gconf = gconf_client_get_default();
1055
value = gconf_client_get (gconf, PREF_SHOW_ICON, NULL);
1056
if (value == NULL) {
1057
show_icon_pref = TRUE;
1059
show_icon_pref = gconf_value_get_bool (value);
1060
gconf_value_free (value);
1063
gconf_client_add_dir(gconf, PREF_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL);
1065
gconf_client_notify_add(gconf, PREF_DIR,
1066
gconf_callback, NULL, NULL, NULL);
933
g_signal_connect (G_OBJECT (applet), "devices-changed",
934
G_CALLBACK (update_device_list), NULL);
935
g_signal_connect (G_OBJECT (applet), "notify::discoverable",
936
G_CALLBACK (update_discoverability), NULL);
937
g_signal_connect (G_OBJECT (applet), "notify::show-full-menu",
938
G_CALLBACK (update_menu_items), NULL);
940
killswitch_state_changed ((GObject*) applet, NULL, NULL);
941
update_menu_items ((GObject*) applet, NULL, NULL);
942
update_discoverability ((GObject*) applet, NULL, NULL);
943
update_device_list (applet, NULL);
945
settings = g_settings_new (SCHEMA_NAME);
946
show_icon_pref = g_settings_get_boolean (settings, PREF_SHOW_ICON);
948
g_signal_connect (G_OBJECT (settings), "changed::" PREF_SHOW_ICON,
949
G_CALLBACK (show_icon_changed), NULL);
1068
951
statusicon = init_notification();