fix systray to work with spec-breaking apps, eg. steam

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
This commit is contained in:
Mike Blumenkrantz 2015-10-04 08:41:07 -04:00
parent 4d30674ab8
commit 6ff98d8a39
3 changed files with 18 additions and 16 deletions

View File

@ -14,8 +14,6 @@
extern const char *Category_Names[]; extern const char *Category_Names[];
extern const char *Status_Names[]; extern const char *Status_Names[];
static Eina_Stringshare *DBUS_PATH;
typedef struct _Notifier_Host_Data { typedef struct _Notifier_Host_Data {
Instance_Notifier_Host *host_inst; Instance_Notifier_Host *host_inst;
void *data; void *data;
@ -445,24 +443,26 @@ notifier_items_get_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pen
} }
static void 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; 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 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; Context_Notifier_Host *ctx = data;
Notifier_Item *item; Notifier_Item *item;
Eina_Stringshare *s; Eina_Stringshare *s, *p;
s = eina_stringshare_add(bus); 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) if (item)
systray_notifier_item_free(item); systray_notifier_item_free(item);
eina_stringshare_del(s); eina_stringshare_del(s);
eina_stringshare_del(p);
} }
static void static void
@ -515,7 +515,6 @@ systray_notifier_dbus_init(Context_Notifier_Host *ctx)
eldbus_init(); eldbus_init();
ctx->conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION); ctx->conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
if (!ctx->conn) return; if (!ctx->conn) return;
DBUS_PATH = eina_stringshare_add("/StatusNotifierItem");
p = eldbus_name_request(ctx->conn, p = eldbus_name_request(ctx->conn,
WATCHER_BUS, ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING, WATCHER_BUS, ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING,
name_request_cb, ctx); name_request_cb, ctx);
@ -542,7 +541,6 @@ void systray_notifier_dbus_shutdown(Context_Notifier_Host *ctx)
eldbus_object_unref(obj); eldbus_object_unref(obj);
ctx->watcher = NULL; ctx->watcher = NULL;
} }
eina_stringshare_replace(&DBUS_PATH, NULL);
eldbus_connection_unref(ctx->conn); eldbus_connection_unref(ctx->conn);
eldbus_shutdown(); eldbus_shutdown();
} }

View File

@ -63,8 +63,8 @@ struct _Notifier_Item
int attnimgw, attnimgh; int attnimgw, attnimgh;
}; };
typedef void (*E_Notifier_Watcher_Item_Registered_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); 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_update_menu(void *data, E_DBusMenu_Item *new_root_item);
void systray_notifier_item_update(Notifier_Item *item); void systray_notifier_item_update(Notifier_Item *item);

View 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); eldbus_service_signal_emit(iface, ITEM_UNREGISTERED, svc);
items = eina_list_remove(items, service); items = eina_list_remove(items, service);
if (unregistered_cb) if (unregistered_cb)
unregistered_cb(user_data, bus); unregistered_cb(user_data, bus, svc);
eldbus_name_owner_changed_callback_del(conn, svc, item_name_monitor_cb, service); eldbus_name_owner_changed_callback_del(conn, bus, item_name_monitor_cb, service);
eina_stringshare_del(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; const char *service, *svc;
char buf[1024]; char buf[1024];
Eina_Bool stupid;
if (!eldbus_message_arguments_get(msg, "s", &service)) if (!eldbus_message_arguments_get(msg, "s", &service))
return NULL; return NULL;
svc = service; 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); service = eina_stringshare_add(buf);
if (eina_list_data_find(items, service)) 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); items = eina_list_append(items, service);
eldbus_service_signal_emit(s_iface, ITEM_REGISTERED, svc); 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, item_name_monitor_cb, service,
EINA_FALSE); EINA_FALSE);
if (registered_cb) 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); return eldbus_message_method_return_new(msg);
} }