cache systray items for each dbus session

the current spec does not directly require any behavior from clients
when a systray host, leading to an issue where clients do not re-register
their items when a new host appears

when using an in-process systray watcher, as the current implementation does,
the best choice for maintaining consistency for systray items across restarts
is to cache them according to the current dbus session. the process of setting
up the item will validate it on subsequent restarts, and changes to the session
will clear the cache

fix T2786
This commit is contained in:
Mike Blumenkrantz 2015-10-14 16:30:41 -04:00
parent 71f7720669
commit 432d1e3776
4 changed files with 89 additions and 5 deletions

View File

@ -391,10 +391,19 @@ e_modapi_init(E_Module *m)
ctx = calloc(1, sizeof(Systray_Context));
ctx->conf_edd = E_CONFIG_DD_NEW("Systray_Config", Systray_Config);
ctx->notifier_item_edd = E_CONFIG_DD_NEW("Notifier_Item_Cache", Notifier_Item_Cache);
#undef T
#undef D
#define T Notifier_Item_Cache
#define D ctx->notifier_item_edd
E_CONFIG_VAL(D, T, path, STR);
#undef T
#undef D
#define T Systray_Config
#define D ctx->conf_edd
E_CONFIG_VAL(D, T, dbus, STR);
E_CONFIG_HASH(D, T, items, ctx->notifier_item_edd);
ctx->config = e_config_domain_load(_name, ctx->conf_edd);
if (!ctx->config)
ctx->config = calloc(1, sizeof(Systray_Config));
@ -415,6 +424,7 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED)
systray_notifier_host_shutdown();
E_CONFIG_DD_FREE(ctx->conf_edd);
E_CONFIG_DD_FREE(ctx->notifier_item_edd);
free(ctx->config);
free(ctx);
return 1;

View File

@ -14,7 +14,7 @@ typedef struct _Context_Notifier_Host Context_Notifier_Host;
typedef struct _Instance_Notifier_Host Instance_Notifier_Host;
typedef struct _Notifier_Item Notifier_Item;
typedef struct _Systray_Context Systray_Context;
typedef struct _E_Config_Dialog_Data Systray_Config;
typedef struct Systray_Config Systray_Config;
struct _E_Config_Dialog_Data
{
@ -24,6 +24,7 @@ struct _Systray_Context
{
Systray_Config *config;
E_Config_DD *conf_edd;
E_Config_DD *notifier_item_edd;
};
struct _Instance
@ -41,6 +42,17 @@ struct _Instance
} job;
};
typedef struct Notifier_Item_Cache
{
Eina_Stringshare *path;
} Notifier_Item_Cache;
struct Systray_Config
{
Eina_Stringshare *dbus;
Eina_Hash *items;
};
E_Gadcon_Orient systray_orient_get(const Instance *inst);
const E_Gadcon *systray_gadcon_get(const Instance *inst);
E_Gadcon_Client *systray_gadcon_client_get(const Instance *inst);

View File

@ -340,6 +340,7 @@ static void
notifier_item_add(const char *path, const char *bus_id, Context_Notifier_Host *ctx)
{
Eldbus_Proxy *proxy;
Notifier_Item_Cache *nic;
Notifier_Item *item = calloc(1, sizeof(Notifier_Item));
Eldbus_Signal_Handler *s;
EINA_SAFETY_ON_NULL_RETURN(item);
@ -368,6 +369,11 @@ notifier_item_add(const char *path, const char *bus_id, Context_Notifier_Host *c
item->signals = eina_list_append(item->signals, s);
s = eldbus_proxy_signal_handler_add(proxy, "NewTitle", new_title_cb, item);
item->signals = eina_list_append(item->signals, s);
if (eina_hash_find(systray_ctx_get()->config->items, bus_id)) return;
nic = malloc(sizeof(Notifier_Item_Cache));
nic->path = eina_stringshare_ref(path);
eina_hash_add(systray_ctx_get()->config->items, bus_id, nic);
e_config_save_queue();
}
static void

View File

@ -27,16 +27,31 @@ static void
item_name_monitor_cb(void *data, const char *bus, const char *old_id EINA_UNUSED, const char *new_id)
{
const char *svc, *service = data;
Eina_List *l;
l = eina_list_data_find_list(items, service);
if (strcmp(new_id, ""))
return;
{
if (l) return;
items = eina_list_append(items, service);
svc = strchr(service, '/') + 1;
registered_cb(user_data, bus, svc);
return;
}
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, bus, svc);
if (l)
{
items = eina_list_remove_list(items, l);
if (unregistered_cb)
unregistered_cb(user_data, bus, svc);
}
bus = eina_stringshare_add(bus);
if (eina_hash_del_by_key(systray_ctx_get()->config->items, bus))
e_config_save_queue();
eina_stringshare_del(bus);
eldbus_name_owner_changed_callback_del(conn, bus, item_name_monitor_cb, service);
eina_stringshare_del(service);
}
@ -152,9 +167,19 @@ static const Eldbus_Service_Interface_Desc iface_desc = {
IFACE, methods, signals, properties, properties_get, NULL
};
static void
systray_notifier_item_hash_del(Notifier_Item_Cache *item)
{
eina_stringshare_del(item->path);
free(item);
}
void
systray_notifier_dbus_watcher_start(Eldbus_Connection *connection, E_Notifier_Watcher_Item_Registered_Cb registered, E_Notifier_Watcher_Item_Unregistered_Cb unregistered, const void *data)
{
const char *dbus;
EINA_SAFETY_ON_TRUE_RETURN(!!conn);
conn = connection;
iface = eldbus_service_interface_register(conn, PATH, &iface_desc);
@ -162,6 +187,37 @@ systray_notifier_dbus_watcher_start(Eldbus_Connection *connection, E_Notifier_Wa
unregistered_cb = unregistered;
user_data = (void *)data;
host_service = eina_stringshare_add("internal");
dbus = getenv("DBUS_SESSION_BUS_ADDRESS");
if (systray_ctx_get()->config->items)
eina_hash_free_cb_set(systray_ctx_get()->config->items, (Eina_Free_Cb)systray_notifier_item_hash_del);
if (systray_ctx_get()->config->dbus && systray_ctx_get()->config->items)
{
if (!strcmp(systray_ctx_get()->config->dbus, dbus))
{
Eina_Iterator *it;
Eina_Hash_Tuple *t;
it = eina_hash_iterator_tuple_new(systray_ctx_get()->config->items);
EINA_ITERATOR_FOREACH(it, t)
{
char buf[1024];
Notifier_Item_Cache *nic = t->data;
snprintf(buf, sizeof(buf), "%s/%s", (char*)t->key, nic->path);
eldbus_name_owner_changed_callback_add(conn, t->key,
item_name_monitor_cb, eina_stringshare_add(buf),
EINA_TRUE);
}
eina_iterator_free(it);
return;
}
}
eina_stringshare_replace(&systray_ctx_get()->config->dbus, dbus);
if (systray_ctx_get()->config->items)
eina_hash_free_buckets(systray_ctx_get()->config->items);
else
systray_ctx_get()->config->items = eina_hash_stringshared_new((Eina_Free_Cb)systray_notifier_item_hash_del);
e_config_save_queue();
}
void