using GLib; namespace Dino.Ui { public struct StatusNotifierIconPixmap { public int width; public int height; public uint8[] data; } public struct StatusNotifierToolTip { public string icon_name; public StatusNotifierIconPixmap[] icon_pixmap; public string title; public string description; } [DBus (name = "org.kde.StatusNotifierItem")] public class StatusNotifierItem : Object { private const string BUS_NAME_TEMPLATE = "org.kde.StatusNotifierItem-%d-1"; private const string ICON_NAME = "im.dino.Dino"; private const string ITEM_OBJECT_PATH = "/StatusNotifierItem"; private const string MENU_OBJECT_PATH = "/MenuBar"; private const string WATCHER_BUS_NAME = "org.kde.StatusNotifierWatcher"; private const string WATCHER_INTERFACE = "org.kde.StatusNotifierWatcher"; private const string WATCHER_OBJECT_PATH = "/StatusNotifierWatcher"; private weak Application application; private DBusConnection connection; private string bus_name; private bool name_acquired; private bool registration_in_progress; private bool shutting_down; private bool watcher_available; private bool registered_with_watcher; private string? activation_token; private string? watcher_owner; private Cancellable registration_cancellable = new Cancellable(); private StatusNotifierMenu status_notifier_menu; private uint bus_name_owner_id; private uint menu_registration_id; private uint object_registration_id; private uint watcher_id; public string category { owned get { return "Communications"; } } public string id { owned get { return "Dino"; } } public string title { owned get { return "Dino"; } } public string status { owned get { return "Active"; } } public int window_id { get { return 0; } } public string icon_theme_path { owned get { return ""; } } public ObjectPath menu { owned get { return new ObjectPath(MENU_OBJECT_PATH); } } public bool item_is_menu { get { return false; } } public string icon_name { owned get { return ICON_NAME; } } public StatusNotifierIconPixmap[] icon_pixmap { owned get { return new StatusNotifierIconPixmap[0]; } } public string overlay_icon_name { owned get { return ""; } } public StatusNotifierIconPixmap[] overlay_icon_pixmap { owned get { return new StatusNotifierIconPixmap[0]; } } public string attention_icon_name { owned get { return ""; } } public StatusNotifierIconPixmap[] attention_icon_pixmap { owned get { return new StatusNotifierIconPixmap[0]; } } public string attention_movie_name { owned get { return ""; } } public StatusNotifierToolTip tool_tip { owned get { StatusNotifierToolTip tool_tip = StatusNotifierToolTip(); tool_tip.icon_name = ICON_NAME; tool_tip.icon_pixmap = new StatusNotifierIconPixmap[0]; tool_tip.title = "Dino"; tool_tip.description = _("Open Dino"); return tool_tip; } } public signal void new_title(); public signal void new_icon(); public signal void new_attention_icon(); public signal void new_overlay_icon(); public signal void new_menu(); public signal void new_tool_tip(); public signal void new_status(string status); public StatusNotifierItem(Application application) throws IOError { this.application = application; this.connection = Bus.get_sync(BusType.SESSION); this.bus_name = BUS_NAME_TEMPLATE.printf((int) Posix.getpid()); status_notifier_menu = new StatusNotifierMenu(application); menu_registration_id = connection.register_object(MENU_OBJECT_PATH, status_notifier_menu); object_registration_id = connection.register_object(ITEM_OBJECT_PATH, this); bus_name_owner_id = Bus.own_name_on_connection( connection, bus_name, BusNameOwnerFlags.NONE, () => { name_acquired = true; register_with_watcher.begin(); }, () => { name_acquired = false; registered_with_watcher = false; }); watcher_id = Bus.watch_name_on_connection( connection, WATCHER_BUS_NAME, BusNameWatcherFlags.NONE, (watcher_connection, watcher_name, name_owner) => { watcher_owner = name_owner; watcher_available = true; registered_with_watcher = false; register_with_watcher.begin(); }, () => { watcher_owner = null; watcher_available = false; registered_with_watcher = false; }); } internal void shutdown() { shutting_down = true; name_acquired = false; watcher_available = false; registration_cancellable.cancel(); if (watcher_id != 0) { Bus.unwatch_name(watcher_id); watcher_id = 0; } if (bus_name_owner_id != 0) { Bus.unown_name(bus_name_owner_id); bus_name_owner_id = 0; } if (object_registration_id != 0) { connection.unregister_object(object_registration_id); object_registration_id = 0; } if (menu_registration_id != 0) { connection.unregister_object(menu_registration_id); menu_registration_id = 0; } } public void provide_xdg_activation_token(string token) throws Error { activation_token = token; } public void context_menu(int x, int y) throws Error { } public void activate(int x, int y) throws Error { show_window(); } public void secondary_activate(int x, int y) throws Error { show_window(); } public void scroll(int delta, string orientation) throws Error { } private async void register_with_watcher() { if (shutting_down || !name_acquired || !watcher_available || registered_with_watcher || registration_in_progress) return; registration_in_progress = true; string? registering_watcher = watcher_owner; try { yield connection.call( WATCHER_BUS_NAME, WATCHER_OBJECT_PATH, WATCHER_INTERFACE, "RegisterStatusNotifierItem", new Variant("(s)", bus_name), null, DBusCallFlags.NONE, 5000, registration_cancellable); if (!shutting_down && name_acquired && watcher_owner == registering_watcher) { registered_with_watcher = true; } } catch (Error e) { if (!(e is IOError.CANCELLED)) { warning("Could not register Dino's tray icon: %s", e.message); } } registration_in_progress = false; if (!shutting_down && name_acquired && watcher_available && !registered_with_watcher && watcher_owner != registering_watcher) { register_with_watcher.begin(); } } private void show_window() { if (application.window == null) { application.activate(); return; } if (activation_token != null) { application.window.set_startup_id(activation_token); activation_token = null; } application.window.present(); } } }