/*
* Copyright 2013 Canonical Ltd.
*
* 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; version 3.
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Authors:
* Charles Kerr
*/
class Desktop: Profile
{
private uint idle_rebuild_id = 0;
private Settings settings;
private SimpleActionGroup action_group;
private Menu device_section;
private HashTable connect_actions;
protected override void dispose ()
{
if (idle_rebuild_id != 0)
{
Source.remove (idle_rebuild_id);
idle_rebuild_id = 0;
}
base.dispose ();
}
public Desktop (Bluetooth bluetooth, SimpleActionGroup action_group)
{
const string profile_name = "desktop";
base (bluetooth, profile_name);
this.action_group = action_group;
connect_actions = new HashTable(direct_hash, direct_equal);
settings = new Settings ("com.canonical.indicator.bluetooth");
// build the static actions
Action[] actions = {};
actions += get_root_action (profile_name);
actions += create_enabled_action (bluetooth);
actions += create_discoverable_action (bluetooth);
actions += create_wizard_action ();
actions += create_browse_files_action ();
actions += create_send_file_action ();
actions += create_show_settings_action ();
foreach (var a in actions)
action_group.insert (a);
build_menu ();
// know when to show the indicator & when to hide it
settings.changed["visible"].connect (()=> update_visibility());
bluetooth.notify.connect (() => update_visibility());
update_visibility ();
// when devices change, rebuild our device section
bluetooth.devices_changed.connect (()=> {
if (idle_rebuild_id == 0)
idle_rebuild_id = Idle.add (() => {
rebuild_device_section();
idle_rebuild_id = 0;
return false;
});
});
}
void update_visibility ()
{
visible = bluetooth.powered && !bluetooth.blocked && settings.get_boolean("visible");
}
///
/// MenuItems
///
MenuItem create_device_connection_menuitem (Device device)
{
var action_name = @"desktop-device-$(device.id)-connected";
var item = new MenuItem (_("Connection"), @"indicator.$action_name");
item.set_attribute ("x-canonical-type", "s", "com.canonical.indicator.switch");
// if this doesn't already have an action, create one
if (!connect_actions.contains (device.id))
{
debug (@"creating action for $action_name");
var action = new SimpleAction.stateful (action_name, null, device.is_connected);
action.activate.connect (() => action.set_state (!action.get_state().get_boolean()));
action.notify["state"].connect (() => bluetooth.set_device_connected (device.id, action.get_state().get_boolean()));
connect_actions.insert (device.id, action);
action_group.insert (action);
}
else
{
debug (@"updating action $(device.id) state to $(device.is_connected)");
var action = connect_actions.lookup (device.id);
action.set_state (device.is_connected);
}
return item;
}
void rebuild_device_section ()
{
device_section.remove_all ();
foreach (var device in bluetooth.get_devices())
{
Menu submenu = new Menu ();
MenuItem item;
if (device.is_connectable)
submenu.append_item (create_device_connection_menuitem (device));
if (device.supports_browsing)
submenu.append (_("Browse files…"), @"indicator.desktop-browse-files::$(device.address)");
if (device.supports_file_transfer)
submenu.append (_("Send files…"), @"indicator.desktop-send-file::$(device.address)");
switch (device.device_type)
{
case Device.Type.KEYBOARD:
submenu.append (_("Keyboard Settings…"), "indicator.desktop-show-settings::keyboard");
break;
case Device.Type.MOUSE:
case Device.Type.TABLET:
submenu.append (_("Mouse and Touchpad Settings…"), "indicator.desktop-show-settings::mouse");
break;
case Device.Type.HEADSET:
case Device.Type.HEADPHONES:
case Device.Type.OTHER_AUDIO:
submenu.append (_("Sound Settings…"), "indicator.desktop-show-settings::sound");
break;
}
/* only show the device if it's got actions that we can perform on it */
if (submenu.get_n_items () > 0)
{
item = new MenuItem (device.name, null);
item.set_attribute_value ("icon", device.icon.serialize());
item.set_submenu (submenu);
device_section.append_item (item);
}
}
}
void build_menu ()
{
Menu section;
MenuItem item;
// quick toggles section
section = new Menu ();
section.append_item (create_enabled_menuitem ());
item = new MenuItem ("Visible", "indicator.desktop-discoverable");
item.set_attribute ("x-canonical-type", "s", "com.canonical.indicator.switch");
section.append_item (item);
menu.append_section (null, section);
// devices section
device_section = new Menu ();
rebuild_device_section ();
menu.append_section (null, device_section);
// settings section
section = new Menu ();
section.append (_("Set Up New Device…"), "indicator.desktop-wizard");
section.append (_("Bluetooth Settings…"), "indicator.desktop-show-settings::bluetooth");
menu.append_section (null, section);
}
///
/// Actions
///
void show_settings (string panel)
{
spawn_command_line_async ("gnome-control-center " + panel);
}
Action create_discoverable_action (Bluetooth bluetooth)
{
var action = new SimpleAction.stateful ("desktop-discoverable", null, bluetooth.discoverable);
action.set_enabled (bluetooth.powered);
action.activate.connect (() => action.set_state (!action.get_state().get_boolean()));
action.notify["state"].connect (() => bluetooth.try_set_discoverable (action.get_state().get_boolean()));
bluetooth.notify["discoverable"].connect (() => action.set_state (bluetooth.discoverable));
bluetooth.notify["powered"].connect (() => action.set_enabled (bluetooth.powered));
return action;
}
Action create_wizard_action ()
{
var action = new SimpleAction ("desktop-wizard", null);
action.activate.connect (() => spawn_command_line_async ("bluetooth-wizard"));
return action;
}
Action create_browse_files_action ()
{
var action = new SimpleAction ("desktop-browse-files", VariantType.STRING);
action.activate.connect ((action, address) => {
var uri = @"obex://[$(address.get_string())]/";
var file = File.new_for_uri (uri);
file.mount_enclosing_volume.begin (MountMountFlags.NONE, null, null, (obj, res) => {
try {
AppInfo.launch_default_for_uri (uri, null);
} catch (Error e) {
warning ("unable to launch '$uri': $(e.message)");
}
});
});
return action;
}
Action create_send_file_action ()
{
var action = new SimpleAction ("desktop-send-file", VariantType.STRING);
action.activate.connect ((action, address) => {
spawn_command_line_async ("bluetooth-sendto --device=$(address.get_string())");
});
return action;
}
Action create_show_settings_action ()
{
var action = new SimpleAction ("desktop-show-settings", VariantType.STRING);
action.activate.connect ((action, panel) => show_settings (panel.get_string()));
return action;
}
}