From 0978d22f8e354176052d19acd10143b7fb79c11d Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Tue, 22 Sep 2015 18:38:34 -0400 Subject: [PATCH] fix systray implementation of notifier watcher (StatusNotifierItem) previously, this would throw dbus errors (or not) and then do nothing in many cases. now it manages bus/path names more effectively and falls back to binary image data when an icon path is not available fix T2626 and probably some others --- src/modules/systray/e_mod_notifier_host.c | 21 ++++- src/modules/systray/e_mod_notifier_host_dbus.c | 96 ++++++++++++++++++++--- src/modules/systray/e_mod_notifier_host_private.h | 4 + src/modules/systray/e_mod_notifier_watcher.c | 21 ++--- 4 files changed, 116 insertions(+), 26 deletions(-) diff --git a/src/modules/systray/e_mod_notifier_host.c b/src/modules/systray/e_mod_notifier_host.c index 3fe3340..e3420b4 100644 --- a/src/modules/systray/e_mod_notifier_host.c +++ b/src/modules/systray/e_mod_notifier_host.c @@ -42,6 +42,8 @@ systray_notifier_item_free(Notifier_Item *item) e_dbusmenu_unload(item->menu_data); eina_stringshare_del(item->bus_id); eina_stringshare_del(item->path); + free(item->imgdata); + free(item->attnimgdata); if (item->attention_icon_name) eina_stringshare_del(item->attention_icon_name); if (item->icon_name) @@ -64,7 +66,7 @@ systray_notifier_item_free(Notifier_Item *item) } static void -image_load(const char *name, const char *path, Evas_Object *image) +image_load(const char *name, const char *path, uint32_t *imgdata, int w, int h, Evas_Object *image) { const char **ext, *exts[] = { @@ -96,7 +98,18 @@ image_load(const char *name, const char *path, Evas_Object *image) } } } - if (!e_util_icon_theme_set(image, name)) + if (name && name[0] && e_util_icon_theme_set(image, name)) return; + if (imgdata) + { + Evas_Object *o; + + o = evas_object_image_filled_add(evas_object_evas_get(image)); + evas_object_image_alpha_set(o, 1); + evas_object_image_size_set(o, w, h); + evas_object_image_data_set(o, imgdata); + e_icon_image_object_set(image, o); + } + else e_util_icon_theme_set(image, "dialog-error"); } @@ -261,7 +274,7 @@ jump_search: { case STATUS_ACTIVE: { - image_load(item->icon_name, item->icon_path, ii->icon); + image_load(item->icon_name, item->icon_path, item->imgdata, item->imgw, item->imgh, ii->icon); if (!evas_object_visible_get(ii->icon)) { systray_edje_box_append(host_inst->inst, ii->icon); @@ -280,7 +293,7 @@ jump_search: } case STATUS_ATTENTION: { - image_load(item->attention_icon_name, item->icon_path, ii->icon); + image_load(item->attention_icon_name, item->icon_path, item->attnimgdata, item->attnimgw, item->attnimgh, ii->icon); if (!evas_object_visible_get(ii->icon)) { systray_edje_box_append(host_inst->inst, ii->icon); diff --git a/src/modules/systray/e_mod_notifier_host_dbus.c b/src/modules/systray/e_mod_notifier_host_dbus.c index f5de199..77ae5b5 100644 --- a/src/modules/systray/e_mod_notifier_host_dbus.c +++ b/src/modules/systray/e_mod_notifier_host_dbus.c @@ -14,6 +14,8 @@ extern const char *Category_Names[]; extern const char *Status_Names[]; +static Eina_Stringshare *DBUS_PATH; + typedef struct _Notifier_Host_Data { Instance_Notifier_Host *host_inst; void *data; @@ -57,6 +59,36 @@ id_find(const char *s, const char *names[]) } static void +icon_pixmap_deserialize(Eldbus_Message_Iter *variant, uint32_t **data, int *w, int *h) +{ + Eldbus_Message_Iter *iter, *struc; + + *data = NULL; + *w = *h = 0; + eldbus_message_iter_arguments_get(variant, "a(iiay)", &iter); + while (eldbus_message_iter_get_and_next(iter, 'r', &struc)) + { + Eldbus_Message_Iter *imgdata; + + if (eldbus_message_iter_arguments_get(struc, "iiay", w, h, &imgdata)) + { + uint32_t *img; + int len; + + if (eldbus_message_iter_fixed_array_get(imgdata, 'y', &img, &len)) + { + unsigned int pos; + + *data = malloc(len * sizeof(int)); + for (pos = 0; pos < (unsigned int)len; pos++) + (*data)[pos] = eina_swap32(img[pos]); + return; + } + } + } +} + +static void item_prop_get(void *data, const void *key, Eldbus_Message_Iter *var) { Notifier_Item *item = data; @@ -73,6 +105,16 @@ item_prop_get(void *data, const void *key, Eldbus_Message_Iter *var) eldbus_message_iter_arguments_get(var, "s", &name); eina_stringshare_replace(&item->icon_name, name); } + else if (!strcmp(key, "IconPixmap")) + { + free(item->imgdata); + icon_pixmap_deserialize(var, &item->imgdata, &item->imgw, &item->imgh); + } + else if (!strcmp(key, "AttentionIconPixmap")) + { + free(item->attnimgdata); + icon_pixmap_deserialize(var, &item->attnimgdata, &item->attnimgw, &item->attnimgh); + } else if (!strcmp(key, "AttentionIconName")) { const char *name; @@ -191,12 +233,27 @@ basic_prop_get(const char *propname, void *data, const Eldbus_Message *msg) } static void +attention_icon_pixmap_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) +{ + Notifier_Item *item = data; + Eldbus_Message_Iter *variant; + + if (!eldbus_message_arguments_get(msg, "v", &variant)) return; + free(item->attnimgdata); + icon_pixmap_deserialize(variant, &item->attnimgdata, &item->attnimgw, &item->attnimgh); + systray_notifier_item_update(item); +} + +static void attention_icon_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { Notifier_Item *item = data; const char *propname = "AttentionIconName"; basic_prop_get(propname, item, msg); - systray_notifier_item_update(item); + if ((!item->attention_icon_name) || (!item->attention_icon_name[0])) + eldbus_proxy_property_get(item->proxy, "AttentionIconPixmap", attention_icon_pixmap_get_cb, item); + else + systray_notifier_item_update(item); } static void @@ -207,12 +264,27 @@ new_attention_icon_cb(void *data, const Eldbus_Message *msg EINA_UNUSED) } static void +icon_pixmap_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) +{ + Notifier_Item *item = data; + Eldbus_Message_Iter *variant; + + if (!eldbus_message_arguments_get(msg, "v", &variant)) return; + free(item->imgdata); + icon_pixmap_deserialize(variant, &item->imgdata, &item->imgw, &item->imgh); + systray_notifier_item_update(item); +} + +static void icon_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { Notifier_Item *item = data; const char *propname = "IconName"; basic_prop_get(propname, item, msg); - systray_notifier_item_update(item); + if ((!item->icon_name) || (!item->icon_name[0])) + eldbus_proxy_property_get(item->proxy, "IconPixmap", icon_pixmap_get_cb, item); + else + systray_notifier_item_update(item); } static void @@ -373,28 +445,24 @@ notifier_items_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pen } static void -item_registered_local_cb(void *data, const char *service) +item_registered_local_cb(void *data, const char *bus) { - const char *bus, *path; Context_Notifier_Host *ctx = data; - if (service_string_parse(service, &path, &bus)) - notifier_item_add(path, bus, ctx); + notifier_item_add(eina_stringshare_ref(DBUS_PATH), eina_stringshare_add(bus), ctx); } static void -item_unregistered_local_cb(void *data, const char *service) +item_unregistered_local_cb(void *data, const char *bus) { - const char *bus, *path; Context_Notifier_Host *ctx = data; Notifier_Item *item; + Eina_Stringshare *s; - if (!service_string_parse(service, &path, &bus)) - return; - item = notifier_item_find(path, bus, ctx); + s = eina_stringshare_add(bus); + item = notifier_item_find(DBUS_PATH, s, ctx); if (item) systray_notifier_item_free(item); - eina_stringshare_del(path); - eina_stringshare_del(bus); + eina_stringshare_del(s); } static void @@ -447,6 +515,7 @@ systray_notifier_dbus_init(Context_Notifier_Host *ctx) eldbus_init(); ctx->conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION); if (!ctx->conn) return; + DBUS_PATH = eina_stringshare_add("/StatusNotifierItem"); p = eldbus_name_request(ctx->conn, WATCHER_BUS, ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING, name_request_cb, ctx); @@ -473,6 +542,7 @@ void systray_notifier_dbus_shutdown(Context_Notifier_Host *ctx) eldbus_object_unref(obj); ctx->watcher = NULL; } + eina_stringshare_replace(&DBUS_PATH, NULL); eldbus_connection_unref(ctx->conn); eldbus_shutdown(); } diff --git a/src/modules/systray/e_mod_notifier_host_private.h b/src/modules/systray/e_mod_notifier_host_private.h index f318916..ad3bcd6 100644 --- a/src/modules/systray/e_mod_notifier_host_private.h +++ b/src/modules/systray/e_mod_notifier_host_private.h @@ -57,6 +57,10 @@ struct _Notifier_Item const char *menu_path; E_DBusMenu_Ctx *menu_data; Eina_List *signals; + uint32_t *imgdata; + int imgw, imgh; + uint32_t *attnimgdata; + int attnimgw, attnimgh; }; typedef void (*E_Notifier_Watcher_Item_Registered_Cb)(void *data, const char *service); diff --git a/src/modules/systray/e_mod_notifier_watcher.c b/src/modules/systray/e_mod_notifier_watcher.c index e31ab45..666a5b4 100644 --- a/src/modules/systray/e_mod_notifier_watcher.c +++ b/src/modules/systray/e_mod_notifier_watcher.c @@ -26,29 +26,32 @@ enum static void item_name_monitor_cb(void *data, const char *bus, const char *old_id EINA_UNUSED, const char *new_id) { - const char *service = data; + const char *svc, *service = data; if (strcmp(new_id, "")) return; - eldbus_service_signal_emit(iface, ITEM_UNREGISTERED, service); + svc = strchr(service, '/') + 1; + + eldbus_service_signal_emit(iface, ITEM_UNREGISTERED, svc); items = eina_list_remove(items, service); if (unregistered_cb) - unregistered_cb(user_data, service); + unregistered_cb(user_data, bus); + eldbus_name_owner_changed_callback_del(conn, svc, item_name_monitor_cb, service); eina_stringshare_del(service); - eldbus_name_owner_changed_callback_del(conn, bus, item_name_monitor_cb, service); } static Eldbus_Message * register_item_cb(const Eldbus_Service_Interface *s_iface, const Eldbus_Message *msg) { - const char *service; + const char *service, *svc; char buf[1024]; if (!eldbus_message_arguments_get(msg, "s", &service)) return NULL; + svc = service; - snprintf(buf, sizeof(buf), "%s%s", eldbus_message_sender_get(msg), service); + snprintf(buf, sizeof(buf), "%s/%s", eldbus_message_sender_get(msg), service); service = eina_stringshare_add(buf); if (eina_list_data_find(items, service)) { @@ -57,13 +60,13 @@ register_item_cb(const Eldbus_Service_Interface *s_iface, const Eldbus_Message * } items = eina_list_append(items, service); - eldbus_service_signal_emit(s_iface, ITEM_REGISTERED, service); - eldbus_name_owner_changed_callback_add(conn, eldbus_message_sender_get(msg), + eldbus_service_signal_emit(s_iface, ITEM_REGISTERED, svc); + eldbus_name_owner_changed_callback_add(conn, svc, item_name_monitor_cb, service, EINA_FALSE); if (registered_cb) - registered_cb(user_data, service); + registered_cb(user_data, svc); return eldbus_message_method_return_new(msg); } -- 2.7.4