enjoy: improved plugin infrastructure.

Plugins can now be disabled and enabled (at least in infrastructure
terms, no UI or code to filter out enabled plugins).

Two new signals will be emitted to main loop:
  - ENJOY_EVENT_STARTED
  - ENJOY_EVENT_QUIT

Plugins will be enabled on start, disabled on quit. Quit will also
preserve the main loop until everything is done using it. It is
required for stuff like FSO that needs to talk to DBus to re-enable
the CPU policy.



SVN revision: 63163
This commit is contained in:
Gustavo Sverzut Barbieri 2011-09-04 18:37:05 +00:00
parent 416b55125d
commit cdc69191ba
6 changed files with 488 additions and 56 deletions

View File

@ -38,13 +38,175 @@ static const Ecore_Getopt options = {
}
};
uint32_t
struct _Enjoy_Plugin {
EINA_INLIST;
const char *name;
const Enjoy_Plugin_Api *api;
int priority;
Eina_Bool deleted:1;
Eina_Bool enabled:1;
};
static int plugins_walking = 0;
static int plugins_deleted = 0;
static Eina_Inlist *plugins_registry = NULL;
static int
_plugin_priority_cmp(const void *pa, const void *pb)
{
const Enjoy_Plugin *a = pa;
const Enjoy_Plugin *b = pb;
int r = a->priority - b->priority;
if (r) return r;
return strcmp(a->name, b->name);
}
EAPI Enjoy_Plugin *
enjoy_plugin_register(const char *name, const Enjoy_Plugin_Api *api, int priority)
{
Enjoy_Plugin *p;
if (!name)
{
ERR("Missing plugin name");
return NULL;
}
if (!api)
{
ERR("Missing plugin api");
return NULL;
}
if (api->version != ENJOY_PLUGIN_API_VERSION)
{
ERR("Invalid Enjoy_Plugin_Api version: plugin=%u, enjoy=%u",
api->version, ENJOY_PLUGIN_API_VERSION);
return NULL;
}
if (!api->enable)
{
ERR("%s: api->enable == NULL", name);
return NULL;
}
if (!api->disable)
{
ERR("%s: api->disable == NULL", name);
return NULL;
}
p = calloc(1, sizeof(Enjoy_Plugin));
if (!p)
{
ERR("Could not allocate plugin structure");
return NULL;
}
p->name = eina_stringshare_add(name);
p->api = api;
p->priority = priority;
plugins_registry = eina_inlist_sorted_insert
(plugins_registry, EINA_INLIST_GET(p), _plugin_priority_cmp);
DBG("plugin %s registered %p", name, p);
return p;
}
void
enjoy_plugins_walk(void)
{
plugins_walking++;
}
void
enjoy_plugins_unwalk(void)
{
Eina_Inlist *l;
plugins_walking--;
if (plugins_walking > 0) return;
plugins_walking = 0;
DBG("delete pending %d plugins", plugins_deleted);
for (l = plugins_registry; l != NULL && plugins_deleted > 0;)
{
Enjoy_Plugin *p = EINA_INLIST_CONTAINER_GET(l, Enjoy_Plugin);
l = l->next;
if (!p->deleted) continue;
DBG("deleted pending %s", p->name);
plugins_registry = eina_inlist_remove
(plugins_registry, EINA_INLIST_GET(p));
eina_stringshare_del(p->name);
free(p);
plugins_deleted--;
}
}
EAPI void
enjoy_plugin_unregister(Enjoy_Plugin *p)
{
if (!p)
{
ERR("No plugin given");
return;
}
if (p->deleted) return;
p->deleted = EINA_TRUE;
if (p->enabled) enjoy_plugin_disable(p);
DBG("plugin %s unregistered %p", p->name, p);
if (plugins_walking > 0)
{
plugins_deleted++;
return;
}
plugins_registry = eina_inlist_remove(plugins_registry, EINA_INLIST_GET(p));
eina_stringshare_del(p->name);
free(p);
}
Eina_Bool
enjoy_plugin_enable(Enjoy_Plugin *p)
{
Eina_Bool r;
if (!p)
{
ERR("No plugin given");
return EINA_FALSE;
}
if (p->enabled) return EINA_TRUE;
DBG("Enable plugin '%s'", p->name);
r = p->api->enable(p);
if (!r) ERR("Failed to enable plugin '%s'", p->name);
else p->enabled = EINA_TRUE;
return r;
}
Eina_Bool
enjoy_plugin_disable(Enjoy_Plugin *p)
{
Eina_Bool r;
if (!p)
{
ERR("No plugin given");
return EINA_FALSE;
}
if (!p->enabled) return EINA_TRUE;
DBG("Disable plugin '%s'", p->name);
r = p->api->disable(p);
if (!r) ERR("Failed to disable plugin '%s'", p->name);
p->enabled = EINA_FALSE;
return r;
}
EAPI uint32_t
enjoy_abi_version(void)
{
return ENJOY_ABI_VERSION;
}
char *
EAPI char *
enjoy_cache_dir_get(void)
{
static char *cache = NULL;
@ -88,6 +250,8 @@ enjoy_cache_dir_get(void)
return cache;
}
EAPI int ENJOY_EVENT_STARTED = -1;
EAPI int ENJOY_EVENT_QUIT = -1;
EAPI int ENJOY_EVENT_PLAYER_CAPS_CHANGE = -1;
EAPI int ENJOY_EVENT_PLAYER_STATUS_CHANGE = -1;
EAPI int ENJOY_EVENT_PLAYER_TRACK_CHANGE = -1;
@ -96,6 +260,8 @@ EAPI int ENJOY_EVENT_TRACKLIST_TRACKLIST_CHANGE = -1;
static void
enjoy_event_id_init(void)
{
ENJOY_EVENT_STARTED = ecore_event_type_new();
ENJOY_EVENT_QUIT = ecore_event_type_new();
ENJOY_EVENT_PLAYER_CAPS_CHANGE = ecore_event_type_new();
ENJOY_EVENT_PLAYER_STATUS_CHANGE = ecore_event_type_new();
ENJOY_EVENT_PLAYER_TRACK_CHANGE = ecore_event_type_new();
@ -153,6 +319,59 @@ enjoy_module_unload(void)
app.modules = NULL;
}
static int _quit_count = 0;
static void
_enjoy_event_quit_done(void *a __UNUSED__, void *b __UNUSED__)
{
if (_quit_count > 0) return;
ecore_main_loop_quit();
}
EAPI void
enjoy_quit(void)
{
static Eina_Bool _called = EINA_FALSE;
Enjoy_Plugin *p;
if (_called) return;
_called = EINA_TRUE;
enjoy_plugins_walk();
EINA_INLIST_FOREACH(plugins_registry, p)
enjoy_plugin_disable(p);
enjoy_plugins_unwalk();
ecore_event_add(ENJOY_EVENT_QUIT, NULL, _enjoy_event_quit_done, NULL);
}
EAPI void
enjoy_quit_freeze(void)
{
_quit_count++;
}
EAPI void
enjoy_quit_thaw(void)
{
_quit_count--;
if (_quit_count > 0) return;
ecore_main_loop_quit();
}
static Eina_Bool
_cb_started(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
{
Enjoy_Plugin *p;
enjoy_plugins_walk();
EINA_INLIST_FOREACH(plugins_registry, p)
enjoy_plugin_enable(p);
enjoy_plugins_unwalk();
return ECORE_CALLBACK_PASS_ON;
}
EAPI int
elm_main(int argc, char **argv)
{
@ -222,8 +441,12 @@ elm_main(int argc, char **argv)
cover_init();
enjoy_event_id_init();
ecore_event_handler_add(ENJOY_EVENT_STARTED, _cb_started, NULL);
enjoy_module_load();
/* will run after other events run, in the main loop */
ecore_event_add(ENJOY_EVENT_STARTED, NULL, NULL, NULL);
elm_run();
end:

View File

@ -11,6 +11,27 @@ typedef struct _Song Song;
typedef struct _Enjoy_Player_Status Enjoy_Player_Status;
typedef struct _Enjoy_Player_Caps Enjoy_Player_Caps;
/**
* Enjoy was started.
*
* Plugins that called enjoy_plugin_register() will be called from here,
* as well as when they are enabled/disabled.
*/
EAPI extern int ENJOY_EVENT_STARTED;
/**
* Enjoy is about to quit
*
* Plugins that called enjoy_plugin_register() will be called from here,
* as well as when they are enabled/disabled.
*
* Plugins should finalize its stuff. If mainloop is required any
* further, call enjoy_quit_freeze(), do its stuff and then
* enjoy_quit_thaw().
*
* When this is called, don't trust any of GUI is live. Just finish
* your stuff.
*/
EAPI extern int ENJOY_EVENT_QUIT;
/**
* Capabilities changed. Use enjoy_player_caps_get() for value.
*/
@ -19,7 +40,14 @@ EAPI extern int ENJOY_EVENT_PLAYER_CAPS_CHANGE;
* Status changed. Use enjoy_player_status_get() for value.
*/
EAPI extern int ENJOY_EVENT_PLAYER_STATUS_CHANGE;
/**
* Current track (song) changed. Use enjoy_song_current_get() for new song.
*/
EAPI extern int ENJOY_EVENT_PLAYER_TRACK_CHANGE;
/**
* Current list view (playlist) changed. Use enjoy_playlist_count() and
* enjoy_playlist_current_position_get() for new values.
*/
EAPI extern int ENJOY_EVENT_TRACKLIST_TRACKLIST_CHANGE;
struct _Enjoy_Player_Caps {
@ -45,19 +73,16 @@ struct _Enjoy_Player_Status {
Eina_Bool endless:1;
};
/**
* When you're loaded use ENJOY_ABI_CHECK() to see if you're okay or not.
*/
#define ENJOY_ABI_VERSION (1U)
EAPI uint32_t enjoy_abi_version(void) EINA_CONST;
#define ENJOY_ABI_CHECK() (ENJOY_ABI_VERSION == enjoy_abi_version())
EAPI void enjoy_quit(void);
EAPI void enjoy_quit_freeze(void);
EAPI void enjoy_quit_thaw(void);
EAPI char *enjoy_cache_dir_get(void);
EAPI Eina_Bool enjoy_repeat_get(void);
EAPI int32_t enjoy_playlist_current_position_get(void);
EAPI int32_t enjoy_position_get(void);
EAPI int32_t enjoy_volume_get(void);
EAPI int32_t enjoy_playlist_count(void);
EAPI int32_t enjoy_playlist_current_position_get(void);
EAPI const Song*enjoy_playlist_song_position_get(int32_t position);
EAPI const Song*enjoy_song_current_get(void);
EAPI const Song*enjoy_song_position_get(int32_t position);
@ -70,11 +95,43 @@ EAPI void enjoy_control_seek(uint64_t position);
EAPI void enjoy_control_shuffle_set(Eina_Bool param);
EAPI void enjoy_control_stop(void);
EAPI void enjoy_position_set(int32_t position);
EAPI void enjoy_quit(void);
EAPI void enjoy_repeat_set(Eina_Bool repeat);
EAPI void enjoy_volume_set(int32_t volume);
EAPI Enjoy_Player_Caps enjoy_player_caps_get(void);
EAPI Enjoy_Player_Status enjoy_player_status_get(void);
/**
* When you're loaded use ENJOY_ABI_CHECK() to see if you're okay or not.
*/
#define ENJOY_ABI_VERSION (1U)
EAPI uint32_t enjoy_abi_version(void) EINA_CONST;
#define ENJOY_ABI_CHECK() (ENJOY_ABI_VERSION == enjoy_abi_version())
typedef struct _Enjoy_Plugin Enjoy_Plugin;
typedef struct _Enjoy_Plugin_Api Enjoy_Plugin_Api;
struct _Enjoy_Plugin_Api {
#define ENJOY_PLUGIN_API_VERSION (1U)
unsigned int version;
Eina_Bool (*enable)(Enjoy_Plugin *plugin);
Eina_Bool (*disable)(Enjoy_Plugin *plugin);
};
typedef enum {
ENJOY_PLUGIN_PRIORITY_HIGH = -1000,
ENJOY_PLUGIN_PRIORITY_NORMAL = 0,
ENJOY_PLUGIN_PRIORITY_LOW = 1000
} Enjoy_Plugin_Priority;
/**
* Register the given plugin name with api at priority.
*
* Priority will define plugin order, but it will also consider the
* name, so relative positioning based on name is possible (use
* namespaces!)
*/
EAPI Enjoy_Plugin *enjoy_plugin_register(const char *name, const Enjoy_Plugin_Api *api, int priority);
EAPI void enjoy_plugin_unregister(Enjoy_Plugin *plugin);
#endif /* __PLUGIN_H__ */

View File

@ -178,4 +178,8 @@ void db_nameid_free(NameID *nameid);
#define db_artist_free(v) db_nameid_free(v)
#define db_genre_free(v) db_nameid_free(v)
Eina_Bool enjoy_plugin_enable(Enjoy_Plugin *p);
Eina_Bool enjoy_plugin_disable(Enjoy_Plugin *p);
#endif

View File

@ -301,6 +301,13 @@ _win_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_
if (w->db_path) eina_stringshare_del(w->db_path);
}
static void
_win_del_request(void *data __UNUSED__, Evas_Object *o, void *event_info __UNUSED__)
{
evas_object_hide(o);
enjoy_quit();
}
static void
_win_prev(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
{
@ -547,12 +554,6 @@ enjoy_control_seek(uint64_t position)
emotion_object_position_set(w->emotion, w->play.position);
}
EAPI void
enjoy_quit(void)
{
ecore_main_loop_quit();
}
EAPI Enjoy_Player_Caps
enjoy_player_caps_get(void)
{
@ -742,8 +743,9 @@ win_new(App *app)
elm_win_resize_object_add(w->win, w->bg);
evas_object_show(w->bg);
elm_win_autodel_set(w->win, 1); // TODO
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
elm_win_autodel_set(w->win, EINA_FALSE);
evas_object_smart_callback_add
(w->win, "delete,request", _win_del_request, w);
snprintf(path, sizeof(path), "%s/media.db", app->configdir);
w->db_path = eina_stringshare_add(path);

View File

@ -1,5 +1,6 @@
#include <Eina.h>
#include <E_DBus.h>
#include <Ecore.h>
#include "plugin.h"
static int _fso_log_domain = -1;
@ -30,53 +31,130 @@ static int _fso_log_domain = -1;
#define FSO_OUSAGED_OBJECT_PATH "/org/freesmartphone/Usage"
#define FSO_OUSAGED_INTERFACE "org.freesmartphone.Usage"
static E_DBus_Connection *sysconn = NULL;
static E_DBus_Connection *conn = NULL;
/* callbacks */
typedef struct _FSO_Cb_Data
{
void (*func)(void *data, Eina_Bool error);
void *data;
} FSO_Cb_Data;
static void
fso_request_reource_cb(void *data, DBusMessage *replymsg, DBusError *error)
fso_request_resource_cb(void *data, DBusMessage *replymsg __UNUSED__, DBusError *error)
{
FSO_Cb_Data *d = data;
Eina_Bool e = EINA_FALSE;
DBG("Request sent to fsousaged to enable resource.");
if (error && dbus_error_is_set(error))
ERR("Error requesting FSO resource: %s - %s", error->name, error->message);
{
ERR("Error requesting FSO resource: %s - %s",
error->name, error->message);
e = EINA_TRUE;
}
if ((d) && (d->func))
d->func(d->data, e);
free(d);
}
static void
fso_release_reource_cb(void *data, DBusMessage *replymsg, DBusError *error)
fso_release_resource_cb(void *data, DBusMessage *replymsg __UNUSED__, DBusError *error)
{
FSO_Cb_Data *d = data;
Eina_Bool e = EINA_FALSE;
DBG("Request sent to fsousaged to disable resource.");
if (error && dbus_error_is_set(error))
ERR("Error releasing FSO resource: %s - %s", error->name, error->message);
{
ERR("Error releasing FSO resource: %s - %s",
error->name, error->message);
e = EINA_TRUE;
}
if ((d) && (d->func))
d->func(d->data, e);
free(d);
}
static void
fso_request_resource(const char *resource)
fso_request_resource(const char *resource, void (*func)(void *data, Eina_Bool error), const void *data)
{
FSO_Cb_Data *d = NULL;
DBusMessage *msg = dbus_message_new_method_call
(FSO_OUSAGED_SERVICE, FSO_OUSAGED_OBJECT_PATH, FSO_OUSAGED_INTERFACE,
"RequestResource");
dbus_message_append_args
(msg, DBUS_TYPE_STRING, &resource, DBUS_TYPE_INVALID);
e_dbus_message_send(sysconn, msg, fso_request_reource_cb, -1, NULL);
if (func)
{
d = malloc(sizeof(FSO_Cb_Data));
if (d)
{
d->func = func;
d->data = (void *)data;
}
}
e_dbus_message_send(conn, msg, fso_request_resource_cb, -1, d);
dbus_message_unref(msg);
}
static void
fso_release_resource(const char *resource)
fso_release_resource(const char *resource, void (*func)(void *data, Eina_Bool error), const void *data)
{
FSO_Cb_Data *d = NULL;
DBusMessage *msg = dbus_message_new_method_call
(FSO_OUSAGED_SERVICE, FSO_OUSAGED_OBJECT_PATH, FSO_OUSAGED_INTERFACE,
"ReleaseResource");
dbus_message_append_args
(msg, DBUS_TYPE_STRING, &resource, DBUS_TYPE_INVALID);
e_dbus_message_send(sysconn, msg, fso_release_reource_cb, -1, NULL);
if (func)
{
d = malloc(sizeof(FSO_Cb_Data));
if (d)
{
d->func = func;
d->data = (void *)data;
}
}
e_dbus_message_send(conn, msg, fso_release_resource_cb, -1, d);
dbus_message_unref(msg);
}
static Eina_Bool
fso_enable(Enjoy_Plugin *p __UNUSED__)
{
fso_request_resource("CPU", NULL, NULL);
return EINA_TRUE;
}
static void
_cb_fso_release_resource_done(void *data __UNUSED__, Eina_Bool error __UNUSED__)
{
enjoy_quit_thaw();
}
static Eina_Bool
fso_disable(Enjoy_Plugin *p __UNUSED__)
{
enjoy_quit_freeze();
fso_release_resource("CPU", _cb_fso_release_resource_done, NULL);
return EINA_TRUE;
}
static const Enjoy_Plugin_Api api = {
ENJOY_PLUGIN_API_VERSION,
fso_enable,
fso_disable
};
static Eina_Bool
fso_init(void)
{
@ -95,26 +173,36 @@ fso_init(void)
{
ERR("ABI versions differ: enjoy=%u, fso=%u",
enjoy_abi_version(), ENJOY_ABI_VERSION);
eina_log_domain_unregister(_fso_log_domain);
_fso_log_domain = -1;
goto error;
}
if (sysconn) return EINA_TRUE;
if (conn) return EINA_TRUE;
e_dbus_init();
sysconn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
fso_request_resource("CPU");
conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
if (!conn)
{
ERR("Could not get DBus session bus");
goto error;
}
enjoy_plugin_register("sys/fso", &api, ENJOY_PLUGIN_PRIORITY_NORMAL);
return EINA_TRUE;
error:
eina_log_domain_unregister(_fso_log_domain);
_fso_log_domain = -1;
return EINA_FALSE;
}
static void
fso_shutdown(void)
{
if (!sysconn) return;
fso_release_resource("CPU");
if (!conn) return;
e_dbus_shutdown();
sysconn = NULL;
conn = NULL;
if (_fso_log_domain >= 0)
{
eina_log_domain_unregister(_fso_log_domain);

View File

@ -106,11 +106,9 @@ struct _MPRIS_Signal {
static E_DBus_Connection *conn = NULL;
static E_DBus_Object *bus_obj = NULL;
static Eina_Hash *interface_list = NULL;
static Ecore_Event_Handler *event_handler_caps_change,
*event_handler_status_change,
*event_handler_track_change,
*event_handler_tracklist_change;
static Eina_List *ev_handlers = NULL;
static const char *object_list[] = { ROOT_NAME, TRACKLIST_NAME, PLAYER_NAME, NULL };
@ -232,6 +230,52 @@ _cb_player_tracklist_change(void *data __UNUSED__, int type __UNUSED__, void *ev
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
mpris_enable(Enjoy_Plugin *p __UNUSED__)
{
#define EV_HANDLER(ev, func, data) \
ev_handlers = eina_list_append \
(ev_handlers, ecore_event_handler_add(ev, func, data))
EV_HANDLER(ENJOY_EVENT_PLAYER_CAPS_CHANGE, _cb_player_caps_change, NULL);
EV_HANDLER(ENJOY_EVENT_PLAYER_STATUS_CHANGE, _cb_player_status_change, NULL);
EV_HANDLER(ENJOY_EVENT_PLAYER_TRACK_CHANGE, _cb_player_track_change, NULL);
EV_HANDLER(ENJOY_EVENT_TRACKLIST_TRACKLIST_CHANGE,
_cb_player_tracklist_change, NULL);
#undef EV_HANDLER
e_dbus_request_name(conn, APPLICATION_NAME, 0, _cb_dbus_request_name, NULL);
return EINA_TRUE;
}
static Eina_Bool
mpris_disable(Enjoy_Plugin *p __UNUSED__)
{
Ecore_Event_Handler *eh;
if (interface_list)
{
eina_hash_free(interface_list);
interface_list = NULL;
}
if (bus_obj)
{
e_dbus_object_free(bus_obj);
bus_obj = NULL;
}
EINA_LIST_FREE(ev_handlers, eh)
ecore_event_handler_del(eh);
return EINA_TRUE;
}
static const Enjoy_Plugin_Api api = {
ENJOY_PLUGIN_API_VERSION,
mpris_enable,
mpris_disable
};
static Eina_Bool
mpris_init(void)
{
@ -250,34 +294,36 @@ mpris_init(void)
{
ERR("ABI versions differ: enjoy=%u, mpris=%u",
enjoy_abi_version(), ENJOY_ABI_VERSION);
eina_log_domain_unregister(_mpris_log_domain);
_mpris_log_domain = -1;
goto error;
}
if (conn) return EINA_TRUE;
e_dbus_init();
conn = e_dbus_bus_get(DBUS_BUS_SESSION);
if (conn)
e_dbus_request_name(conn, APPLICATION_NAME, 0, _cb_dbus_request_name, NULL);
event_handler_caps_change = ecore_event_handler_add(ENJOY_EVENT_PLAYER_CAPS_CHANGE, _cb_player_caps_change, NULL);
event_handler_status_change = ecore_event_handler_add(ENJOY_EVENT_PLAYER_STATUS_CHANGE, _cb_player_status_change, NULL);
event_handler_track_change = ecore_event_handler_add(ENJOY_EVENT_PLAYER_TRACK_CHANGE, _cb_player_track_change, NULL);
event_handler_tracklist_change = ecore_event_handler_add(ENJOY_EVENT_TRACKLIST_TRACKLIST_CHANGE, _cb_player_tracklist_change, NULL);
if (!conn)
{
ERR("Could not get DBus session bus");
goto error;
}
enjoy_plugin_register("listener/mpris", &api, ENJOY_PLUGIN_PRIORITY_HIGH);
return EINA_TRUE;
error:
eina_log_domain_unregister(_mpris_log_domain);
_mpris_log_domain = -1;
return EINA_FALSE;
}
void
mpris_shutdown(void)
{
if (!conn) return;
ecore_event_handler_del(event_handler_caps_change);
ecore_event_handler_del(event_handler_status_change);
ecore_event_handler_del(event_handler_track_change);
ecore_event_handler_del(event_handler_tracklist_change);
eina_hash_free(interface_list);
e_dbus_shutdown();
conn = NULL;
interface_list = NULL;
if (_mpris_log_domain >= 0)
{
@ -297,6 +343,18 @@ _cb_dbus_request_name(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
dbus_error_free(err);
return;
}
if (interface_list)
{
eina_hash_free(interface_list);
interface_list = NULL;
}
if (bus_obj)
{
e_dbus_object_free(bus_obj);
bus_obj = NULL;
}
dbus_error_init(&new_err);
dbus_message_get_args(msg, &new_err, DBUS_TYPE_UINT32, &msgtype, DBUS_TYPE_INVALID);
@ -310,9 +368,9 @@ _cb_dbus_request_name(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
for (i = 0; object_list[i]; i++)
{
E_DBus_Object *object = e_dbus_object_add(conn, object_list[i], NULL);
bus_obj = e_dbus_object_add(conn, object_list[i], NULL);
E_DBus_Interface *interface = e_dbus_interface_new(PLAYER_INTERFACE_NAME);
e_dbus_object_interface_attach(object, interface);
e_dbus_object_interface_attach(bus_obj, interface);
eina_hash_add(interface_list, object_list[i], interface);
}