enjoy: single instance using DBus name org.enlightenment.enjoy

Also provide minor Control interface, later to be extended with DB
management.



SVN revision: 63180
This commit is contained in:
Gustavo Sverzut Barbieri 2011-09-04 23:27:15 +00:00
parent 862f5dd781
commit 74ca53a96f
8 changed files with 234 additions and 46 deletions

14
TODO
View File

@ -9,24 +9,22 @@ Consider the following order to implement this todo:
- window geometry - window geometry
- volume - volume
- repeat and shuffle states - repeat and shuffle states
3. Single instance with dbus: 3. Create preferences infrastructure:
- just get a name
4. Create preferences infrastructure:
- new elm_layout style (in Elementary) for preferences - new elm_layout style (in Elementary) for preferences
- choose media backend (xine, gstreamer) - choose media backend (xine, gstreamer)
5. Create library manager preferences: 4. Create library manager preferences:
- add/remove directories (or at least choose folder) - add/remove directories (or at least choose folder)
- rescan, stop-scan. with progress feedback - rescan, stop-scan. with progress feedback
- option to choose rescan schedule - option to choose rescan schedule
- remove command line scan - remove command line scan
6. Refactor some features into plugins 5. Refactor some features into plugins
- define ecore_events and plugin interface - define ecore_events and plugin interface
- coverart-lastfm - coverart-lastfm
- cover art local fs lookup - cover art local fs lookup
7. Modular plugins (elm_module) 6. Modular plugins (elm_module)
- selection saved in eet - selection saved in eet
- gui to select enabled plugins - gui to select enabled plugins
8. Save/Resume between runs (list, nowplaying and navigation) 7. Save/Resume between runs (list, nowplaying and navigation)
Library (from "Preferences") Library (from "Preferences")
@ -90,8 +88,6 @@ Work to cover the above cases:
More More
---- ----
* Single instance using dbus (otherwise configuration will be screwed with
multiple processes writing it);
* Save/Resume state between runs (start from the same place as last time); * Save/Resume state between runs (start from the same place as last time);
- window geometry - window geometry
- volume - volume

View File

@ -43,6 +43,9 @@ VMIC=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $3);}'`
SNAP=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $4);}'` SNAP=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $4);}'`
version_info=`expr $VMAJ + $VMIN`":$VMIC:$VMIN" version_info=`expr $VMAJ + $VMIN`":$VMIC:$VMIN"
m4_ifdef([v_rev], , [m4_define([v_rev], [0])]) m4_ifdef([v_rev], , [m4_define([v_rev], [0])])
AC_DEFINE_UNQUOTED(VMAJ, [v_maj], [Major version])
AC_DEFINE_UNQUOTED(VMIN, [v_min], [Minor version])
AC_DEFINE_UNQUOTED(VMIC, [v_mic], [Micro version])
AC_DEFINE_UNQUOTED(VREV, [v_rev], [Revison]) AC_DEFINE_UNQUOTED(VREV, [v_rev], [Revison])
AC_SUBST(VMAJ) AC_SUBST(VMAJ)
AC_SUBST(version_info) AC_SUBST(version_info)

View File

@ -20,7 +20,7 @@ endif
enjoy_LDADD = @ELEMENTARY_LIBS@ @EMOTION_LIBS@ @LMS_LIBS@ @SQLITE3_LIBS@ @EDBUS_LIBS@ enjoy_LDADD = @ELEMENTARY_LIBS@ @EMOTION_LIBS@ @LMS_LIBS@ @SQLITE3_LIBS@ @EDBUS_LIBS@
enjoy_CFLAGS = -rdynamic enjoy_CFLAGS = -rdynamic
enjoy_SOURCES = main.c win.c db.c list.c page.c cover.c nowplaying.c libmanager.c coverart-lastfm.c enjoy_SOURCES = main.c win.c db.c list.c page.c cover.c nowplaying.c libmanager.c coverart-lastfm.c dbus.c
if BUILD_QUICKLAUNCH if BUILD_QUICKLAUNCH
############################################################################ ############################################################################

View File

@ -26,6 +26,7 @@ struct _LastFM_Cover_Request {
}; };
static char *_local_cache_dir = NULL; static char *_local_cache_dir = NULL;
static Eina_Bool _lastfm_inited = EINA_FALSE;
/* /*
* This API Key belongs to leandro@profusion.mobi -- do not use it for commercial * This API Key belongs to leandro@profusion.mobi -- do not use it for commercial
@ -281,6 +282,9 @@ lastfm_cover_init(void)
{ {
int i; int i;
if (_lastfm_inited) return;
_lastfm_inited = EINA_TRUE;
ecore_init(); ecore_init();
ecore_file_init(); ecore_file_init();
ecore_con_url_init(); ecore_con_url_init();
@ -320,6 +324,7 @@ lastfm_cover_shutdown(void)
{ {
int i; int i;
if (!_lastfm_inited) return;
for (i = 0; disc_number_regexes[i].str; i++) for (i = 0; disc_number_regexes[i].str; i++)
{ {
regfree(disc_number_regexes[i].exp); regfree(disc_number_regexes[i].exp);

135
src/bin/dbus.c Normal file
View File

@ -0,0 +1,135 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "private.h"
#include <E_DBus.h>
#define DBUS_NAME "org.enlightenment.enjoy"
#define DBUS_IFACE "org.enlightenment.enjoy.Control"
#define DBUS_PATH "/org/enlightenment/enjoy/Control"
static E_DBus_Connection *conn = NULL;
static E_DBus_Object *dbus_obj = NULL;
static E_DBus_Interface *dbus_iface = NULL;
typedef struct _Enjoy_DBus_Method Enjoy_DBus_Method;
struct _Enjoy_DBus_Method {
const char *name;
const char *par;
const char *ret;
E_DBus_Method_Cb cb;
};
static DBusMessage *
_cb_dbus_quit(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
{
enjoy_quit();
return dbus_message_new_method_return(msg);
}
static DBusMessage *
_cb_dbus_version(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter, siter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &siter);
#define APPEND_UINT16(val) \
do { \
unsigned short _tmp_val = val; \
dbus_message_iter_append_basic(&siter, DBUS_TYPE_UINT16, &_tmp_val); \
} while (0)
APPEND_UINT16(VMAJ);
APPEND_UINT16(VMIN);
APPEND_UINT16(VMIC);
#undef APPEND_UINT16
dbus_message_iter_close_container(&iter, &siter);
return reply;
}
/* Avoid duplicating MPRIS -- see src/plugins/mpris */
static const Enjoy_DBus_Method control_methods[] = {
{"Quit", "", "", _cb_dbus_quit},
{"Version", "", "(qqq)", _cb_dbus_version},
/* TODO: DB management */
{NULL, NULL, NULL, NULL}
};
static void
_dbus_methods_add(E_DBus_Interface *iface, const Enjoy_DBus_Method desc[])
{
const Enjoy_DBus_Method *itr = desc;
for (; itr->name; itr++)
e_dbus_interface_method_add(iface, itr->name, itr->par, itr->ret, itr->cb);
}
static void
_cb_dbus_request_name(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
{
DBusError new_err;
dbus_uint32_t msgtype;
E_DBus_Interface *iface;
if (dbus_error_is_set(err))
{
ERR("Could not get DBus name: %s", err->message);
goto error;
}
dbus_error_init(&new_err);
dbus_message_get_args
(msg, &new_err, DBUS_TYPE_UINT32, &msgtype, DBUS_TYPE_INVALID);
if (msgtype != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
{
ERR("Could not get the DBus name: reply=%d", msgtype);
goto error;
}
INF("Got DBus name - unique instance running.");
dbus_obj = e_dbus_object_add(conn, DBUS_PATH, NULL);
if (!dbus_obj)
{
ERR("Could not create Control DBus object.");
goto error;
}
dbus_iface = e_dbus_interface_new(DBUS_IFACE);
e_dbus_object_interface_attach(dbus_obj, dbus_iface);
_dbus_methods_add(dbus_iface, control_methods);
/* will run after other events run, in the main loop */
ecore_event_add(ENJOY_EVENT_STARTED, NULL, NULL, NULL);
return;
error:
ecore_main_loop_quit();
return;
}
Eina_Bool
enjoy_dbus_init(void)
{
e_dbus_init();
conn = e_dbus_bus_get(DBUS_BUS_SESSION);
if (!conn)
{
ERR("Could not get DBus session bus");
return EINA_FALSE;
}
e_dbus_request_name
(conn, DBUS_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE,
_cb_dbus_request_name, NULL);
}
void
enjoy_dbus_shutdown(void)
{
if (dbus_obj) e_dbus_object_free(dbus_obj);
if (dbus_iface) e_dbus_interface_unref(dbus_iface);
conn = NULL;
e_dbus_shutdown();
}

View File

@ -319,6 +319,7 @@ enjoy_module_load(void)
static void static void
enjoy_module_unload(void) enjoy_module_unload(void)
{ {
if (!app.modules) return;
while (eina_array_count_get(app.modules)) while (eina_array_count_get(app.modules))
eina_module_unload(eina_array_pop(app.modules)); eina_module_unload(eina_array_pop(app.modules));
eina_array_free(app.modules); eina_array_free(app.modules);
@ -370,6 +371,17 @@ _cb_started(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
{ {
Enjoy_Plugin *p; Enjoy_Plugin *p;
app.win = win_new(&app);
if (!app.win)
{
ERR("Could not create main window");
enjoy_quit();
return ECORE_CALLBACK_PASS_ON;
}
cover_init();
enjoy_module_load();
enjoy_plugins_walk(); enjoy_plugins_walk();
EINA_INLIST_FOREACH(plugins_registry, p) EINA_INLIST_FOREACH(plugins_registry, p)
enjoy_plugin_enable(p); enjoy_plugin_enable(p);
@ -378,6 +390,35 @@ _cb_started(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
return ECORE_CALLBACK_PASS_ON; return ECORE_CALLBACK_PASS_ON;
} }
static DBusMessage *
_cb_dbus_quit(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
{
enjoy_quit();
return dbus_message_new_method_return(msg);
}
static DBusMessage *
_cb_dbus_version(E_DBus_Object *obj __UNUSED__, DBusMessage *msg)
{
DBusMessage *reply = dbus_message_new_method_return(msg);
DBusMessageIter iter, siter;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &siter);
#define APPEND_UINT16(val) \
do { \
unsigned short _tmp_val = val; \
dbus_message_iter_append_basic(&siter, DBUS_TYPE_UINT16, &_tmp_val); \
} while (0)
APPEND_UINT16(VMAJ);
APPEND_UINT16(VMIN);
APPEND_UINT16(VMIC);
#undef APPEND_UINT16
dbus_message_iter_close_container(&iter, &siter);
return reply;
}
EAPI int EAPI int
elm_main(int argc, char **argv) elm_main(int argc, char **argv)
{ {
@ -396,6 +437,8 @@ elm_main(int argc, char **argv)
ECORE_GETOPT_VALUE_NONE ECORE_GETOPT_VALUE_NONE
}; };
memset(&app, 0, sizeof(app));
#if ENABLE_NLS #if ENABLE_NLS
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
@ -442,28 +485,31 @@ elm_main(int argc, char **argv)
goto end; goto end;
} }
app.win = win_new(&app);
if (!app.win) goto end;
cover_init();
enjoy_event_id_init(); enjoy_event_id_init();
ecore_event_handler_add(ENJOY_EVENT_STARTED, _cb_started, NULL); ecore_event_handler_add(ENJOY_EVENT_STARTED, _cb_started, NULL);
enjoy_module_load(); /* will call ENJOY_EVENT_STARTED whenever it's ready */
if (!enjoy_dbus_init())
{
ERR("Could not start Enjoy's DBus subsystem");
r = -1;
goto end;
}
/* will run after other events run, in the main loop */
ecore_event_add(ENJOY_EVENT_STARTED, NULL, NULL, NULL);
elm_run(); elm_run();
end: end:
EINA_LIST_FREE(app.add_dirs, s) free(s); EINA_LIST_FREE(app.add_dirs, s) free(s);
EINA_LIST_FREE(app.del_dirs, s) free(s); EINA_LIST_FREE(app.del_dirs, s) free(s);
enjoy_module_unload();
cover_shutdown();
enjoy_dbus_shutdown();
eina_log_domain_unregister(_log_domain); eina_log_domain_unregister(_log_domain);
_log_domain = -1; _log_domain = -1;
elm_shutdown(); elm_shutdown();
enjoy_module_unload();
cover_shutdown();
return r; return r;
} }

View File

@ -181,5 +181,7 @@ void db_nameid_free(NameID *nameid);
Eina_Bool enjoy_plugin_enable(Enjoy_Plugin *p); Eina_Bool enjoy_plugin_enable(Enjoy_Plugin *p);
Eina_Bool enjoy_plugin_disable(Enjoy_Plugin *p); Eina_Bool enjoy_plugin_disable(Enjoy_Plugin *p);
Eina_Bool enjoy_dbus_init(void);
void enjoy_dbus_shutdown(void);
#endif #endif

View File

@ -244,7 +244,8 @@ mpris_enable(Enjoy_Plugin *p __UNUSED__)
_cb_player_tracklist_change, NULL); _cb_player_tracklist_change, NULL);
#undef EV_HANDLER #undef EV_HANDLER
e_dbus_request_name(conn, APPLICATION_NAME, 0, _cb_dbus_request_name, NULL); e_dbus_request_name(conn, APPLICATION_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE,
_cb_dbus_request_name, NULL);
return EINA_TRUE; return EINA_TRUE;
} }
@ -337,10 +338,11 @@ _cb_dbus_request_name(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
{ {
DBusError new_err; DBusError new_err;
dbus_uint32_t msgtype; dbus_uint32_t msgtype;
int i;
if (dbus_error_is_set(err)) if (dbus_error_is_set(err))
{ {
dbus_error_free(err); ERR("Could not get DBus name: %s", err->message);
return; return;
} }
@ -355,33 +357,32 @@ _cb_dbus_request_name(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
e_dbus_object_free(bus_obj); e_dbus_object_free(bus_obj);
bus_obj = NULL; bus_obj = NULL;
} }
dbus_error_init(&new_err); dbus_error_init(&new_err);
dbus_message_get_args(msg, &new_err, DBUS_TYPE_UINT32, &msgtype, DBUS_TYPE_INVALID); dbus_message_get_args
(msg, &new_err, DBUS_TYPE_UINT32, &msgtype, DBUS_TYPE_INVALID);
if (msgtype == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER || if (msgtype != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
msgtype == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER)
{ {
int i; ERR("Could not get the DBus name: reply=%d", msgtype);
return;
interface_list = eina_hash_string_small_new((Eina_Free_Cb)e_dbus_interface_unref);
for (i = 0; object_list[i]; i++)
{
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(bus_obj, interface);
eina_hash_add(interface_list, object_list[i], interface);
}
_mpris_signals_add(PLAYER_NAME, mpris_player_signals);
_mpris_signals_add(TRACKLIST_NAME, mpris_tracklist_signals);
_mpris_methods_add(ROOT_NAME, mpris_root_methods);
_mpris_methods_add(PLAYER_NAME, mpris_player_methods);
_mpris_methods_add(TRACKLIST_NAME, mpris_tracklist_methods);
} }
interface_list = eina_hash_string_small_new
((Eina_Free_Cb)e_dbus_interface_unref);
for (i = 0; object_list[i]; i++)
{
bus_obj = e_dbus_object_add(conn, object_list[i], NULL);
E_DBus_Interface *iface = e_dbus_interface_new(PLAYER_INTERFACE_NAME);
e_dbus_object_interface_attach(bus_obj, iface);
eina_hash_add(interface_list, object_list[i], iface);
}
_mpris_signals_add(PLAYER_NAME, mpris_player_signals);
_mpris_signals_add(TRACKLIST_NAME, mpris_tracklist_signals);
_mpris_methods_add(ROOT_NAME, mpris_root_methods);
_mpris_methods_add(PLAYER_NAME, mpris_player_methods);
_mpris_methods_add(TRACKLIST_NAME, mpris_tracklist_methods);
} }
static void static void