fix systray to work with spec-breaking apps, eg. steam
authorMike Blumenkrantz <zmike@osg.samsung.com>
Sun, 4 Oct 2015 12:41:07 +0000 (08:41 -0400)
committerMike Blumenkrantz <zmike@osg.samsung.com>
Sun, 4 Oct 2015 12:49:01 +0000 (08:49 -0400)
according to the StatusNotifierItem specification, applications
register "service org.freedesktop.StatusNotifierItem-PID-ID" on the
session bus, and then "must register the unique instance name
to the StatusNotifierWatcher".

some applications, such as steam, instead register the path that they
will run on (/org/ayatana/NotificationItem/steam) and then expect the
watcher to register the method call's send id bus: this is totally bogus.

to catch this, when registering the new item the enlightenment watcher must
first determine if the item is spec-conforming. if yes, proceed as normal.
if no, pretend the application knows what it's doing and try to make things
work as expected anyway

for more details, read the full spec here
http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem

fix T2763

src/modules/systray/e_mod_notifier_host_dbus.c
src/modules/systray/e_mod_notifier_host_private.h
src/modules/systray/e_mod_notifier_watcher.c

index 77ae5b5..8eba2b1 100644 (file)
@@ -14,8 +14,6 @@
 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;
@@ -445,24 +443,26 @@ notifier_items_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pen
 }
 
 static void
-item_registered_local_cb(void *data, const char *bus)
+item_registered_local_cb(void *data, const char *bus, const char *path)
 {
    Context_Notifier_Host *ctx = data;
-   notifier_item_add(eina_stringshare_ref(DBUS_PATH), eina_stringshare_add(bus), ctx);
+   notifier_item_add(eina_stringshare_add(path), eina_stringshare_add(bus), ctx);
 }
 
 static void
-item_unregistered_local_cb(void *data, const char *bus)
+item_unregistered_local_cb(void *data, const char *bus, const char *path)
 {
    Context_Notifier_Host *ctx = data;
    Notifier_Item *item;
-   Eina_Stringshare *s;
+   Eina_Stringshare *s, *p;
 
    s = eina_stringshare_add(bus);
-   item = notifier_item_find(DBUS_PATH, s, ctx);
+   p = eina_stringshare_add(path);
+   item = notifier_item_find(p, s, ctx);
    if (item)
      systray_notifier_item_free(item);
    eina_stringshare_del(s);
+   eina_stringshare_del(p);
 }
 
 static void
@@ -515,7 +515,6 @@ 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);
@@ -542,7 +541,6 @@ 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();
 }
index ad3bcd6..a7e2ea8 100644 (file)
@@ -63,8 +63,8 @@ struct _Notifier_Item
    int attnimgw, attnimgh;
 };
 
-typedef void (*E_Notifier_Watcher_Item_Registered_Cb)(void *data, const char *service);
-typedef void (*E_Notifier_Watcher_Item_Unregistered_Cb)(void *data, const char *service);
+typedef void (*E_Notifier_Watcher_Item_Registered_Cb)(void *data, const char *service, const char *path);
+typedef void (*E_Notifier_Watcher_Item_Unregistered_Cb)(void *data, const char *service, const char *path);
 
 void systray_notifier_update_menu(void *data, E_DBusMenu_Item *new_root_item);
 void systray_notifier_item_update(Notifier_Item *item);
index 666a5b4..3e9a47b 100644 (file)
@@ -36,8 +36,8 @@ item_name_monitor_cb(void *data, const char *bus, const char *old_id EINA_UNUSED
    eldbus_service_signal_emit(iface, ITEM_UNREGISTERED, svc);
    items = eina_list_remove(items, service);
    if (unregistered_cb)
-     unregistered_cb(user_data, bus);
-   eldbus_name_owner_changed_callback_del(conn, svc, item_name_monitor_cb, service);
+     unregistered_cb(user_data, bus, svc);
+   eldbus_name_owner_changed_callback_del(conn, bus, item_name_monitor_cb, service);
    eina_stringshare_del(service);
 }
 
@@ -46,12 +46,16 @@ register_item_cb(const Eldbus_Service_Interface *s_iface, const Eldbus_Message *
 {
    const char *service, *svc;
    char buf[1024];
+   Eina_Bool stupid;
 
    if (!eldbus_message_arguments_get(msg, "s", &service))
      return NULL;
    svc = service;
+   /* if stupid, this app does not conform to http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/
+    * and is expecting to have its send id watched as it is not providing a real bus name here */
+   stupid = !!strncmp(svc, "org.", 4);
 
-   snprintf(buf, sizeof(buf), "%s/%s", eldbus_message_sender_get(msg), service);
+   snprintf(buf, sizeof(buf), "%s/%s", stupid ? eldbus_message_sender_get(msg) : svc, stupid ? svc : "/StatusNotifierItem");
    service = eina_stringshare_add(buf);
    if (eina_list_data_find(items, service))
      {
@@ -61,12 +65,12 @@ 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, svc);
-   eldbus_name_owner_changed_callback_add(conn, svc,
+   eldbus_name_owner_changed_callback_add(conn, stupid ? eldbus_message_sender_get(msg) : svc,
                                          item_name_monitor_cb, service,
                                          EINA_FALSE);
 
    if (registered_cb)
-     registered_cb(user_data, svc);
+     registered_cb(user_data, stupid ? eldbus_message_sender_get(msg) : svc, stupid ? svc : "/StatusNotifierItem");
    return eldbus_message_method_return_new(msg);
 }