diff options
Diffstat (limited to 'lib/tray/tray.vala')
-rw-r--r-- | lib/tray/tray.vala | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/lib/tray/tray.vala b/lib/tray/tray.vala new file mode 100644 index 0000000..09b0643 --- /dev/null +++ b/lib/tray/tray.vala @@ -0,0 +1,135 @@ +namespace AstalTray { +[DBus (name="org.kde.StatusNotifierWatcher")] +internal interface IWatcher : Object { + public abstract string[] RegisteredStatusNotifierItems { owned get; } + public abstract int ProtocolVersion { owned get; } + + public abstract void RegisterStatusNotifierItem(string service, BusName sender) throws DBusError, IOError; + public abstract void RegisterStatusNotifierHost(string service) throws DBusError, IOError; + + public signal void StatusNotifierItemRegistered(string service); + public signal void StatusNotifierItemUnregistered(string service); + public signal void StatusNotifierHostRegistered(); + public signal void StatusNotifierHostUnregistered(); +} + +public Tray get_default() { + return Tray.get_default(); +} + +public class Tray : Object { + private static Tray? instance; + public static unowned Tray get_default() { + if (instance == null) + instance = new Tray(); + + return instance; + } + + private StatusNotifierWatcher watcher; + private IWatcher proxy; + + private HashTable<string, TrayItem> _items = + new HashTable<string, TrayItem>(str_hash, str_equal); + + public List<weak TrayItem> items { owned get { return _items.get_values(); }} + + public signal void item_added(string service) { + notify_property("items"); + } + + public signal void item_removed(string service) { + notify_property("items"); + } + + construct { + try { + Bus.own_name( + BusType.SESSION, + "org.kde.StatusNotifierWatcher", + BusNameOwnerFlags.NONE, + start_watcher, + () => { + if (proxy != null) { + proxy = null; + } + }, + start_host + ); + } catch (Error err) { + critical(err.message); + } + + } + + private void start_watcher(DBusConnection conn) { + try { + watcher = new StatusNotifierWatcher(); + conn.register_object("/StatusNotifierWatcher", watcher); + watcher.StatusNotifierItemRegistered.connect(on_item_register); + watcher.StatusNotifierItemUnregistered.connect(on_item_unregister); + } catch (Error err) { + critical(err.message); + } + } + + private void start_host() { + if (proxy != null) + return; + + try { + proxy = Bus.get_proxy_sync(BusType.SESSION, + "org.kde.StatusNotifierWatcher", + "/StatusNotifierWatcher"); + + proxy.StatusNotifierItemRegistered.connect(on_item_register); + proxy.StatusNotifierItemUnregistered.connect(on_item_unregister); + + proxy.notify["g-name-owner"].connect(() => { + _items.foreach((service, _) => { + item_removed(service); + }); + + _items.remove_all(); + + if(proxy != null) { + foreach (string item in proxy.RegisteredStatusNotifierItems) { + on_item_register(item); + } + } else { + foreach (string item in watcher.RegisteredStatusNotifierItems) { + on_item_register(item); + } + } + }); + + foreach (string item in proxy.RegisteredStatusNotifierItems) { + on_item_register(item); + } + } catch (Error err) { + critical("cannot get proxy: %s", err.message); + } + } + + private void on_item_register(string service) { + if (_items.contains(service)) + return; + + var parts = service.split("/", 2); + TrayItem item = new TrayItem(parts[0], "/" + parts[1]); + item.ready.connect(() => { + _items.set(service, item); + item_added(service); + }); + } + + private void on_item_unregister(string service) { + _items.remove(service); + item_removed(service); + } + + public TrayItem get_item(string service) { + return _items.get(service); + } +} +} |