aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Ancell <robert.ancell@canonical.com>2012-12-06 15:35:57 +1300
committerRobert Ancell <robert.ancell@canonical.com>2012-12-06 15:35:57 +1300
commit4993d0aae0511ae56a830fe8b51b1cde5723a1a8 (patch)
tree9830954bcb9bafff96ab13abadd32391c17f539d
parent34c7299d98efbcdfeab355c447a5fc1312a97d9e (diff)
downloadayatana-indicator-bluetooth-4993d0aae0511ae56a830fe8b51b1cde5723a1a8.tar.gz
ayatana-indicator-bluetooth-4993d0aae0511ae56a830fe8b51b1cde5723a1a8.tar.bz2
ayatana-indicator-bluetooth-4993d0aae0511ae56a830fe8b51b1cde5723a1a8.zip
Make into a proper indicator
-rw-r--r--Makefile.am2
-rwxr-xr-xautogen.sh1
-rw-r--r--configure.ac41
-rw-r--r--data/Makefile.am9
-rw-r--r--data/indicator-bluetooth.service.in3
-rw-r--r--src/Makefile.am40
-rw-r--r--src/indicator-bluetooth-service.vala379
-rw-r--r--src/indicator-bluetooth.vala407
-rw-r--r--src/indicator3-0.4.vapi145
-rw-r--r--src/libido3-0.1.vapi9
10 files changed, 682 insertions, 354 deletions
diff --git a/Makefile.am b/Makefile.am
index 8d48c26..0d6e86d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS = po src
+SUBDIRS = data po src
EXTRA_DIST = autogen.sh NEWS
diff --git a/autogen.sh b/autogen.sh
index dfd3fb8..672b25b 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,6 +1,7 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
+libtoolize
intltoolize --force
aclocal
automake --add-missing --copy --foreign
diff --git a/configure.ac b/configure.ac
index eee0f17..f430bd2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,16 +5,25 @@ AM_MAINTAINER_MODE
AM_PROG_VALAC([0.16.0])
AM_PROG_CC_C_O
+LT_INIT
dnl ###########################################################################
dnl Dependencies
dnl ###########################################################################
+PKG_CHECK_MODULES(INDICATOR_BLUETOOTH_SERVICE, [
+ glib-2.0
+ gnome-bluetooth-1.0
+ indicator3-0.4
+ dbusmenu-gtk3-0.4
+])
+
PKG_CHECK_MODULES(INDICATOR_BLUETOOTH, [
glib-2.0
gtk+-3.0
- gnome-bluetooth-1.0
- appindicator3-0.1
+ indicator3-0.4
+ dbusmenu-gtk3-0.4
+ libido3-0.1
])
dnl ###########################################################################
@@ -24,12 +33,40 @@ dnl ###########################################################################
IT_PROG_INTLTOOL([0.35.0])
AC_SUBST(GETTEXT_PACKAGE, indicator-bluetooth)
+with_localinstall="no"
+AC_ARG_ENABLE(localinstall, AS_HELP_STRING([--enable-localinstall], [install all of the files localy instead of system directories (for distcheck)]), with_localinstall=$enableval, with_localinstall=no)
+
+dnl ###########################################################################
+dnl Indicator Info
+dnl ###########################################################################
+
+AS_IF([test "x$with_localinstall" = "xyes"],
+ [
+ INDICATORDIR="${libdir}/indicators3/7/"
+ ],
+ [
+ INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator3-0.4`
+ ])
+AC_SUBST(INDICATORDIR)
+
+dnl ###########################################################################
+dnl DBus Service Info
+dnl ###########################################################################
+
+if test "x$with_localinstall" = "xyes"; then
+ DBUSSERVICEDIR="${datadir}/dbus-1/services/"
+else
+ DBUSSERVICEDIR=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1`
+fi
+AC_SUBST(DBUSSERVICEDIR)
+
dnl ###########################################################################
dnl Files to generate
dnl ###########################################################################
AC_OUTPUT([
Makefile
+data/Makefile
po/Makefile.in
src/Makefile
])
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644
index 0000000..c96ea3f
--- /dev/null
+++ b/data/Makefile.am
@@ -0,0 +1,9 @@
+dbus_servicesdir = $(DBUSSERVICEDIR)
+dist_dbus_services_DATA = indicator-bluetooth.service
+
+%.service: %.service.in
+ sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
+
+CLEANFILES = \
+ $(dbus_services_DATA)
+ \ No newline at end of file
diff --git a/data/indicator-bluetooth.service.in b/data/indicator-bluetooth.service.in
new file mode 100644
index 0000000..8b7a8cb
--- /dev/null
+++ b/data/indicator-bluetooth.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=com.canonical.indicator.bluetooth
+Exec=@libexecdir@/indicator-bluetooth-service
diff --git a/src/Makefile.am b/src/Makefile.am
index 2dd7e41..d2ed9dd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,25 +1,49 @@
-bin_PROGRAMS = indicator-bluetooth
+libexec_PROGRAMS = indicator-bluetooth-service
+indicatordir = $(INDICATORDIR)
+indicator_LTLIBRARIES = libbluetooth.la
-indicator_bluetooth_SOURCES = \
+indicator_bluetooth_service_SOURCES = \
config.vapi \
+ indicator3-0.4.vapi \
gnome-bluetooth-1.0.vapi \
- indicator-bluetooth.vala
+ indicator-bluetooth-service.vala
-indicator_bluetooth_VALAFLAGS = \
+indicator_bluetooth_service_VALAFLAGS = \
--pkg posix \
--pkg glib-2.0 \
--pkg gtk+-3.0 \
- --pkg appindicator3-0.1
+ --pkg Dbusmenu-0.4
-indicator_bluetooth_CFLAGS = \
- -DVERSION=\"$(VERSION)\" \
+indicator_bluetooth_service_CFLAGS = \
-DGETTEXT_PACKAGE=\"$(GETTEXT_PACKAGE)\" \
-DLOCALE_DIR=\"$(datadir)/locale\" \
+ $(INDICATOR_BLUETOOTH_SERVICE_CFLAGS)
+
+indicator_bluetooth_service_LDADD = \
+ $(INDICATOR_BLUETOOTH_SERVICE_LIBS)
+
+libbluetooth_la_SOURCES = \
+ config.vapi \
+ indicator3-0.4.vapi \
+ indicator-bluetooth.vala \
+ libido3-0.1.vapi
+
+libbluetooth_la_VALAFLAGS = \
+ --pkg posix \
+ --pkg glib-2.0 \
+ --pkg gtk+-3.0 \
+ --pkg Dbusmenu-0.4 \
+ --pkg DbusmenuGtk3-0.4
+
+libbluetooth_la_CFLAGS = \
$(INDICATOR_BLUETOOTH_CFLAGS)
-indicator_bluetooth_LDADD = \
+libbluetooth_la_LIBADD = \
$(INDICATOR_BLUETOOTH_LIBS)
+libbluetooth_la_LDFLAGS = \
+ -module -avoid-version
+
CLEANFILES = \
$(patsubst %.vala,%.c,$(filter %.vala, $(SOURCES))) \
*_vala.stamp
diff --git a/src/indicator-bluetooth-service.vala b/src/indicator-bluetooth-service.vala
new file mode 100644
index 0000000..4ecf2b6
--- /dev/null
+++ b/src/indicator-bluetooth-service.vala
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2012 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, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+public class BluetoothIndicator
+{
+ private DBusConnection bus;
+ private Indicator.Service indicator_service;
+ private Dbusmenu.Server menu_server;
+ private BluetoothService bluetooth_service;
+ private GnomeBluetooth.Client client;
+ private GnomeBluetooth.Killswitch killswitch;
+ private bool updating_killswitch = false;
+ private Dbusmenu.Menuitem enable_item;
+ private Dbusmenu.Menuitem visible_item;
+ private bool updating_visible = false;
+ private Dbusmenu.Menuitem devices_separator;
+ private List<BluetoothMenuItem> device_items;
+ private Dbusmenu.Menuitem settings_item;
+ private Dbusmenu.Menuitem menu;
+ private string icon_name = "bluetooth-active";
+
+ public BluetoothIndicator () throws Error
+ {
+ bus = Bus.get_sync (BusType.SESSION);
+
+ indicator_service = new Indicator.Service ("com.canonical.indicator.bluetooth");
+ menu_server = new Dbusmenu.Server ("/com/canonical/indicator/bluetooth/menu");
+
+ bluetooth_service = new BluetoothService ();
+ bus.register_object ("/com/canonical/indicator/bluetooth/service", bluetooth_service);
+
+ killswitch = new GnomeBluetooth.Killswitch ();
+ killswitch.state_changed.connect (killswitch_state_changed_cb);
+
+ client = new GnomeBluetooth.Client ();
+
+ menu = new Dbusmenu.Menuitem ();
+ menu_server.set_root (menu);
+
+ enable_item = new Dbusmenu.Menuitem ();
+ enable_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Enabled"));
+ enable_item.property_set (Dbusmenu.MENUITEM_PROP_TYPE, "x-canonical-switch");
+ enable_item.item_activated.connect (() =>
+ {
+ if (updating_killswitch)
+ return;
+ if (killswitch.state == GnomeBluetooth.KillswitchState.UNBLOCKED)
+ killswitch.state = GnomeBluetooth.KillswitchState.SOFT_BLOCKED;
+ else
+ killswitch.state = GnomeBluetooth.KillswitchState.UNBLOCKED;
+ });
+ menu.child_append (enable_item);
+
+ visible_item = new Dbusmenu.Menuitem ();
+ visible_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Visible"));
+ visible_item.property_set (Dbusmenu.MENUITEM_PROP_TYPE, "x-canonical-switch");
+ bool discoverable;
+ client.get ("default-adapter-discoverable", out discoverable);
+ visible_item.property_set_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, discoverable ? Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED : Dbusmenu.MENUITEM_TOGGLE_STATE_UNCHECKED);
+ client.notify["default-adapter-discoverable"].connect (() =>
+ {
+ updating_visible = true;
+ bool is_discoverable;
+ client.get ("default-adapter-discoverable", out is_discoverable);
+ visible_item.property_set_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, is_discoverable ? Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED : Dbusmenu.MENUITEM_TOGGLE_STATE_UNCHECKED);
+ updating_visible = false;
+ });
+ visible_item.item_activated.connect (() =>
+ {
+ if (updating_visible)
+ return;
+ client.set ("default-adapter-discoverable", visible_item.property_get_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE) == Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED);
+ });
+ menu.child_append (visible_item);
+
+ devices_separator = new Dbusmenu.Menuitem ();
+ devices_separator.property_set (Dbusmenu.MENUITEM_PROP_TYPE, Dbusmenu.CLIENT_TYPES_SEPARATOR);
+ menu.child_append (devices_separator);
+
+ device_items = new List<BluetoothMenuItem> ();
+
+ client.model.row_inserted.connect (device_changed_cb);
+ client.model.row_changed.connect (device_changed_cb);
+ client.model.row_deleted.connect (device_removed_cb);
+ Gtk.TreeIter iter;
+ var have_iter = client.model.get_iter_first (out iter);
+ while (have_iter)
+ {
+ Gtk.TreeIter child_iter;
+ var have_child_iter = client.model.iter_children (out child_iter, iter);
+ while (have_child_iter)
+ {
+ device_changed_cb (null, child_iter);
+ have_child_iter = client.model.iter_next (ref child_iter);
+ }
+ have_iter = client.model.iter_next (ref iter);
+ }
+
+ var sep = new Dbusmenu.Menuitem ();
+ sep.property_set (Dbusmenu.MENUITEM_PROP_TYPE, Dbusmenu.CLIENT_TYPES_SEPARATOR);
+ menu.child_append (sep);
+
+ settings_item = new Dbusmenu.Menuitem ();
+ settings_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Bluetooth Settings..."));
+ settings_item.item_activated.connect (() => { show_control_center ("bluetooth"); });
+ menu.child_append (settings_item);
+
+ killswitch_state_changed_cb (killswitch.state);
+ }
+
+ private BluetoothMenuItem? find_menu_item (DBusProxy proxy)
+ {
+ foreach (var item in device_items)
+ if (item.proxy == proxy)
+ return item;
+
+ return null;
+ }
+
+ private void device_changed_cb (Gtk.TreePath? path, Gtk.TreeIter iter)
+ {
+ /* Ignore adapters */
+ Gtk.TreeIter parent_iter;
+ if (!client.model.iter_parent (out parent_iter, iter))
+ return;
+
+ DBusProxy proxy;
+ string address;
+ string alias;
+ GnomeBluetooth.Type type;
+ string icon;
+ bool connected;
+ HashTable services;
+ string[] uuids;
+ client.model.get (iter,
+ GnomeBluetooth.Column.PROXY, out proxy,
+ GnomeBluetooth.Column.ADDRESS, out address,
+ GnomeBluetooth.Column.ALIAS, out alias,
+ GnomeBluetooth.Column.TYPE, out type,
+ GnomeBluetooth.Column.ICON, out icon,
+ GnomeBluetooth.Column.CONNECTED, out connected,
+ GnomeBluetooth.Column.SERVICES, out services,
+ GnomeBluetooth.Column.UUIDS, out uuids);
+
+ /* Skip if haven't actually got any information yet */
+ if (proxy == null)
+ return;
+
+ /* Find or create menu item */
+ var item = find_menu_item (proxy);
+ if (item == null)
+ {
+ item = new BluetoothMenuItem (client, proxy);
+ var last_item = devices_separator as Dbusmenu.Menuitem;
+ if (device_items != null)
+ last_item = device_items.last ().data;
+ device_items.append (item);
+ menu.child_add_position (item, last_item.get_position (menu) + 1);
+ }
+
+ item.update (type, address, alias, icon, connected, services, uuids);
+ }
+
+ private void device_removed_cb (Gtk.TreePath path)
+ {
+ Gtk.TreeIter iter;
+ if (!client.model.get_iter (out iter, path))
+ return;
+
+ DBusProxy proxy;
+ client.model.get (iter, GnomeBluetooth.Column.PROXY, out proxy);
+
+ var item = find_menu_item (proxy);
+ if (item == null)
+ return;
+
+ device_items.remove (item);
+ menu.child_delete (item);
+ }
+
+ private void killswitch_state_changed_cb (GnomeBluetooth.KillswitchState state)
+ {
+ updating_killswitch = true;
+
+ icon_name = state == GnomeBluetooth.KillswitchState.UNBLOCKED ? "bluetooth-active" : "bluetooth-disabled";
+
+ /*var builder = new VariantBuilder (VariantType.ARRAY);
+ builder.add ("{sv}", "IconName", new Variant.string (icon_name));
+ try
+ {
+ var properties = new Variant ("(sa{sv}as)", "com.canonical.indicator.vala.service", builder, null);
+ bus.emit_signal (null,
+ "/com/canonical/indicator/vala/service",
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ properties);
+ }
+ catch (Error e)
+ {
+ warning ("Failed to emit signal: %s", e.message);
+ }*/
+
+ enable_item.property_set_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, state == GnomeBluetooth.KillswitchState.UNBLOCKED ? Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED : Dbusmenu.MENUITEM_TOGGLE_STATE_UNCHECKED);
+
+ /* Disable devices when locked */
+ visible_item.property_set_bool (Dbusmenu.MENUITEM_PROP_VISIBLE, state == GnomeBluetooth.KillswitchState.UNBLOCKED);
+ devices_separator.property_set_bool (Dbusmenu.MENUITEM_PROP_VISIBLE, state == GnomeBluetooth.KillswitchState.UNBLOCKED);
+ foreach (var item in device_items)
+ item.property_set_bool (Dbusmenu.MENUITEM_PROP_VISIBLE, state == GnomeBluetooth.KillswitchState.UNBLOCKED);
+
+ updating_killswitch = false;
+ }
+}
+
+private class BluetoothMenuItem : Dbusmenu.Menuitem
+{
+ private GnomeBluetooth.Client client;
+ public DBusProxy proxy;
+ private Dbusmenu.Menuitem? connect_item = null;
+ private bool make_submenu = false;
+
+ public BluetoothMenuItem (GnomeBluetooth.Client client, DBusProxy proxy)
+ {
+ this.client = client;
+ this.proxy = proxy;
+ }
+
+ public void update (GnomeBluetooth.Type type, string address, string alias, string icon, bool connected, HashTable? services, string[] uuids)
+ {
+ property_set (Dbusmenu.MENUITEM_PROP_LABEL, alias);
+ property_set (Dbusmenu.MENUITEM_PROP_ICON_NAME, icon);
+ if (connect_item != null)
+ connect_item.property_set_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, connected ? Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED : Dbusmenu.MENUITEM_TOGGLE_STATE_UNCHECKED);
+
+ /* FIXME: Not sure if the GUI elements below can change over time */
+ if (make_submenu)
+ return;
+ make_submenu = true;
+
+ if (services != null)
+ {
+ connect_item = new Dbusmenu.Menuitem ();
+ connect_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Connection"));
+ connect_item.property_set (Dbusmenu.MENUITEM_PROP_TYPE, "x-canonical-switch");
+ connect_item.property_set_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, connected ? Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED : Dbusmenu.MENUITEM_TOGGLE_STATE_UNCHECKED);
+ connect_item.item_activated.connect (() => { connect_service (proxy.get_object_path (), true); });
+ child_append (connect_item);
+ }
+
+ var can_send = false;
+ var can_browse = false;
+ if (uuids != null)
+ {
+ for (var i = 0; uuids[i] != null; i++)
+ {
+ if (uuids[i] == "OBEXObjectPush")
+ can_send = true;
+ if (uuids[i] == "OBEXFileTransfer")
+ can_browse = true;
+ }
+ }
+
+ if (can_send)
+ {
+ var send_item = new Dbusmenu.Menuitem ();
+ send_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Send files..."));
+ send_item.item_activated.connect (() => { GnomeBluetooth.send_to_address (address, alias); });
+ child_append (send_item);
+ }
+
+ if (can_browse)
+ {
+ var browse_item = new Dbusmenu.Menuitem ();
+ browse_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Browse files..."));
+ browse_item.item_activated.connect (() => { GnomeBluetooth.browse_address (null, address, Gdk.CURRENT_TIME, null); });
+ child_append (browse_item);
+ }
+
+ switch (type)
+ {
+ case GnomeBluetooth.Type.KEYBOARD:
+ var keyboard_item = new Dbusmenu.Menuitem ();
+ keyboard_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Keyboard Settings..."));
+ keyboard_item.item_activated.connect (() => { show_control_center ("keyboard"); });
+ child_append (keyboard_item);
+ break;
+
+ case GnomeBluetooth.Type.MOUSE:
+ case GnomeBluetooth.Type.TABLET:
+ var mouse_item = new Dbusmenu.Menuitem ();
+ mouse_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Mouse and Touchpad Settings..."));
+ mouse_item.item_activated.connect (() => { show_control_center ("mouse"); });
+ child_append (mouse_item);
+ break;
+
+ case GnomeBluetooth.Type.HEADSET:
+ case GnomeBluetooth.Type.HEADPHONES:
+ case GnomeBluetooth.Type.OTHER_AUDIO:
+ var sound_item = new Dbusmenu.Menuitem ();
+ sound_item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, _("Sound Settings..."));
+ sound_item.item_activated.connect (() => { show_control_center ("sound"); });
+ child_append (sound_item);
+ break;
+ }
+ }
+
+ private void connect_service (string device, bool connect)
+ {
+ client.connect_service.begin (device, connect, null, (object, result) =>
+ {
+ var connected = false;
+ try
+ {
+ connected = client.connect_service.end (result);
+ }
+ catch (Error e)
+ {
+ warning ("Failed to connect service: %s", e.message);
+ }
+ });
+ }
+}
+
+private void show_control_center (string panel)
+{
+ try
+ {
+ Process.spawn_command_line_async ("gnome-control-center %s".printf (panel));
+ }
+ catch (GLib.SpawnError e)
+ {
+ warning ("Failed to open control center: %s", e.message);
+ }
+}
+
+public static int main (string[] args)
+{
+ Intl.setlocale (LocaleCategory.ALL, "");
+ Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
+ Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ Intl.textdomain (GETTEXT_PACKAGE);
+
+ var loop = new MainLoop ();
+
+ BluetoothIndicator indicator;
+ try
+ {
+ indicator = new BluetoothIndicator ();
+ }
+ catch (Error e)
+ {
+ warning ("Failed to start bluetooth indicator service: %s", e.message);
+ return Posix.EXIT_FAILURE;
+ }
+ // FIXMEindicator.shutdown.connect (() => { loop.quit (); });
+
+ loop.run ();
+
+ indicator = null;
+
+ return Posix.EXIT_SUCCESS;
+}
+
+[DBus (name = "com.canonical.indicator.bluetooth.service")]
+private class BluetoothService : Object
+{
+ public string icon_name
+ {
+ get { return "bluetooth-active"; }
+ }
+}
diff --git a/src/indicator-bluetooth.vala b/src/indicator-bluetooth.vala
index 9f7468a..3881fc7 100644
--- a/src/indicator-bluetooth.vala
+++ b/src/indicator-bluetooth.vala
@@ -9,376 +9,97 @@
* license.
*/
-public class BluetoothIndicator : AppIndicator.Indicator
+public class BluetoothIndicator : Indicator.Object
{
- private GnomeBluetooth.Client client;
- private GnomeBluetooth.Killswitch killswitch;
- private bool updating_killswitch = false;
- private Gtk.MenuItem status_item;
- private Gtk.MenuItem enable_item;
- private bool enable_value = false;
- private Gtk.CheckMenuItem visible_item;
- private bool updating_visible = false;
- private Gtk.SeparatorMenuItem devices_separator;
- private List<BluetoothMenuItem> device_items;
- private Gtk.MenuItem settings_item;
- private Gtk.Menu menu;
+ private Indicator.ServiceManager service;
+ private Gtk.Image image;
+ private DbusmenuGtk.Menu menu;
+ private BluetoothService proxy;
- public BluetoothIndicator ()
+ construct
{
- Object (id: "indicator-bluetooth", icon_name: "bluetooth-active", category: "Hardware");
-
- killswitch = new GnomeBluetooth.Killswitch ();
- killswitch.state_changed.connect (killswitch_state_changed_cb);
-
- client = new GnomeBluetooth.Client ();
-
- set_status (AppIndicator.IndicatorStatus.ACTIVE);
-
- menu = new Gtk.Menu ();
- set_menu (menu);
-
- status_item = new Gtk.MenuItem ();
- status_item.sensitive = false;
- status_item.visible = true;
- menu.append (status_item);
-
- enable_item = new Gtk.MenuItem ();
- enable_item.activate.connect (() =>
- {
- if (updating_killswitch)
- return;
- if (killswitch.state == GnomeBluetooth.KillswitchState.UNBLOCKED)
- killswitch.state = GnomeBluetooth.KillswitchState.SOFT_BLOCKED;
- else
- killswitch.state = GnomeBluetooth.KillswitchState.UNBLOCKED;
- });
- menu.append (enable_item);
-
- visible_item = new Gtk.CheckMenuItem.with_label (_("Visible"));
- bool discoverable;
- client.get ("default-adapter-discoverable", out discoverable);
- visible_item.active = discoverable;
- client.notify["default-adapter-discoverable"].connect (() =>
- {
- updating_visible = true;
- bool is_discoverable;
- client.get ("default-adapter-discoverable", out is_discoverable);
- visible_item.active = is_discoverable;
- updating_visible = false;
- });
- visible_item.activate.connect (() =>
- {
- if (updating_visible)
- return;
- client.set ("default-adapter-discoverable", visible_item.active);
- });
- menu.append (visible_item);
-
- devices_separator = new Gtk.SeparatorMenuItem ();
- menu.append (devices_separator);
-
- device_items = new List<BluetoothMenuItem> ();
-
- client.model.row_inserted.connect (device_changed_cb);
- client.model.row_changed.connect (device_changed_cb);
- client.model.row_deleted.connect (device_removed_cb);
- Gtk.TreeIter iter;
- var have_iter = client.model.get_iter_first (out iter);
- while (have_iter)
- {
- Gtk.TreeIter child_iter;
- var have_child_iter = client.model.iter_children (out child_iter, iter);
- while (have_child_iter)
- {
- device_changed_cb (null, child_iter);
- have_child_iter = client.model.iter_next (ref child_iter);
- }
- have_iter = client.model.iter_next (ref iter);
- }
-
- var sep = new Gtk.SeparatorMenuItem ();
- sep.visible = true;
- menu.append (sep);
-
- settings_item = new Gtk.MenuItem.with_label (_("Bluetooth Settings..."));
- settings_item.activate.connect (() => { show_control_center ("bluetooth"); });
- settings_item.visible = true;
- menu.append (settings_item);
-
- killswitch_state_changed_cb (killswitch.state);
+ 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 BluetoothMenuItem? find_menu_item (DBusProxy proxy)
+ private bool new_switch_cb (Dbusmenu.Menuitem newitem, Dbusmenu.Menuitem parent, Dbusmenu.Client client)
{
- foreach (var item in device_items)
- if (item.proxy == proxy)
- return item;
-
- return null;
+ var item = new Ido.SwitchMenuItem ();
+ item.active = newitem.property_get_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE) == Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED;
+ var label = new Gtk.Label (newitem.property_get (Dbusmenu.MENUITEM_PROP_LABEL));
+ label.visible = true;
+ item.content_area.add (label);
+ newitem.property_changed.connect ((mi, prop, value) =>
+ {
+ label.label = mi.property_get (Dbusmenu.MENUITEM_PROP_LABEL);
+ item.active = mi.property_get_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE) == Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED;
+ });
+ (client as DbusmenuGtk.Client).newitem_base (newitem, item, parent);
+ return true;
}
- private void device_changed_cb (Gtk.TreePath? path, Gtk.TreeIter iter)
+ public override unowned Gtk.Image get_image ()
{
- /* Ignore adapters */
- Gtk.TreeIter parent_iter;
- if (!client.model.iter_parent (out parent_iter, iter))
- return;
-
- DBusProxy proxy;
- string address;
- string alias;
- GnomeBluetooth.Type type;
- string icon;
- bool connected;
- HashTable services;
- string[] uuids;
- client.model.get (iter,
- GnomeBluetooth.Column.PROXY, out proxy,
- GnomeBluetooth.Column.ADDRESS, out address,
- GnomeBluetooth.Column.ALIAS, out alias,
- GnomeBluetooth.Column.TYPE, out type,
- GnomeBluetooth.Column.ICON, out icon,
- GnomeBluetooth.Column.CONNECTED, out connected,
- GnomeBluetooth.Column.SERVICES, out services,
- GnomeBluetooth.Column.UUIDS, out uuids);
-
- /* Skip if haven't actually got any information yet */
- if (proxy == null)
- return;
-
- /* Find or create menu item */
- var item = find_menu_item (proxy);
- if (item == null)
- {
- item = new BluetoothMenuItem (client, proxy);
- item.visible = true;
- var last_item = devices_separator as Gtk.MenuItem;
- if (device_items != null)
- last_item = device_items.last ().data;
- device_items.append (item);
- menu.insert (item, menu.get_children ().index (last_item) + 1);
- }
-
- item.update (type, address, alias, icon, connected, services, uuids);
+ return image;
}
- private void device_removed_cb (Gtk.TreePath path)
+ public override unowned Gtk.Menu get_menu ()
{
- Gtk.TreeIter iter;
- if (!client.model.get_iter (out iter, path))
- return;
-
- DBusProxy proxy;
- client.model.get (iter, GnomeBluetooth.Column.PROXY, out proxy);
-
- var item = find_menu_item (proxy);
- if (item == null)
- return;
-
- device_items.remove (item);
- menu.remove (item);
+ return menu;
}
- private void killswitch_state_changed_cb (GnomeBluetooth.KillswitchState state)
+ private void connection_change_cb (bool connected)
{
- updating_killswitch = true;
+ if (!connected)
+ return;
- if (state == GnomeBluetooth.KillswitchState.HARD_BLOCKED)
- {
- icon_name = "bluetooth-inactive";
- status_item.label = _("Bluetooth: Disabled");
- enable_item.visible = false;
- }
- if (state == GnomeBluetooth.KillswitchState.SOFT_BLOCKED)
- {
- icon_name = "bluetooth-inactive";
- status_item.label = _("Bluetooth: Off");
- enable_item.label = _("Turn on Bluetooth");
- enable_item.visible = true;
- enable_value = false;
- }
- else
+ // FIXME: Set proxy to null on disconnect?
+ // FIXME: Use Cancellable to cancel existing connection
+ if (proxy == null)
{
- status_item.label = _("Bluetooth: On");
- enable_item.label = _("Turn off Bluetooth");
- enable_item.visible = true;
- enable_value = true;
+ 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 (update_icon_cb);
+ update_icon_cb ();
+ }
+ catch (IOError e)
+ {
+ warning ("Failed to connect to bluetooth service: %s", e.message);
+ }
+ });
}
+ }
- if (state == GnomeBluetooth.KillswitchState.UNBLOCKED)
- icon_name = "bluetooth-active";
- else
- icon_name = "bluetooth-disabled";
-
- /* Disable devices when locked */
- visible_item.visible = state == GnomeBluetooth.KillswitchState.UNBLOCKED;
- devices_separator.visible = state == GnomeBluetooth.KillswitchState.UNBLOCKED;
- foreach (var item in device_items)
- item.visible = state == GnomeBluetooth.KillswitchState.UNBLOCKED;
-
- updating_killswitch = false;
+ private void update_icon_cb ()
+ {
+ Indicator.image_helper_update (image, proxy.icon_name);
}
}
-private class BluetoothMenuItem : Gtk.ImageMenuItem
+[DBus (name = "com.canonical.indicator.bluetooth.service")]
+public interface BluetoothService : DBusProxy
{
- private GnomeBluetooth.Client client;
- public DBusProxy proxy;
- private Gtk.MenuItem? status_item = null;
- private Gtk.MenuItem? connect_item = null;
-
- public BluetoothMenuItem (GnomeBluetooth.Client client, DBusProxy proxy)
- {
- this.client = client;
- this.proxy = proxy;
- label = ""; /* Workaround for https://bugs.launchpad.net/bugs/1086563 - without a label it thinks this is a separator */
- image = new Gtk.Image ();
- always_show_image = true;
- }
-
- public void update (GnomeBluetooth.Type type, string address, string alias, string icon, bool connected, HashTable? services, string[] uuids)
- {
- label = alias;
- (image as Gtk.Image).icon_name = icon;
-
- submenu = new Gtk.Menu ();
-
- if (services != null)
- {
- status_item = new Gtk.MenuItem ();
- status_item.visible = true;
- status_item.sensitive = false;
- submenu.append (status_item);
-
- connect_item = new Gtk.MenuItem ();
- connect_item.visible = true;
- connect_item.activate.connect (() => { connect_service (proxy.get_object_path (), true); });
- submenu.append (connect_item);
- }
-
- update_connect_items (connected);
-
- var can_send = false;
- var can_browse = false;
- if (uuids != null)
- {
- for (var i = 0; uuids[i] != null; i++)
- {
- if (uuids[i] == "OBEXObjectPush")
- can_send = true;
- if (uuids[i] == "OBEXFileTransfer")
- can_browse = true;
- }
- }
-
- if (can_send)
- {
- var send_item = new Gtk.MenuItem.with_label (_("Send files..."));
- send_item.visible = true;
- send_item.activate.connect (() => { GnomeBluetooth.send_to_address (address, alias); });
- submenu.append (send_item);
- }
-
- if (can_browse)
- {
- var browse_item = new Gtk.MenuItem.with_label (_("Browse files..."));
- browse_item.visible = true;
- browse_item.activate.connect (() => { GnomeBluetooth.browse_address (null, address, Gdk.CURRENT_TIME, null); });
- submenu.append (browse_item);
- }
-
- switch (type)
- {
- case GnomeBluetooth.Type.KEYBOARD:
- var keyboard_item = new Gtk.MenuItem.with_label (_("Keyboard Settings..."));
- keyboard_item.visible = true;
- keyboard_item.activate.connect (() => { show_control_center ("keyboard"); });
- submenu.append (keyboard_item);
- break;
-
- case GnomeBluetooth.Type.MOUSE:
- case GnomeBluetooth.Type.TABLET:
- var mouse_item = new Gtk.MenuItem.with_label (_("Mouse and Touchpad Settings..."));
- mouse_item.visible = true;
- mouse_item.activate.connect (() => { show_control_center ("mouse"); });
- submenu.append (mouse_item);
- break;
-
- case GnomeBluetooth.Type.HEADSET:
- case GnomeBluetooth.Type.HEADPHONES:
- case GnomeBluetooth.Type.OTHER_AUDIO:
- var sound_item = new Gtk.MenuItem.with_label (_("Sound Settings..."));
- sound_item.visible = true;
- sound_item.activate.connect (() => { show_control_center ("sound"); });
- submenu.append (sound_item);
- break;
- }
- }
-
- private void connect_service (string device, bool connect)
- {
- status_item.label = _("Connecting...");
- client.connect_service.begin (device, connect, null, (object, result) =>
- {
- var connected = false;
- try
- {
- connected = client.connect_service.end (result);
- }
- catch (Error e)
- {
- warning ("Failed to connect service: %s", e.message);
- }
- update_connect_items (connected);
- });
- }
-
- private void update_connect_items (bool connected)
- {
- if (status_item != null)
- {
- if (connected)
- status_item.label = _("Connected");
- else
- status_item.label = _("Disconnected");
- }
- if (connect_item != null)
- {
- if (connected)
- connect_item.label = _("Disconnect");
- else
- connect_item.label = _("Connect");
- }
- }
+ public abstract string icon_name { owned get; }
}
-private void show_control_center (string panel)
+public static string get_version ()
{
- try
- {
- Process.spawn_command_line_async ("gnome-control-center %s".printf (panel));
- }
- catch (GLib.SpawnError e)
- {
- warning ("Failed to open control center: %s", e.message);
- }
+ return Indicator.VERSION;
}
-public static int main (string[] args)
+public static GLib.Type get_type ()
{
- Intl.setlocale (LocaleCategory.ALL, "");
- Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
- Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- Intl.textdomain (GETTEXT_PACKAGE);
-
- Gtk.init (ref args);
-
- var indicator = new BluetoothIndicator ();
-
- Gtk.main ();
-
- indicator = null;
-
- return Posix.EXIT_SUCCESS;
+ return typeof (BluetoothIndicator);
}
diff --git a/src/indicator3-0.4.vapi b/src/indicator3-0.4.vapi
new file mode 100644
index 0000000..44204cd
--- /dev/null
+++ b/src/indicator3-0.4.vapi
@@ -0,0 +1,145 @@
+/* indicator-0.4.vapi generated by vapigen, do not modify. */
+
+namespace Indicator {
+ [CCode (cheader_filename = "libindicator/indicator-desktop-shortcuts.h", type_check_function = "INDICATOR_IS_DESKTOP_SHORTCUTS", type_id = "indicator_desktop_shortcuts_get_type")]
+ public class DesktopShortcuts : GLib.Object {
+ [CCode (has_construct_function = false)]
+ public DesktopShortcuts (string file, string identity);
+ public unowned string get_nicks ();
+ public bool nick_exec (string nick);
+ public unowned string nick_get_name (string nick);
+ public string desktop_file { construct; }
+ [NoAccessorMethod]
+ public string identity { owned get; construct; }
+ }
+ [CCode (cheader_filename = "libindicator/indicator-object.h", type_check_function = "INDICATOR_IS_OBJECT", type_id = "indicator_object_get_type ()")]
+ public class Object : GLib.Object {
+ [CCode (has_construct_function = false)]
+ public Object ();
+ public bool check_environment (string env);
+ [NoWrapper]
+ public virtual void entry_activate (Indicator.ObjectEntry entry, uint timestamp);
+ [NoWrapper]
+ public virtual void entry_activate_window (Indicator.ObjectEntry entry, uint windowid, uint timestamp);
+ [NoWrapper]
+ public virtual void entry_being_removed (Indicator.ObjectEntry entry);
+ [NoWrapper]
+ public virtual void entry_close (Indicator.ObjectEntry entry, uint timestamp);
+ [NoWrapper]
+ public virtual void entry_was_added (Indicator.ObjectEntry entry);
+ [CCode (has_construct_function = false)]
+ public Object.from_file (string file);
+ [NoWrapper]
+ public virtual signal unowned string get_accessible_desc ();
+ public virtual GLib.List<weak Indicator.ObjectEntry> get_entries ();
+ public unowned string[] get_environment ();
+ [NoWrapper]
+ public virtual unowned Gtk.Image get_image ();
+ [NoWrapper]
+ public virtual unowned Gtk.Label get_label ();
+ public virtual uint get_location (Indicator.ObjectEntry entry);
+ [NoWrapper]
+ public virtual unowned Gtk.Menu get_menu ();
+ [NoWrapper]
+ public virtual unowned string get_name_hint ();
+ public virtual bool get_show_now (Indicator.ObjectEntry entry);
+ public void set_environment (string[] env);
+ public void set_visible (bool visible);
+ [NoAccessorMethod]
+ public bool indicator_object_default_visibility { get; set; }
+ public virtual signal void accessible_desc_update (Indicator.ObjectEntry entry);
+ public virtual signal void entry_added (Indicator.ObjectEntry entry);
+ public virtual signal void entry_moved (Indicator.ObjectEntry entry, uint old_pos, uint new_pos);
+ public virtual signal void entry_removed (Indicator.ObjectEntry entry);
+ public virtual signal void entry_scrolled (Indicator.ObjectEntry entry, uint delta, Indicator.ScrollDirection direction);
+ public virtual signal void menu_show (Indicator.ObjectEntry entry, uint timestamp);
+ public virtual signal void secondary_activate (Indicator.ObjectEntry entry, uint timestamp);
+ public virtual signal void show_now_changed (Indicator.ObjectEntry entry, bool show_now_state);
+ }
+ [CCode (cheader_filename = "libindicator/indicator-object.h")]
+ [Compact]
+ public class ObjectEntry {
+ public weak string accessible_desc;
+ public weak Gtk.Image image;
+ public weak Gtk.Label label;
+ public weak Gtk.Menu menu;
+ public weak string name_hint;
+ public weak Indicator.Object parent_object;
+ public static void activate (Indicator.Object io, Indicator.ObjectEntry entry, uint timestamp);
+ public static void activate_window (Indicator.Object io, Indicator.ObjectEntry entry, uint windowid, uint timestamp);
+ public static void close (Indicator.Object io, Indicator.ObjectEntry entry, uint timestamp);
+ }
+ [CCode (cheader_filename = "libindicator/indicator-service.h", type_check_function = "INDICATOR_IS_SERVICE", type_id = "indicator_service_get_type")]
+ public class Service : GLib.Object {
+ [CCode (has_construct_function = false)]
+ public Service (string name);
+ [CCode (cname = "indicator_service_new_version", has_construct_function = false)]
+ public Service.with_version (string name, uint version);
+ [NoAccessorMethod]
+ public string name { owned get; set; }
+ [NoAccessorMethod]
+ public uint version { get; set; }
+ public virtual signal void shutdown ();
+ }
+ [CCode (cheader_filename = "libindicator/indicator-service-manager.h", type_check_function = "INDICATOR_IS_SERVICE_MANAGER", type_id = "indicator_service_manager_get_type")]
+ public class ServiceManager : GLib.Object {
+ [CCode (has_construct_function = false)]
+ public ServiceManager (string dbus_name);
+ public bool connected ();
+ public void set_refresh (uint time_in_ms);
+ [CCode (cname = "indicator_service_manager_new_version", has_construct_function = false)]
+ public ServiceManager.with_version (string dbus_name, uint version);
+ [NoAccessorMethod]
+ public string name { owned get; set; }
+ [NoAccessorMethod]
+ public uint version { get; set; }
+ public virtual signal void connection_change (bool connected);
+ }
+ [CCode (cheader_filename = "libindicator/indicator-object.h", cprefix = "INDICATOR_OBJECT_SCROLL_", has_type_id = false)]
+ public enum ScrollDirection {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT
+ }
+ [CCode (cheader_filename = "libindicator/indicator.h", has_target = false)]
+ public delegate GLib.Type get_type_t ();
+ [CCode (cheader_filename = "libindicator/indicator.h", has_target = false)]
+ public delegate unowned string get_version_t ();
+ [CCode (cheader_filename = "libindicator/indicator.h")]
+ public const string GET_TYPE_S;
+ [CCode (cheader_filename = "libindicator/indicator.h")]
+ public const string GET_VERSION_S;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_DEFAULT_VISIBILITY;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_SIGNAL_ENTRY_ADDED;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_SIGNAL_ENTRY_MOVED;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_SIGNAL_ENTRY_REMOVED;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_SIGNAL_ENTRY_SCROLLED;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_SIGNAL_MENU_SHOW;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_SIGNAL_SECONDARY_ACTIVATE;
+ [CCode (cheader_filename = "libindicator/indicator-gobject.h")]
+ public const string OBJECT_SIGNAL_SHOW_NOW_CHANGED;
+ [CCode (cheader_filename = "libindicator/indicator-service-manager.h")]
+ public const string SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE;
+ [CCode (cheader_filename = "libindicator/indicator-service.h")]
+ public const string SERVICE_SIGNAL_SHUTDOWN;
+ [CCode (cheader_filename = "libindicator/indicator.h")]
+ public const int SET_VERSION;
+ [CCode (cheader_filename = "libindicator/indicator.h")]
+ public const string VERSION;
+ [CCode (cheader_filename = "libindicator/indicator.h", cname = "get_version")]
+ public static unowned string get_version ();
+ [CCode (cheader_filename = "libindicator/indicator-image-helper.h")]
+ public static unowned Gtk.Image image_helper (string name);
+ [CCode (cheader_filename = "libindicator/indicator-image-helper.h")]
+ public static void image_helper_update (Gtk.Image image, string name);
+} \ No newline at end of file
diff --git a/src/libido3-0.1.vapi b/src/libido3-0.1.vapi
new file mode 100644
index 0000000..1d17cac
--- /dev/null
+++ b/src/libido3-0.1.vapi
@@ -0,0 +1,9 @@
+namespace Ido
+{
+ [CCode (cheader_filename = "libido/idoswitchmenuitem.h")]
+ public class SwitchMenuItem : Gtk.CheckMenuItem
+ {
+ public SwitchMenuItem ();
+ public Gtk.Container content_area { get; }
+ }
+}