1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
/*
* Copyright (C) 2012-2013 Canonical Ltd.
* Author: Robert Ancell <robert.ancell@canonical.com>
*
* 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 of the License.
* See http://www.gnu.org/copyleft/gpl.html the full text of the license.
*/
public class BluetoothIndicator : Indicator.Object
{
private Indicator.ServiceManager service;
private Gtk.Image image;
private DbusmenuGtk.Menu menu;
private BluetoothService proxy;
private string accessible_description = _("Bluetooth: On");
construct
{
service = new Indicator.ServiceManager ("com.canonical.indicator.bluetooth");
service.connection_change.connect (connection_change_cb);
menu = new DbusmenuGtk.Menu ("com.canonical.indicator.bluetooth", "/com/canonical/indicator/bluetooth/menu");
image = Indicator.image_helper ("bluetooth-active");
image.visible = true;
var menu_client = menu.get_client ();
menu_client.add_type_handler_full ("x-canonical-switch", new_switch_cb);
}
private bool new_switch_cb (Dbusmenu.Menuitem newitem, Dbusmenu.Menuitem parent, Dbusmenu.Client client)
{
var item = new Switch (newitem);
(client as DbusmenuGtk.Client).newitem_base (newitem, item, parent);
return true;
}
public override unowned Gtk.Image get_image ()
{
return image;
}
public override unowned Gtk.Menu get_menu ()
{
return menu;
}
public override unowned string get_accessible_desc ()
{
return accessible_description;
}
private void connection_change_cb (bool connected)
{
if (!connected)
return;
// FIXME: Set proxy to null on disconnect?
// FIXME: Use Cancellable to cancel existing connection
if (proxy == null)
{
Bus.get_proxy.begin<BluetoothService> (BusType.SESSION,
"com.canonical.indicator.bluetooth",
"/com/canonical/indicator/bluetooth/service",
DBusProxyFlags.NONE, null, (object, result) =>
{
try
{
proxy = Bus.get_proxy.end (result);
proxy.g_properties_changed.connect (server_properties_changed_cb);
server_properties_changed_cb ();
}
catch (IOError e)
{
warning ("Failed to connect to bluetooth service: %s", e.message);
}
});
}
}
private void server_properties_changed_cb ()
{
Indicator.image_helper_update (image, proxy.icon_name);
accessible_description = proxy.accessible_description;
}
}
public class Switch : Ido.SwitchMenuItem
{
public Dbusmenu.Menuitem menuitem;
public new Gtk.Label label;
private bool updating_switch = false;
public Switch (Dbusmenu.Menuitem menuitem)
{
this.menuitem = menuitem;
label = new Gtk.Label ("");
label.visible = true;
content_area.add (label);
/* Be the first listener to the activate signal so we can stop it
* emitting when we change the state. Without this you get feedback loops */
activate.connect (() =>
{
if (updating_switch)
Signal.stop_emission_by_name (this, "activate");
});
menuitem.property_changed.connect ((mi, prop, value) => { update (); });
update ();
}
private void update ()
{
updating_switch = true;
label.label = menuitem.property_get (Dbusmenu.MENUITEM_PROP_LABEL);
active = menuitem.property_get_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE) == Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED;
updating_switch = false;
}
}
[DBus (name = "com.canonical.indicator.bluetooth.service")]
public interface BluetoothService : DBusProxy
{
public abstract string icon_name { owned get; }
public abstract string accessible_description { owned get; }
}
public static string get_version ()
{
return Indicator.VERSION;
}
public static GLib.Type get_type ()
{
return typeof (BluetoothIndicator);
}
|