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
- volume
- repeat and shuffle states
3. Single instance with dbus:
- just get a name
4. Create preferences infrastructure:
3. Create preferences infrastructure:
- new elm_layout style (in Elementary) for preferences
- choose media backend (xine, gstreamer)
5. Create library manager preferences:
4. Create library manager preferences:
- add/remove directories (or at least choose folder)
- rescan, stop-scan. with progress feedback
- option to choose rescan schedule
- remove command line scan
6. Refactor some features into plugins
5. Refactor some features into plugins
- define ecore_events and plugin interface
- coverart-lastfm
- cover art local fs lookup
7. Modular plugins (elm_module)
6. Modular plugins (elm_module)
- selection saved in eet
- 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")
@ -90,8 +88,6 @@ Work to cover the above cases:
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);
- window geometry
- 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);}'`
version_info=`expr $VMAJ + $VMIN`":$VMIC:$VMIN"
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_SUBST(VMAJ)
AC_SUBST(version_info)

View File

@ -20,7 +20,7 @@ endif
enjoy_LDADD = @ELEMENTARY_LIBS@ @EMOTION_LIBS@ @LMS_LIBS@ @SQLITE3_LIBS@ @EDBUS_LIBS@
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
############################################################################

View File

@ -26,6 +26,7 @@ struct _LastFM_Cover_Request {
};
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
@ -281,6 +282,9 @@ lastfm_cover_init(void)
{
int i;
if (_lastfm_inited) return;
_lastfm_inited = EINA_TRUE;
ecore_init();
ecore_file_init();
ecore_con_url_init();
@ -320,6 +324,7 @@ lastfm_cover_shutdown(void)
{
int i;
if (!_lastfm_inited) return;
for (i = 0; disc_number_regexes[i].str; i++)
{
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
enjoy_module_unload(void)
{
if (!app.modules) return;
while (eina_array_count_get(app.modules))
eina_module_unload(eina_array_pop(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;
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();
EINA_INLIST_FOREACH(plugins_registry, 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;
}
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
elm_main(int argc, char **argv)
{
@ -396,6 +437,8 @@ elm_main(int argc, char **argv)
ECORE_GETOPT_VALUE_NONE
};
memset(&app, 0, sizeof(app));
#if ENABLE_NLS
setlocale(LC_ALL, "");
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
@ -442,28 +485,31 @@ elm_main(int argc, char **argv)
goto end;
}
app.win = win_new(&app);
if (!app.win) goto end;
cover_init();
enjoy_event_id_init();
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();
end:
EINA_LIST_FREE(app.add_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);
_log_domain = -1;
elm_shutdown();
enjoy_module_unload();
cover_shutdown();
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_disable(Enjoy_Plugin *p);
Eina_Bool enjoy_dbus_init(void);
void enjoy_dbus_shutdown(void);
#endif

View File

@ -244,7 +244,8 @@ mpris_enable(Enjoy_Plugin *p __UNUSED__)
_cb_player_tracklist_change, NULL);
#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;
}
@ -337,10 +338,11 @@ _cb_dbus_request_name(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
{
DBusError new_err;
dbus_uint32_t msgtype;
int i;
if (dbus_error_is_set(err))
{
dbus_error_free(err);
ERR("Could not get DBus name: %s", err->message);
return;
}
@ -355,33 +357,32 @@ _cb_dbus_request_name(void *data __UNUSED__, DBusMessage *msg, DBusError *err)
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);
if (msgtype == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ||
msgtype == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER)
dbus_message_get_args
(msg, &new_err, DBUS_TYPE_UINT32, &msgtype, DBUS_TYPE_INVALID);
if (msgtype != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
{
int i;
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);
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 *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