summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/tray/trayItem.vala395
1 files changed, 277 insertions, 118 deletions
diff --git a/lib/tray/trayItem.vala b/lib/tray/trayItem.vala
index b335eb6..787e9ae 100644
--- a/lib/tray/trayItem.vala
+++ b/lib/tray/trayItem.vala
@@ -3,6 +3,34 @@ public struct Pixmap {
int width;
int height;
uint8[] bytes;
+
+ internal static Pixmap from_variant(GLib.Variant variant) {
+ Pixmap pixmap = new Pixmap();
+
+ int width, height;
+ Variant data;
+
+ variant.get("(ii@ay)", out width, out height, out data);
+ pixmap.width = width;
+ pixmap.height = height;
+ pixmap.bytes = data.get_data_as_bytes().get_data();
+
+
+ return pixmap;
+ }
+
+ internal static Pixmap[] array_from_variant(GLib.Variant variant) {
+ Pixmap[] icons = new Pixmap[0];
+
+ GLib.VariantIter iter = variant.iterator();
+
+ GLib.Variant child;
+ while ((child = iter.next_value()) != null) {
+ Pixmap pm = Pixmap.from_variant(child);
+ icons += pm;
+ }
+ return icons;
+ }
}
public struct Tooltip {
@@ -10,6 +38,36 @@ public struct Tooltip {
Pixmap[] icon;
string title;
string description;
+
+
+ internal static Tooltip from_variant(GLib.Variant variant) {
+ Tooltip tooltip = Tooltip();
+
+ string icon_name;
+ GLib.VariantIter iter;
+ string title;
+ string description;
+
+ variant.get("(sa(iiay)ss)", out icon_name, out iter, out title, out description);
+ tooltip.icon_name = icon_name;
+ tooltip.title = title;
+ tooltip.description = description;
+
+ int x, y;
+ uint8[] data;
+ GLib.Variant child;
+
+ Pixmap[] icons = new Pixmap[0];
+
+ while ((child = iter.next_value()) != null) {
+ Pixmap pm = Pixmap.from_variant(child);
+ icons += pm;
+ }
+
+ tooltip.icon = icons;
+
+ return tooltip;
+ }
}
[DBus (use_string_marshalling = true)]
@@ -31,6 +89,8 @@ public enum Category {
unowned var eval = enumc.get_value(this);
return eval.value_nick;
}
+
+ public static extern Category from_string(string value) throws Error;
}
@@ -50,24 +110,27 @@ public enum Status {
unowned var eval = enumc.get_value(this);
return eval.value_nick;
}
+
+ public static extern Status from_string(string value) throws Error;
}
[DBus (name="org.kde.StatusNotifierItem")]
internal interface IItem : DBusProxy {
- public abstract string Title { owned get; }
- public abstract Category Category { get; }
- public abstract Status Status { get; }
- public abstract Tooltip? ToolTip { owned get; }
- public abstract string Id { owned get; }
- public abstract string? IconThemePath { owned get; }
- public abstract bool ItemIsMenu { 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; }
- public abstract Pixmap[] AttentionIconPixmap { owned get; }
- public abstract string OverlayIconName { owned get; }
- public abstract Pixmap[] OverlayIconPixmap { owned get; }
+
+ // public abstract string Id { owned get; }
+ // public abstract Category Category { get; }
+ // public abstract string Title { owned get; }
+ // public abstract Status Status { get; }
+ // public abstract Tooltip? ToolTip { owned get; }
+ // public abstract string IconThemePath { owned get; }
+ // public abstract bool ItemIsMenu { 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; }
+ // public abstract Pixmap[] AttentionIconPixmap { owned get; }
+ // public abstract string OverlayIconName { owned get; }
+ // public abstract Pixmap[] OverlayIconPixmap { owned get; }
public abstract void ContexMenu(int x, int y) throws DBusError, IOError;
public abstract void Activate(int x, int y) throws DBusError, IOError;
@@ -84,19 +147,20 @@ internal interface IItem : DBusProxy {
public class TrayItem : Object {
private IItem proxy;
- private List<ulong> connection_ids;
+ private bool needs_update = false;
+
/** The Title of the TrayItem */
- public string title { owned get { return proxy.Title; } }
+ public string title { get; private set; }
/** The category this item belongs to */
- public Category category { get { return proxy.Category; } }
+ public Category category { get; private set; }
/** The current status of this item */
- public Status status { get { return proxy.Status; } }
+ public Status status { get; private set; }
/** The tooltip of this item */
- public Tooltip? tooltip { owned get { return proxy.ToolTip; } }
+ public Tooltip? tooltip { get; private set; }
/**
* A markup representation of the tooltip. This is basically equvivalent
@@ -104,36 +168,40 @@ public class TrayItem : Object {
*/
public string tooltip_markup {
owned get {
- if (proxy.ToolTip == null)
+ if (tooltip == null)
return "";
- var tt = proxy.ToolTip.title;
- if (proxy.ToolTip.description != "")
- tt += "\n" + proxy.ToolTip.description;
+ var tt = tooltip.title;
+ if (tooltip.description != "")
+ tt += "\n" + tooltip.description;
return tt;
}
}
/** the id of the item. This id is specified by the tray app.*/
- public string id { owned get { return proxy.Id ;} }
+ public string id { get; private set; }
/**
* If set, this only supports the menu, so showing the menu should be prefered
* over calling [[email protected]].
*/
- public bool is_menu {
- get {
- return proxy.ItemIsMenu || proxy.get_cached_property("ItemIsMenu") == null;
- }
- }
+ public bool is_menu { get; private set; default = true; }
/**
* The icon theme path, where to look for the [[email protected]:icon-name].
* It is recommended to use the [[email protected]:gicon] property,
* which does the icon lookups for you.
*/
- public string icon_theme_path { owned get { return proxy.IconThemePath ;} }
+ public string icon_theme_path { get; private set; }
+
+ // icon properties from the dbus for internal use only
+ private string IconName;
+ private Pixmap[] IconPixmap;
+ private string AttentionIconName;
+ private Pixmap[] AttentionIconPixmap;
+ private string OverlayIconName;
+ private Pixmap[] OverlayIconPixmap;
/**
* The name of the icon. This should be looked up in the [[email protected]:icon-theme-path]
@@ -143,9 +211,9 @@ public class TrayItem : Object {
*/
public string icon_name {
owned get {
- return proxy.Status == Status.NEEDS_ATTENTION
- ? proxy.AttentionIconName
- : proxy.IconName;
+ return status == Status.NEEDS_ATTENTION
+ ? AttentionIconName
+ : IconName;
}
}
@@ -167,6 +235,9 @@ public class TrayItem : Object {
/** The id of the item used to uniquely identify the TrayItems by this lib.*/
public string item_id { get; private set; }
+ /** The object path to the dbusmenu */
+ public ObjectPath menu_path { get; private set; }
+
private DBusMenu.Importer menu_importer;
/**
@@ -196,7 +267,6 @@ public class TrayItem : Object {
public signal void ready();
internal TrayItem(string service, string path) {
- connection_ids = new List<ulong>();
item_id = service + path;
setup_proxy.begin(service, path, (_, res) => setup_proxy.end(res));
}
@@ -209,109 +279,198 @@ public class TrayItem : Object {
path
);
- proxy.g_default_timeout = 1000;
-
- 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);
- }
- });
-
- Variant? menuVariant = proxy.get_cached_property("Menu");
- if (proxy.Menu != null && menuVariant != null && menuVariant.is_of_type(VariantType.OBJECT_PATH)) {
- this.menu_importer = new DBusMenu.Importer(proxy.get_name_owner(), proxy.Menu);
- this.menu_importer.notify["model"].connect(() => {
- notify_property("menu-model");
- notify_property("action-group");
- });
- }
+ proxy.g_signal.connect(handle_signal);
- update_gicon();
+ yield refresh_all_properties();
ready();
} catch (Error err) {
critical(err.message);
}
}
- private void _notify() {
- string[] props = {
- "category",
- "id",
- "title",
- "status",
- "is-menu",
- "tooltip-markup",
- "icon-name",
- "icon-pixbuf"
- };
-
- foreach (string prop in props) {
- notify_property(prop);
- }
-
- changed();
- }
-
private void update_gicon() {
if (icon_name != null && icon_name != "") {
if (GLib.FileUtils.test(icon_name, GLib.FileTest.EXISTS)) {
gicon = new GLib.FileIcon(GLib.File.new_for_path(icon_name));
}
else if(icon_theme_path != null && icon_theme_path != "") {
- gicon = new GLib.FileIcon(GLib.File.new_for_path(
- find_icon_in_theme(icon_name, icon_theme_path)
- ));
+ string path = find_icon_in_theme(icon_name, icon_theme_path);
+ if(path != null) gicon = new GLib.FileIcon(GLib.File.new_for_path(path));
+ else gicon = new GLib.ThemedIcon(icon_name);
} else {
gicon = new GLib.ThemedIcon(icon_name);
}
}
else {
- Pixmap[] pixmaps = proxy.Status == Status.NEEDS_ATTENTION
- ? proxy.AttentionIconPixmap
- : proxy.IconPixmap;
+ Pixmap[] pixmaps = status == Status.NEEDS_ATTENTION
+ ? AttentionIconPixmap
+ : IconPixmap;
gicon = pixmap_to_pixbuf(pixmaps);
}
}
+ private void handle_signal(DBusProxy proxy, string? sender_name, string signal_name, Variant parameters) {
+ if (needs_update) return;
+ needs_update = true;
+ GLib.Timeout.add_once(10, () => {
+ needs_update = false;
+ refresh_all_properties.begin();
+ });
+ }
- 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;
-
- while (prop_iter.next ("{sv}", out prop_key, out prop_value)) {
- proxy.set_cached_property(prop_key, prop_value);
- }
+ private void set_dbus_property(string prop_name, Variant prop_value) {
+ try {
+ switch(prop_name) {
+ case "Category": {
+ var new_category = Category.from_string(prop_value.get_string());
+ if (category != new_category) {
+ category = new_category;
+ }
+ break;
+ }
+ case "Id": {
+ var new_id = prop_value.get_string();
+ if (id != new_id) {
+ id = new_id;
+ }
+ break;
+ }
+ case "Title": {
+ var new_title = prop_value.get_string();
+ if (title != new_title) {
+ title = new_title;
+ }
+ break;
+ }
+ case "Status": {
+ var new_status = Status.from_string(prop_value.get_string());
+ if (status != new_status) {
+ status = new_status;
+ update_gicon();
+ }
+ break;
+ }
+ case "ToolTip": {
+ tooltip = Tooltip.from_variant(prop_value);
+ break;
+ }
+ case "IconThemePath": {
+ var new_path = prop_value.get_string();
+ if (icon_theme_path != new_path) {
+ icon_theme_path = new_path;
+ update_gicon();
+ }
+ break;
+ }
+ case "ItemIsMenu": {
+ var new_is_menu = prop_value.get_boolean();
+ if (is_menu != new_is_menu) {
+ is_menu = new_is_menu;
+ }
+ break;
+ }
+ case "Menu": {
+ if(!prop_value.is_of_type(VariantType.OBJECT_PATH)) break;
+ var new_menu_path = (ObjectPath) prop_value.get_string();
+ if (new_menu_path != menu_path) {
+ menu_path = new_menu_path;
+ if (menu_path != null) {
+ this.menu_importer = new DBusMenu.Importer(proxy.get_name_owner(), menu_path);
+ this.menu_importer.notify["model"].connect(() => {
+ notify_property("menu-model");
+ notify_property("action-group");
+ });
+ } else {
+ this.menu_importer = null;
+ notify_property("menu-model");
+ notify_property("action-group");
+ }
+ }
+ break;
+ }
+ case "IconName": {
+ var new_icon_name = prop_value.get_string();
+ if (IconName != new_icon_name) {
+ IconName = new_icon_name;
+ notify_property("icon-name");
+ update_gicon();
+ }
+ break;
+ }
+ case "IconPixmap": {
+ IconPixmap = Pixmap.array_from_variant(prop_value);
update_gicon();
-
- _notify();
- } catch(Error e) {
- //silently ignore
+ notify_property("icon-pixbuf");
+ break;
+ }
+ case "AttentionIconName": {
+ var new_attention_icon_name = prop_value.get_string();
+ if (AttentionIconName != new_attention_icon_name) {
+ AttentionIconName = new_attention_icon_name;
+ update_gicon();
+ notify_property("icon-name");
+ }
+ break;
+ }
+ case "AttentionIconPixmap": {
+ AttentionIconPixmap = Pixmap.array_from_variant(prop_value);
+ update_gicon();
+ notify_property("icon-pixbuf");
+ break;
+ }
+ case "OverlayIconName": {
+ var new_overlay_icon_name = prop_value.get_string();
+ if (OverlayIconName != new_overlay_icon_name) {
+ OverlayIconName = new_overlay_icon_name;
+ update_gicon();
+ notify_property("icon-name");
+ }
+ break;
+ }
+ case "OverlayIconPixmap": {
+ OverlayIconPixmap = Pixmap.array_from_variant(prop_value);
+ update_gicon();
+ notify_property("icon-pixbuf");
+ break;
}
}
- );
+ }
+ catch(Error e) {
+ //silently ignore
+ }
+ }
+
+
+ private async void refresh_all_properties() {
+ this.freeze_notify();
+ try {
+ Variant parameters = yield proxy.g_connection.call(
+ 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);
+
+ VariantIter prop_iter;
+ parameters.get("(a{sv})", out prop_iter);
+
+ string prop_key;
+ Variant prop_value;
+
+ while (prop_iter.next ("{sv}", out prop_key, out prop_value)) {
+ set_dbus_property(prop_key, prop_value);
+ }
+ }
+ catch(Error e) {
+ //silently ignode
+ }
+ this.thaw_notify();
+ this.changed();
}
/**
@@ -320,11 +479,11 @@ public class TrayItem : Object {
* before openening the menu.
*/
public void about_to_show() {
- if(proxy.Menu == null) return;
+ if(menu_path == null) return;
try {
Bus.get_sync(BusType.SESSION).call_sync(
this.proxy.g_name_owner,
- this.proxy.Menu,
+ menu_path,
"com.canonical.dbusmenu",
"AboutToShow",
new Variant("(i)", 0),
@@ -411,15 +570,15 @@ public class TrayItem : Object {
}
private Gdk.Pixbuf? _get_icon_pixbuf() {
- Pixmap[] pixmaps = proxy.Status == Status.NEEDS_ATTENTION
- ? proxy.AttentionIconPixmap
- : proxy.IconPixmap;
+ Pixmap[] pixmaps = status == Status.NEEDS_ATTENTION
+ ? AttentionIconPixmap
+ : IconPixmap;
return pixmap_to_pixbuf(pixmaps);
}
private Gdk.Pixbuf? pixmap_to_pixbuf(Pixmap[] pixmaps) {
- if (pixmaps == null || pixmaps.length == 0)
+ if (pixmaps == null || pixmaps.length <= 0)
return null;
Pixmap pixmap = pixmaps[0];
@@ -467,9 +626,9 @@ public class TrayItem : Object {
.set_member_name("status").add_string_value(status.to_nick())
.set_member_name("category").add_string_value(category.to_nick())
.set_member_name("tooltip").add_string_value(tooltip_markup)
- .set_member_name("icon_theme_path").add_string_value(proxy.IconThemePath)
+ .set_member_name("icon_theme_path").add_string_value(icon_theme_path)
.set_member_name("icon_name").add_string_value(icon_name)
- .set_member_name("menu_path").add_string_value(proxy.Menu)
+ .set_member_name("menu_path").add_string_value(menu_path)
.set_member_name("is_menu").add_boolean_value(is_menu)
.end_object()
.get_root();