diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/meson.build | 28 | ||||
-rw-r--r-- | src/tray.vala | 16 | ||||
-rw-r--r-- | src/trayItem.vala | 175 | ||||
-rw-r--r-- | src/watcherProxy.vala | 49 |
4 files changed, 196 insertions, 72 deletions
diff --git a/src/meson.build b/src/meson.build index af71701..9110030 100644 --- a/src/meson.build +++ b/src/meson.build @@ -10,8 +10,29 @@ deps = [ dependency('gio-2.0'), dependency('json-glib-1.0'), dependency('gdk-pixbuf-2.0'), + dependency('gtk+-3.0'), ] +dbusmenu_cflags = run_command( + find_program('pkg-config', required: true), + '--cflags', + 'dbusmenu-gtk3-0.4', + 'gobject-introspection-1.0', + 'gobject-2.0', 'glib-2.0', + capture: true, + check: true, +).stdout().strip() + +dbusmenu_libs = run_command( + find_program('pkg-config', required: true), + '--libs', + 'dbusmenu-gtk3-0.4', + 'gobject-introspection-1.0', + 'gobject-2.0', 'glib-2.0', + capture: true, + check: true, +).stdout().strip() + sources = files( 'tray.vala', 'watcher.vala', @@ -21,11 +42,14 @@ sources = files( libtray = library( meson.project_name(), sources, - dependencies: deps, + dependencies: deps + meson.get_compiler('vala').find_library('posix'), vala_header: meson.project_name() + '.h', vala_vapi: meson.project_name() + '.vapi', vala_gir: tray_gir, + vala_args: ['--pkg', 'DbusmenuGtk3-0.4', '--pkg', 'Dbusmenu-0.4'], version: meson.project_version(), + c_args: dbusmenu_cflags.split(' '), + link_args: dbusmenu_libs.split(' '), install: true, install_dir: [true, true, true, true], ) @@ -37,7 +61,7 @@ import('pkgconfig').generate( filebase: meson.project_name() + '-' + api_version, version: meson.project_version(), subdirs: meson.project_name(), - requires: 'gio-2.0', + requires: deps + [dependency('dbusmenu-gtk3-0.4')], install_dir: get_option('libdir') / 'pkgconfig', ) diff --git a/src/tray.vala b/src/tray.vala index 380eaa1..5bf9270 100644 --- a/src/tray.vala +++ b/src/tray.vala @@ -22,7 +22,7 @@ public class Tray : Object { private IWatcher proxy; private HashTable<string, TrayItem> _items; - public TrayItem[] items { get { return _items.get_values_as_ptr_array().data; }} + public List<weak TrayItem> items { owned get { return _items.get_values(); }} public signal void item_added(string service); public signal void item_removed(string service); @@ -38,6 +38,9 @@ public class Tray : Object { start_watcher, () => { if (proxy != null) { + //foreach (string item in proxy.RegisteredStatusNotifierItems) { + // on_item_unregister(item); + //} proxy = null; } }, @@ -68,18 +71,23 @@ public class Tray : Object { proxy.StatusNotifierItemRegistered.connect(on_item_register); proxy.StatusNotifierItemUnregistered.connect(on_item_unregister); + + foreach (string item in proxy.RegisteredStatusNotifierItems) { + on_item_register(item); + } } private void on_item_register(string service) { if(_items.contains(service)) return; string[] parts = service.split("/", 2); TrayItem item = new TrayItem(parts[0], "/" + parts[1]); - _items.set(service, item); - item_added(service); + item.ready.connect(() => { + _items.set(service, item); + item_added(service); + }); } private void on_item_unregister(string service) { - string[] parts = service.split("/", 2); _items.remove(service); item_removed(service); } diff --git a/src/trayItem.vala b/src/trayItem.vala index b4f8207..6bee7ed 100644 --- a/src/trayItem.vala +++ b/src/trayItem.vala @@ -1,3 +1,6 @@ +using DbusmenuGtk; +using Posix; + namespace AstalTray { public struct Pixmap { @@ -8,7 +11,7 @@ namespace AstalTray { public struct Tooltip { string icon_name; - Pixmap icon; + Pixmap[] icon; string title; string description; } @@ -41,11 +44,11 @@ internal interface IItem : DBusProxy { public abstract string Title { owned get; } public abstract Category Category { owned get; } public abstract Status Status { owned get; } - public abstract Tooltip Tooltip { owned get; } + public abstract Tooltip? ToolTip { owned get; } public abstract string Id { owned get; } - public abstract string IconThemePath { owned get; } + public abstract string? IconThemePath { owned get; } public abstract bool ItemIsMenu { owned get; } - public abstract ObjectPath Menu { owned get; } + public abstract ObjectPath? Menu { owned get; } public abstract string IconName { owned get; } public abstract Pixmap[] IconPixmap { owned get; } public abstract string AttentionIconName { owned get; } @@ -75,42 +78,180 @@ public class TrayItem : Object { public string title { owned get { return proxy.Title; } } public Category category { get { return proxy.Category; } } public Status status { get { return proxy.Status; } } - public Tooltip tooltip { owned get { return proxy.Tooltip; } } - public string tooltip_string { owned get { return proxy.Tooltip.title; } } + public Tooltip? tooltip { owned get { return proxy.ToolTip; } } + public string tooltip_markup { + owned get { + if(proxy.ToolTip == null) return ""; + + string tt = proxy.ToolTip.title; + if (proxy.ToolTip.description != "") + tt += "\n" + proxy.ToolTip.description; + + return tt; + } + } public string id { owned get { return proxy.Id ;} } public string icon_theme_path { owned get { return proxy.IconThemePath ;} } public bool is_menu { get { return proxy.ItemIsMenu ;} } - public signal void removed(); + public DbusmenuGtk.Menu? menu { get; private set;} + public string icon_name { + owned get { + if(proxy.Status == Status.NEEDS_ATTENTION) + return proxy.AttentionIconName; + else return proxy.IconName; + } + } + + public Gdk.Pixbuf icon_pixbuf { owned get { return _get_icon_pixbuf(); } } + + public signal void changed(); + public signal void ready(); public TrayItem(string service, string path) { connection_ids = new List<ulong>(); + setup_proxy(service, path); + + } - proxy = Bus.get_proxy_sync( + private async void setup_proxy(string service, string path) { + + proxy = yield Bus.get_proxy( BusType.SESSION, service, path ); - - //connection_ids.append(proxy.NewIcon.connect(() => notify(icon))); - connection_ids.append(proxy.NewTitle.connect(() => notify_property("title"))); - connection_ids.append(proxy.NewToolTip.connect(() => { - notify_property("tooltip"); - notify_property("tooltip_string"); - })); - connection_ids.append(proxy.NewStatus.connect(() => notify_property("status"))); + + if(proxy.Menu != null) { + menu = new DbusmenuGtk.Menu( + proxy.get_name_owner(), + proxy.Menu); + } + + connection_ids.append(proxy.NewStatus.connect(() => refresh_all_properties())); + connection_ids.append(proxy.NewToolTip.connect(() => refresh_all_properties())); + connection_ids.append(proxy.NewTitle.connect(() => refresh_all_properties())); + connection_ids.append(proxy.NewIcon.connect(() => refresh_all_properties())); proxy.notify["g-name-owner"].connect( () => { if (proxy.g_name_owner == null) { foreach (var id in connection_ids) SignalHandler.disconnect(proxy, id); + } + } + ); + + ready(); + + } + + private void _notify() { + string[] props = { + "category", "id", "title", "status", "is-menu", + "tooltip-markup" + }; + + foreach (string prop in props) + notify_property(prop); + + changed(); + } + + private void refresh_all_properties() { + proxy.g_connection.call.begin( + proxy.g_name, + proxy.g_object_path, + "org.freedesktop.DBus.Properties", + "GetAll", + new Variant("(s)", proxy.g_interface_name), + new VariantType("(a{sv})"), + DBusCallFlags.NONE, + -1, + null, + (_, result) => { + try { + Variant parameters = proxy.g_connection.call.end(result); + VariantIter prop_iter; + parameters.get("(a{sv})", out prop_iter); + + string prop_key; + Variant prop_value; - removed(); + while (prop_iter.next ("{sv}", out prop_key, out prop_value)) { + proxy.set_cached_property(prop_key, prop_value); } + _notify(); + + } catch(Error e) { + //silently ignore } + }); + } + + + public Gdk.Pixbuf? _get_icon_pixbuf() { + Pixmap[] pixmaps = proxy.Status == Status.NEEDS_ATTENTION + ? proxy.AttentionIconPixmap + : proxy.IconPixmap; + + + string icon_name = proxy.Status == Status.NEEDS_ATTENTION + ? proxy.AttentionIconName + : proxy.IconName; + + Gdk.Pixbuf pixbuf = null; + + + if(icon_name != null && proxy.IconThemePath != null) + pixbuf = load_from_theme(icon_name, proxy.IconThemePath); + if (pixbuf == null) pixbuf = pixmap_to_pixbuf(pixmaps); + + return pixbuf; + + } + + private Gdk.Pixbuf? load_from_theme(string icon_name, string theme_path) { + if(theme_path == "" || theme_path == null) return null; + if(icon_name == "" || icon_name == null) return null; + + Gtk.IconTheme icon_theme = new Gtk.IconTheme(); + string[] paths = {theme_path}; + icon_theme.set_search_path(paths); + + int size = icon_theme.get_icon_sizes(icon_name)[0]; + Gtk.IconInfo icon_info = icon_theme.lookup_icon( + icon_name, size, Gtk.IconLookupFlags.FORCE_SIZE); + + if (icon_info != null) + return icon_info.load_icon(); + return null; + } + + private Gdk.Pixbuf? pixmap_to_pixbuf(Pixmap[] pixmaps) { + if(pixmaps == null || pixmaps.length == 0) return null; + Pixmap pixmap = pixmaps[0]; + uint8[] image_data = pixmap.bytes.copy(); + + for (int i = 0; i < pixmap.width * pixmap.height * 4; i += 4) { + uint8 alpha = image_data[i]; + image_data[i] = image_data[i + 1]; + image_data[i + 1] = image_data[i + 2]; + image_data[i + 2] = image_data[i + 3]; + image_data[i + 3] = alpha; + } + + return new Gdk.Pixbuf.from_bytes( + new Bytes(image_data), + Gdk.Colorspace.RGB, + true, + 8, + (int)pixmap.width, + (int)pixmap.height, + (int)(pixmap.width * 4) ); + } } } diff --git a/src/watcherProxy.vala b/src/watcherProxy.vala deleted file mode 100644 index 18cb296..0000000 --- a/src/watcherProxy.vala +++ /dev/null @@ -1,49 +0,0 @@ -namespace AstalTray { - -[DBus (name="org.kde.StatusNotifierWatcher")] -internal interface IWatcher : Object { - - public abstract string[] RegisteredStatusNotifierItems { get; } - public abstract int ProtocolVersion { 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(); - -} - - -internal class StatusNotifierWatcherProxy : Object { - - - private IWatcher proxy; - - public string[] RegisteredStatusNotifierItems { get { return proxy.RegisteredStatusNotifierItems; } } - public int ProtocolVersion { get {return proxy.ProtocolVersion;} } - - public signal void StatusNotifierItemRegistered(string service); - public signal void StatusNotifierItemUnregistered(string service); - - construct { - - proxy = Bus.get_proxy_sync( - BusType.SESSION, - "org.kde.StatusNotifierWatcher", - "/StatusNotifierWatcher" - ); - - foreach (string item in proxy.RegisteredStatusNotifierItems) { - StatusNotifierItemRegistered(item); - } - - proxy.StatusNotifierItemRegistered.connect((s) => StatusNotifierItemRegistered(s)); - proxy.StatusNotifierItemUnregistered.connect((s) => StatusNotifierItemUnregistered(s)); - - } - -} -} |