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 *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();
}

View 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);

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);
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);
}